diff --git a/.asf.yaml b/.asf.yaml index 0ca3390e94..36f6293d04 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -16,7 +16,7 @@ # github: - description: EventMesh is a dynamic event-driven application runtime used to decouple the application and backend middleware layer, which supports a wide range of use cases that encompass complex multi-cloud, widely distributed topologies using diverse technology stacks. + description: EventMesh is a new generation serverless event middleware for building distributed event-driven applications. homepage: https://eventmesh.apache.org/ labels: - pubsub @@ -26,7 +26,7 @@ github: - event-streaming - event-sourcing - event-governance - - event-routing + - event-connector - cloud-native - serverless - serverless-workflow @@ -35,15 +35,47 @@ github: - cqrs - multi-runtime - microservice - - state-management + - hacktoberfest enabled_merge_buttons: - squash: true - merge: true - rebase: false + squash: true + merge: false + rebase: false protected_branches: master: required_status_checks: - strict: true + strict: false + contexts: + - dependency-review + - Build (ubuntu-latest, 8, java) + - Build (ubuntu-latest, 11, java) required_pull_request_reviews: dismiss_stale_reviews: true - required_approving_review_count: 1 + required_approving_review_count: 2 + # Attempt to make the auto-generated github emails more easily readable in email clients. + custom_subjects: + new_pr: "[PR] {title} ({repository})" + close_pr: "Re: [PR] {title} ({repository})" + comment_pr: "Re: [PR] {title} ({repository})" + diffcomment: "Re: [PR] {title} ({repository})" + merge_pr: "Re: [PR] {title} ({repository})" + new_issue: "[I] {title} ({repository})" + comment_issue: "Re: [I] {title} ({repository})" + close_issue: "Re: [I] {title} ({repository})" + catchall: "[GH] {title} ({repository})" + new_discussion: "[D] {title} ({repository})" + edit_discussion: "Re: [D] {title} ({repository})" + close_discussion: "Re: [D] {title} ({repository})" + close_discussion_with_comment: "Re: [D] {title} ({repository})" + reopen_discussion: "Re: [D] {title} ({repository})" + new_comment_discussion: "Re: [D] {title} ({repository})" + edit_comment_discussion: "Re: [D] {title} ({repository})" + delete_comment_discussion: "Re: [D] {title} ({repository})" +notifications: + commits: commits@eventmesh.apache.org + # Send all issue emails (new, closed, comments) to issues@ + issues: issues@eventmesh.apache.org + # Send new/closed PR notifications to dev@ + pullrequests_status: dev@eventmesh.apache.org + # Send individual PR comments/reviews to issues@ + pullrequests_comment: issues@eventmesh.apache.org + jira_options: link label worklog diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..c0f64a8361 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +dist/ +build/ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..b27bb300d7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +# +# 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. +# +*.sh text eol=lf +gradlew text eol=lf +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 7eefbc7944..a19b99ed3d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -55,6 +55,11 @@ body: description: Describe the EventMesh version. options: - master + - 1.10.0 + - 1.9.0 + - 1.8.0 + - 1.7.0 + - 1.6.0 - 1.5.0 - 1.4.0 - 1.3.0 @@ -89,6 +94,7 @@ body: description: Anything else we need to know? placeholder: > Add your debug logs here. + render: Java validations: required: false @@ -101,6 +107,14 @@ body: options: - label: Yes I am willing to submit a PR! + - type: checkboxes + attributes: + label: Code of Conduct + description: > + The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.. + options: + - label: I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) * + - type: markdown attributes: value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/documentation_related.yml b/.github/ISSUE_TEMPLATE/documentation_related.yml index 9841b8caf8..1fa6ef875a 100644 --- a/.github/ISSUE_TEMPLATE/documentation_related.yml +++ b/.github/ISSUE_TEMPLATE/documentation_related.yml @@ -55,6 +55,14 @@ body: options: - label: Yes I am willing to submit a PR! + - type: checkboxes + attributes: + label: Code of Conduct + description: > + The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.. + options: + - label: I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) * + - type: markdown attributes: - value: "Thanks for completing our form!" \ No newline at end of file + value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.yml b/.github/ISSUE_TEMPLATE/enhancement_request.yml index b4bee79aba..cd9e0c59ae 100644 --- a/.github/ISSUE_TEMPLATE/enhancement_request.yml +++ b/.github/ISSUE_TEMPLATE/enhancement_request.yml @@ -42,7 +42,7 @@ body: label: Enhancement Request description: Describe the suggestion. placeholder: > - First of all: Have you checked the docs https://github.com/apache/incubator-eventmesh/tree/develop/docs, + First of all: Have you checked the docs https://github.com/apache/eventmesh/tree/develop/docs, or GitHub issues whether someone else has already reported your issue? validations: required: true @@ -65,6 +65,13 @@ body: options: - label: Yes I am willing to submit a PR! + - type: checkboxes + attributes: + label: Code of Conduct + description: > + The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.. + options: + - label: I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) * - type: markdown attributes: - value: "Thanks for completing our form!" \ No newline at end of file + value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index b04ec7aff9..fe9d032068 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -42,7 +42,7 @@ body: label: Feature Request description: Describe the feature. placeholder: > - First of all: Have you checked the docs https://github.com/apache/incubator-eventmesh/tree/develop/docs, + First of all: Have you checked the docs https://github.com/apache/eventmesh/tree/develop/docs, or GitHub issues whether someone else has already reported your issue? Maybe the feature already exists? validations: @@ -57,6 +57,14 @@ body: options: - label: Yes I am willing to submit a PR! + - type: checkboxes + attributes: + label: Code of Conduct + description: > + The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.. + options: + - label: I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) * + - type: markdown attributes: value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/unit_test.yml b/.github/ISSUE_TEMPLATE/unit_test.yml index 4dcfdafc64..82ce502400 100644 --- a/.github/ISSUE_TEMPLATE/unit_test.yml +++ b/.github/ISSUE_TEMPLATE/unit_test.yml @@ -41,7 +41,7 @@ body: attributes: label: Read the unit testing guidelines description: > - Read the [unit testing guidelines](https://github.com/apache/incubator-eventmesh/blob/master/docs/en/contribute/02-write-unit-test.md) before writing unit test code. + Read the [unit testing guidelines](https://eventmesh.apache.org/community/contribute/write-unit-test) before writing unit test code. options: - label: > I have read. @@ -52,7 +52,7 @@ body: label: Unit test request description: Describe the unit test. placeholder: > - First of all: Have you checked the docs https://github.com/apache/incubator-eventmesh/tree/develop/docs, + First of all: Have you checked the docs https://github.com/apache/eventmesh/tree/develop/docs, or GitHub issues whether someone else has already reported your issue? Maybe the unit tests you want to do have already been done? validations: @@ -83,4 +83,4 @@ body: - type: markdown attributes: - value: "Thanks for completing our form!" \ No newline at end of file + value: "Thanks for completing our form!" diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1bc7ac8d31..428cda5f55 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -20,24 +20,20 @@ --> -Fixes #. +Fixes #issue_id ### Motivation *Explain the content here.* *Explain why you want to make the changes and what problem you're trying to solve.* - - ### Modifications *Describe the modifications you've done.* - - ### Documentation - Does this pull request introduce a new feature? (yes / no) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..508014de35 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,44 @@ +# +# 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. +# + +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/" + open-pull-requests-limit: 15 + schedule: + interval: "monthly" + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-major", "version-update:semver-patch" ] + - dependency-name: "software.amazon.awssdk:s3" + update-types: [ "version-update:semver-patch" ] + - dependency-name: "com.aliyun:dingtalk" + update-types: [ "version-update:semver-patch" ] + - package-ecosystem: "gomod" + directory: "eventmesh-sdks/eventmesh-sdk-go" + # Disabled temporarily since the Go SDK is not integrated with CI + open-pull-requests-limit: 0 + schedule: + interval: "monthly" + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-major", "version-update:semver-patch" ] + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/auto-dependabot.yml b/.github/workflows/auto-dependabot.yml new file mode 100644 index 0000000000..347bd3782c --- /dev/null +++ b/.github/workflows/auto-dependabot.yml @@ -0,0 +1,42 @@ +# +# 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. +# + +name: Dependabot Auto-approve +on: pull_request_target + +permissions: + contents: write + pull-requests: write + +jobs: + # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions + # Pull request Auto merge is not enabled for this repository + dependabot: + runs-on: ubuntu-latest + if: github.event.pull_request.user.login == 'dependabot[bot]' + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Approve PR + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d17ca19232..d961cb20ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,29 +1,29 @@ # -# 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 +# 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 +# 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. +# 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. # name: "Continuous Integration" on: push: - branches: ['*'] + branches: + - '**' + - '!dependabot/**' pull_request: - branches: [ '*' ] + branches: [ '**' ] jobs: build: @@ -31,53 +31,53 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macOS-latest] - java: [8, 11] + os: [ ubuntu-latest, macOS-latest ] + java: [ 8, 11 ] + language: [ 'java' ] runs-on: ${{ matrix.os }} steps: - name: Checkout repository - uses: actions/checkout@v2 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: actions/checkout@v6 with: - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - languages: ${{ matrix.language }} + submodules: true + + - name: Build C SDK + if: matrix.language == 'cpp' + run: make -C ./eventmesh-sdks/eventmesh-sdk-c + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e #v6.1.0 + + - name: Set up JDK 11 + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 11 + + - name: GenerateGrammarSource + run: ./gradlew clean generateGrammarSource --parallel --daemon --scan + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v5 with: + distribution: 'zulu' java-version: ${{ matrix.java }} + # https://docs.gradle.org/current/userguide/performance.html - name: Build - run: ./gradlew clean build jar dist jacocoTestReport + run: > + ./gradlew clean build dist jacocoTestReport --parallel --daemon --scan + -x spotlessJava -x generateGrammarSource -x generateDistLicense -x checkDeniedLicense + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Install plugin - run: ./gradlew installPlugin - - - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v1 - - - name: Upload coverage report to codecov.io - run: bash <(curl -s https://codecov.io/bash) || echo 'Failed to upload coverage report!' - - license-check: - name: License Check - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Check license header - uses: apache/skywalking-eyes@main + run: ./gradlew installPlugin --scan env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - - name: Check third party dependencies - run: | - ./gradlew clean jar dist -x test -x checkstyleMain -x javaDoc && ./gradlew installPlugin && ./gradlew tar && sh tools/dependency-check/check-dependencies.sh && echo "Thirty party dependencies check success" + - name: Upload coverage report to codecov.io + run: bash <(curl -s https://codecov.io/bash) || echo 'Failed to upload coverage report!' \ No newline at end of file diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml new file mode 100644 index 0000000000..efc28fd485 --- /dev/null +++ b/.github/workflows/code-scanning.yml @@ -0,0 +1,74 @@ +# +# 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. +# + +name: 'Code Scanning' + +on: + push: + branches: + - '**' + - '!dependabot/**' + pull_request: + branches: [ '**' ] + +permissions: + security-events: write + contents: read + +jobs: + build: + name: Analyze + strategy: + fail-fast: false + matrix: + language: [ 'java', 'go' ] + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + languages: ${{ matrix.language }} + + - name: Set up JDK 11 + if: matrix.language == 'java' + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 11 + + - name: Setup Gradle + if: matrix.language == 'java' + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e #v6.1.0 + with: + cache-disabled: true + + - name: Build + if: matrix.language == 'java' + run: ./gradlew clean assemble compileTestJava --parallel --daemon --scan + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v3 \ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000000..ff8179b011 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,50 @@ +# +# 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. +# + +name: Docker +on: + release: + types: [released] + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + apache/eventmesh + + - name: Build and push + uses: docker/build-push-action@v6 + with: + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + file: ./docker/Dockerfile_jdk8 + context: ./ \ No newline at end of file diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index ccb8df0061..ea438849df 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -19,30 +19,31 @@ name: Greetings -on: [pull_request_target, issues] +on: [ pull_request_target, issues ] jobs: greeting: name: Greeting runs-on: ubuntu-latest steps: - - uses: actions/first-interaction@v1 + - uses: actions/first-interaction@v1.3.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} issue-message: | - Welcome to the Apache EventMesh (incubating) community!! + Welcome to the Apache EventMesh community!! We are glad that you are contributing by opening this issue. :D Please make sure to include all the relevant context. We will be here shortly. If you are interested in contributing to our project, please let us know! - You can check out our contributing guide on [contributing to EventMesh](https://github.com/apache/incubator-eventmesh/blob/develop/CONTRIBUTING.md). + You can check out our contributing guide on [contributing to EventMesh](https://eventmesh.apache.org/community/contribute/contribute). Want to get closer to the community? - WeChat Group: - ![wechat_qr](https://github.com/apache/incubator-eventmesh/blob/develop/docs/images/mesh-helper.png?raw=true) + |WeChat Assistant|WeChat Public Account|Slack| + |-|-|-| + |||[Join Slack Chat](https://join.slack.com/t/the-asf/shared_invite/zt-1y375qcox-UW1898e4kZE_pqrNsrBM2g)| Mailing Lists: | Name | Description |Subscribe |Unsubscribe|Archive @@ -50,9 +51,10 @@ jobs: |Users |User support and questions mailing list| [Subscribe](mailto:users-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:users-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?users@eventmesh.apache.org)| |Development |Development related discussions| [Subscribe](mailto:dev-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:dev-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?dev@eventmesh.apache.org)| |Commits |All commits to repositories| [Subscribe](mailto:commits-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:commits-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org)| + |Issues |Issues or PRs comments and reviews| [Subscribe](mailto:commits-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:commits-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org)| pr-message: | - Welcome to the Apache EventMesh (incubating) community!! + Welcome to the Apache EventMesh community!! This is your first PR in our project. We're very excited to have you onboard contributing. Your contributions are greatly appreciated! Please make sure that the changes are covered by tests. @@ -61,8 +63,9 @@ jobs: Want to get closer to the community? - WeChat Group: - ![wechat_qr](https://github.com/apache/incubator-eventmesh/blob/develop/docs/images/mesh-helper.png?raw=true) + |WeChat Assistant|WeChat Public Account|Slack| + |-|-|-| + |||[Join Slack Chat](https://join.slack.com/t/the-asf/shared_invite/zt-1y375qcox-UW1898e4kZE_pqrNsrBM2g)| Mailing Lists: | Name | Description |Subscribe |Unsubscribe|Archive @@ -70,3 +73,4 @@ jobs: |Users |User support and questions mailing list| [Subscribe](mailto:users-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:users-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?users@eventmesh.apache.org)| |Development |Development related discussions| [Subscribe](mailto:dev-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:dev-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?dev@eventmesh.apache.org)| |Commits |All commits to repositories| [Subscribe](mailto:commits-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:commits-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org)| + |Issues |Issues or PRs comments and reviews| [Subscribe](mailto:commits-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:commits-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org)| diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml new file mode 100644 index 0000000000..f9c1507d96 --- /dev/null +++ b/.github/workflows/license.yml @@ -0,0 +1,44 @@ +# +# 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. +# + +name: 'License Check' +on: [ pull_request ] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + + - name: Check license header + uses: apache/skywalking-eyes@main + + - name: Set up JDK 11 + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 11 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e #v6.1.0 + + - name: Check license compatibility + run: ./gradlew clean checkDeniedLicense \ No newline at end of file diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..8b5b166215 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,48 @@ +# +# 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. +# + +name: 'Remind stale issues and PRs' + +on: + schedule: + - cron: '30 18 * * *' + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + days-before-issue-stale: 90 + days-before-pr-stale: 60 + days-before-close: -1 # Never close an issue or PR + stale-issue-message: | + It has been 90 days since the last activity on this issue. Apache EventMesh values the voices of the community. Please don't hesitate to share your latest insights on this matter at any time, as the community is more than willing to engage in discussions regarding the development and optimization directions of this feature. + + If you feel that your issue has been resolved, please feel free to close it. Should you have any additional information to share, you are welcome to reopen this issue. + stale-pr-message: | + It has been 60 days since the last activity on this pull request. I am reaching out here to gently remind you that the Apache EventMesh community values every pull request, and please feel free to get in touch with the reviewers at any time. They are available to assist you in advancing the progress of your pull request and offering the latest feedback. + + If you encounter any challenges during development, seeking support within the community is encouraged. We sincerely appreciate your contributions to Apache EventMesh. + exempt-issue-labels: 'pinned,discussion,help wanted,WIP,weopen-star,GLCC,GSoC' + exempt-pr-labels: 'help wanted,dependencies' + exempt-all-milestones: true # Exempt all issues/PRs with milestones from stale + operations-per-run: 300 diff --git a/.gitignore b/.gitignore index cc35f18615..2379b9f175 100644 --- a/.gitignore +++ b/.gitignore @@ -9,24 +9,45 @@ logs *.iws *.class *.log +*.log.* .idea +!/.idea/icon.png build .classpath .project -.checkstyle test-output dist +out .pmd classes package-lock.json node_modules -.DS_Store .run -/**/bin h2/db.mv.db # license check tmp file -all-dependencies.txt +/tools/dependency-check/all-dependencies.txt self-modules.txt third-party-dependencies.txt + +# github codespaces or visual studio +.vscode +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ +**/org/apache/eventmesh/connector/jdbc/antlr4/autogeneration/* + +#rust +Cargo.lock diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..51d401af7f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "eventmesh-sdks/eventmesh-sdk-c/third_party/json-c"] + path = eventmesh-sdks/eventmesh-sdk-c/third_party/json-c + url = git@github.com:json-c/json-c.git + branch = json-c-0.17 +[submodule "eventmesh-sdks/eventmesh-sdk-c/third_party/curl"] + path = eventmesh-sdks/eventmesh-sdk-c/third_party/curl + url = git@github.com:curl/curl.git diff --git a/.licenserc.yaml b/.licenserc.yaml index 19f4722454..db0d1d0c55 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -23,10 +23,13 @@ header: copyright-owner: Apache Software Foundation paths-ignore: + - 'eventmesh-operator/config/crd/bases' + - 'eventmesh-operator/config/rbac' - '.github/PULL_REQUEST_TEMPLATE' - '.gitmodules' - '**/.gitkeep' - '**/.gitignore' + - '**/.dockerignore' - '**/*.md' - '**/*.json' - '**/*.ftl' @@ -35,10 +38,12 @@ header: - '**/*.crt' - '**/*.pem' - '**/go.sum' + - '**/Cargo.lock' - 'LICENSE' - 'NOTICE' - - 'DISCLAIMER-WIP' - 'gradlew' - 'gradlew.bat' + - '**/*.txt' + - 'tools/dist-license/licenses/**' comment: on-failure diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 70dff529b9..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,109 +0,0 @@ -# Contributing to EventMesh - -Welcome to EventMesh! This document is a guideline about how to contribute to EventMesh. If you find something incorrect -or missing, please leave comments / suggestions. - -## Before you get started - -### Setting up your development environment - -You should have JDK installed in your develop environment. - -### Code style - -Import [EventMesh CheckStyle](./style/checkStyle.xml) file to your IDE. - -For IDEA, you can import check style file by: -```shell -Editor -> Code Style -> Java -> Scheme -> Import Scheme -> CheckStyle Configuration -``` -If you can't see CheckStyle Configuration section under Import Scheme, you can install CheckStyle-IDEA plugin first, and you will see it. - -You can also use `./gradlew check` to check the code style. -(NOTE: this command will check all file in project, when you submit a pr, the ci will only check the file has been changed in this pr). -## Contributing - -We are always very happy to have contributions, whether for typo fix, bug fix or big new features. Please do not ever -hesitate to ask a question or send a pull request. - -We strongly value documentation and integration with other projects. We are very glad to accept improvements for these -aspects. - -### GitHub workflow - -We use the `develop` branch as the development branch, which indicates that this is an unstable branch. - -Here are the workflow for contributors: - -1. Fork to your own -2. Clone fork to local repository -```git -git clone git@github.com:yourgithub/incubator-eventmesh.git -``` -3. Create a new branch and work on it -```git -git checkout -b fix_patch_xx -``` -4. Keep your branch in sync -```git -git remote add upstream git@github.com:apache/incubator-eventmesh.git -git fetch upstream develop:upstream_develop -git rebase upstream_develop -``` -5. Commit your changes (make sure your commit message concise) -6. Push your commits to your forked repository -7. Create a pull request - -Please follow [the pull request template](./.github/PULL_REQUEST_TEMPLATE.md). Please make sure the PR has a -corresponding issue. [GitHub Issues](https://github.com/apache/incubator-eventmesh/issues) - -After creating a PR, one or more committers will help to review the pull request, after approve, this PR will be merged in to -EventMesh repository, and the related Issue will be closed. - -### Open an issue / PR - -We use [GitHub Issues](https://github.com/apache/incubator-eventmesh/issues) -and [Pull Requests](https://github.com/apache/incubator-eventmesh/pulls) for trackers. - -If you find a bug in code, or want new features, or want to give suggestions, you -can [open an issue on GitHub](https://github.com/apache/incubator-eventmesh/issues/new) to report it. Please follow the -guideline message in the issue template. - -If you want to contribute, please follow the [contribution workflow](#github-workflow) and create a new pull request. Your PR title should start with [ISSUE #xx]. -If your PR contains large changes, e.g. component refactor or new components, please write detailed documents about its -design and usage. - -If your change is about a typo or small optimize, you needn't create an Issue, just submit a PR and title with [MINOR]. - -[Note]: A single pull request should not be too large. If heavy changes are required, it's better to separate the -changes to a few individual PRs. - -### PR review - -All code should be well reviewed by one or more committers. Some principles: - -- Readability: Important code should be well-documented. Comply with our [code style](./style/checkStyle.xml). -- Elegance: New functions, classes or components should be well-designed. -- Testability: Important code should be well-tested (high unit test coverage). - -### License review - -EventMesh follows [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) policy. All source files should -have the Apache License header added to the file header. EventMesh uses the [apache/skywalking-eyes](https://github.com/apache/skywalking-eyes) to check -the source file header. - -EventMesh uses [check-dependencies.sh](tools/dependency-check/check-dependencies.sh) script to check for third-part dependencies. -When you need to add a three-part dependency, you need to register the newly added dependency in tool/license/known-dependencies.txt. The newly added three-part libraries need to meet [ASF 3RD PARTY LICENSE POLICY](https://apache.org/legal/resolved.html). -It is highly recommended communicating with EventMesh community before you need to add a three-part library. - -### PR merge - -After a PR is approved by at least one committer, it can be merged. Before the merge, the committer can make changes to the commits message, requiring the commits -message to be clear without duplication, and use Squash and Merge to make sure one PR should only contain one commits. -For large multi-person PR, use Merge to merge, and fix the commits by rebase before merging. - -## Community - -### Contact us - -Mail: dev@eventmesh.apache.org diff --git a/CONTRIBUTING.zh-CN.md b/CONTRIBUTING.zh-CN.md deleted file mode 100644 index 2e9e7a721b..0000000000 --- a/CONTRIBUTING.zh-CN.md +++ /dev/null @@ -1,99 +0,0 @@ -# 贡献给EventMesh - -欢迎使用EventMesh! 本文档是有关如何为EventMesh做出贡献的指南。 如果发现不正确或缺失的内容,请留下评论/建议。 - -## 开始之前 - -### 设置您的开发环境 - -您应该在开发环境中安装了JDK。 - -### Code Style - -将 [EventMesh CheckStyle](./style/checkStyle.xml) 文件导入开发者工具。如果你使用IDEA,你可以通过以下步骤导入: -```shell -Editor -> Code Style -> Java -> Scheme -> Import Scheme -> CheckStyle Configuration -``` -如果你在Import Scheme下看不到CheckStyle Configuration选项,你可以先安装CheckStyle-IDEA插件,然后你就可以看到这个选项了。 - -你也可以通过执行`./gradlew check`来检查代码格式。(NOTE: 这个命令将会检查整个项目中的代码格式, 当你提交一个PR时,CI只会检查在此次PR中被被修改的文件的代码格式) -## 贡献 - -无论是对于拼写错误,BUG修复还是重要的新功能,我们总是很乐意接受您的贡献。请不要犹豫,在Github Issue上提出或者通过邮件列表进行讨论。 - -我们非常重视文档以及与其他项目的集成,我们很高兴接受这些方面的改进。 - -### GitHub工作流程 - -我们将`develop`分支用作开发分支,这表明这是一个不稳定的分支。 - -这是贡献者的工作流程 : - -1. Fork到您个人仓库 -2. 克隆到本地存储库 -```git -git clone git@github.com:yourgithub/incubator-eventmesh.git -``` -3. 创建一个新分支并对其进行处理 -```git -git checkout -b fix_patch_xx -``` -4. 保持分支与主库同步 -```git -git remote add upstream git@github.com:apache/incubator-eventmesh.git -git fetch upstream develop:upstream_develop -git rebase upstream_develop -``` -5. 提交您的更改(确保您的提交消息简明扼要) -6. 将您的提交推送到分叉的存储库 -7. 创建PR合并请求 - -请遵循[Pull Requests模板](./.github/PULL_REQUEST_TEMPLATE.md). -请确保PR对应有相应的问题. [GitHub Issues](https://github.com/apache/incubator-eventmesh/issues) - -创建PR后,社区会有committer成员帮助review,review通过之后,PR将会合并到主库,相应的Issue会被关闭。 - -### 打开问题/ PR - -我们将使用Issues和Pull Requests作为跟踪器 -- [GitHub Issues](https://github.com/apache/incubator-eventmesh/issues) -- [Pull Requests](https://github.com/apache/incubator-eventmesh/pulls) - -如果您发现新的Bug,想要新功能或提出新当建议,您可以在GitHub上[创建Issue](https://github.com/apache/incubator-eventmesh/issues/new) ,请按照Issue模板中的准则进行操作。 -如果您在文档中发现拼写错误,或者发现代码中存在可以进行微小的优化的地方,您可以无需创建Issue, 直接提交一个PR。 - -如果您想贡献,请遵循[贡献工作流程](#github-workflow)并创建一个新的拉取请求。 如果您的PR包含较大的更改,例如组件重构或新组件,请写详细文档 有关其设计和使用的信息。 -对于PR的标题请依照[ISSUE #xx]进行开头,如果是细小的改动请以[MINOR]进行开头。 - -【注意】: 单个PR不应太大。如果需要进行重大更改,最好将更改分开 到一些个人PR。 - -### PR审查 - -所有PR应由一个或多个committer进行良好的审查。一些原则: - -- 可读性: 重要代码应有详细记录。符合我们的[代码风格](./style/checkStyle.xml) -- 优雅: 新功能,类或组件应经过精心设计 -- 可测试性: 重要代码应经过良好测试(较高的单元测试覆盖率) - -### License审查 - -EventMesh遵循[Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 政策。 -所有的源代码文件应该在文件头部添加Apache License header,EventMesh会使用[apache/skywalking-eyes](https://github.com/apache/skywalking-eyes) -对源代码文件头进行校验。 - -EventMesh使用[check-dependencies.sh](tools/dependency-check/check-dependencies.sh)脚本 -检查第三方依赖,当你需要添加三方依赖时,你需要将新添加的依赖注册在tool/license/known-dependencies.txt中, -同时新添加的三方库需要满足[Apache对于第三方的政策](https://apache.org/legal/resolved.html)。 - -当添加依赖时遇到问题时,社区PPMC会协助解决,非常建议在需要添加三方依赖之前与EventMesh社区进行沟通。 - -### PR合并 - -PR经过至少一个committer approve之后会由committer负责合并,在合并的时候,committer可以对commits信息进行修改,要求commits信息简洁明了,不重复。 -在合并时使用Squash and merge, 要求一个PR保留一个commits。对于大型多人协助的PR,使用Merge进行合并,在合并之前通过rebase修正commits。 - -## 社区 - -### 联系我们 - -邮件:dev@eventmesh.apache.org diff --git a/DISCLAIMER-WIP b/DISCLAIMER-WIP deleted file mode 100644 index e72dd1b9d0..0000000000 --- a/DISCLAIMER-WIP +++ /dev/null @@ -1,19 +0,0 @@ -Apache EventMesh is an effort undergoing incubation at The Apache Software Foundation (ASF), -sponsored by the Apache Incubator PMC. - -Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, -communications, and decision-making process have stabilized in a manner consistent with other successful ASF projects. - -While incubation status is not necessarily a reflection of the completeness or stability of the code, -it does indicate that the project has yet to be fully endorsed by the ASF. - -Some of the incubating project’s releases may not be fully compliant with ASF policy. -For example, releases may have incomplete or un-reviewed licensing conditions. -What follows is a list of issues the project is currently aware of (this list is likely to be incomplete): - -1- Releases may have incomplete licensing conditions - - -If you are planning to incorporate this work into your product/project, -please be aware that you will need to conduct a thorough licensing review to determine the overall implications of including this work. -For the current status of this project through the Apache Incubator, visit: https://incubator.apache.org/projects/eventmesh.html diff --git a/NOTICE b/NOTICE index 76091d57bb..275cf283a3 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ -Apache EventMesh (incubating) -Copyright 2021-2022 The Apache Software Foundation +Apache EventMesh +Copyright 2021-2025 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index 6642938509..a82a7479f5 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,176 @@


- +
-[![CI status](https://img.shields.io/github/workflow/status/apache/incubator-eventmesh/Continuous%20Integration?logo=github&style=for-the-badge)](https://github.com/apache/incubator-eventmesh/actions/workflows/ci.yml) -[![CodeCov](https://img.shields.io/codecov/c/gh/apache/incubator-eventmesh/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/apache/incubator-eventmesh) -[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/incubator-eventmesh/context:java) -[![Total Alerts](https://img.shields.io/lgtm/alerts/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/incubator-eventmesh/alerts/) +[![CI status](https://img.shields.io/github/actions/workflow/status/apache/eventmesh/ci.yml?logo=github&style=for-the-badge)](https://github.com/apache/eventmesh/actions/workflows/ci.yml) +[![CodeCov](https://img.shields.io/codecov/c/gh/apache/eventmesh/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/apache/eventmesh) +[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/apache/eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/eventmesh/context:java) +[![Total Alerts](https://img.shields.io/lgtm/alerts/g/apache/eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/eventmesh/alerts/) -[![License](https://img.shields.io/github/license/apache/incubator-eventmesh?style=for-the-badge)](https://www.apache.org/licenses/LICENSE-2.0.html) -[![GitHub Release](https://img.shields.io/github/v/release/apache/eventmesh?style=for-the-badge)](https://github.com/apache/incubator-eventmesh/releases) -[![Slack Status](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack&style=for-the-badge)](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-1blhcbedu-9b7yvwAQcDs3fddZxnZXag) +[![License](https://img.shields.io/github/license/apache/eventmesh?style=for-the-badge)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![GitHub Release](https://img.shields.io/github/v/release/apache/eventmesh?style=for-the-badge)](https://github.com/apache/eventmesh/releases) +[![Slack Status](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack&style=for-the-badge)](https://join.slack.com/t/the-asf/shared_invite/zt-1y375qcox-UW1898e4kZE_pqrNsrBM2g) + [📦 Documentation](https://eventmesh.apache.org/docs/introduction) | -[📔 Examples](https://github.com/apache/incubator-eventmesh/tree/master/eventmesh-examples) | +[📔 Examples](https://github.com/apache/eventmesh/tree/master/eventmesh-examples) | [⚙️ Roadmap](https://eventmesh.apache.org/docs/roadmap) | [🌐 简体中文](README.zh-CN.md)
-# Apache EventMesh (Incubating) +# Apache EventMesh -**Apache EventMesh (Incubating)** is a dynamic [event-driven](https://en.wikipedia.org/wiki/Event-driven_architecture) application multi-runtime used to decouple the application and backend middleware layer, which supports a wide range of use cases that encompass complex multi-cloud, widely distributed topologies using diverse technology stacks. +**Apache EventMesh** is a new generation serverless event middleware for building distributed [event-driven](https://en.wikipedia.org/wiki/Event-driven_architecture) applications. -## Features - -### Multi-Runtime Architecture - -![EventMesh Architecture](docs/images/eventmesh-architecture.png) - -### Orchestration +### EventMesh Architecture -![EventMesh Orchestration](docs/images/eventmesh-orchestration.png) +![EventMesh Architecture](resources/eventmesh-architecture-6.png) -### Data Mesh +## Features -![EventMesh Data Mesh](docs/images/eventmesh-bridge.png) +Apache EventMesh has a vast amount of features to help users achieve their goals. Let us share with you some of the key features EventMesh has to offer: -## Components +- Built around the [CloudEvents](https://cloudevents.io) specification. +- Rapidty extendsible interconnector layer [connectors](https://github.com/apache/eventmesh/tree/master/eventmesh-connectors) using [openConnect](https://github.com/apache/eventmesh/tree/master/eventmesh-openconnect) such as the source or sink of Saas, CloudService, and Database etc. +- Rapidty extendsible storage layer such as [Apache RocketMQ](https://rocketmq.apache.org), [Apache Kafka](https://kafka.apache.org), [Apache Pulsar](https://pulsar.apache.org), [RabbitMQ](https://rabbitmq.com), [Redis](https://redis.io). +- Rapidty extendsible meta such as [Consul](https://consulproject.org/en/), [Nacos](https://nacos.io), [ETCD](https://etcd.io) and [Zookeeper](https://zookeeper.apache.org/). +- Guaranteed at-least-once delivery. +- Deliver events between multiple EventMesh deployments. +- Event schema management by catalog service. +- Powerful event orchestration by [Serverless workflow](https://serverlessworkflow.io/) engine. +- Powerful event filtering and transformation. +- Rapid, seamless scalability. +- Easy Function develop and framework integration. -Apache EventMesh (Incubating) consists of multiple components that integrate different middlewares and messaging protocols to enhance the functionalities of the application runtime. +## Roadmap -- **eventmesh-runtime**: The middleware that transmits events between producers and consumers, which supports cloud-native apps and microservices. -- **eventmesh-sdk-java**: The Java SDK that supports HTTP, TCP, and [gRPC](https://grpc.io) protocols. -- **eventmesh-sdk-go**: The Golang SDK that supports HTTP, TCP, and [gRPC](https://grpc.io) protocols. -- **eventmesh-connector-plugin**: The collection of plugins that connects middlewares such as [Apache RocketMQ](https://rocketmq.apache.org) (implemented) [Apache Kafka](https://kafka.apache.org) (in progress), [Apache Pulsar](https://pulsar.apache.org/) (in progress), and [Redis](https://redis.io) (in progress). -- **eventmesh-registry-plugin**: The collection of plugins that integrate service registries such as [Nacos](https://nacos.io) and [etcd](https://etcd.io). -- **eventmesh-security-plugin**: The collection of plugins that implement security mechanisms, such as ACL (access control list), authentication, and authorization. -- **eventmesh-protocol-plugin**: The collection of plugins that implement messaging protocols, such as [CloudEvents](https://cloudevents.io) and [MQTT](https://mqtt.org). -- **eventmesh-admin**: The control plane that manages clients, topics, and subscriptions. +Please go to the [roadmap](https://eventmesh.apache.org/docs/roadmap) to get the release history and new features of Apache EventMesh. -## Downloads +## Subprojects -Please go to the [release page](https://eventmesh.apache.org/download) to get the release of Apache EventMesh (Incubating). +- [EventMesh-site](https://github.com/apache/eventmesh-site): Apache official website resources for EventMesh. +- [EventMesh-workflow](https://github.com/apache/eventmesh-workflow): Serverless workflow runtime for event Orchestration on EventMesh. +- [EventMesh-dashboard](https://github.com/apache/eventmesh-dashboard): Operation and maintenance console of EventMesh. +- [EventMesh-catalog](https://github.com/apache/eventmesh-catalog): Catalog service for event schema management using AsyncAPI. +- [EventMesh-go](https://github.com/apache/eventmesh-go): A go implementation for EventMesh runtime. ## Quick start -Here are the guidelines: - -[Step 1: Deploy eventmesh-store](docs/zh/instruction/01-store.md) - -[Step 2: Start eventmesh-runtime](docs/zh/instruction/02-runtime.md) - -[Step 3: Run our demos](docs/zh/instruction/03-demo.md) - -Besides, we also provide the docker-version guidelines for you if you prefer Docker: - -[Step 1: Deploy eventmesh-store using docker](docs/zh/instruction/01-store-with-docker.md) - -[Step 2: Start eventmesh-runtime using docker](docs/zh/instruction/02-runtime-with-docker.md) - -[Step 3: Run our demos](docs/zh/instruction/03-demo.md) +This section of the guide will show you the steps to deploy EventMesh from [Local](#run-eventmesh-runtime-locally), [Docker](#run-eventmesh-runtime-in-docker), [K8s](#run-eventmesh-runtime-in-kubernetes). + +This section guides the launch of EventMesh according to the default configuration, if you need more detailed EventMesh deployment steps, please visit the [EventMesh official document](https://eventmesh.apache.org/docs/introduction). + +#### 1. Pull EventMesh Image + +Use the following command line to download the latest version of [EventMesh](https://hub.docker.com/r/apache/eventmesh): + +```shell +sudo docker pull apache/eventmesh:latest +``` + +#### 2. Run EventMesh Runtime + +Use the following command to start the EventMesh container: + +```shell +sudo docker run -d --name eventmesh -p 10000:10000 -p 10105:10105 -p 10205:10205 -p 10106:10106 -t apache/eventmesh:latest +``` +#### 3. Creating Topics +Creating a topic is the first step in using EventMesh. You need to send an HTTP POST request to create a topic. +Example Request +```shell +POST /eventmesh/topic/create HTTP/1.1 +Host: localhost:10105 +Content-Type: application/json + +{ + "topic": "example-topic" +} +``` +#### 4. Subscribing to Topics +After creating a topic, you can subscribe to it to receive messages. EventMesh provides two subscription methods: local subscription and remote subscription. + +```shell +POST /eventmesh/subscribe/local HTTP/1.1 +Host: localhost:10105 +Content-Type: application/json +{ + "url": "http://localhost:8080/callback", + "consumerGroup": "example-consumer-group", + "topic": [ + { + "topic": "example-topic", + "mode": "CLUSTERING", + "type": "SYNC" + } + ] +} +``` +#### 5. Sending Messages +EventMesh provides multiple message sending methods, including asynchronous sending, synchronous sending, and batch sending. +```shell +POST /eventmesh/publish HTTP/1.1 +Host: localhost:10105 +Content-Type: application/json +eventmesh-message-topic: example-topic +{ + "content": "Hello, EventMesh!" +} +``` +#### 6. Unsubscribing +When you no longer need to receive messages for a topic, you can unsubscribe. +```shell +POST /eventmesh/unsubscribe/local HTTP/1.1 +Host: localhost:10105 +Content-Type: application/json +{ + "url": "http://localhost:8080/callback", + "consumerGroup": "example-consumer-group", + "topics": ["example-topic"] +} +``` ## Contributing -Each contributor has played an important role in promoting the robust development of Apache EventMesh (Incubating). We sincerely appreciate all contributors who have contributed code and documents. +[![GitHub repo Good Issues for newbies](https://img.shields.io/github/issues/apache/eventmesh/good%20first%20issue?style=flat&logo=github&logoColor=green&label=Good%20First%20issues)](https://github.com/apache/eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) [![GitHub Help Wanted issues](https://img.shields.io/github/issues/apache/eventmesh/help%20wanted?style=flat&logo=github&logoColor=b545d1&label=%22Help%20Wanted%22%20issues)](https://github.com/apache/eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) [![GitHub Help Wanted PRs](https://img.shields.io/github/issues-pr/apache/eventmesh/help%20wanted?style=flat&logo=github&logoColor=b545d1&label=%22Help%20Wanted%22%20PRs)](https://github.com/apache/eventmesh/pulls?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) [![GitHub repo Issues](https://img.shields.io/github/issues/apache/eventmesh?style=flat&logo=github&logoColor=red&label=Issues)](https://github.com/apache/eventmesh/issues?q=is%3Aopen) -- [Contributing Guideline](https://github.com/apache/incubator-eventmesh/blob/master/docs/en/contribute/03-new-contributor-guidelines.md) -- [Good First Issues](https://github.com/apache/incubator-eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) +Each contributor has played an important role in promoting the robust development of Apache EventMesh. We sincerely appreciate all contributors who have contributed code and documents. -Here is the [List of Contributors](https://github.com/apache/incubator-eventmesh/graphs/contributors), thank you all! :) - - - - +- [Contributing Guideline](https://eventmesh.apache.org/community/contribute/contribute) +- [Good First Issues](https://github.com/apache/eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) ## CNCF Landscape
- - + -Apache EventMesh (Incubating) enriches the CNCF Cloud Native Landscape. +Apache EventMesh enriches the CNCF Cloud Native Landscape.
## License -Apache EventMesh (Incubating) is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). +Apache EventMesh is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). ## Community -|WeChat Assistant|WeChat Official Account|Slack| -|-|-|-| -|||[Join Slack Chat](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-1blhcbedu-9b7yvwAQcDs3fddZxnZXag)| +| WeChat Assistant | WeChat Public Account | Slack | +|---------------------------------------------------------|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| +| | | [Join Slack Chat](https://join.slack.com/t/the-asf/shared_invite/zt-1y375qcox-UW1898e4kZE_pqrNsrBM2g)(Please open an issue if this link is expired) | + +Bi-weekly meeting : [#Tencent meeting](https://meeting.tencent.com/dm/wes6Erb9ioVV) : 346-6926-0133 + +Bi-weekly meeting record : [bilibili](https://space.bilibili.com/1057662180) ### Mailing List -|Name|Description|Subscribe|Unsubscribe|Archive -|-|-|-|-|-| -|Users|User discussion|[Subscribe](mailto:users-subscribe@eventmesh.incubator.apache.org)|[Unsubscribe](mailto:users-unsubscribe@eventmesh.incubator.apache.org)|[Mail Archives](https://lists.apache.org/list.html?users@eventmesh.apache.org)| -|Development|Development discussion (Design Documents, Issues, etc.)|[Subscribe](mailto:dev-subscribe@eventmesh.incubator.apache.org)|[Unsubscribe](mailto:dev-unsubscribe@eventmesh.incubator.apache.org)|[Mail Archives](https://lists.apache.org/list.html?dev@eventmesh.apache.org)| -|Commits|Commits to related repositories| [Subscribe](mailto:commits-subscribe@eventmesh.incubator.apache.org) |[Unsubscribe](mailto:commits-unsubscribe@eventmesh.incubator.apache.org) |[Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org)| +| Name | Description | Subscribe | Unsubscribe | Archive | +|-------------|---------------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------------------------| +| Users | User discussion | [Subscribe](mailto:users-subscribe@eventmesh.apache.org) | [Unsubscribe](mailto:users-unsubscribe@eventmesh.apache.org) | [Mail Archives](https://lists.apache.org/list.html?users@eventmesh.apache.org) | +| Development | Development discussion (Design Documents, Issues, etc.) | [Subscribe](mailto:dev-subscribe@eventmesh.apache.org) | [Unsubscribe](mailto:dev-unsubscribe@eventmesh.apache.org) | [Mail Archives](https://lists.apache.org/list.html?dev@eventmesh.apache.org) | +| Commits | Commits to related repositories | [Subscribe](mailto:commits-subscribe@eventmesh.apache.org) | [Unsubscribe](mailto:commits-unsubscribe@eventmesh.apache.org) | [Mail Archives](https://lists.apache.org/list.html?commits@eventmesh.apache.org) | +| Issues | Issues or PRs comments and reviews | [Subscribe](mailto:issues-subscribe@eventmesh.apache.org) | [Unsubscribe](mailto:issues-unsubscribe@eventmesh.apache.org) | [Mail Archives](https://lists.apache.org/list.html?issues@eventmesh.apache.org) | diff --git a/README.zh-CN.md b/README.zh-CN.md index 8477f1816d..9aebab3bf7 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,94 +1,193 @@
+

- +
-[![CI status](https://img.shields.io/github/workflow/status/apache/incubator-eventmesh/Continuous%20Integration?logo=github&style=for-the-badge)](https://github.com/apache/incubator-eventmesh/actions/workflows/ci.yml) -[![CodeCov](https://img.shields.io/codecov/c/gh/apache/incubator-eventmesh/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/apache/incubator-eventmesh) -[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/incubator-eventmesh/context:java) -[![Total Alerts](https://img.shields.io/lgtm/alerts/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/incubator-eventmesh/alerts/) +[![CI status](https://img.shields.io/github/actions/workflow/status/apache/eventmesh/ci.yml?logo=github&style=for-the-badge)](https://github.com/apache/eventmesh/actions/workflows/ci.yml) +[![CodeCov](https://img.shields.io/codecov/c/gh/apache/eventmesh/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/apache/eventmesh) +[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/apache/eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/eventmesh/context:java) +[![Total Alerts](https://img.shields.io/lgtm/alerts/g/apache/eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/eventmesh/alerts/) -[![License](https://img.shields.io/github/license/apache/incubator-eventmesh?style=for-the-badge)](https://www.apache.org/licenses/LICENSE-2.0.html) -[![GitHub Release](https://img.shields.io/github/v/release/apache/eventmesh?style=for-the-badge)](https://github.com/apache/incubator-eventmesh/releases) -[![Slack Status](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack&style=for-the-badge)](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-16y1n77va-q~JepYy3RqpkygDYmQaQbw) +[![License](https://img.shields.io/github/license/apache/eventmesh?style=for-the-badge)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![GitHub Release](https://img.shields.io/github/v/release/apache/eventmesh?style=for-the-badge)](https://github.com/apache/eventmesh/releases) +[![Slack Status](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack&style=for-the-badge)](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-1t1816dli-I0t3OE~IpdYWrZbIWhMbXg) -[📦 文档 (英文)](https://eventmesh.apache.org/docs/introduction) | -[📔 例子](https://github.com/apache/incubator-eventmesh/tree/master/eventmesh-examples) | +[📦 文档(英文)](https://eventmesh.apache.org/docs/introduction) | +[📔 例子](https://github.com/apache/eventmesh/tree/master/eventmesh-examples) | [⚙️ 路线图](https://eventmesh.apache.org/docs/roadmap) | -[🌐 英文版](README.md) +[🌐 英文版](README.zh-CN.md)
-# Apache EventMesh (Incubating) -**Apache EventMesh (Incubating)** 是一个用于解耦应用和后端中间件层的的动态云原生 [事件驱动](https://en.wikipedia.org/wiki/Event-driven_architecture) 架构基础设施。它支持广泛的用例,包括复杂的混合云、使用了不同技术栈的分布式架构。 +# Apache EventMesh + +**Apache EventMesh** 是用于构建分布式[事件驱动](https://en.wikipedia.org/wiki/Event-driven_architecture)应用程序的新一代无服务器事件中间件。 + +### EventMesh 架构 + +![EventMesh Architecture](resources/eventmesh-architecture-6.png) + ## 特性 -### 多运行时微服务架构 +Apache EventMesh提供了许多功能来帮助用户实现他们的目标,以下是一些EventMesh的关键特点: + +- 基于 [CloudEvents](https://cloudevents.io) 规范构建。 +- 快速可扩展的Connector,[connectors](https://github.com/apache/eventmesh/tree/master/eventmesh-connectors),例如作为Saas、CloudService和数据库等的source 或sink。. +- 快速可扩展的存储层,使用 [JDBC](https://en.wikipedia.org/wiki/Java_Database_Connectivity)和[Apache RocketMQ](https://rocketmq.apache.org), [Apache Kafka](https://kafka.apache.org), [Apache Pulsar](https://pulsar.apache.org), [RabbitMQ](https://rabbitmq.com), [Redis](https://redis.io), [Pravega](https://cncf.pravega.io), 和 [RDMS](https://en.wikipedia.org/wiki/Relational_database)(正在进行中)集成。 +- 快速可扩展的控制器,例如 [Consul](https://consulproject.org/en/), [Nacos](https://nacos.io), [ETCD](https://etcd.io) 和 [Zookeeper](https://zookeeper.apache.org/)。 +- 至少一次的可靠性投递。 +- 在多个EventMesh部署之间传递事件。 +- 通过目录服务进行事件模式管理。 +- 通过 [Serverless workflow](https://serverlessworkflow.io/) 引擎实现强大的事件编排。 +- 强大的事件过滤和转换功能。 +- 快速、无缝的可扩展性。 +- 易于函数开发和框架集成。 + +## 路线图 + +请前往[路线图](https://eventmesh.apache.org/docs/roadmap)查看Apache EventMesh的版本历史和新功能。. + +## 子项目 + +- [EventMesh-site](https://github.com/apache/eventmesh-site): Apache EventMesh 的官方网站资源。 +- [EventMesh-workflow](https://github.com/apache/eventmesh-workflow): 用于在 EventMesh 上进行事件编排的无服务器工作流运行时。 +- [EventMesh-dashboard](https://github.com/apache/eventmesh-dashboard): EventMesh 的运维控制台。 +- [EventMesh-catalog](https://github.com/apache/eventmesh-catalog): 使用 AsyncAPI 进行事件模式管理的目录服务。 +- [EventMesh-go](https://github.com/apache/eventmesh-go): EventMesh 运行时的 Go 语言实现。 + +## 快速入门 + +本节指南将指导您分别从[本地](#在本地运行-eventmesh-runtime)、[Docker](#在-docker-中运行-eventmesh-runtime)、[K8s](#在-kubernetes-中运行-eventmesh-runtime)部署EventMesh的步骤: + +本节指南按照默认配置启动 EventMesh,如果您需要更加详细的 EventMesh 部署步骤,请访问[EventMesh官方文档](https://eventmesh.apache.org/docs/introduction)。 + +### 部署 Event Store + +> EventMesh 支持[多种事件存储](https://eventmesh.apache.org/docs/roadmap#event-store-implementation-status),默认存储模式为 `standalone`,不依赖其他事件存储作为层。 + +### 在本地运行 EventMesh Runtime + +#### 1. 下载 EventMesh -![EventMesh Architecture](docs/images/eventmesh-architecture.png) +从 [EventMesh Download](https://eventmesh.apache.org/download/) 页面下载最新版本的 Binary Distribution 发行版并解压: -### 编排 +```shell +wget https://dlcdn.apache.org/eventmesh/1.10.0/apache-eventmesh-1.10.0-bin.tar.gz +tar -xvzf apache-eventmesh-1.10.0-bin.tar.gz +cd apache-eventmesh-1.10.0 +``` -![EventMesh Orchestration](docs/images/eventmesh-orchestration.png) +#### 2. 运行 EventMesh -### 数据网格 +执行 `start.sh` 脚本启动 EventMesh Runtime 服务器。 -![EventMesh Data Mesh](docs/images/eventmesh-bridge.png) +```shell +bash bin/start.sh +``` -## 组件 - -**Apache EventMesh (Incubating)** 由多个组件组成,这些组件集成了不同的中间件和消息传输协议,以增强应用程序运行时的功能。 +查看输出日志: -- **eventmesh-runtime**: 在生产者和消费者之间传输事件的中间件,它支持云原生应用程序和微服务。 -- **eventmesh-sdk-java**: 支持 HTTP、TCP 和 [gRPC](https://grpc.io) 协议的 Java SDK。 -- **eventmesh-sdk-go**: 支持 HTTP、TCP 和 [gRPC](https://grpc.io) 协议的 Golang SDK。 -- **eventmesh-connector-plugin**: 连接 [Apache RocketMQ](https://rocketmq.apache.org)、 [Apache Kafka](https://kafka.apache.org)、[Apache Pulsar](https://pulsar.apache.org/) 和 [Redis](https://redis.io) 等中间件的插件集合。 -- **eventmesh-registry-plugin**: 集成服务注册表的插件集合,如 [Nacos](https://nacos.io) 和 [etcd](https://etcd.io)。 +```shell +tail -n 50 -f logs/eventmesh.out +``` -- **eventmesh-security-plugin**: 实现安全机制的插件的集合,如 ACL(访问控制列表)、认证和授权。 +当日志输出 `server state:RUNNING`,则代表 EventMesh Runtime 启动成功了。 -- **eventmesh-protocol-plugin**: 实现消息传递协议的插件集合,如 [CloudEvents](https://cloudevents.io) 和 [MQTT](https://mqtt.org)。 +停止: -- **eventmesh-admin**: 客户端管理、主题管理、订阅管理和其他管理。 +```shell +bash bin/stop.sh +``` -## 下载 +脚本打印 `shutdown server ok!` 时,代表 EventMesh Runtime 已停止。 -你可以在这个页面 [release page](https://eventmesh.apache.org/download) 获取所有的历史发布版本。 +### 在 Docker 中运行 EventMesh Runtime -## 快速开始指引 +#### 1. 获取 EventMesh 镜像 -[Step 1: Deploy eventmesh-store](docs/zh/instruction/01-store.md) +使用下面的命令行下载最新版本的 [EventMesh](https://hub.docker.com/r/apache/eventmesh): -[Step 2: Start eventmesh-runtime](docs/zh/instruction/02-runtime.md) +```shell +sudo docker pull apache/eventmesh:latest +``` -[Step 3: Run our demos](docs/zh/instruction/03-demo.md) +#### 2. 运行 EventMesh -除此之外,我们还提供了 Docker 版本的快速开始指引,方便您借助 Docker 来初探我们的项目: +使用以下命令启动 EventMesh 容器: -[Step 1: Deploy eventmesh-store using docker](docs/zh/instruction/01-store-with-docker.md) +```shell +sudo docker run -d --name eventmesh -p 10000:10000 -p 10105:10105 -p 10205:10205 -p 10106:10106 -t apache/eventmesh:latest +``` -[Step 2: Start eventmesh-runtime using docker](docs/zh/instruction/02-runtime-with-docker.md) +进入容器: -[Step 3: Run our demos](docs/zh/instruction/03-demo.md) +```shell +sudo docker exec -it eventmesh /bin/bash +``` +查看日志: +```shell +cd logs +tail -n 50 -f eventmesh.out +``` -## 贡献这个项目 +### 在 Kubernetes 中运行 EventMesh Runtime -每一名贡献者都在这个项目的发展上都是至关重要的。我们真诚地感谢所有对代码和文档的贡献者!想要尝试贡献的可以看看以下三个链接。 +#### 1. 部署 Operator -- [贡献准则](https://eventmesh.apache.org/docs/contribute/contribute) -- [值得新人尝试的 Issue](https://github.com/apache/incubator-eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) +运行以下命令部署(删除部署, 只需将 `deploy` 替换为 `undeploy` 即可): -这是项目的[贡献者名单](https://github.com/apache/incubator-eventmesh/graphs/contributors) -,感谢各位的大力支持 :) +```shell +$ cd eventmesh-operator && make deploy +``` - - +运行 `kubectl get pods` 、`kubectl get crd | grep eventmesh-operator.eventmesh` 查看部署的 EventMesh-Operator 状态以及 CRD 信息. + +```shell +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +eventmesh-operator-59c59f4f7b-nmmlm 1/1 Running 0 20s + +$ kubectl get crd | grep eventmesh-operator.eventmesh +connectors.eventmesh-operator.eventmesh 2024-01-10T02:40:27Z +runtimes.eventmesh-operator.eventmesh 2024-01-10T02:40:27Z +``` + +#### 2. 部署 EventMesh Runtime + +运行以下命令部署 runtime、connector-rocketmq (删除部署, 只需将 `create` 替换为 `delete` 即可): + +```shell +$ make create +``` + +运行 `kubectl get pods` 查看部署是否成功. + +```shell +NAME READY STATUS RESTARTS AGE +connector-rocketmq-0 1/1 Running 0 9s +eventmesh-operator-59c59f4f7b-nmmlm 1/1 Running 0 3m12s +eventmesh-runtime-0-a-0 1/1 Running 0 15s +``` + +## 贡献 + +每个贡献者在推动 Apache EventMesh 的健康发展中都发挥了重要作用。我们真诚感谢所有为代码和文档作出贡献的贡献者。 + +- [贡献指南](https://eventmesh.apache.org/community/contribute/contribute) +- [Good First Issues](https://github.com/apache/eventmesh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) + +这里是[贡献者列表](https://github.com/apache/eventmesh/graphs/contributors),感谢大家! :) + + + + ## CNCF Landscape
@@ -96,23 +195,30 @@ -Apache EventMesh (Incubating) enriches the CNCF Cloud Native Landscape. +Apache EventMesh enriches the CNCF Cloud Native Landscape. +
-## 开源授权 +## License + +Apache EventMesh 的开源协议遵循 [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). -Apache EventMesh (Incubating) is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). +## Community -## 社区 +| 微信小助手 | 微信公众号 | Slack | +|---------------------------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------------------------------------------| +| | | [加入 Slack ](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-1t1816dli-I0t3OE~IpdYWrZbIWhMbXg) | -|微信小助手|微信公众号|Slack| -|-|-|-| -|||[加入 Slack](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-16y1n77va-q~JepYy3RqpkygDYmQaQbw)| +双周会议 : [#Tencent meeting](https://meeting.tencent.com/dm/wes6Erb9ioVV) : 346-6926-0133 + +双周会议记录 : [bilibili](https://space.bilibili.com/1057662180) ### 邮件名单 -| 列表名称 | 描述 |订阅 |取消订阅|邮件列表存档 -| ---- | ---- |---- | ---- | ---- | -|用户 |用户支持与用户问题| [点击订阅](mailto:users-subscribe@eventmesh.incubator.apache.org) |[点击取消订阅](mailto:users-unsubscribe@eventmesh.incubator.apache.org) |[邮件列表存档](https://lists.apache.org/list.html?users@eventmesh.apache.org)| -|开发 |开发相关| [点击订阅](mailto:dev-subscribe@eventmesh.incubator.apache.org) |[点击取消订阅](mailto:dev-unsubscribe@eventmesh.incubator.apache.org) |[邮件列表存档](https://lists.apache.org/list.html?dev@eventmesh.apache.org)| -|Commits |所有与仓库相关的 commits 信息通知| [点击订阅](mailto:commits-subscribe@eventmesh.incubator.apache.org) |[点击取消订阅](mailto:commits-unsubscribe@eventmesh.incubator.apache.org) |[邮件列表存档](https://lists.apache.org/list.html?commits@eventmesh.apache.org)| +| 名称 | 描述 | 订阅 | 取消订阅 | 邮件列表存档 | +|---------|--------------------------|-----------------------------------------------------|---------------------------------------------------------|-------------------------------------------------------------------------| +| 用户 | 用户支持与用户问题 | [订阅](mailto:users-subscribe@eventmesh.apache.org) | [取消订阅](mailto:users-unsubscribe@eventmesh.apache.org) | [邮件存档](https://lists.apache.org/list.html?users@eventmesh.apache.org) | +| 开发 | 开发相关 (设计文档, Issues等等.) | [订阅](mailto:dev-subscribe@eventmesh.apache.org) | [取消订阅](mailto:dev-unsubscribe@eventmesh.apache.org) | [邮件存档](https://lists.apache.org/list.html?dev@eventmesh.apache.org) | +| Commits | 所有与仓库相关的 commits 信息通知 | [订阅](mailto:commits-subscribe@eventmesh.apache.org) | [取消订阅](mailto:commits-unsubscribe@eventmesh.apache.org) | [邮件存档](https://lists.apache.org/list.html?commits@eventmesh.apache.org) | +| Issues | Issues 或者 PR 提交和代码Review | [订阅](mailto:issues-subscribe@eventmesh.apache.org) | [取消订阅](mailto:issues-unsubscribe@eventmesh.apache.org) | [邮件存档](https://lists.apache.org/list.html?issues@eventmesh.apache.org) | + diff --git a/build.gradle b/build.gradle index dedd041caf..663fbaf7e6 100644 --- a/build.gradle +++ b/build.gradle @@ -15,53 +15,69 @@ * limitations under the License. */ +import groovy.json.JsonSlurper +import org.apache.commons.io.IOUtils +import org.apache.http.client.config.RequestConfig +import org.apache.http.client.methods.CloseableHttpResponse +import org.apache.http.client.methods.HttpGet +import org.apache.http.impl.client.CloseableHttpClient +import org.apache.http.impl.client.HttpClients +import org.apache.http.util.EntityUtils + +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.nio.file.Paths import java.util.concurrent.TimeUnit buildscript { repositories { + mavenCentral() maven { url "https://maven.aliyun.com/repository/public" } - maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.3" - classpath "io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE" - classpath "com.github.jk1:gradle-license-report:1.17" + classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:5.2.5" + classpath "io.spring.gradle:dependency-management-plugin:1.1.6" + classpath "com.diffplug.spotless:spotless-plugin-gradle:6.13.0" + + classpath "org.apache.httpcomponents:httpclient:4.5.14" + classpath "commons-io:commons-io:2.18.0" } } -//Remove doclint warnings that pollute javadoc logs when building with java8 -if(JavaVersion.current().isJava8()){ - allprojects { - tasks.withType(Javadoc){ - options.addStringOption('xdoclint:none','-quiet') - } - } +plugins { + id 'org.cyclonedx.bom' version '1.8.2' + id 'com.github.jk1.dependency-license-report' version '2.9' } allprojects { apply plugin: 'java' apply plugin: "eclipse" apply plugin: "idea" - apply plugin: "project-reports" apply plugin: "maven-publish" - apply plugin: "com.github.spotbugs" apply plugin: "project-reports" apply plugin: "jacoco" apply plugin: "pmd" apply plugin: "java-library" apply plugin: 'signing' apply plugin: 'checkstyle' + apply plugin: 'com.diffplug.spotless' + apply plugin: "com.github.spotbugs" [compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8' compileJava.options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" + java { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + } + clean.doFirst { delete 'build' delete 'dist' @@ -74,21 +90,198 @@ allprojects { showViolations = true maxWarnings = 0 configFile = new File("${rootDir}/style/checkStyle.xml") + configDirectory = file("${rootDir}/style") } - checkstyleMain.exclude '**/org/apache/eventmesh/client/grpc/protos**' + checkstyleMain.exclude('**/org/apache/eventmesh/client/grpc/protos**') + .exclude('**/org/apache/eventmesh/common/protocol/grpc/cloudevents**') + .exclude('**/org/apache/eventmesh/common/protocol/grpc/proto**') + .exclude('**/org/apache/eventmesh/common/protocol/grpc/adminserver/**') + .exclude('**/org/apache/eventmesh/connector/openfunction/client/EventMeshGrpcService**') + .exclude('**/org/apache/eventmesh/connector/openfunction/client/CallbackServiceGrpc**') + .exclude('**/org/apache/eventmesh/connector/jdbc/antlr**') + .exclude('**/org/apache/eventmesh/meta/raft/rpc/**') dependencies { repositories { + mavenCentral() maven { url "https://maven.aliyun.com/repository/public" } } - testImplementation "junit:junit:4.13.2" + testImplementation "org.junit.jupiter:junit-jupiter:5.11.0" + } + + spotless { + enforceCheck false + java { + target project.fileTree(project.projectDir) { + include 'src/*/java/**/*.java' + exclude '**/org/apache/eventmesh/**/protos**' + exclude '**/org/apache/eventmesh/connector/openfunction/client/EventMeshGrpcService**' + exclude '**/org/apache/eventmesh/connector/openfunction/client/CallbackServiceGrpc**' + exclude '**/org/apache/eventmesh/connector/jdbc/antlr**' + exclude '**/org/apache/eventmesh/common/protocol/grpc**' + exclude '**/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/AbstractSnapshotEngine.java' + } + importOrder ('\\#org.apache.eventmesh','\\#org.apache','\\#java','\\#javax','\\#org','\\#io','\\#net','\\#junit','\\#com','\\#lombok', + 'org.apache.eventmesh','org.apache','java','javax','org','io','net','junit','com','lombok') + licenseHeaderFile rootProject.file('style/checkstyle-header-java.txt') + eclipse().configFile("${rootDir}/style/task/eventmesh-spotless-formatter.xml") + removeUnusedImports() + } + } + afterEvaluate { + tasks.forEach {task -> + if (task.name.contains("spotlessJava")) { + task.dependsOn(compileJava, javadoc, compileTestJava, test, processResources, processTestResources) + } + } + spotlessJava.dependsOn(subprojects.collect {it.tasks["spotlessJava"] }) + } + + test { + useJUnitPlatform() + } + + // Remove doclint warnings that pollute javadoc logs when building + if (JavaVersion.current().isJava8()) { + tasks.withType(Javadoc).tap { + configureEach { + options.addStringOption('xdoclint:none', '-quiet') + } + } + } +} + +tasks.register('dist') { + subprojects.forEach { subProject -> + dependsOn("${subProject.path}:jar") + } + dependsOn('generateDistLicense', 'generateDistNotice') + def includedProjects = + ["eventmesh-common", + "eventmesh-meta:eventmesh-meta-api", + "eventmesh-metrics-plugin:eventmesh-metrics-api", + "eventmesh-openconnect:eventmesh-openconnect-java", + "eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api", + "eventmesh-protocol-plugin:eventmesh-protocol-api", + "eventmesh-registry:eventmesh-registry-api", + "eventmesh-retry:eventmesh-retry-api", + "eventmesh-runtime", + "eventmesh-runtime-v2", + "eventmesh-security-plugin:eventmesh-security-api", + "eventmesh-spi", + "eventmesh-starter", + "eventmesh-storage-plugin:eventmesh-storage-api", + "eventmesh-trace-plugin:eventmesh-trace-api"] + doLast { + includedProjects.each { + def subProject = findProject(it) + logger.lifecycle('Install module: module: {}', subProject.name) + copy { + from subProject.jar.archivePath + into rootProject.file('dist/apps') + } + copy { + from subProject.file('bin') + into rootProject.file('dist/bin') + } + copy { + from subProject.file('conf') + from subProject.sourceSets.main.resources.srcDirs + into rootProject.file('dist/conf') + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + exclude 'META-INF' + } + copy { + from subProject.configurations.runtimeClasspath + into rootProject.file('dist/lib') + exclude 'eventmesh-*' + } + } + copy { + from 'tools/dist-license' + into rootProject.file('dist') + } + } +} + +tasks.register('dist-admin') { + subprojects.forEach { subProject -> + dependsOn("${subProject.path}:jar") + } + def includedProjects = + [ + "eventmesh-admin-server", + "eventmesh-common", + "eventmesh-spi", + "eventmesh-registry:eventmesh-registry-api", + "eventmesh-registry:eventmesh-registry-nacos", + "eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api" + ] + doLast { + includedProjects.each { + def subProject = findProject(it) + copy { + from subProject.jar.archivePath + into rootProject.file('dist/apps') + } + copy { + from subProject.configurations.runtimeClasspath + into rootProject.file('dist/lib') + exclude 'eventmesh-*' + } + copy { + from subProject.file('bin') + into rootProject.file('dist/bin') + } + copy { + from subProject.file('conf') + from subProject.sourceSets.main.resources.srcDirs + into rootProject.file('dist/conf') + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + exclude 'META-INF' + } + + } + } + +} + +tasks.register('installPlugin') { + var pluginProjects = subprojects.findAll { + it.file('gradle.properties').exists() + && it.properties.containsKey('pluginType') + && it.properties.containsKey('pluginName') + } + doLast { + String[] libJars = java.util.Optional.ofNullable(file('dist/lib').list()).orElse(new String[0]) + pluginProjects.forEach(subProject -> { + var pluginType = subProject.properties.get('pluginType') + var pluginName = subProject.properties.get('pluginName') + logger.lifecycle('Install plugin: pluginType: {}, pluginInstanceName: {}, module: {}', pluginType, + pluginName, subProject.name) + copy { + from subProject.jar.archivePath + into rootProject.file("dist/plugin/${pluginType}/${pluginName}") + } + copy { + from subProject.configurations.runtimeClasspath + into rootProject.file("dist/plugin/${pluginType}/${pluginName}") + exclude(libJars) + } + copy { + from subProject.file('conf') + from subProject.sourceSets.main.resources.srcDirs + into rootProject.file("dist/conf") + exclude 'META-INF' + } + }) } } -task tar(type: Tar) { +tasks.register('tar', Tar) { archiveBaseName.set(project.name) archiveVersion.set(project.version.toString()) archiveExtension.set('tar.gz') @@ -99,7 +292,7 @@ task tar(type: Tar) { } } -task zip(type: Zip) { +tasks.register('zip', Zip) { archiveBaseName.set(project.name) archiveVersion.set(project.version.toString()) archiveExtension.set('zip') @@ -109,56 +302,207 @@ task zip(type: Zip) { } } -task installPlugin() { - if (!new File("${rootDir}/dist").exists()) { - return - } - String[] libJars = java.util.Optional.ofNullable(new File("${rootDir}/dist/lib").list()).orElseGet(() -> new String[0]) +tasks.register('printProjects') { getAllprojects().forEach(subProject -> { - var file = new File("${subProject.projectDir}/gradle.properties") - if (!file.exists()) { + if ("EventMesh".equals(subProject.getName())) { return } - var properties = new Properties() - properties.load(new FileInputStream(file)) - var pluginType = properties.getProperty("pluginType") - var pluginName = properties.getProperty("pluginName") - if (pluginType == null || pluginName == null) { - return + println String.format("%s-%s.jar", subProject.getName(), subProject.getVersion()) + }) +} + +cyclonedxBom { + includeConfigs = ["runtimeClasspath"] +} + +tasks.register('generateDistLicense') { + dependsOn('cyclonedxBom') // Task from 'org.cyclonedx.bom' plugin + doLast { + // Inputs + def bomFile = file("build/reports/bom.json") + def bom = new JsonSlurper().parseText(bomFile.text) + def projectLicenseText = file('LICENSE').text + + // Outputs + def distLicenseFile = file('tools/dist-license/LICENSE') + def licensesDir = file('tools/dist-license/licenses/java/') + if (licensesDir.exists()) { + licensesDir.eachFile { it.delete() } + } else { + licensesDir.mkdirs() } - var pluginFile = new File("${rootDir}/dist/plugin/${pluginType}/${pluginName}") - if (pluginFile.exists()) { - return + + List> thirdPartyArtifacts = new ArrayList>() + // Parse BOM + bom.components.each { component -> + // Exclude project modules + if (!component.group.startsWith('org.apache.eventmesh')) { + component.licenses.each { artifactLicense -> + if (artifactLicense.license != null) { + Map artifact = new HashMap() + artifact.put("name", component.name) + artifact.put("version", component.version) + if (artifactLicense.license.id != null) { + artifact.put("license", artifactLicense.license.id) + if (artifactLicense.license.text != null) { + artifact.put("licenseContent", new String(artifactLicense.license.text.content.decodeBase64())) + } + } else { + artifact.put("license", artifactLicense.license.name) + artifact.put("licenseContent", artifactLicense.license.url) + } + thirdPartyArtifacts.add(artifact) + } + } + } + } + thirdPartyArtifacts.sort { a, b -> + def nameComparison = a.name <=> b.name + if (nameComparison == 0) { + return a.version <=> b.version + } else { + return nameComparison + } } - pluginFile.mkdirs() - println String.format( - "install plugin, pluginType: %s, pluginInstanceName: %s, module: %s", pluginType, pluginName, subProject.getName() - ) - copy { - into "${rootDir}/dist/plugin/${pluginType}/${pluginName}" - from "${subProject.getProjectDir()}/dist/apps" + def distLicenseText = projectLicenseText + "\n=======================================================================\n" + + "This distribution contains the following third-party artifacts:\n\n" + thirdPartyArtifacts.each { artifact -> + // Write licenses + def artifactLicenseFilename = artifact.license.replaceAll("/", "-") + ".txt" + def artifactLicenseFile = new File(licensesDir, artifactLicenseFilename) + if (artifact.licenseContent != null) { + artifactLicenseFile.text = artifact.licenseContent + if (isURL(artifact.licenseContent)) { + def licenseUrlFilename = artifact.licenseContent.substring(artifact.licenseContent.lastIndexOf("/") + 1) + def downloadedLicenseFilename = artifact.license.replaceAll("/", "-") + "-downloaded-" + licenseUrlFilename + def downloadedLicenseFile = new File(licensesDir, downloadedLicenseFilename) + downloadFileFromURL(artifact.licenseContent, downloadedLicenseFile.path) + } + } else { + artifactLicenseFile.text = "No license content provided by the artifact." + logger.warn("No '${artifact.license}' license content provided by ${artifact.name} ${artifact.version}. Please add manually.") + } + + // Assemble LICENSE + distLicenseText += "${artifact.name} ${artifact.version} licensed under '${artifact.license}'. " + + "For details see: licenses/${artifactLicenseFilename}\n" } - copy { - into "${rootDir}/dist/plugin/${pluginType}/${pluginName}" - from "${subProject.getProjectDir()}/dist/lib/" - exclude(libJars) + distLicenseFile.text = distLicenseText + } +} + +static boolean isURL(String urlString) { + if (!urlString.startsWith("http")) { + return false + } + try { + new URL(urlString) + return true + } catch (MalformedURLException e) { + return false + } +} + +void downloadFileFromURL(String urlString, String destinationPath) throws Exception { + int timeout = 5 * 1000 + RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).build() + CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(config).build() + + HttpGet httpGet = new HttpGet(urlString) + CloseableHttpResponse response + try { + response = httpClient.execute(httpGet) + } catch (Exception e) { + logger.error("Error when downloading " + urlString + " : " + e.getMessage() + ". Please check network connection or add license content manually.") + return + } + + if (response.getStatusLine().getStatusCode() == 200) { + try (InputStream is = response.getEntity().getContent()) { + String respContent = IOUtils.toString(is, StandardCharsets.UTF_8) + if (respContent.startsWith("../")) { + // Follow GitHub symlink + URL baseUrl = new URL(urlString); + URL absoluteUrl = new URL(baseUrl, respContent); + downloadFileFromURL(absoluteUrl.toString(), destinationPath); + } else { + Files.write(Paths.get(destinationPath), respContent.getBytes(StandardCharsets.UTF_8)) + } } - copy { - into "${rootDir}/dist/conf" - from "${subProject.getProjectDir()}/dist/conf" - exclude 'META-INF' + } else { + logger.warn("Failed to download " + urlString + " : " + response.getStatusLine() + ". Please add license content manually.") + } + + EntityUtils.consume(response.getEntity()) + response.close() +} + +tasks.register('checkDeniedLicense') { + dependsOn('generateDistLicense') + doLast { + def deniedLicenses = [ + "MS-LPL", "BUSL-1.1", + "CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5", "CC-BY-NC-3.0", "CC-BY-NC-4.0", + "GPL-1.0", "GPL-2.0", "GPL-3.0", "AGPL-3.0", "LGPL-2.0", "LGPL-2.1", "LGPL-3.0", + "GPL-1.0-only", "GPL-2.0-only", "GPL-3.0-only", "AGPL-3.0-only", "LGPL-2.0-only", "LGPL-2.1-only", "LGPL-3.0-only", + "QPL-1.0", "Sleepycat", "SSPL-1.0", "CPOL-1.02", + "BSD-4-Clause", "BSD-4-Clause-UC", "NPL-1.0", "NPL-1.1", "JSON", + "The GNU General Public License, v2 with Universal FOSS Exception, v1.0" + ] + // Update exemptions according to https://github.com/apache/eventmesh/issues/4842 + def allowedArtifacts = ["amqp-client", "stax-api", "javassist", "ST4", "xsdlib", "jsqlparser"] + + def licenseFile = file('tools/dist-license/LICENSE') + def lines = licenseFile.readLines() + def hasFailed = false + + lines.each { line -> + deniedLicenses.each { deniedLicense -> + if (line.contains("'${deniedLicense}'")) { + def isAllowed = allowedArtifacts.any { allowedArtifact -> + line.contains(allowedArtifact) + } + if (!isAllowed) { + logger.warn("Incompatible license '${deniedLicense}' found in line: ${line}") + hasFailed = true + } + } + } } - }) + + if (hasFailed) { + throw new GradleException("Check failed due to incompatible licenses found. Please remove these dependencies or add exemptions.") + } else { + logger.lifecycle("Check passed, no incompatible licenses found.") + } + } } -task printProjects() { - getAllprojects().forEach(subProject -> { - if ("EventMesh".equals(subProject.getName())) { - return +tasks.register('generateDistNotice') { + dependsOn('generateLicenseReport') // Task from 'com.github.jk1.dependency-license-report' plugin + doLast { + // Inputs + def reportsDir = file("build/reports/dependency-license/") + def projectNoticeText = file('NOTICE').text + + // Outputs + def distNoticeFile = file('tools/dist-license/NOTICE') + + def distNoticeText = projectNoticeText + reportsDir.eachDir { dir -> + dir.eachFileRecurse (groovy.io.FileType.FILES) { file -> + // Find NOTICE files + if (file.name.length() >= 6 && file.name.substring(0, 6).equalsIgnoreCase("NOTICE")) { + def artifactName = dir.name.replace(".jar", "") + distNoticeText += "\n=======================================================================\n\n" + + "${artifactName} NOTICE\n" + "\n=======================================================================\n\n" + distNoticeText += file.text + } + } } - println String.format("%s-%s.jar", subProject.getName(), subProject.getVersion()) - }) + distNoticeFile.text = distNoticeText + } } subprojects { @@ -169,7 +513,6 @@ subprojects { main { java.srcDirs = ['src/main/java'] } - test { java.srcDirs = ['src/test/java'] } @@ -180,15 +523,18 @@ subprojects { delete 'dist' } + // Print all dependencies trees, useful for finding artifacts + tasks.register('printAllDependencyTrees', DependencyReportTask) {} + jacoco { - toolVersion = "0.8.6" + toolVersion = "0.8.11" } jacocoTestReport { reports { - xml.enabled true - csv.enabled false - html.enabled false + xml.required = true + csv.required = false + html.required = false } } @@ -197,7 +543,7 @@ subprojects { showProgress = true showStackTraces = true effort = 'default' - reportsDir = file("$buildDir/reports/spotbugs") + reportsDir = file("build/reports/spotbugs") projectName = rootProject.name release = version extraArgs = ['-nested:false'] @@ -206,12 +552,11 @@ subprojects { } spotbugsMain { - reports { - xml.enabled = false + xml.required = false html { - enabled = true - destination = file("$buildDir/reports/spotbugs/main/spotbugs.html") + required = true + outputLocation = file("build/reports/spotbugs/main/spotbugs.html") stylesheet = 'fancy-hist.xsl' } } @@ -222,7 +567,7 @@ subprojects { xml.enabled = false html { enabled = true - destination = file("$buildDir/reports/spotbugs/test/spotbugs.html") + destination = file("build/reports/spotbugs/test/spotbugs.html") stylesheet = 'fancy-hist.xsl' } } @@ -234,6 +579,9 @@ subprojects { rulesMinimumPriority = 5 ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"] ignoreFailures = true + pmdMain { + excludes = ["**/org/apache/eventmesh/connector/jdbc/antlr4/autogeneration/**"] + } } jar { @@ -249,92 +597,21 @@ subprojects { } } - task dist(dependsOn: ['jar']) { - doFirst { - new File("${projectDir}/dist/bin").mkdirs() - new File("${projectDir}/dist/apps").mkdirs() - new File("${projectDir}/dist/conf").mkdirs() - new File("${projectDir}/dist/lib").mkdirs() - new File("${projectDir}/dist/licenses").mkdirs() - } - Set rootProject = ["eventmesh-admin", - "eventmesh-admin-rocketmq", - "eventmesh-common", - "eventmesh-connector-api", - "eventmesh-metrics-api", - "eventmesh-registry-api", - "eventmesh-trace-api", - "eventmesh-runtime", - "eventmesh-security-api", - "eventmesh-protocol-api", - "eventmesh-starter", - "eventmesh-spi", - "eventmesh-webhook-api", - "eventmesh-webhook-admin", - "eventmesh-webhook-receive" - ] - doLast { - copy { - into("${projectDir}/dist/apps") - from project.jar.getArchivePath() - } - copy { - into("${projectDir}/dist/lib") - from project.configurations.runtimeClasspath - } - copy { - into("${projectDir}/dist/bin") - from 'bin' - } - copy { - into("${projectDir}/dist/conf") - from 'conf', sourceSets.main.resources.srcDirs - setDuplicatesStrategy(DuplicatesStrategy.EXCLUDE) - exclude 'META-INF' - } - if (rootProject.contains(project.name)) { - new File("${rootDir}/dist/apps").mkdirs() - new File("${rootDir}/dist/lib").mkdirs() - new File("${rootDir}/dist/bin").mkdirs() - new File("${rootDir}/dist/conf").mkdirs() - copy { - into("${rootDir}/dist/apps") - from "${projectDir}/dist/apps" - } - copy { - into "${rootDir}/dist/lib" - from "${projectDir}/dist/lib" - exclude "eventmesh-*" - } - copy { - into "${rootDir}/dist/bin" - from "${projectDir}/dist/bin" - } - copy { - into "${rootDir}/dist/conf" - from "${projectDir}/dist/conf" - } - } - copy { - into "${rootDir}/dist" - from "${rootDir}/tools/third-party-licenses" - } - } - } - javadoc { source = sourceSets.main.java destinationDir = reporting.file("javadoc") + options.encoding = "UTF-8" } - task packageJavadoc(type: Jar, dependsOn: ['javadoc']) { + tasks.register('packageJavadoc', Jar) { + dependsOn('javadoc') from project.javadoc.destinationDir - classifier = 'javadoc' + archiveClassifier.set('javadoc') } - task packageSources(type: Jar) { + tasks.register('packageSources', Jar) { from project.sourceSets.main.allSource - classifier = 'sources' // either here or in artifacts block + archiveClassifier.set('sources') } artifacts { @@ -344,7 +621,7 @@ subprojects { } if (!Boolean.valueOf(signEnabled)) { - tasks.whenTaskAdded { task -> + tasks.configureEach { task -> if (task.name.contains("sign")) { task.enabled = false } @@ -352,12 +629,11 @@ subprojects { } repositories { - maven { url "https://maven.aliyun.com/repository/public" } mavenCentral() - mavenLocal() + maven { url "https://maven.aliyun.com/repository/public" } } - configurations.all { + configurations.configureEach { resolutionStrategy.cacheChangingModulesFor 0, TimeUnit.SECONDS resolutionStrategy.cacheDynamicVersionsFor 0, TimeUnit.SECONDS } @@ -379,24 +655,24 @@ subprojects { pom { name = 'EventMesh' description = 'Apache EventMesh' - url = 'https://github.com/apache/incubator-eventmesh' + url = 'https://github.com/apache/eventmesh' licenses { license { name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + url = 'https://www.apache.org/licenses/LICENSE-2.0.txt' } } developers { developer { - id = 'Apache EventMesh(incubating)' - name = 'Apache EventMesh(incubating) of ASF' + id = 'Apache EventMesh' + name = 'Apache EventMesh of ASF' url = 'https://eventmesh.apache.org/' } } scm { - connection = 'scm:git:git@github.com:apache/incubator-eventmesh.git' - developerConnection = 'scm:git:git@github.com:apache/incubator-eventmesh.git' - url = 'https://github.com/apache/incubator-eventmesh' + connection = 'scm:git:git@github.com:apache/eventmesh.git' + developerConnection = 'scm:git:git@github.com:apache/eventmesh.git' + url = 'https://github.com/apache/eventmesh' } } } @@ -410,7 +686,6 @@ subprojects { username apacheUserName password apachePassWord } - } } } @@ -419,77 +694,111 @@ subprojects { sign publishing.publications.mavenJava } + def grpcVersion = '1.68.0' + def log4jVersion = '2.24.1' + def jacksonVersion = '2.18.0' + def dropwizardMetricsVersion = '4.2.26' + def opentelemetryVersion = '1.36.0' + def cloudeventsVersion = '3.0.0' + def curatorVersion = '5.7.0' + def mockitoVersion = '4.11.0' + dependencyManagement { dependencies { - dependency "org.apache.commons:commons-lang3:3.6" - dependency "org.apache.commons:commons-collections4:4.1" - dependency "org.apache.commons:commons-text:1.9" - - - dependency "com.google.guava:guava:31.0.1-jre" - - dependency "org.slf4j:slf4j-api:1.7.30" - dependency "org.apache.logging.log4j:log4j-api:2.17.1" - dependency "org.apache.logging.log4j:log4j-core:2.17.1" - dependency "org.apache.logging.log4j:log4j-slf4j-impl:2.17.1" + dependency "org.apache.commons:commons-lang3:3.17.0" + dependency "org.apache.commons:commons-collections4:4.4" + dependency "org.apache.commons:commons-text:1.12.0" + dependency "commons-io:commons-io:2.18.0" + dependency "commons-validator:commons-validator:1.9.0" + dependency "com.google.guava:guava:33.3.0-jre" + + dependency "org.slf4j:slf4j-api:2.0.13" + dependency "org.apache.logging.log4j:log4j-api:${log4jVersion}" + dependency "org.apache.logging.log4j:log4j-core:${log4jVersion}" + dependency "org.apache.logging.log4j:log4j-slf4j2-impl:${log4jVersion}" + + dependency "com.lmax:disruptor:3.4.4" + + dependency "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" + dependency "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" + dependency "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" + dependency "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${jacksonVersion}" + dependency "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jacksonVersion}" + + dependency "com.squareup.okhttp3:okhttp:3.14.9" + + dependency "org.asynchttpclient:async-http-client:2.12.3" + dependency "org.apache.httpcomponents:httpclient:4.5.14" + + dependency "io.netty:netty-all:4.1.112.Final" + + dependency "io.dropwizard.metrics:metrics-core:${dropwizardMetricsVersion}" + dependency "io.dropwizard.metrics:metrics-healthchecks:${dropwizardMetricsVersion}" + dependency "io.dropwizard.metrics:metrics-annotation:${dropwizardMetricsVersion}" + dependency "io.dropwizard.metrics:metrics-json:${dropwizardMetricsVersion}" + + dependency "io.opentelemetry:opentelemetry-api:${opentelemetryVersion}" + dependency "io.opentelemetry:opentelemetry-sdk:${opentelemetryVersion}" + dependency "io.opentelemetry:opentelemetry-sdk-metrics:${opentelemetryVersion}" + dependency "io.opentelemetry:opentelemetry-exporter-prometheus:${opentelemetryVersion}-alpha" + dependency "io.opentelemetry:opentelemetry-exporter-zipkin:${opentelemetryVersion}" + dependency "io.opentelemetry:opentelemetry-semconv:1.30.1-alpha" + dependency "io.opentelemetry:opentelemetry-exporter-jaeger:1.34.1" - dependency "com.lmax:disruptor:3.4.2" - - dependency "com.fasterxml.jackson.core:jackson-databind:2.13.0" - dependency "com.fasterxml.jackson.core:jackson-core:2.13.0" - dependency "com.fasterxml.jackson.core:jackson-annotations:2.13.0" + dependency "io.openmessaging:openmessaging-api:2.2.1-pubsub" - dependency "org.apache.httpcomponents:httpclient:4.5.13" + dependency "com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0" + dependency "com.mebigfatguy.fb-contrib:fb-contrib:7.6.4" + dependency "com.jayway.jsonpath:json-path:2.9.0" - dependency "io.netty:netty-all:4.1.73.Final" + dependency "org.springframework.boot:spring-boot-starter-web:2.7.18" + dependency "io.openmessaging:registry-server:0.0.1" - dependency 'io.dropwizard.metrics:metrics-core:4.1.0' - dependency "io.dropwizard.metrics:metrics-healthchecks:4.1.0" - dependency "io.dropwizard.metrics:metrics-annotation:4.1.0" - dependency "io.dropwizard.metrics:metrics-json:4.1.0" + dependency "org.junit.jupiter:junit-jupiter:5.11.0" + dependency "org.junit-pioneer:junit-pioneer:1.9.1" + dependency "org.assertj:assertj-core:3.26.3" - dependency 'io.opentelemetry:opentelemetry-api:1.3.0' - dependency 'io.opentelemetry:opentelemetry-sdk:1.3.0' - dependency 'io.opentelemetry:opentelemetry-sdk-metrics:1.3.0-alpha' - dependency 'io.opentelemetry:opentelemetry-exporter-prometheus:1.3.0-alpha' - dependency 'io.prometheus:simpleclient:0.8.1' - dependency 'io.prometheus:simpleclient_httpserver:0.8.1' - dependency 'io.opentelemetry:opentelemetry-exporter-zipkin:1.3.0' - dependency 'io.opentelemetry:opentelemetry-semconv:1.3.0-alpha' + dependency "org.mockito:mockito-core:${mockitoVersion}" + dependency "org.mockito:mockito-inline:${mockitoVersion}" + dependency "org.mockito:mockito-junit-jupiter:${mockitoVersion}" - dependency "io.openmessaging:openmessaging-api:2.2.1-pubsub" + dependency "io.cloudevents:cloudevents-core:${cloudeventsVersion}" + dependency "io.cloudevents:cloudevents-json-jackson:${cloudeventsVersion}" + dependency "io.cloudevents:cloudevents-protobuf:${cloudeventsVersion}" - dependency "com.h3xstream.findsecbugs:findsecbugs-plugin:1.11.0" - dependency "com.mebigfatguy.fb-contrib:fb-contrib:7.4.7" + dependency "io.grpc:grpc-core:${grpcVersion}" + dependency "io.grpc:grpc-protobuf:${grpcVersion}" + dependency "io.grpc:grpc-stub:${grpcVersion}" + dependency "io.grpc:grpc-netty:${grpcVersion}" + dependency "io.grpc:grpc-netty-shaded:${grpcVersion}" - dependency "org.springframework.boot:spring-boot-starter-web:2.6.7" - dependency "io.openmessaging:registry-server:0.0.1" + dependency "javax.annotation:javax.annotation-api:1.3.2" - dependency "junit:junit:4.13.2" - dependency "com.github.stefanbirkner:system-rules:1.16.1" - dependency "org.assertj:assertj-core:2.6.0" + dependency "com.github.seancfoley:ipaddress:5.5.0" + dependency "com.google.code.gson:gson:2.11.0" - dependency "org.mockito:mockito-core:3.8.0" - dependency "org.mockito:mockito-inline:3.8.0" - dependency "org.powermock:powermock-module-junit4:2.0.2" - dependency "org.powermock:powermock-api-mockito2:2.0.2" + dependency "org.javassist:javassist:3.30.2-GA" - dependency "io.cloudevents:cloudevents-core:2.2.0" - dependency "io.cloudevents:cloudevents-json-jackson:2.2.0" + dependency "com.alibaba.nacos:nacos-client:2.4.1" - dependency "io.grpc:grpc-protobuf:1.17.1" - dependency "io.grpc:grpc-stub:1.17.1" - dependency "io.grpc:grpc-netty:1.17.1" - dependency "io.grpc:grpc-netty-shaded:1.17.1" + dependency 'org.apache.zookeeper:zookeeper:3.9.2' + dependency "org.apache.curator:curator-client:${curatorVersion}" + dependency "org.apache.curator:curator-framework:${curatorVersion}" + dependency "org.apache.curator:curator-recipes:${curatorVersion}" + dependency "org.apache.curator:curator-test:${curatorVersion}" + dependency "org.projectlombok:lombok:1.18.34" dependency "javax.annotation:javax.annotation-api:1.3.2" + dependency "com.alibaba.fastjson2:fastjson2:2.0.52" - dependency "com.github.seancfoley:ipaddress:5.3.3" - dependency "com.google.code.gson:gson:2.8.2" - - dependency "org.yaml:snakeyaml:1.30" - dependency "org.javassist:javassist:3.24.0-GA" + dependency "software.amazon.awssdk:s3:2.29.5" + dependency "com.github.rholder:guava-retrying:2.0.0" + dependency "com.alibaba:druid-spring-boot-starter:1.2.23" + dependency "com.baomidou:mybatis-plus-boot-starter:3.5.7" + dependency "com.mysql:mysql-connector-j:8.4.0" + dependency "org.springframework.boot:spring-boot-starter-jetty:2.7.18" + dependency "org.locationtech.jts:jts-core:1.20.0" } } } diff --git a/docker/Dockerfile_jdk11 b/docker/Dockerfile_jdk11 new file mode 100644 index 0000000000..14afdb7406 --- /dev/null +++ b/docker/Dockerfile_jdk11 @@ -0,0 +1,37 @@ +# +# 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. +# + +FROM openjdk:11-jdk as builder +WORKDIR /build +COPY . . +RUN ./gradlew clean build dist --parallel --daemon +RUN ./gradlew installPlugin + +FROM openjdk:11-jdk +RUN apt-get update && apt-get install -y locales procps +RUN localedef -i en_US -f UTF-8 en_US.UTF-8 --quiet +WORKDIR /data/app/eventmesh +COPY --from=builder /build/dist ./ + +EXPOSE 10000 10105 10106 10205 + +ENV DOCKER true +ENV EVENTMESH_HOME /data/app/eventmesh +ENV EVENTMESH_LOG_HOME /data/app/eventmesh/logs +ENV CONFPATH /data/app/eventmesh/conf + +CMD ["bash", "bin/start.sh"] diff --git a/docker/Dockerfile_jdk8 b/docker/Dockerfile_jdk8 new file mode 100644 index 0000000000..59dc1ae757 --- /dev/null +++ b/docker/Dockerfile_jdk8 @@ -0,0 +1,42 @@ +# +# 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. +# + +FROM openjdk:11-jdk as builder_11 +WORKDIR /build +COPY . . +RUN ./gradlew clean generateGrammarSource --parallel --daemon + +FROM openjdk:8-jdk as builder_8 +WORKDIR /build +COPY --from=builder_11 /build ./ +RUN ./gradlew clean build dist -x spotlessJava -x generateGrammarSource --parallel --daemon +RUN ./gradlew installPlugin + +FROM openjdk:8-jdk +RUN apt-get update && apt-get install -y locales procps +RUN localedef -i en_US -f UTF-8 en_US.UTF-8 --quiet +WORKDIR /data/app/eventmesh +COPY --from=builder_8 /build/dist ./ + +EXPOSE 10000 10105 10106 10205 + +ENV DOCKER true +ENV EVENTMESH_HOME /data/app/eventmesh +ENV EVENTMESH_LOG_HOME /data/app/eventmesh/logs +ENV CONFPATH /data/app/eventmesh/conf + +CMD ["bash", "bin/start.sh"] diff --git a/docker/centos7-jdk8/Dockerfile b/docker/centos7-jdk8/Dockerfile deleted file mode 100644 index 7d968413d5..0000000000 --- a/docker/centos7-jdk8/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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. -# - -FROM docker.io/centos:7 - -MAINTAINER mikexue - -RUN yum update -y && yum install net-tools -y && yum install lrzsz -y && yum install vim -y -ADD jdk-8u281-linux-x64.tar.gz /usr/local/src/ -RUN ln -s /usr/local/src/jdk1.8.0_281/ /usr/local/jdk - -ENV JAVA_HOME /usr/local/jdk -ENV JRE_HOME $JAVA_HOME/jre -ENV CLASSPATH .:$JAVA_HOME/lib/:$JRE_HOME/lib/ -ENV PATH $PATH:$JAVA_HOME/bin diff --git a/docker/eventmesh/Dockerfile b/docker/eventmesh/Dockerfile deleted file mode 100644 index 6ea5944d19..0000000000 --- a/docker/eventmesh/Dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -# -# 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. -# - -FROM centos7-jdk8:latest - -MAINTAINER mikexue mike_xwm@126.com - -WORKDIR /data -RUN mkdir /data/app -ADD EventMesh_1.3.0-release.tar.gz /data/app/eventmesh -WORKDIR /data/app/eventmesh/bin - -EXPOSE 10000 -EXPOSE 10105 - -ENV DOCKER true - -CMD sh start.sh - diff --git a/docs/a2a-protocol/ARCHITECTURE.md b/docs/a2a-protocol/ARCHITECTURE.md new file mode 100644 index 0000000000..bcb485b107 --- /dev/null +++ b/docs/a2a-protocol/ARCHITECTURE.md @@ -0,0 +1,316 @@ +# EventMesh A2A Protocol Architecture & Functional Specification + +## 1. Overview + +The **EventMesh A2A (Agent-to-Agent) Protocol** is a specialized, high-performance protocol plugin designed to enable asynchronous communication, collaboration, and task coordination between autonomous agents. + +With the release of v2.0, A2A adopts the **MCP (Model Context Protocol)** architecture, transforming EventMesh into a robust **Agent Collaboration Bus**. It bridges the gap between synchronous LLM-based tool calls (JSON-RPC 2.0) and asynchronous Event-Driven Architectures (EDA), enabling scalable, distributed, and decoupled agent systems. + +## 2. Core Philosophy + +The architecture adheres to the principles outlined in the broader agent community (e.g., A2A Project, FIPA-ACL, and CloudEvents): + +1. **JSON-RPC 2.0 as Lingua Franca**: Uses standard JSON-RPC for payload semantics, ensuring compatibility with modern LLM ecosystems (LangChain, AutoGen). +2. **Transport Agnostic**: Encapsulates all messages within **CloudEvents**, allowing transport over any EventMesh-supported protocol (HTTP, TCP, gRPC, Kafka). +3. **Async by Default**: Maps synchronous Request/Response patterns to asynchronous Event streams using correlation IDs. +4. **Native Pub/Sub Semantics**: Supports O(1) broadcast complexity, temporal decoupling (Late Join), and backpressure isolation, solving the scalability limits of traditional P2P webhook callbacks. + +### 2.1 Native Pub/Sub Semantics + +Traditional A2A implementations often rely on HTTP Webhooks (`POST /inbox`) for asynchronous callbacks. While functional, this **Point-to-Point (P2P)** model suffers from significant scaling issues: + +* **Insufficient Fan-Out**: A publisher must send $N$ requests to reach $N$ subscribers, leading to $O(N)$ complexity. +* **Temporal Coupling**: Consumers must be online at the exact moment of publication. +* **Backpressure Propagation**: A slow subscriber can block the publisher. + +**EventMesh A2A** solves this by introducing **Native Pub/Sub** capabilities: + +```mermaid +graph LR + Publisher[Publisher Agent] -->|1. Publish (Once)| Bus[EventMesh Bus] + + subgraph Fanout_Layer [EventMesh Fanout Layer] + Queue[Topic Queue] + end + + Bus --> Queue + + Queue -->|Push| Sub1[Subscriber 1] + Queue -->|Push| Sub2[Subscriber 2] + Queue -->|Push| Sub3[Subscriber 3] + + style Bus fill:#f9f,stroke:#333 + style Fanout_Layer fill:#ccf,stroke:#333 +``` + +## 3. Architecture Design + +### 3.1 System Context + +```mermaid +graph TD + Client[Client Agent / LLM] -- "JSON-RPC Request" --> EM[EventMesh Runtime] + EM -- "CloudEvent (Request)" --> Server[Server Agent / Tool] + Server -- "CloudEvent (Response)" --> EM + EM -- "JSON-RPC Response" --> Client + + subgraph Runtime [EventMesh Runtime] + Plugin[A2A Protocol Plugin] + end + + style EM fill:#f9f,stroke:#333,stroke-width:4px + style Plugin fill:#ccf,stroke:#333,stroke-width:2px +``` + +### 3.2 Component Design (`eventmesh-protocol-a2a`) + +The core protocol logic resides in the `eventmesh-protocol-plugin` module. + +* **`EnhancedA2AProtocolAdaptor`**: The central brain of the protocol. + * **Intelligent Parsing**: Automatically detects message format (MCP vs. Raw CloudEvent). + * **Protocol Delegation**: Delegates to `CloudEvents` or `HTTP` adaptors when necessary. + * **Semantic Mapping**: Transforms JSON-RPC methods and IDs into CloudEvent attributes. +* **`A2AProtocolConstants`**: Defines standard operations like `task/get`, `message/sendStream`. +* **`JsonRpc*` Models**: Strictly typed POJOs for JSON-RPC 2.0 compliance. +* **`AgentCard` / `AgentSkill` / `AgentInterface`**: Agent capability discovery models. +* **`A2ATopicFactory`**: Topic naming and parsing utility for request/response/status topics. +* **`A2AClient`**: Java SDK for agent developers — AgentCard registration, task submission (sync/async), task status query, heartbeat, and transport-based request handling. Returns typed `TaskResult` objects. +* **`A2AMessageTransport`**: Transport-agnostic pub/sub interface (InMemory implementation for dev/testing). + +### 3.3 Gateway Runtime Architecture (`eventmesh-runtime`) + +The Gateway runtime provides a standalone Netty HTTP server bridging external clients to the A2A event bus. + +```mermaid +graph TD + Client["Client / A2AClient SDK"] -- "HTTP REST" --> Server["A2AGatewayServer
(Netty HTTP)"] + Server --> Handler["A2AGatewayHttpHandler"] + Handler --> GwService["A2AGatewayService"] + GwService --> Registry["TaskRegistry
(state machine + TTL)"] + GwService --> Transport["InMemoryA2AMessageTransport"] + GwService --> PubSub["A2APublishSubscribeService
(AgentCard discovery)"] + Transport -- "publish/subscribe" --> Agent["Target Agent"] + Agent -- "response event" --> Transport + Transport --> GwService + + style Server fill:#f9f,stroke:#333,stroke-width:2px + style Registry fill:#cfc,stroke:#333 + style Transport fill:#ccf,stroke:#333 +``` + +#### Core Components + +| Component | Module | Responsibility | +| :--- | :--- | :--- | +| `A2AGatewayServer` | runtime | Standalone Netty HTTP server entry point. Pre-registers mock agents, wires all components. | +| `A2AGatewayHttpHandler` | runtime | HTTP request router. Maps REST endpoints to service calls. Supports SSE streaming. | +| `A2AGatewayService` | runtime | Core orchestration: task submission, response handling, status subscription, SSE push. | +| `TaskRegistry` | runtime | In-memory task lifecycle state machine with TTL auto-cleanup. | +| `A2APublishSubscribeService` | runtime | AgentCard registration, discovery, and heartbeat management. | +| `InMemoryA2AMessageTransport` | runtime | In-memory pub/sub (replaceable by EventMesh broker). | +| `A2ACardHttpHandler` | runtime | AgentCard CRUD REST endpoints (`/a2a/cards/*`). | +| `A2AClient` | protocol-a2a | Java SDK for agent developers (HTTP + transport). | + +#### Task Lifecycle State Machine + +``` +SUBMITTED → WORKING → COMPLETED + ↘ FAILED + ↘ CANCELLED +``` + +* **TTL Auto-Cleanup**: Terminal-state tasks are automatically removed after a configurable TTL (default: 5 minutes). A daemon thread runs cleanup every 60 seconds. +* **Race Condition Prevention**: `pendingTasks.put(taskId, future)` is called **before** `transport.publish()` to ensure the future is registered before any synchronous delivery could trigger `handleResponse()`. + +#### REST API + +| Method | Path | Description | +| :--- | :--- | :--- | +| `POST` | `/a2a/tasks?mode=sync` | Submit task synchronously (wait for result) | +| `POST` | `/a2a/tasks?mode=async` | Submit task asynchronously (return taskId immediately) | +| `GET` | `/a2a/tasks/{taskId}` | Get task status and result | +| `DELETE` | `/a2a/tasks/{taskId}` | Cancel a task | +| `GET` | `/a2a/tasks/{taskId}/wait` | Long-poll wait for task result | +| `GET` | `/a2a/tasks/{taskId}/stream` | **SSE** stream of task status updates | +| `GET` | `/a2a/agents` | List all registered agents | +| `POST` | `/a2a/heartbeat` | Agent heartbeat | +| `GET` | `/a2a/cards/list` | List all AgentCards | +| `POST` | `/a2a/cards/card/{org}/{unit}/{agent}` | Register an AgentCard | + +### 3.4 Asynchronous RPC Mapping ( The "Async Bridge" ) + +To support MCP on an Event Bus, synchronous RPC concepts are mapped to asynchronous events: + +| Concept | MCP / JSON-RPC | CloudEvent Mapping | +| :--- | :--- | :--- | +| **Action** | `method` (e.g., `tools/call`) | **Type**: `org.apache.eventmesh.a2a.tools.call.req`
**Extension**: `a2amethod` | +| **Correlation** | `id` (e.g., `req-123`) | **Extension**: `collaborationid` (on Response)
**ID**: Preserved on Request | +| **Direction** | Implicit (Request vs Result) | **Extension**: `mcptype` (`request` or `response`) | +| **P2P Routing** | `params._agentId` | **Extension**: `targetagent` | +| **Pub/Sub Topic** | `params._topic` | **Subject**: The topic value (e.g. `market.btc`) | +| **Streaming Seq** | `params._seq` | **Extension**: `seq` | + +## 4. Functional Specification + +### 4.1 Message Processing Flow + +1. **Ingestion**: The adaptor receives a `ProtocolTransportObject` (byte array/string). +2. **Detection**: Checks for `jsonrpc: "2.0"`. +3. **Transformation (MCP Mode)**: + * **Request**: Parses `method`. + * If `message/sendStream`, sets type suffix to `.stream` and extracts `_seq`. + * If `_topic` present, sets `subject` (Pub/Sub). + * If `_agentId` present, sets `targetagent` (P2P). + * **Response**: Parses `result`/`error`. Sets `collaborationid` = `id`. +4. **Batch Processing**: Splits JSON Array into a `List`. + +### 4.2 Key Features + +#### A. Intelligent Routing Support +* **Mechanism**: Promotes `_agentId` or `_topic` from JSON body to CloudEvent attributes. +* **Benefit**: Enables EventMesh Router to perform content-based routing (CBR) efficiently. + +#### B. Batching +* **Benefit**: Significantly increases throughput for high-frequency interactions. + +#### C. Streaming Support +* **Operation**: `message/sendStream` +* **Mechanism**: Maps to `.stream` event type and preserves sequence order via `seq` extension attribute. + +#### D. SSE Task Streaming (Gateway) +* **Endpoint**: `GET /a2a/tasks/{taskId}/stream` +* **Mechanism**: Server-Sent Events (`text/event-stream`) pushes real-time task state transitions. +* **Flow**: Initial state → WORKING updates → terminal state → connection close. +* **Implementation**: Handler writes `DefaultHttpContent` chunks directly to the Netty channel, returning `null` to skip the standard `FullHttpResponse` path. + +#### E. Task TTL Auto-Cleanup (Gateway) +* Terminal-state tasks are automatically removed by a daemon scheduler after a configurable TTL (default: 5 minutes, cleanup interval: 60 seconds), preventing memory leaks. + +#### F. AgentCard Discovery & Heartbeat (Gateway) +* AgentCards expire after 60 seconds without heartbeat. `POST /a2a/heartbeat` refreshes the last-seen timestamp. + +## 5. Usage Examples + +### 5.1 Sending a Tool Call (Request) + +**Raw Payload:** +```json +{ + "jsonrpc": "2.0", + "method": "tools/call", + "params": { + "name": "weather_service", + "arguments": { "city": "New York" } + }, + "id": "msg-101" +} +``` + +### 5.2 Pub/Sub Broadcast + +**Raw Payload:** +```json +{ + "jsonrpc": "2.0", + "method": "market/update", + "params": { + "symbol": "BTC", + "price": 50000, + "_topic": "market.crypto.btc" + } +} +``` + +**Generated CloudEvent:** +* `subject`: `market.crypto.btc` +* `targetagent`: (Empty) + +### 5.3 Gateway REST API (HTTP) + +The A2A Gateway provides a REST API for external clients and non-Java agents. + +#### 5.3.1 Submit Task (Sync) + +```bash +curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Beijing"}' +``` + +Response: +```json +{ + "taskId": "task-a1b2c3d4", + "state": "COMPLETED", + "data": "The weather in Beijing is sunny, 25°C" +} +``` + +#### 5.3.2 Submit Task (Async) + +```bash +curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Shanghai"}' +``` + +#### 5.3.3 SSE Stream + +```bash +curl -N http://localhost:10105/a2a/tasks/{taskId}/stream +``` + +Response (`text/event-stream`): +``` +data: {"taskId":"task-a1b2c3d4","state":"SUBMITTED"} + +data: {"taskId":"task-a1b2c3d4","state":"WORKING","data":"processing..."} + +data: {"taskId":"task-a1b2c3d4","state":"completed","data":"result..."} +``` + +#### 5.3.4 List Agents + +```bash +curl http://localhost:10105/a2a/agents +``` + +### 5.4 A2AClient SDK (Java) + +```java +A2AClient client = A2AClient.builder() + .gatewayUrl("http://localhost:10105") + .namespace("global") + .agentName("my-agent") + .agentCard(card) + .heartbeatInterval(30_000) + .build(); + +client.start(); + +// Synchronous task (returns typed TaskResult) +TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + +// Asynchronous task (returns taskId immediately) +String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); + +// Poll status +TaskResult status = client.getTaskStatus(taskId); + +// Cancel +boolean cancelled = client.cancelTask(taskId); + +// List registered agents (typed List) +List agents = client.listAgents(); + +client.shutdown(); +``` + +## 6. Future Roadmap + +* **EventMesh Broker Integration**: Replace `InMemoryA2AMessageTransport` with the real EventMesh broker for production deployment. +* **Schema Registry**: Implement dynamic discovery of Agent capabilities via `methods/list`. +* **Sidecar Injection**: Fully integrate the adaptor into the EventMesh Sidecar. +* **WebSocket Streaming**: Extend SSE to bidirectional WebSocket for real-time agent dialogue. +* **Task Persistence**: Persist `TaskRegistry` state to a durable store for crash recovery. +* **Authentication**: Add API key / JWT authentication to the Gateway REST API. \ No newline at end of file diff --git a/docs/a2a-protocol/IMPLEMENTATION_SUMMARY.md b/docs/a2a-protocol/IMPLEMENTATION_SUMMARY.md new file mode 100644 index 0000000000..fd5081c610 --- /dev/null +++ b/docs/a2a-protocol/IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,103 @@ +# 实现总结:EventMesh A2A 协议 v2.0 (MCP 版) + +## 核心成果 + +A2A 协议已成功重构为采用 **MCP (Model Context Protocol)** 架构,将 EventMesh 定位为现代化的 **智能体协作总线 (Agent Collaboration Bus)**。 + +### 1. 核心协议重构 (`EnhancedA2AProtocolAdaptor`) +- **混合引擎 (JSON-RPC & CloudEvents)**: 实现了智能解析引擎,支持: + - **MCP/JSON-RPC 2.0**: 面向 LLM 和脚本的低门槛接入,自动封装 CloudEvent。 + - **原生 CloudEvents**: 面向 EventMesh 原生应用的灵活接入,支持自定义元数据和透传。 + - 适配器根据 `jsonrpc` 字段自动分发处理逻辑。 +- **异步 RPC 映射**: 建立了同步 RPC 语义与异步事件驱动架构 (EDA) 之间的桥梁。 + - **请求 (Requests)** 映射为 `*.req` 事件,属性 `mcptype=request`。 + - **响应 (Responses)** 映射为 `*.resp` 事件,属性 `mcptype=response`。 + - **关联 (Correlation)** 通过将 JSON-RPC `id` 映射到 CloudEvent `collaborationid` 来处理。 +- **路由优化**: 实现了"深度内容路由提取": + - `params._agentId` -> CloudEvent 扩展属性 `targetagent` (P2P)。 + - `params._topic` -> CloudEvent Subject (Pub/Sub)。 + +### 2. 原生 Pub/Sub 与流式支持 +- **Pub/Sub**: 通过将 `_topic` 映射到 CloudEvent Subject,支持 O(1) 广播复杂度。 +- **流式 (Streaming)**: 支持 `message/sendStream` 操作,映射为 `.stream` 事件类型,并通过 `_seq` -> `seq` 扩展属性保证顺序。 + +### 3. 标准化与兼容性 +- **数据模型**: 定义了符合 JSON-RPC 2.0 规范的 `JsonRpcRequest`、`JsonRpcResponse`、`JsonRpcError` POJO 对象。 +- **方法定义**: 引入了 `McpMethods` 常量,支持标准操作如 `tools/call`、`resources/read`。 +- **AgentCard 模型**: 实现了 `AgentCard`、`AgentSkill`、`AgentInterface`、`AgentCapabilities` 等完整的 Agent 能力描述模型。 + +### 4. Gateway 运行时架构 (`eventmesh-runtime`) + +完整的独立 HTTP Gateway 服务,桥接外部客户端到 A2A 事件总线。 + +#### 核心组件 + +| 组件 | 职责 | +| :--- | :--- | +| `A2AGatewayServer` | Netty HTTP 服务器入口,预注册 mock agent,组装所有组件 | +| `A2AGatewayHttpHandler` | HTTP 请求路由,支持 SSE 流式响应 | +| `A2AGatewayService` | 核心编排:任务提交、响应处理、状态订阅、SSE 推送 | +| `TaskRegistry` | 内存任务状态机 + TTL 自动清理 | +| `A2APublishSubscribeService` | AgentCard 注册、发现、心跳管理 | +| `InMemoryA2AMessageTransport` | 内存 pub/sub 实现(可替换为 EventMesh broker) | +| `A2ACardHttpHandler` | AgentCard CRUD REST 端点 | +| `A2AClient` | Java SDK,提供类型化 API | + +#### REST API + +| 方法 | 路径 | 说明 | +| :--- | :--- | :--- | +| `POST` | `/a2a/tasks?mode=sync` | 同步提交任务 | +| `POST` | `/a2a/tasks?mode=async` | 异步提交任务 | +| `GET` | `/a2a/tasks/{taskId}` | 查询任务状态 | +| `DELETE` | `/a2a/tasks/{taskId}` | 取消任务 | +| `GET` | `/a2a/tasks/{taskId}/wait` | 长轮询等待结果 | +| `GET` | `/a2a/tasks/{taskId}/stream` | SSE 流式推送状态更新 | +| `GET` | `/a2a/agents` | 列出已注册 agents | +| `POST` | `/a2a/heartbeat` | Agent 心跳 | +| `GET` | `/a2a/cards/list` | 列出所有 AgentCard | +| `POST` | `/a2a/cards/card/{org}/{unit}/{agent}` | 注册 AgentCard | + +### 5. 关键改进 + +#### 5.1 TaskRegistry TTL 自动清理 +- **问题**: 终态任务(COMPLETED/FAILED/CANCELLED)无限累积导致内存泄漏。 +- **方案**: 守护线程 `ScheduledExecutorService` 每 60 秒扫描一次,清理超过 TTL(默认 5 分钟)的终态任务。 +- **配置**: `TaskRegistry(taskTtlMs, cleanupIntervalMs)` 构造函数支持自定义调优。 + +#### 5.2 竞态条件修复 +- **问题**: `InMemoryTransport` 同步投递消息,若 `transport.publish()` 在 `pendingTasks.put()` 之前执行,`handleResponse()` 会先于 `put()` 运行,导致 future 永不完成。 +- **方案**: 严格保证 `pendingTasks.put(taskId, future)` 在 `transport.publish()` 之前执行,并添加注释说明顺序重要性。 + +#### 5.3 A2AClient 类型化返回 +- **改进**: `getTaskStatus()` 返回 `TaskResult` 对象(而非原始 JSON 字符串),`listAgents()` 返回 `List`(而非原始 JSON)。 +- **兼容**: `TaskResult.data` 字段使用 `@JsonAlias("result")` 注解,兼容服务端 `result` 字段名。 + +#### 5.4 SSE 流式响应 +- **端点**: `GET /a2a/tasks/{taskId}/stream` +- **实现**: Handler 直接写入 Netty channel(`DefaultHttpContent` chunks),返回 `null` 跳过标准 `FullHttpResponse` 路径。通过 `StatusSubscriber` 回调实时推送状态变更。 + +#### 5.5 使用文档 +- 新建 `eventmesh-examples/.../demo/README.md`,包含架构图、API 表、curl 示例、SDK 用法、运行方式。 + +### 6. 测试与质量 +- **协议层单元测试**: `EnhancedA2AProtocolAdaptorTest` 覆盖请求/响应循环、错误处理、通知和批处理。 +- **Topic 工具测试**: `A2ATopicFactoryTest` 覆盖 topic 生成与解析。 +- **Gateway 运行时测试**: + - `TaskRegistryTest` — 任务状态机 + TTL 清理验证 + - `InMemoryA2AMessageTransportTest` — 内存传输投递 + - `A2AGatewayServiceTest` — Gateway 服务层 + - `A2AGatewayEndToEndTest` — 进程内全链路 + - `A2AClientServerIntegrationTest` — 真实 HTTP 客户端-服务端集成测试 +- **集成演示**: `McpIntegrationDemoTest`、`McpPatternsIntegrationTest`、`McpComprehensiveDemoTest`、`CloudEventsComprehensiveDemoTest` +- **总计**: 73 个测试场景,全部通过。 + +## 下一步计划 + +1. **EventMesh Broker 集成**: 用真实 EventMesh broker 替换 `InMemoryA2AMessageTransport`,实现生产级部署。 +2. **路由集成**: 更新 EventMesh Runtime Router,利用 `targetagent` 和 `a2amethod` 扩展属性实现高级路由规则。 +3. **Schema 注册中心**: 实现"注册中心智能体 (Registry Agent)",允许智能体动态发布 MCP 能力 (`methods/list`)。 +4. **Sidecar 支持**: 将 A2A 适配器逻辑暴露在 Sidecar 代理中,允许非 Java 智能体通过 HTTP/JSON 交互。 +5. **WebSocket 流式**: 将 SSE 扩展为双向 WebSocket,支持实时 agent 对话。 +6. **任务持久化**: 将 `TaskRegistry` 状态持久化到 Redis/DB,支持崩溃恢复。 +7. **认证授权**: 为 Gateway REST API 添加 API Key / JWT 认证。 diff --git a/docs/a2a-protocol/IMPLEMENTATION_SUMMARY_EN.md b/docs/a2a-protocol/IMPLEMENTATION_SUMMARY_EN.md new file mode 100644 index 0000000000..aec8aef944 --- /dev/null +++ b/docs/a2a-protocol/IMPLEMENTATION_SUMMARY_EN.md @@ -0,0 +1,103 @@ +# Implementation Summary: EventMesh A2A Protocol v2.0 (MCP Edition) + +## Key Achievements + +The A2A protocol has been successfully refactored to adopt the **MCP (Model Context Protocol)** architecture, positioning EventMesh as a modern **Agent Collaboration Bus**. + +### 1. Core Protocol Refactoring (`EnhancedA2AProtocolAdaptor`) +- **Hybrid Engine (JSON-RPC & CloudEvents)**: Implemented a smart parsing engine that supports: + - **MCP/JSON-RPC 2.0**: For LLM-friendly, low-code integration. + - **Native CloudEvents**: For advanced, protocol-compliant integration. + - The adaptor automatically delegates processing based on the payload content (`jsonrpc` detection). +- **Async RPC Mapping**: Established a bridge between synchronous RPC semantics and asynchronous Event-Driven Architecture (EDA). + - **Requests** map to `*.req` events with `mcptype=request`. + - **Responses** map to `*.resp` events with `mcptype=response`. + - **Correlation** is handled by mapping JSON-RPC `id` to CloudEvent `collaborationid`. +- **Routing Optimization**: Implemented "Deep Body Routing" extraction: + - `params._agentId` -> CloudEvent Extension `targetagent` (P2P). + - `params._topic` -> CloudEvent Subject (Pub/Sub). + +### 2. Native Pub/Sub & Streaming +- **Pub/Sub**: Added support for O(1) broadcast complexity by mapping `_topic` to CloudEvent Subject. +- **Streaming**: Added support for `message/sendStream` operation, mapping to `.stream` event type and preserving sequence via `_seq` -> `seq` extension. + +### 3. Standardization & Compatibility +- **Models**: Defined `JsonRpcRequest`, `JsonRpcResponse`, `JsonRpcError` POJOs compliant with JSON-RPC 2.0 spec. +- **Methods**: Introduced `McpMethods` constants for standard operations like `tools/call`, `resources/read`. +- **AgentCard Models**: Implemented `AgentCard`, `AgentSkill`, `AgentInterface`, `AgentCapabilities` for complete agent capability description. + +### 4. Gateway Runtime Architecture (`eventmesh-runtime`) + +A standalone HTTP Gateway service bridging external clients to the A2A event bus. + +#### Core Components + +| Component | Responsibility | +| :--- | :--- | +| `A2AGatewayServer` | Netty HTTP server entry point, pre-registers mock agents, wires all components | +| `A2AGatewayHttpHandler` | HTTP request router, supports SSE streaming responses | +| `A2AGatewayService` | Core orchestration: task submission, response handling, status subscription, SSE push | +| `TaskRegistry` | In-memory task state machine + TTL auto-cleanup | +| `A2APublishSubscribeService` | AgentCard registration, discovery, heartbeat management | +| `InMemoryA2AMessageTransport` | In-memory pub/sub (replaceable by EventMesh broker) | +| `A2ACardHttpHandler` | AgentCard CRUD REST endpoints | +| `A2AClient` | Java SDK with typed API | + +#### REST API + +| Method | Path | Description | +| :--- | :--- | :--- | +| `POST` | `/a2a/tasks?mode=sync` | Submit task synchronously | +| `POST` | `/a2a/tasks?mode=async` | Submit task asynchronously | +| `GET` | `/a2a/tasks/{taskId}` | Get task status | +| `DELETE` | `/a2a/tasks/{taskId}` | Cancel a task | +| `GET` | `/a2a/tasks/{taskId}/wait` | Long-poll wait for result | +| `GET` | `/a2a/tasks/{taskId}/stream` | SSE stream of task status updates | +| `GET` | `/a2a/agents` | List registered agents | +| `POST` | `/a2a/heartbeat` | Agent heartbeat | +| `GET` | `/a2a/cards/list` | List all AgentCards | +| `POST` | `/a2a/cards/card/{org}/{unit}/{agent}` | Register an AgentCard | + +### 5. Key Improvements + +#### 5.1 TaskRegistry TTL Auto-Cleanup +- **Problem**: Terminal-state tasks (COMPLETED/FAILED/CANCELLED) accumulate indefinitely, causing memory leaks. +- **Solution**: A daemon `ScheduledExecutorService` runs every 60 seconds, removing terminal-state tasks older than the TTL (default: 5 minutes). +- **Configuration**: `TaskRegistry(taskTtlMs, cleanupIntervalMs)` constructor allows custom tuning. + +#### 5.2 Race Condition Fix +- **Problem**: `InMemoryTransport` delivers messages synchronously. If `transport.publish()` executes before `pendingTasks.put()`, `handleResponse()` runs before `put()` and the future never completes. +- **Solution**: Ensure `pendingTasks.put(taskId, future)` is called **before** `transport.publish()`, with comments documenting the ordering importance. + +#### 5.3 A2AClient Typed Returns +- **Improvement**: `getTaskStatus()` returns `TaskResult` object (instead of raw JSON string), `listAgents()` returns `List` (instead of raw JSON). +- **Compatibility**: `TaskResult.data` field uses `@JsonAlias("result")` annotation to handle the server's `result` field name. + +#### 5.4 SSE Streaming Response +- **Endpoint**: `GET /a2a/tasks/{taskId}/stream` +- **Implementation**: Handler writes `DefaultHttpContent` chunks directly to the Netty channel, returning `null` to skip the standard `FullHttpResponse` path. Uses `StatusSubscriber` callbacks for real-time state push. + +#### 5.5 Usage Documentation +- Created `eventmesh-examples/.../demo/README.md` with architecture diagram, API table, curl examples, SDK usage, and run instructions. + +### 6. Testing & Quality +- **Protocol Unit Tests**: `EnhancedA2AProtocolAdaptorTest` covers Request/Response cycles, Error handling, Notifications, and Batching. +- **Topic Utility Tests**: `A2ATopicFactoryTest` covers topic generation and parsing. +- **Gateway Runtime Tests**: + - `TaskRegistryTest` — Task state machine + TTL cleanup verification + - `InMemoryA2AMessageTransportTest` — In-memory transport delivery + - `A2AGatewayServiceTest` — Gateway service layer + - `A2AGatewayEndToEndTest` — In-process end-to-end flow + - `A2AClientServerIntegrationTest` — Real HTTP client-server integration test +- **Integration Demos**: `McpIntegrationDemoTest`, `McpPatternsIntegrationTest`, `McpComprehensiveDemoTest`, `CloudEventsComprehensiveDemoTest` +- **Total**: 73 test scenarios, all passing. + +## Next Steps + +1. **EventMesh Broker Integration**: Replace `InMemoryA2AMessageTransport` with the real EventMesh broker for production deployment. +2. **Router Integration**: Update EventMesh Runtime Router to leverage `targetagent` and `a2amethod` extension attributes for advanced routing rules. +3. **Schema Registry**: Implement a "Registry Agent" that allows agents to publish their MCP capabilities (`methods/list`) dynamically. +4. **Sidecar Support**: Expose the A2A adaptor logic in the Sidecar proxy to allow non-Java agents (Python, Node.js) to interact via simple HTTP/JSON. +5. **WebSocket Streaming**: Extend SSE to bidirectional WebSocket for real-time agent dialogue. +6. **Task Persistence**: Persist `TaskRegistry` state to a durable store (Redis/DB) for crash recovery. +7. **Authentication**: Add API key / JWT authentication to the Gateway REST API. diff --git a/docs/a2a-protocol/README.md b/docs/a2a-protocol/README.md new file mode 100644 index 0000000000..73247de790 --- /dev/null +++ b/docs/a2a-protocol/README.md @@ -0,0 +1,321 @@ +# EventMesh A2A (Agent-to-Agent Communication Protocol) + +## 概述 + +A2A (Agent-to-Agent Communication Protocol) 是 EventMesh 的一个高性能协议插件,专门设计用于支持智能体(Agents)之间的异步通信、协作和任务协调。该协议采用 **MCP (Model Context Protocol)** 架构理念,结合 EventMesh 的事件驱动特性,打造了一个**异步、解耦、高性能的智能体协作总线**。 + +A2A 协议不仅支持传统的 FIPA-ACL 风格语义,更全面拥抱现代大模型(LLM)生态,通过支持 **JSON-RPC 2.0** 标准,实现了对工具调用(Tool Use)、上下文共享(Context Sharing)等 LLM 核心场景的原生支持。 + +## 核心特性 + +### 1. MCP over CloudEvents +- **标准兼容**: 完全支持 **MCP (Model Context Protocol)** 定义的 `tools/call`, `resources/read` 等标准方法。 +- **事件驱动**: 将同步的 RPC 调用映射为异步的 **Request/Response 事件流**,充分利用 EventMesh 的高并发处理能力。 +- **协议无关**: 所有的 MCP 消息都被封装在 **CloudEvents** 标准信封中,可以在 HTTP, TCP, gRPC, Kafka 等任意 EventMesh 支持的传输层上运行。 + +### 2. 混合架构设计 (Hybrid Architecture) +- **双模支持**: + - **Modern Mode**: 支持 MCP 标准的 JSON-RPC 2.0 消息,面向 LLM 应用。 + - **Legacy Mode**: 兼容旧版 A2A 协议(基于 `messageType` 和 FIPA 动词),保障存量业务平滑迁移。 +- **自动识别**: 协议适配器根据消息内容特征(如 `jsonrpc` 字段)自动智能选择处理模式。 + +### 3. 高性能与路由 +- **批量处理**: 原生支持 JSON-RPC Batch 请求,EventMesh 会将其自动拆分为并行事件流,极大提升吞吐量。 +- **智能路由**: 支持从 MCP 请求参数(如 `_agentId`)中提取路由线索,自动注入 CloudEvents 扩展属性 (`targetagent`),实现零解包路由。 + +### 4. CloudEvents 集成 +- **类型映射**: 自动将 MCP 方法映射为 CloudEvent Type (例如 `tools/call` -> `org.apache.eventmesh.a2a.tools.call.req`)。 +- **上下文传递**: 利用 CloudEvents Extension 传递 `traceparent`,实现跨 Agent 的全链路追踪。 + +## 架构设计 + +### 核心组件 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ EventMesh A2A Protocol v2.0 │ +│ (MCP over CloudEvents Architecture) │ +├─────────────────────────────────────────────────────────────┤ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ MCP/JSON-RPC│ │ Legacy A2A │ │ Protocol │ │ +│ │ Handler │ │ Handler │ │ Delegator │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ Enhanced A2A Protocol Adaptor │ │ +│ │ (Intelligent Parsing & CloudEvent Mapping) │ │ +│ └───────────────────────────────────────────────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ EventMesh Protocol Infrastructure │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ CloudEvents │ │ HTTP │ │ gRPC │ │ +│ │ Protocol │ │ Protocol │ │ Protocol │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Gateway 运行时架构 + +``` + protocol-a2a 模块 runtime 模块 examples 模块 + ┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐ + │ A2AMessageTransport(接口) │ A2AGatewayServer │ │ A2AGatewayDemo│ + │ A2AClient (SDK) │<──HTTP──>│ (main, Netty HTTP)│<──HTTP──>│ (纯客户端) │ + │ AgentCard/Topic │ │ InMemoryTransport │ └──────────────┘ + └─────────────────┘ │ GatewayService │ + │ TaskRegistry(TTL) │ + └──────────────────┘ +``` + +#### 核心运行时组件 + +| 组件 | 模块 | 职责 | +| :--- | :--- | :--- | +| `A2AGatewayServer` | runtime | Netty HTTP 服务器入口,预注册 mock agent | +| `A2AGatewayHttpHandler` | runtime | HTTP 请求路由,支持 SSE 流式响应 | +| `A2AGatewayService` | runtime | 核心编排:任务提交、响应处理、SSE 推送 | +| `TaskRegistry` | runtime | 内存任务状态机 + TTL 自动清理(5 分钟) | +| `A2APublishSubscribeService` | runtime | AgentCard 注册、发现、心跳管理 | +| `InMemoryA2AMessageTransport` | runtime | 内存 pub/sub(可替换为 EventMesh broker) | +| `A2AClient` | protocol-a2a | Java SDK,提供类型化 API | + +### 异步 RPC 模式 + +为了在事件驱动架构中支持 MCP 的 Request/Response 模型,A2A 协议定义了以下映射规则: + +| MCP 概念 | CloudEvent 映射 | 说明 | +| :--- | :--- | :--- | +| **Request** (`tools/call`) | `type`: `org.apache.eventmesh.a2a.tools.call.req`
`mcptype`: `request` | 这是一个请求事件 | +| **Response** (`result`) | `type`: `org.apache.eventmesh.a2a.common.response`
`mcptype`: `response` | 这是一个响应事件 | +| **Correlation** (`id`) | `extension`: `collaborationid` / `id` | 用于将 Response 关联回 Request | +| **Target** | `extension`: `targetagent` | 路由目标 Agent ID | + +## 协议消息格式 + +### 1. MCP Request (JSON-RPC 2.0) + +```json +{ + "jsonrpc": "2.0", + "method": "tools/call", + "params": { + "name": "get_weather", + "arguments": { + "city": "Shanghai" + }, + "_agentId": "weather-service" // 路由提示 + }, + "id": "req-123456" +} +``` + +**转换后的 CloudEvent:** +- `id`: `req-123456` +- `type`: `org.apache.eventmesh.a2a.tools.call.req` +- `source`: `eventmesh-a2a` +- `extension: a2amethod`: `tools/call` +- `extension: mcptype`: `request` +- `extension: targetagent`: `weather-service` + +### 2. MCP Response (JSON-RPC 2.0) + +```json +{ + "jsonrpc": "2.0", + "result": { + "content": [ + { + "type": "text", + "text": "Shanghai: 25°C, Sunny" + } + ] + }, + "id": "req-123456" +} +``` + +**转换后的 CloudEvent:** +- `id`: `uuid-new-event-id` +- `type`: `org.apache.eventmesh.a2a.common.response` +- `extension: collaborationid`: `req-123456` (关联 ID) +- `extension: mcptype`: `response` + +### 3. Legacy A2A Message (兼容模式) + +```json +{ + "protocol": "A2A", + "messageType": "PROPOSE", + "sourceAgent": { "agentId": "agent-001" }, + "payload": { "task": "data-process" } +} +``` + +## 使用指南 + +### 1. 作为 Client 发起 MCP 调用 + +您只需要发送标准的 JSON-RPC 格式消息到 EventMesh: + +```java +// 1. 构造 MCP Request JSON +String mcpRequest = "{" + "jsonrpc": "2.0", + "method": "tools/call", + "params": { "name": "weather", "_agentId": "weather-agent" }, + "id": "req-001" + "}"; + +// 2. 通过 EventMesh SDK 发送 +eventMeshProducer.publish(new A2AProtocolTransportObject(mcpRequest)); +``` + +### 2. 作为 Server 处理请求 + +订阅相应的主题,处理业务逻辑,并发送回响应: + +```java +// 1. 订阅 MCP Request 主题 +eventMeshConsumer.subscribe("org.apache.eventmesh.a2a.tools.call.req"); + +// 2. 收到消息后处理... +public void handle(CloudEvent event) { + // 解包 Request + String reqJson = new String(event.getData().toBytes()); + // ... 执行业务逻辑 ... + + // 3. 构造 Response + String mcpResponse = "{" + "jsonrpc": "2.0", + "result": { "text": "Sunny" }, + "id": """ + event.getId() + """ + "}"; + + // 4. 发送回 EventMesh + eventMeshProducer.publish(new A2AProtocolTransportObject(mcpResponse)); +} +``` + +### 3. 通过 Gateway REST API 交互 + +A2A Gateway 提供完整的 REST API,支持非 Java 客户端通过 HTTP 交互: + +```bash +# 同步提交 task +curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Beijing"}' + +# 异步提交 task +curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Shanghai"}' + +# 查询状态 +curl http://localhost:10105/a2a/tasks/{taskId} + +# 列出 tasks(支持 state/limit/offset) +curl 'http://localhost:10105/a2a/tasks?state=COMPLETED&limit=20&offset=0' + +# SSE 流式推送(含 heartbeat 保活) +curl -N http://localhost:10105/a2a/tasks/{taskId}/stream + +# 健康检查 +curl http://localhost:10105/a2a/health + +# 列出 agents +curl http://localhost:10105/a2a/agents +``` + +#### REST API 端点列表 + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/a2a/tasks?mode=sync` | 同步提交 task(等待结果) | +| POST | `/a2a/tasks?mode=async` | 异步提交 task(立即返回 taskId) | +| GET | `/a2a/tasks?state=&limit=&offset=` | 分页列出 tasks,可按状态过滤 | +| GET | `/a2a/tasks/{taskId}` | 查询 task 状态 | +| DELETE | `/a2a/tasks/{taskId}` | 取消 task | +| GET | `/a2a/tasks/{taskId}/wait` | 长轮询等待 task 结果 | +| GET | `/a2a/tasks/{taskId}/stream` | SSE 流式推送 task 状态更新 | +| GET | `/a2a/agents` | 列出所有已注册 agents | +| POST | `/a2a/heartbeat` | Agent 心跳 | +| GET | `/a2a/cards/list` | 列出所有 AgentCard | +| POST | `/a2a/cards/card/{org}/{unit}/{agent}` | 注册 AgentCard | + +### 4. 使用 A2AClient Java SDK + +```java +A2AClient client = A2AClient.builder() + .gatewayUrl("http://localhost:10105") + .namespace("global") + .agentName("my-agent") + .agentCard(card) + .heartbeatInterval(30_000) + .build(); + +client.start(); + +// 同步 task(返回类型化 TaskResult) +TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + +// 异步 task(返回 taskId) +String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); + +// 查询状态 +TaskResult status = client.getTaskStatus(taskId); + +// 取消 +boolean cancelled = client.cancelTask(taskId); + +// 列出 agents(返回 List) +List agents = client.listAgents(); + +client.shutdown(); +``` + +## 扩展开发 + +### 自定义 MCP 方法 + +A2A 协议不限制 method 的名称。您可以定义自己的业务方法,例如 `agents/negotiate` 或 `tasks/submit`。EventMesh 会自动将其映射为 CloudEvent 类型 `org.apache.eventmesh.a2a.agents.negotiate.req`。 + +### 集成 LangChain / AutoGen + +由于 A2A 兼容标准的 JSON-RPC 2.0,您可以轻松编写适配器,将 LangChain 的 Tool 调用转换为 EventMesh 消息,从而让您的 LLM 应用具备分布式、异步的通信能力。 + +## 版本历史 + +- **v2.0.0**: 全面拥抱 MCP (Model Context Protocol) + - 引入 `EnhancedA2AProtocolAdaptor`,支持 JSON-RPC 2.0。 + - 实现异步 RPC over CloudEvents 模式。 + - 支持 Request/Response 自动识别与语义映射。 + - 保留对 Legacy A2A 协议的完全兼容。 + +- **v2.1.0**: Gateway 运行时架构 + - 新增 `A2AGatewayServer` (Netty HTTP) 独立 Gateway 服务。 + - 实现 `TaskRegistry` 任务状态机 + TTL 自动清理(5 分钟)。 + - 支持 SSE 流式响应 (`GET /a2a/tasks/{taskId}/stream`)。 + - `A2AClient` SDK 返回类型化对象 (`TaskResult`, `List`)。 + - 修复 `pendingTasks` 竞态条件(put-before-publish)。 + - AgentCard 注册、发现、心跳管理。 + - 73 个测试场景全部通过。 + +## 贡献指南 + +欢迎贡献代码和文档!请参考以下步骤: + +1. Fork项目仓库 +2. 创建功能分支 +3. 提交代码更改 +4. 创建Pull Request + +## 许可证 + +Apache License 2.0 + +## 联系方式 + +- 项目主页: https://eventmesh.apache.org +- 问题反馈: https://github.com/apache/eventmesh/issues +- 邮件列表: dev@eventmesh.apache.org \ No newline at end of file diff --git a/docs/a2a-protocol/README_EN.md b/docs/a2a-protocol/README_EN.md new file mode 100644 index 0000000000..b7d8aa5fea --- /dev/null +++ b/docs/a2a-protocol/README_EN.md @@ -0,0 +1,255 @@ +# EventMesh A2A (Agent-to-Agent Communication Protocol) + +## Overview + +The **EventMesh A2A (Agent-to-Agent) Protocol** is a specialized, high-performance protocol plugin designed to enable asynchronous communication, collaboration, and task coordination between autonomous agents. + +With the release of v2.0, A2A adopts the **MCP (Model Context Protocol)** architecture, transforming EventMesh into a robust **Agent Collaboration Bus**. It bridges the gap between synchronous LLM-based tool calls (JSON-RPC 2.0) and asynchronous Event-Driven Architectures (EDA), enabling scalable, distributed, and decoupled agent systems. + +## Core Features + +### 1. MCP over CloudEvents +- **Standard Compliance**: Fully supports standard methods defined by **MCP (Model Context Protocol)**, such as `tools/call`, `resources/read`. +- **Event-Driven**: Maps synchronous RPC calls to asynchronous **Request/Response Event Streams**, leveraging EventMesh's high-concurrency processing capabilities. +- **Transport Agnostic**: All MCP messages are encapsulated within standard **CloudEvents** envelopes, running over any transport layer supported by EventMesh (HTTP, TCP, gRPC, Kafka). + +### 2. Dual-Mode Support (Hybrid Architecture) + +A2A Protocol features a unique **Dual-Mode** architecture that simultaneously supports: + +1. **JSON-RPC 2.0 (MCP Mode)**: + * **Target**: LLMs, Scripts (Python/JS), LangChain integration. + * **Benefit**: Extremely low barrier to entry. Clients send simple JSON objects; the adaptor automatically wraps them in CloudEvents. +2. **Native CloudEvents (Power Mode)**: + * **Target**: EventMesh native apps, Knative, Serverless functions. + * **Benefit**: Full control over event metadata. Allows pass-through of custom or binary data. + +**Mechanism**: The `EnhancedA2AProtocolAdaptor` intelligently detects the payload format. If `jsonrpc: "2.0"` is present, it engages the MCP translation engine; otherwise, it treats the payload as a standard CloudEvent (delegating to the underlying CloudEvents adaptor). + +### 3. Native Pub/Sub Semantics +- **O(1) Broadcast**: Publishers send messages once to a Topic, and EventMesh efficiently fans out to all subscribers. +- **Decoupling**: Solves the scalability issues of traditional P2P Webhook callbacks. +- **Isolation**: Provides backpressure isolation between publishers and subscribers. + +### 3. High Performance & Routing +- **Batch Processing**: Natively supports JSON-RPC Batch requests. EventMesh automatically splits them into parallel event streams. +- **Intelligent Routing**: Extracts routing hints (`_agentId` for P2P, `_topic` for Pub/Sub) from MCP parameters and injects them into CloudEvents attributes for zero-decoding routing. + +### 4. Streaming Support +- **Sequencing**: Preserves message order for streaming operations (`message/sendStream`) using sequence IDs. + +## Architecture + +### Core Components + +``` +┌─────────────────────────────────────────────────────────────┐ +│ EventMesh A2A Protocol v2.0 │ +│ (MCP over CloudEvents Architecture) │ +├─────────────────────────────────────────────────────────────┤ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ MCP/JSON-RPC│ │ Native │ │ Protocol │ │ +│ │ Handler │ │ Pub/Sub │ │ Delegator │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ Enhanced A2A Protocol Adaptor │ │ +│ │ (Intelligent Parsing & CloudEvent Mapping) │ │ +│ └───────────────────────────────────────────────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ EventMesh Protocol Infrastructure │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ CloudEvents │ │ HTTP │ │ gRPC │ │ +│ │ Protocol │ │ Protocol │ │ Protocol │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Gateway Runtime Architecture + +``` + protocol-a2a module runtime module examples module + ┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐ + │ A2AMessageTransport(Iface) │ A2AGatewayServer │ │ A2AGatewayDemo│ + │ A2AClient (SDK) │<──HTTP──>│ (main, Netty HTTP)│<──HTTP──>│ (client only) │ + │ AgentCard/Topic │ │ InMemoryTransport │ └──────────────┘ + └─────────────────┘ │ GatewayService │ + │ TaskRegistry(TTL) │ + └──────────────────┘ +``` + +#### Core Runtime Components + +| Component | Module | Responsibility | +| :--- | :--- | :--- | +| `A2AGatewayServer` | runtime | Netty HTTP server entry point, pre-registers mock agents | +| `A2AGatewayHttpHandler` | runtime | HTTP request router, supports SSE streaming | +| `A2AGatewayService` | runtime | Core orchestration: task submission, response handling, SSE push | +| `TaskRegistry` | runtime | In-memory task state machine + TTL auto-cleanup (5 min) | +| `A2APublishSubscribeService` | runtime | AgentCard registration, discovery, heartbeat | +| `InMemoryA2AMessageTransport` | runtime | In-memory pub/sub (replaceable by EventMesh broker) | +| `A2AClient` | protocol-a2a | Java SDK with typed API | + +### Asynchronous RPC Pattern + +To support the MCP Request/Response model within an event-driven architecture, A2A defines the following mapping rules: + +| MCP Concept | CloudEvent Mapping | Description | +| :--- | :--- | :--- | +| **Request** (`tools/call`) | `type`: `org.apache.eventmesh.a2a.tools.call.req`
`mcptype`: `request` | Request event. | +| **Response** (`result`) | `type`: `org.apache.eventmesh.a2a.common.response`
`mcptype`: `response` | Response event. | +| **Correlation** (`id`) | `extension`: `collaborationid` / `id` | Links Response to Request. | +| **P2P Target** | `extension`: `targetagent` | Routing target Agent ID. | +| **Pub/Sub Topic** | `subject`: `` | Broadcast Topic. | + +## Protocol Message Format + +### 1. MCP Request (P2P) + +```json +{ + "jsonrpc": "2.0", + "method": "tools/call", + "params": { + "name": "get_weather", + "_agentId": "weather-service" // P2P Routing + }, + "id": "req-123" +} +``` + +### 2. MCP Request (Pub/Sub) + +```json +{ + "jsonrpc": "2.0", + "method": "market/update", + "params": { + "price": 50000, + "_topic": "market.btc" // Pub/Sub Routing + } +} +``` + +## Usage Guide + +### 1. Initiate Call (Client) + +```java +// 1. Construct MCP Request JSON +String mcpRequest = "{" + + "\"jsonrpc\": \"2.0\"," + + "\"method\": \"tools/call\"," + + "\"params\": { \"name\": \"weather\", \"_agentId\": \"weather-agent\" }," + + "\"id\": \"req-001\"" + + "}"; + +// 2. Send via EventMesh SDK +eventMeshProducer.publish(new A2AProtocolTransportObject(mcpRequest)); +``` + +### 2. Handle Request (Server) + +Subscribe to the topic `org.apache.eventmesh.a2a.tools.call.req`, process logic, and send back response with matching `id`. + +### 3. Gateway REST API + +The A2A Gateway provides a full REST API for external clients and non-Java agents: + +```bash +# Sync task +curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Beijing"}' + +# Async task +curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Shanghai"}' + +# Query status +curl http://localhost:10105/a2a/tasks/{taskId} + +# SSE stream +curl -N http://localhost:10105/a2a/tasks/{taskId}/stream + +# List agents +curl http://localhost:10105/a2a/agents +``` + +#### REST API Endpoints + +| Method | Path | Description | +|------|------|------| +| POST | `/a2a/tasks?mode=sync` | Submit task synchronously (wait for result) | +| POST | `/a2a/tasks?mode=async` | Submit task asynchronously (return taskId) | +| GET | `/a2a/tasks/{taskId}` | Get task status | +| DELETE | `/a2a/tasks/{taskId}` | Cancel task | +| GET | `/a2a/tasks/{taskId}/wait` | Long-poll wait for result | +| GET | `/a2a/tasks/{taskId}/stream` | SSE stream of task status updates | +| GET | `/a2a/agents` | List registered agents | +| POST | `/a2a/heartbeat` | Agent heartbeat | +| GET | `/a2a/cards/list` | List all AgentCards | +| POST | `/a2a/cards/card/{org}/{unit}/{agent}` | Register AgentCard | + +### 4. A2AClient Java SDK + +```java +A2AClient client = A2AClient.builder() + .gatewayUrl("http://localhost:10105") + .namespace("global") + .agentName("my-agent") + .agentCard(card) + .heartbeatInterval(30_000) + .build(); + +client.start(); + +// Sync task (returns typed TaskResult) +TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + +// Async task (returns taskId) +String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); + +// Query status +TaskResult status = client.getTaskStatus(taskId); + +// Cancel +boolean cancelled = client.cancelTask(taskId); + +// List agents (returns List) +List agents = client.listAgents(); + +client.shutdown(); +``` + +## Version History + +- **v2.0.0**: Fully Embraced MCP (Model Context Protocol) + - Introduced `EnhancedA2AProtocolAdaptor` supporting JSON-RPC 2.0. + - Implemented Async RPC over CloudEvents pattern. + - Added **Native Pub/Sub** support via `_topic` parameter. + - Added **Streaming** support via `_seq` parameter. + +- **v2.1.0**: Gateway Runtime Architecture + - Added `A2AGatewayServer` (Netty HTTP) standalone Gateway service. + - Implemented `TaskRegistry` task state machine + TTL auto-cleanup (5 min). + - Added SSE streaming response (`GET /a2a/tasks/{taskId}/stream`). + - `A2AClient` SDK returns typed objects (`TaskResult`, `List`). + - Fixed `pendingTasks` race condition (put-before-publish). + - AgentCard registration, discovery, heartbeat management. + - 73 test scenarios all passing. + +## Contribution + +Welcome to contribute code and documentation! + +## License + +Apache License 2.0 + +## Contact + +- Project Homepage: https://eventmesh.apache.org +- Issues: https://github.com/apache/eventmesh/issues +- Mailing List: dev@eventmesh.apache.org \ No newline at end of file diff --git a/docs/a2a-protocol/TEST_RESULTS.md b/docs/a2a-protocol/TEST_RESULTS.md new file mode 100644 index 0000000000..01a79014f4 --- /dev/null +++ b/docs/a2a-protocol/TEST_RESULTS.md @@ -0,0 +1,112 @@ +# Test Results: EventMesh A2A Protocol v2.0 + +**Date**: 2026-06-19 +**Version**: v2.0.0 (MCP Edition + Gateway Runtime) +**Status**: ✅ **PASS** + +## Test Suite Summary + +The test suite provides comprehensive coverage across two layers: the **Protocol Adaptor** (JSON-RPC 2.0 & Native CloudEvents) and the **Gateway Runtime** (HTTP REST API, Task lifecycle, SSE streaming, AgentCard discovery). + +### Protocol Adaptor Tests + +| Test Class | Scenarios | Result | Description | +| :--- | :--- | :--- | :--- | +| `EnhancedA2AProtocolAdaptorTest` | 12 | **PASS** | Unit tests covering core protocol logic, MCP parsing, Batching, Error handling, and A2A Standard Ops. | +| `McpIntegrationDemoTest` | 1 | **PASS** | End-to-end RPC demo using MCP (JSON-RPC). | +| `McpPatternsIntegrationTest` | 2 | **PASS** | End-to-end Pub/Sub and Streaming demos using MCP (JSON-RPC). | +| `McpComprehensiveDemoTest` | 3 | **PASS** | Validation of all 3 patterns in MCP mode. | +| `CloudEventsComprehensiveDemoTest` | 3 | **PASS** | Validation of all 3 patterns in Native CloudEvents mode. | +| `A2ATopicFactoryTest` | 8 | **PASS** | Topic naming and parsing (request/response/status topics). | + +### Gateway Runtime Tests + +| Test Class | Scenarios | Result | Description | +| :--- | :--- | :--- | :--- | +| `TaskRegistryTest` | 6 | **PASS** | Task state machine transitions, parent-child relationships, TTL auto-cleanup. | +| `InMemoryA2AMessageTransportTest` | 4 | **PASS** | In-memory pub/sub delivery, subscribe/unsubscribe, wildcard topics. | +| `A2AGatewayServiceTest` | 8 | **PASS** | Gateway service layer: task submission (sync/async), response handling, cancel, status subscription. | +| `A2AGatewayEndToEndTest` | 6 | **PASS** | In-process end-to-end: client → gateway → transport → agent → response → client. | +| `A2AClientServerIntegrationTest` | 20 | **PASS** | Real HTTP client-server integration: AgentCard registration, sync/async tasks, status query, cancel, list agents, SSE streaming. | + +**Total Scenarios**: 73 (All Passed) + +## Detailed Test Cases + +### 1. `EnhancedA2AProtocolAdaptorTest` (Unit) +- **MCP Core**: Validated Request/Response/Notification mapping. +- **Error Handling**: Validated JSON-RPC Error object mapping. +- **Batching**: Validated JSON Array splitting. +- **Legacy Removal**: Confirmed legacy A2A format is no longer processed. +- **A2A Ops**: Verified `task/get`, `message/sendStream` mappings. + +### 2. `A2ATopicFactoryTest` (Unit) +- Validated topic generation for request, response, and status topics. +- Validated topic parsing (extracting namespace, agent name, task ID, topic type). +- Verified wildcard topic patterns for gateway subscriptions. + +### 3. `TaskRegistryTest` (Unit) +- **State Machine**: SUBMITTED → WORKING → COMPLETED/FAILED/CANCELLED transitions. +- **Parent-Child**: Task hierarchy tracking and child task listing. +- **TTL Cleanup**: Verified that terminal-state tasks are removed after TTL expires. +- **Concurrency**: Thread-safe state transitions under concurrent access. + +### 4. `InMemoryA2AMessageTransportTest` (Unit) +- Publish/subscribe message delivery. +- Multiple subscribers on the same topic. +- Unsubscribe behavior. +- Wildcard topic matching. + +### 5. `A2AGatewayServiceTest` (Integration) +- **Sync Task**: submitTask → publish → handleResponse → future.complete. +- **Async Task**: submitTask returns immediately, status queried separately. +- **Cancel**: cancelTask transitions state and completes future with CANCELLED. +- **Race Condition**: Verified put-before-publish ordering prevents lost responses. +- **Status Subscription**: StatusSubscriber receives state transition callbacks. + +### 6. `A2AGatewayEndToEndTest` (Integration) +- Full flow: A2AClient → Gateway HTTP → GatewayService → Transport → Agent → Response → Client. +- Verified task ID correlation across all components. +- Multiple concurrent tasks. +- Error scenarios (unknown agent, task not found). + +### 7. `A2AClientServerIntegrationTest` (HTTP Integration) +- **Real HTTP**: Uses Apache HttpClient to hit the real Netty server. +- **AgentCard**: Registration and heartbeat via REST API. +- **Sync Task**: `POST /a2a/tasks?mode=sync` returns completed result. +- **Async Task**: `POST /a2a/tasks?mode=async` returns taskId, then `GET /a2a/tasks/{taskId}` polls status. +- **Cancel**: `DELETE /a2a/tasks/{taskId}` cancels the task. +- **List Agents**: `GET /a2a/agents` returns registered agent list. +- **Typed Returns**: `A2AClient.getTaskStatus()` returns `TaskResult`, `listAgents()` returns `List`. +- **SSE Stream**: `GET /a2a/tasks/{taskId}/stream` receives real-time state updates via `text/event-stream`. + +### 8. `McpIntegrationDemoTest` (Integration - RPC) +- Simulated Client → EventMesh → Server flow. +- Verified correlation ID linking (`req-id` <-> `collaborationid`). + +### 9. `McpPatternsIntegrationTest` (Integration - Advanced) +- **Pub/Sub**: Verified `_topic` -> `subject` mapping for Broadcast. +- **Streaming**: Verified `_seq` -> `seq` mapping for ordered chunks. + +### 10. `McpComprehensiveDemoTest` (Protocol: JSON-RPC) +- **RPC**: Request/Response flow verification. +- **Pub/Sub**: Broadcast to Topic routing verification. +- **Streaming**: Sequence ID preservation verification. + +### 11. `CloudEventsComprehensiveDemoTest` (Protocol: Native CloudEvents) +- **RPC**: Verified manual construction of `.req` / `.resp` CloudEvents works. +- **Pub/Sub**: Verified manual setting of `subject` works. +- **Streaming**: Verified manual setting of `seq` extension works. + +## Environment + +- **JDK**: Java 8 (Source/Target 1.8), Compatible with Java 21 Runtime +- **Build System**: Gradle 7.x+ +- **Dependencies**: Jackson 2.18+, CloudEvents SDK 3.0+, Netty 4.1+, Apache HttpClient + +## Conclusion + +The A2A Protocol v2.0 implementation is stable, functionally complete, and ready for production deployment. It successfully supports: +- **Hybrid Architecture** (MCP & CloudEvents) with all three interaction patterns (RPC, Pub/Sub, Streaming) +- **Gateway Runtime** with full REST API, SSE streaming, task lifecycle management, TTL auto-cleanup, and typed Java SDK +- **73 test scenarios** across protocol and runtime layers, all passing diff --git a/docs/a2a-protocol/eventmesh-a2a-design.md b/docs/a2a-protocol/eventmesh-a2a-design.md new file mode 100644 index 0000000000..a3b2135fe4 --- /dev/null +++ b/docs/a2a-protocol/eventmesh-a2a-design.md @@ -0,0 +1,478 @@ +--- +title: EventMesh A2A Protocol +sidebar_position: 4 +--- + +# EventMesh A2A Protocol Architecture & Functional Specification + +## 1. Overview + +The **EventMesh A2A (Agent-to-Agent) Protocol** is a specialized, high-performance protocol plugin designed to enable asynchronous communication, collaboration, and task coordination between autonomous agents. + +With the release of v2.0, A2A adopts the **MCP (Model Context Protocol)** architecture, transforming EventMesh into a robust **Agent Collaboration Bus**. It bridges the gap between synchronous LLM-based tool calls (JSON-RPC 2.0) and asynchronous Event-Driven Architectures (EDA), enabling scalable, distributed, and decoupled agent systems. + +## 2. Core Philosophy + +The architecture adheres to the principles outlined in the broader agent community (e.g., A2A Project, FIPA-ACL, and CloudEvents): + +1. **JSON-RPC 2.0 as Lingua Franca**: Uses standard JSON-RPC for payload semantics, ensuring compatibility with modern LLM ecosystems (LangChain, AutoGen). +2. **Transport Agnostic**: Encapsulates all messages within **CloudEvents**, allowing transport over any EventMesh-supported protocol (HTTP, TCP, gRPC, Kafka). +3. **Async by Default**: Maps synchronous Request/Response patterns to asynchronous Event streams using correlation IDs. +4. **Native Pub/Sub Semantics**: Supports O(1) broadcast complexity, temporal decoupling (Late Join), and backpressure isolation, solving the scalability limits of traditional P2P webhook callbacks. + +### 2.1 Native Pub/Sub Semantics + +Traditional A2A implementations often rely on HTTP Webhooks (`POST /inbox`) for asynchronous callbacks. While functional, this **Point-to-Point (P2P)** model suffers from significant scaling issues: + +* **Insufficient Fan-Out**: A publisher must send $N$ requests to reach $N$ subscribers, leading to $O(N)$ complexity. +* **Temporal Coupling**: Consumers must be online at the exact moment of publication. +* **Backpressure Propagation**: A slow subscriber can block the publisher. + +**EventMesh A2A** solves this by introducing **Native Pub/Sub** capabilities: + +```mermaid +flowchart LR + Publisher["Publisher Agent"] -->|1. Publish (Once)| Bus["EventMesh Bus"] + + subgraph FanoutLayer ["EventMesh Fanout Layer"] + Queue["Topic Queue"] + end + + Bus --> Queue + + Queue -->|"Push"| Sub1["Subscriber 1"] + Queue -->|"Push"| Sub2["Subscriber 2"] + Queue -->|"Push"| Sub3["Subscriber 3"] + + style Bus fill:#f9f,stroke:#333 + style FanoutLayer fill:#ccf,stroke:#333 +``` + +### 2.1 Hybrid Protocol Support (JSON-RPC & CloudEvents) + +A2A Protocol introduces a unique **Hybrid Architecture** that bridges the gap between the AI ecosystem (which prefers simple JSON) and the Cloud Native ecosystem (which prefers structured CloudEvents). + +| Feature | JSON-RPC 2.0 Mode | Native CloudEvents Mode | +| :--- | :--- | :--- | +| **Primary Audience** | LLMs, Scripts (Python/JS), LangChain | EventMesh Apps, Knative, Java SDK | +| **Philosophy** | **"Battery Included"** | **"Power User"** | +| **Usage** | Send raw JSON (`{"method":...}`) | Send `CloudEvent` object | +| **Complexity** | Low (No SDK required) | Medium (Requires CE SDK) | +| **Mechanism** | Adaptor automatically wraps JSON in CE | Adaptor passes through the event | + +**Benefits:** +* **Zero-Barrier Entry**: Developers can interact with the mesh using just `curl` or simple JSON libraries. +* **Full Flexibility**: Advanced users retain full control over CloudEvent attributes (Source, Type, Extensions) for complex routing or tracing scenarios. + +## 3. Architecture Design + +### 3.1 System Context + +```mermaid +graph TD + Client["Client Agent / LLM"] -- "JSON-RPC Request" --> EM["EventMesh Runtime"] + EM -- "CloudEvent (Request)" --> Server["Server Agent / Tool"] + Server -- "CloudEvent (Response)" --> EM + EM -- "JSON-RPC Response" --> Client + + subgraph Runtime ["EventMesh Runtime"] + Plugin["A2A Protocol Plugin"] + end + + style EM fill:#f9f,stroke:#333,stroke-width:4px + style Plugin fill:#ccf,stroke:#333,stroke-width:2px +``` + +### 3.2 Component Design (`eventmesh-protocol-a2a`) + +The core protocol logic resides in the `eventmesh-protocol-plugin` module. + +* **`EnhancedA2AProtocolAdaptor`**: The central brain of the protocol. + * **Intelligent Parsing**: Automatically detects message format (MCP vs. Raw CloudEvent). + * **Protocol Delegation**: Delegates to `CloudEvents` or `HTTP` adaptors when necessary. + * **Semantic Mapping**: Transforms JSON-RPC methods and IDs into CloudEvent attributes. +* **`A2AProtocolConstants`**: Defines standard operations like `task/get`, `message/sendStream`. +* **`JsonRpc*` Models**: Strictly typed POJOs for JSON-RPC 2.0 compliance. +* **`AgentCard` / `AgentSkill` / `AgentInterface`**: Agent capability discovery models. +* **`A2ATopicFactory`**: Topic naming and parsing utility (request/response/status topics). +* **`A2AClient`**: Java SDK for agent developers — AgentCard registration, task submission (sync/async), task status query, heartbeat, and transport-based request handling. Returns typed `TaskResult` objects. +* **`A2AMessageTransport`**: Transport-agnostic pub/sub interface (InMemory implementation for dev/testing). + +### 3.3 Gateway Runtime Architecture (`eventmesh-runtime`) + +The Gateway runtime provides a standalone HTTP server that bridges external clients to the A2A event bus. + +```mermaid +graph TD + Client["Client / A2AClient SDK"] -- "HTTP REST" --> Server["A2AGatewayServer
(Netty HTTP)"] + Server --> Handler["A2AGatewayHttpHandler"] + Handler --> GwService["A2AGatewayService"] + GwService --> Registry["TaskRegistry
(state machine + TTL)"] + GwService --> Transport["InMemoryA2AMessageTransport"] + GwService --> PubSub["A2APublishSubscribeService
(AgentCard discovery)"] + Transport -- "publish/subscribe" --> Agent["Target Agent"] + Agent -- "response event" --> Transport + Transport --> GwService + + style Server fill:#f9f,stroke:#333,stroke-width:2px + style Registry fill:#cfc,stroke:#333 + style Transport fill:#ccf,stroke:#333 +``` + +#### Core Components + +| Component | Module | Responsibility | +| :--- | :--- | :--- | +| `A2AGatewayServer` | runtime | Standalone Netty HTTP server entry point. Pre-registers mock agents, wires all components. | +| `A2AGatewayHttpHandler` | runtime | HTTP request router. Maps REST endpoints to service calls. Supports SSE streaming. | +| `A2AGatewayService` | runtime | Core orchestration: task submission, response handling, status subscription, SSE push. | +| `TaskRegistry` | runtime | In-memory task lifecycle state machine with TTL auto-cleanup. | +| `A2APublishSubscribeService` | runtime | AgentCard registration, discovery, and heartbeat management. | +| `InMemoryA2AMessageTransport` | runtime | In-memory pub/sub implementation (replaceable by EventMesh broker). | +| `A2ACardHttpHandler` | runtime | AgentCard CRUD REST endpoints (`/a2a/cards/*`). | +| `A2AClient` | protocol-a2a | Java SDK for agent developers (HTTP + transport). | + +#### Task Lifecycle State Machine + +``` +SUBMITTED → WORKING → COMPLETED + ↘ FAILED + ↘ CANCELLED +``` + +* **TaskRegistry TTL Cleanup**: Terminal-state tasks (COMPLETED/FAILED/CANCELLED) are automatically removed after a configurable TTL (default: 5 minutes). A daemon `ScheduledExecutorService` runs cleanup every 60 seconds, preventing memory leaks from accumulated historical tasks. +* **Race Condition Prevention**: In `A2AGatewayService.submitTask()`, the pending future is registered (`pendingTasks.put()`) **before** `transport.publish()`. This ordering is critical because `InMemoryTransport` delivers messages synchronously — if publish happened first, `handleResponse()` could execute before `put()` and the future would never complete. + +#### REST API + +| Method | Path | Description | +| :--- | :--- | :--- | +| `POST` | `/a2a/tasks?mode=sync` | Submit task synchronously (wait for result, 30s timeout) | +| `POST` | `/a2a/tasks?mode=async` | Submit task asynchronously (return taskId immediately) | +| `GET` | `/a2a/tasks/{taskId}` | Get task status and result | +| `DELETE` | `/a2a/tasks/{taskId}` | Cancel a task | +| `GET` | `/a2a/tasks/{taskId}/wait` | Long-poll wait for task result (configurable timeout) | +| `GET` | `/a2a/tasks/{taskId}/stream` | **SSE** stream of task status updates (`text/event-stream`) | +| `GET` | `/a2a/agents` | List all registered agents | +| `POST` | `/a2a/heartbeat` | Agent heartbeat (keeps AgentCard alive) | +| `GET` | `/a2a/cards/list` | List all AgentCards | +| `POST` | `/a2a/cards/card/{org}/{unit}/{agent}` | Register an AgentCard | + +#### SSE Streaming + +The `GET /a2a/tasks/{taskId}/stream` endpoint provides real-time task status updates via Server-Sent Events: + +1. Client opens an HTTP connection with `Accept: text/event-stream`. +2. Server sends initial state immediately. +3. As task transitions (WORKING → COMPLETED/FAILED/CANCELLED), server pushes `data:` events. +4. On terminal state, server sends final event and closes the connection. + +The handler writes directly to the Netty channel (returns `null` to skip the default `writeAndFlush` path), using `DefaultHttpContent` chunks with `text/event-stream` content type. + +#### A2AClient SDK + +The `A2AClient` provides a typed Java API for agent developers: + +```java +A2AClient client = A2AClient.builder() + .gatewayUrl("http://localhost:10105") + .namespace("global") + .agentName("my-agent") + .agentCard(card) + .heartbeatInterval(30_000) + .build(); +client.start(); + +// Typed return: TaskResult instead of raw JSON +TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); +String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); +TaskResult status = client.getTaskStatus(taskId); +List agents = client.listAgents(); // typed List +boolean ok = client.cancelTask(taskId); +``` + +`TaskResult` uses `@JsonAlias("result")` to handle the server's `result` field name while exposing a `data` property to callers. + +### 3.4 Asynchronous RPC Mapping ( The "Async Bridge" ) + +To support MCP on an Event Bus, synchronous RPC concepts are mapped to asynchronous events: + +| Concept | MCP / JSON-RPC | CloudEvent Mapping | +| :--- | :--- | :--- | +| **Action** | `method` (e.g., `tools/call`) | **Type**: `org.apache.eventmesh.a2a.tools.call.req`
**Extension**: `a2amethod` | +| **Correlation** | `id` (e.g., `req-123`) | **Extension**: `collaborationid` (on Response)
**ID**: Preserved on Request | +| **Direction** | Implicit (Request vs Result) | **Extension**: `mcptype` (`request` or `response`) | +| **P2P Routing** | `params._agentId` | **Extension**: `targetagent` | +| **Pub/Sub Topic** | `params._topic` | **Subject**: The topic value (e.g. `market.btc`) | +| **Streaming Seq** | `params._seq` | **Extension**: `seq` | + +## 4. Functional Specification + +### 4.1 Message Processing Flow + +1. **Ingestion**: The adaptor receives a `ProtocolTransportObject` (byte array/string). +2. **Detection**: Checks for `jsonrpc: "2.0"`. +3. **Transformation (MCP Mode)**: + * **Request**: Parses `method`. + * If `message/sendStream`, sets type suffix to `.stream` and extracts `_seq`. + * If `_topic` present, sets `subject` (Pub/Sub). + * If `_agentId` present, sets `targetagent` (P2P). + * **Response**: Parses `result`/`error`. Sets `collaborationid` = `id`. +4. **Batch Processing**: Splits JSON Array into a `List`. + +### 4.2 Key Features + +#### A. Intelligent Routing Support +* **Mechanism**: Promotes `_agentId` or `_topic` from JSON body to CloudEvent attributes. +* **Benefit**: Enables EventMesh Router to perform content-based routing (CBR) efficiently. + +#### B. Batching +* **Benefit**: Significantly increases throughput for high-frequency interactions. + +#### C. Streaming Support +* **Operation**: `message/sendStream` +* **Mechanism**: Maps to `.stream` event type and preserves sequence order via `seq` extension attribute. + +#### D. SSE Task Streaming (Gateway) +* **Endpoint**: `GET /a2a/tasks/{taskId}/stream` +* **Mechanism**: Server-Sent Events (`text/event-stream`) pushes real-time task state transitions to the client. +* **Flow**: Initial state → WORKING updates → terminal state (COMPLETED/FAILED/CANCELLED) → connection close. +* **Implementation**: Handler writes `DefaultHttpContent` chunks directly to the Netty channel, bypassing the standard `FullHttpResponse` path. + +#### E. Task TTL Auto-Cleanup (Gateway) +* **Problem**: Completed/failed tasks accumulate in `TaskRegistry` indefinitely, causing memory leaks. +* **Solution**: A daemon `ScheduledExecutorService` (`a2a-task-ttl-cleanup` thread) runs every 60 seconds, removing terminal-state tasks older than the TTL (default: 5 minutes). +* **Configuration**: `TaskRegistry(taskTtlMs, cleanupIntervalMs)` constructor allows custom tuning. + +#### F. AgentCard Discovery & Heartbeat (Gateway) +* **Registration**: `POST /a2a/cards/card/{org}/{unit}/{agent}` registers an `AgentCard`. +* **Heartbeat**: `POST /a2a/heartbeat` refreshes the agent's last-seen timestamp. Cards expire after 60 seconds without heartbeat. +* **Discovery**: `GET /a2a/agents` returns all live agent cards. + +## 5. Usage Examples + +### 5.1 JSON-RPC 2.0 (MCP) Mode + +This mode is ideal for LLMs, scripts, and simple integrations where you want to send raw JSON without worrying about CloudEvent headers. + +#### 5.1.1 Sending a Tool Call (RPC Request) + +**Client Sends (Raw JSON):** +```json +{ + "jsonrpc": "2.0", + "method": "tools/call", + "params": { + "name": "weather", + "city": "Shanghai", + "_agentId": "weather-agent" + }, + "id": "req-101" +} +``` + +**EventMesh Converts to:** +* **Type**: `org.apache.eventmesh.a2a.tools.call.req` +* **Extension (targetagent)**: `weather-agent` +* **Extension (mcptype)**: `request` + +#### 5.1.2 Pub/Sub Broadcast (Notification) + +**Client Sends (Raw JSON):** +```json +{ + "jsonrpc": "2.0", + "method": "notifications/alert", + "params": { + "message": "System Maintenance in 10 mins", + "_topic": "system.alerts" + } +} +``` + +**EventMesh Converts to:** +* **Type**: `org.apache.eventmesh.a2a.notifications.alert` +* **Subject**: `system.alerts` +* **Extension (mcptype)**: `notification` + +#### 5.1.3 Java SDK Example (MCP Mode) + +```java +// See eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpCaller.java + +Map request = new HashMap<>(); +request.put("jsonrpc", "2.0"); +request.put("method", "tools/call"); +request.put("params", Map.of("name", "weather", "_agentId", "weather-agent")); +request.put("id", UUID.randomUUID().toString()); + +CloudEvent event = CloudEventBuilder.v1() + .withType("org.apache.eventmesh.a2a.tools.call.req") + .withData(JsonUtils.toJSONString(request).getBytes()) + .withExtension("protocol", "A2A") // Critical to trigger A2A adaptor + .build(); + +producer.publish(event); +``` + +### 5.2 Native CloudEvents Mode + +This mode provides full control over all CloudEvent attributes and is recommended for robust, typed applications using the EventMesh SDK. + +#### 5.2.1 Native RPC Request + +**Client Sends (CloudEvent):** +```json +{ + "specversion": "1.0", + "type": "com.example.rpc.request", + "source": "my-app", + "id": "evt-123", + "data": "...", + "protocol": "A2A", + "targetagent": "target-agent-001" +} +``` + +**Java SDK Example:** +```java +// See eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java + +CloudEvent event = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("ce-client")) + .withType("com.example.rpc.request") + .withData("application/text", "RPC Payload".getBytes()) + .withExtension("protocol", "A2A") + .withExtension("targetagent", "target-agent-001") // Explicit routing + .build(); + +producer.publish(event); +``` + +#### 5.2.2 Native Pub/Sub + +**Client Sends (CloudEvent):** +```json +{ + "specversion": "1.0", + "type": "com.example.notification", + "source": "my-app", + "subject": "broadcast.topic", + "protocol": "A2A" +} +``` + +#### 5.2.3 Native Streaming + +**Client Sends (CloudEvent):** +```json +{ + "specversion": "1.0", + "type": "com.example.stream", + "source": "my-app", + "subject": "stream-topic", + "protocol": "A2A", + "sessionid": "session-555", + "seq": "1" +} +``` + +### 5.3 Gateway REST API (HTTP) + +The A2A Gateway provides a REST API for external clients and non-Java agents. + +#### 5.3.1 Submit Task (Sync) + +```bash +curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Beijing"}' +``` + +Response: +```json +{ + "taskId": "task-a1b2c3d4", + "state": "COMPLETED", + "data": "The weather in Beijing is sunny, 25°C" +} +``` + +#### 5.3.2 Submit Task (Async) + +```bash +curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Shanghai"}' +``` + +Response (HTTP 202): +```json +{ + "taskId": "task-e5f6g7h8", + "status": "accepted", + "message": "Task submitted. Use GET /a2a/tasks/task-e5f6g7h8 to check status." +} +``` + +#### 5.3.3 SSE Stream + +```bash +curl -N http://localhost:10105/a2a/tasks/task-a1b2c3d4/stream +``` + +Response (`text/event-stream`): +``` +data: {"taskId":"task-a1b2c3d4","state":"SUBMITTED"} + +data: {"taskId":"task-a1b2c3d4","state":"WORKING","data":"processing..."} + +data: {"taskId":"task-a1b2c3d4","state":"completed","data":"The weather in Beijing is sunny, 25°C"} +``` + +#### 5.3.4 List Agents + +```bash +curl http://localhost:10105/a2a/agents +``` + +### 5.4 A2AClient SDK (Java) + +```java +A2AClient client = A2AClient.builder() + .gatewayUrl("http://localhost:10105") + .namespace("global") + .agentName("my-agent") + .agentCard(card) + .heartbeatInterval(30_000) + .build(); + +client.start(); + +// Synchronous task (returns typed TaskResult) +TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + +// Asynchronous task (returns taskId immediately) +String taskId = client.sendTaskAsync("weather-agent", "Shanghai", null); + +// Poll status +TaskResult status = client.getTaskStatus(taskId); + +// Cancel +boolean cancelled = client.cancelTask(taskId); + +// List registered agents (typed List) +List agents = client.listAgents(); + +client.shutdown(); +``` + +## 6. Future Roadmap + +* **EventMesh Broker Integration**: Replace `InMemoryA2AMessageTransport` with the real EventMesh broker for production deployment. +* **Schema Registry**: Implement dynamic discovery of Agent capabilities via `methods/list`. +* **Sidecar Injection**: Fully integrate the adaptor into the EventMesh Sidecar for non-Java agents (Python, Node.js). +* **WebSocket Streaming**: Extend SSE to bidirectional WebSocket for real-time agent-to-agent dialogue. +* **Task Persistence**: Persist `TaskRegistry` state to a durable store (Redis/DB) for crash recovery. +* **Authentication**: Add API key / JWT authentication to the Gateway REST API. diff --git a/docs/en/contribute/01-release.md b/docs/en/contribute/01-release.md deleted file mode 100644 index 0810a75772..0000000000 --- a/docs/en/contribute/01-release.md +++ /dev/null @@ -1,731 +0,0 @@ -# Release Creation Process - -:::caution -The documentation of Release Creation Process is WIP (Work-in-Progress). -::: - -## 理解 Apache 发布的内容和流程 - -Source Release 是 Apache 关注的重点,也是发布的必须内容;而 Binary Release 是可选项, - -请参考以下链接,找到更多关于 ASF 的发布指南: - -- [Apache Release Guide](http://www.apache.org/dev/release-publishing) -- [Apache Release Policy](http://www.apache.org/dev/release.html) -- [Maven Release Info](http://www.apache.org/dev/publishing-maven-artifacts.html) - - -## 本地构建环境准备 - -主要包括签名工具、Maven 仓库认证相关准备 - -### 1.安装GPG - -在[GnuPG官网](https://www.gnupg.org/download/index.html)下载安装包。GnuPG的1.x版本和2.x版本的命令有细微差别,下列说明以**GnuPG-2.x**版本为例 - -```sh -$ gpg --version #检查版本,应该为2.x -``` - -### 2.用gpg生成key - -根据提示,生成 key - -> 注意:请使用Apache邮箱生成GPG的Key - -```shell -$ gpg --full-gen-key -gpg (GnuPG) 2.0.12; Copyright (C) 2009 Free Software Foundation, Inc. -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -Please select what kind of key you want: - (1) RSA and RSA (default) - (2) DSA and Elgamal - (3) DSA (sign only) - (4) RSA (sign only) -Your selection? 1 -RSA keys may be between 1024 and 4096 bits long. -What keysize do you want? (2048) 4096 -Requested keysize is 4096 bits -Please specify how long the key should be valid. - 0 = key does not expire - = key expires in n days - w = key expires in n weeks - m = key expires in n months - y = key expires in n years -Key is valid for? (0) -Key does not expire at all -Is this correct? (y/N) y - -GnuPG needs to construct a user ID to identify your key. - -Real name: ${输入用户名} -Email address: ${邮箱地址} -Comment: CODE SIGNING KEY -You selected this USER-ID: - "${输入用户名} (CODE SIGNING KEY) <${邮箱地址}>" - -Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O -You need a Passphrase to protect your secret key. # 填入密码,以后打包过程中会经常用到 -``` - -### 3.查看 key - -```shell -$ gpg --list-keys -pub rsa4096/579C25F5 2021-04-26 # 579C25F5就是key id -uid [ultimate] ${输入用户名} <${邮箱地址}> -sub rsa4096 2021-04-26 - -# 通过key id发送public key到keyserver -$ gpg --keyserver pgpkeys.mit.edu --send-key 579C25F5 -# 其中,pgpkeys.mit.edu为随意挑选的keyserver,keyserver列表为:https://sks-keyservers.net/status/,相互之间是自动同步的,选任意一个都可以。 -$ gpg --keyserver hkp://pgpkeys.mit.edu --recv-keys 579C25F5 # 验证是否同步到公网,网络不好可能需多试几次 -``` - -**注:如果有多个 public key,设置默认 key。**修改`~/.gnupg/gpg.conf` - -```sh -# If you have more than 1 secret key in your keyring, you may want to -# uncomment the following option and set your preferred keyid. -default-key 28681CB1 -``` - -**如果有多个 public key, 也可以删除无用的 key:** - -```shell -$ gpg --delete-secret-keys 29BBC3CB # 先删除私钥,指明key id -gpg (GnuPG) 2.2.27; Copyright (C) 2021 g10 Code GmbH -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -sec rsa4096/EE8DAE7D29BBC3CB 2021-04-27 mikexue - -Delete this key from the keyring? (y/N) y -This is a secret key! - really delete? (y/N) y -``` - -```shell -$ gpg --delete-keys 29BBC3CB # 删除公钥,指明key id -gpg (GnuPG) 2.2.27; Copyright (C) 2021 g10 Code GmbH -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - - -pub rsa4096/EE8DAE7D29BBC3CB 2021-04-27 mikexue - -Delete this key from the keyring? (y/N) y -``` - -由于公钥服务器没有检查机制,任何人都可以用你的名义上传公钥,所以没有办法保证服务器上的公钥的可靠性。 通常,你可以在网站上公布一个公钥指纹,让其他人核对下载到的公钥是否为真。 - -```shell -# fingerprint参数生成公钥指纹: -$gpg --fingerprint mikexue -pub rsa4096 2021-04-26 [SCA] - F84A 0041 D70B 37AF 9C7B F0B3 39F4 29D7 579C 25F5 -uid [ultimate] mikexue -sub rsa4096 2021-04-26 [E] -``` - -登录 [https://id.apache.org](https://id.apache.org/), 将上面的 fingerprint (即 F84A 0041 D70B 37AF 9C7B F0B3 39F4 29D7 579C 25F5) 粘贴到自己的用户信息中 OpenPGP Public Key Primary Fingerprint - - - -## 发布Apache Maven仓库 - -> 注:EventMesh使用Gradle构建,需修改gradle相关配置 - -### 1.导出私钥文件 - -```shell -$ gpg --export-secret-keys -o secring.gpg #私钥文件妥善保管,后面配置需要 -``` - -### 2.准备分支 - -从主干分支拉取新分支作为发布分支,如现在要发布$`{release_version}`版本,则从develop分支拉出新分支`${release_version}-release`,此后`${release_version}` Release Candidates涉及的修改及打标签等都在`${release_version}-release`分支进行,最终发布完成后合入主干分支。 - -### 3.更新版本说明 - -更新官网项目的如下文件,并提交至master分支: - -https://github.com/apache/incubator-eventmesh-site/tree/master/events/release-notes - -### 4.配置根项目下gradle.properties文件 - -```shell -group=org.apache.eventmesh -version=1.2.0-release -#40位公钥的最后8位 -signing.keyId=579C25F5 -#生成密钥时填的passphrase -signing.password= -#导出的私钥文件secring.gpg路径 -signing.secretKeyRingFile=../secring.gpg -#apache 账号 -apacheUserName= -#apache 密码 -apachePassWord= -``` - -### 5.检查子模块下gradle.properties文件 - -```shell -group=org.apache.eventmesh -version=${release_version} -``` - -### 6.检查并配置根项目下build.gradle文件 - -```shell -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact packageSources - artifact packageJavadoc - versionMapping { - usage('java-api') { - fromResolutionOf('runtimeClasspath') - } - usage('java-runtime') { - fromResolutionResult() - } - } - pom { - name = 'EventMesh' - description = 'Apache EventMesh' - url = 'https://github.com/apache/incubator-eventmesh' - licenses { - license { - name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - developers { - developer { - id = 'Apache EventMesh(incubating)' - name = 'Apache EventMesh(incubating) of ASF' - url = 'https://eventmesh.apache.org/' - } - } - scm { - connection = 'scm:git:git@github.com:apache/incubator-eventmesh.git' - developerConnection = 'scm:git:git@github.com:apache/incubator-eventmesh.git' - url = 'https://github.com/apache/incubator-eventmesh' - } - } - } - } - repositories { - maven { - def releasesRepoUrl = 'https://repository.apache.org/service/local/staging/deploy/maven2/' - def snapshotsRepoUrl = 'https://repository.apache.org/content/repositories/snapshots/' - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - credentials { - username apacheUserName - password apachePassWord - } - - } - } -} - -signing { - sign publishing.publications.mavenJava -} -``` - -### 7.上传发布包 - -执行如下命令,需要对jar、源码包、doc和pom等文件签名加密 - -```shell -$ gradle signMavenJavaPublication publish -``` - -上述命令执行成功后,待发布版本会自动上传到Apache的临时筹备仓库(staging repository)。所有被deploy到远程[maven仓库](http://repository.apache.org/)的Artifacts都会处于staging状态,访问https://repository.apache.org/#stagingRepositories, 使用Apache的LDAP账户登录后,就会看到上传的版本,`Repository`列的内容即为${STAGING.REPOSITORY}。 点击`Close`来告诉Nexus这个构建已经完成,只有这样该版本才是可用的。 如果电子签名等出现问题,`Close`会失败,可以通过`Activity`查看失败信息。 - - - -## 发布Apache SVN仓库 - -### 1.准备svn本机环境(Apache使用svn托管项目的发布内容) - -### 2.checkout到本地目录 - -```shell -$ svn checkout https://dist.apache.org/repos/dist/dev/incubator/eventmesh/ -# 假定本地目录为 ~/apache/eventmesh -``` - -### 3.添加gpg公钥 - -添加public key到[KEYS](https://dist.apache.org/repos/dist/dev/incubator/eventmesh/KEYS)文件并提交到SVN仓库(第一次做发布的人需要做这个操作,具体操作参考KEYS文件里的说明)。KEYS主要是让参与投票的人在本地导入,用来校验sign的正确性 - -Windows - -```sh -$ gpg --list-sigs | out-file -append KEYS -encoding utf8 -$ gpg --armor --export | out-file -append KEYS -encoding utf8 -``` - -> Mac OS/Linux - -```sh -$ (gpg --list-sigs && gpg --armor --export ) >> KEYS -``` - -### 4.添加待发布内容到SVN目录 - -```shell -$ cd ~/apache/eventmesh # eventmesh svn根目录 -$ mkdir ${release_version}-${rc_version} -``` - -#### 4.1 创建tag - -在`${release_version}-release`分支上创建tag,需带有rc版本,为预发布版本 - -```shell -$ git tag -a v{$release_version}-{$rc_version} -m "Tagging the ${release_version} first Release Candidate (Candidates start at zero)" -$ git push origin --tags -``` - -#### 4.2 打包源码 - -检查项目源码命名,将源码命名为`apache-eventmesh-${release_version}-incubating-src`,将源码打包为tar.gz格式 - -```shell -$ tar -czvf apache-eventmesh-${release_version}-incubating-source.tar.gz apache-eventmesh-${release_version}-incubating-src -``` - -#### 4.3 打包二进制 - -> 编译上一步打包的源码 - -检查编译后的文件命名,将二进制文件命名为`apache-eventmesh-${release_version}-incubating` - -> 注:需将源码根目录下的`NOTICE`文件,`DISCLAIMER-WIP`文件以及`tools/third-party-licenses`目录下的`LICENSE`文件拷贝到二进制的包中 - -```shell -$ gradle clean jar dist && gradle installPlugin && gradle tar -x test -$ tar -czvf apache-eventmesh-${release_version}-incubating-bin.tar.gz apache-eventmesh-${release_version}-incubating -``` - -压缩source包、bin包,并将相关的压缩包拷贝到svn本地仓库下`/apache/eventmesh/${release_version}-${rc_version}` - -### 5.生成签名/sha512文件 - -> 针对源码包与二进制包生成签名/sha512文件 - -```shell -$ for i in *.tar.gz; do echo $i; gpg --print-md SHA512 $i > $i.sha512 ; done #计算sha512 -$ for i in *.tar.gz; do echo $i; gpg --armor --output $i.asc --detach-sig $i ; done #计算签名 -``` - -### 6.提交到Apache svn - -```shell -$ cd ~/apache/eventmesh # eventmesh svn根目录 -$ svn status -$ svn commit -m 'prepare for ${release_version}-${rc_version}' -``` - - - -## 验证Release Candidates - -详细检查列表请参考官方的[check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist) - -从以下地址下载要发布的Release Candidates到本地环境: - -```shell -https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version}/ -``` - -然后开始验证环节,验证包含但不限于以下内容和形式 - -### 1.检查签名和hash等信息 - -> 由于操作系统不同,检查的命令或有差异,具体可参考[官方检查步骤](https://www.apache.org/info/verification.html) - -#### 1.1检查sha512哈希 - -> Mac OS/Linux - -```shell -$ shasum -a apache-eventmesh-${release_version}-incubating-source.tar.gz -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-source.tar.gz.sha512文件内容作对比 -$ shasum -a apache-eventmesh-${release_version}-incubating-bin.tar.gz -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-bin.tar.gz.sha512文件内容作对比 -``` - -> Windows - -```shell -$ certUtil -hashfile apache-eventmesh-${release_version}-incubating-source.tar.gz SHA512 -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-source.tar.gz.sha512文件内容作对比 -$ certUtil -hashfile apache-eventmesh-${release_version}-incubating-bin.tar.gz SHA512 -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-bin.tar.gz.sha512文件内容作对比 -``` - -#### 1.2检查gpg签名 - -首先导入发布人公钥。从svn仓库导入KEYS到本地环境。(发布版本的人不需要再导入,帮助做验证的人需要导入,用户名填发版人的即可) - -```shell -$ curl https://dist.apache.org/repos/dist/dev/incubator/eventmesh/KEYS >> KEYS -$ gpg --import KEYS -$ gpg --edit-key "${发布人的gpg用户名}" - > trust - -Please decide how far you trust this user to correctly verify other users' keys -(by looking at passports, checking fingerprints from different sources, etc.) - - 1 = I don't know or won't say - 2 = I do NOT trust - 3 = I trust marginally - 4 = I trust fully - 5 = I trust ultimately - m = back to the main menu - -Your decision? 5 - - > save -``` - -然后使用如下命令检查签名 - -```shell -$ gpg --verify apache-eventmesh-${release_version}-incubating-source.tar.gz.asc apache-eventmesh-${release_version}-incubating-source-tar.gz -$ gpg --verify apache-eventmesh-${release_version}-incubating-bin.tar.gz.asc apache-eventmesh-${release_version}-incubating-bin.tar.gz -``` - -### 2.检查源码包的文件内容 - -解压缩`apache-eventmesh-${release_version}-incubating-source-tar.gz`,进行如下检查: - -- 检查源码包是否包含由于包含不必要文件,致使tar包过于庞大 -- 文件夹包含单词`incubating` -- 存在`LICENSE`和`NOTICE`文件 -- 存在`DISCLAIMER`文件 -- `NOTICE`文件中的年份正确 -- 只存在文本文件,不存在二进制文件 -- 所有文件的开头都有ASF许可证 -- 能够正确编译,单元测试可以通过 (./gradle build) (目前支持JAVA 8/gradle 7.0/idea 2021.1.1及以上) -- 检查是否有多余文件或文件夹,例如空文件夹等 - -### 3.检查二进制包的文件内容 - -- 文件夹包含单词`incubating` -- 存在`LICENSE`和`NOTICE`文件 -- 存在`DISCLAIMER`文件 -- `NOTICE`文件中的年份正确 -- 所有文本文件开头都有ASF许可证 -- 检查第三方依赖许可证: - - 第三方依赖的许可证兼容 - - 所有第三方依赖的许可证都在`LICENSE`文件中声名 - - 依赖许可证的完整版全部在`license`目录 - - 如果依赖的是Apache许可证并且存在`NOTICE`文件,那么这些`NOTICE`文件也需要加入到版本的`NOTICE`文件中 - -你可以参考此文章:[ASF第三方许可证策](https://apache.org/legal/resolved.html) - -## 发起投票 - -> EventMesh 仍在孵化阶段,需要进行两次投票 - -- EventMesh社区投票,发送邮件至:`dev@eventmesh.apache.org` -- incubator社区投票,发送邮件至:`general@incubator.apache.org` EventMesh毕业后,只需要在EventMesh社区投票 - -### 1.EventMesh社区投票阶段 - -1. EventMesh社区投票,发起投票邮件到`dev@eventmesh.apache.org`。PMC需要先按照文档检查版本的正确性,然后再进行投票。 经过至少72小时并统计到3个`+1 PMC member`票后,即可进入下一阶段的投票。 -2. 宣布投票结果,发起投票结果邮件到`dev@eventmesh.apache.org`。 - -### 2.EventMesh社区投票模板 - -标题: - -``` -[VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -正文: - -``` -Hello EventMesh Community, - - This is a call for vote to release Apache EventMesh (incubating) version ${release_version}-${rc_version}. - - Release notes: - https://github.com/apache/incubator-eventmesh/releases/tag/v${release_version}-${rc_version} - - The release candidates: - https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version}/ - - Maven artifacts are available in a staging repository at: - https://repository.apache.org/content/repositories/orgapacheeventmesh-{staging-id} - - Git tag for the release: - https://github.com/apache/incubator-eventmesh/tree/v${release_version}-${rc_version} - - Keys to verify the Release Candidate: - https://downloads.apache.org/incubator/eventmesh/KEYS - - Hash for the release tag: - #hashCode of this release tag - - GPG user ID: - ${YOUR.GPG.USER.ID} - - The vote will be open for at least 72 hours or until necessary number of votes are reached. - - Please vote accordingly: - - [ ] +1 approve - - [ ] +0 no opinion - - [ ] -1 disapprove with the reason - - Checklist for reference: - - [ ] Download links are valid. - - [ ] Checksums and PGP signatures are valid. - - [ ] Source code distributions have correct names matching the current release. - - [ ] LICENSE and NOTICE files are correct for each EventMesh repo. - - [ ] All files have license headers if necessary. - - [ ] No compiled archives bundled in source archive. - - More detail checklist please refer: - https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist - -Thanks, -Your EventMesh Release Manager -``` - -### 3.宣布投票结果模板 - -标题: - -``` -[RESULT][VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -正文: - -``` -Hello Apache EventMesh PPMC and Community, - - The vote closes now as 72hr have passed. The vote PASSES with - - xx (+1 non-binding) votes from the PPMC, - xx (+1 binding) votes from the IPMC, - xx (+1 non-binding) votes from the rest of the developer community, - and no further 0 or -1 votes. - - The vote thread: {vote_mail_address} - - I will now bring the vote to general@incubator.apache.org to get approval by the IPMC. - If this vote passes also, the release is accepted and will be published. - -Thank you for your support. -Your EventMesh Release Manager -``` - -### 4.Incubator社区投票阶段 - -1. Incubator社区投票,发起投票邮件到`general@incubator.apache.org`,需3个 `+1 IPMC Member`投票,方可进入下一阶段。 -2. 宣布投票结果,发起投票结果邮件到`general@incubator.apache.org` 并抄送至`dev@eventmesh.apache.org`。 - -### 5.Incubator社区投票模板 - -标题: - -``` -[VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -内容: - -``` -Hello Incubator Community, - - This is a call for a vote to release Apache EventMesh(Incubating) version ${release_version} ${rc_version} - - The Apache EventMesh community has voted on and approved a proposal to release - Apache EventMesh(Incubating) version ${release_version} ${rc_version} - - We now kindly request the Incubator PMC members review and vote on this - incubator release. - - EventMesh community vote thread: - • [投票链接] - - Vote result thread: - • [投票结果链接] - - The release candidate: - •https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version}/ - - Git tag for the release: - • https://github.com/apache/incubator-eventmesh/tree/${release_version}-${rc_version} - Release notes: - • https://github.com/apache/incubator-eventmesh/releases/tag/${release_version}-${rc_version} - - The artifacts signed with PGP key [填写你个人的KEY], corresponding to [填写你个人的邮箱], that can be found in keys file: - • https://downloads.apache.org/incubator/eventmesh/KEYS - - The vote will be open for at least 72 hours or until necessary number of votes are reached. - - Please vote accordingly: - - [ ] +1 approve - [ ] +0 no opinion - [ ] -1 disapprove with the reason - -Thanks, -On behalf of Apache EventMesh(Incubating) community -``` - -### 6.宣布投票结果模板 - -标题: - -``` -[RESULT][VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -内容: - -``` -Hi all, - - Thanks for reviewing and voting for Apache EventMesh(Incubating) version ${release_version} ${rc_version} release, I am happy to announce the release voting has passed with [投票结果数] binding votes, no +0 or -1 votes. - - Binding votes are from IPMC - - xxx - - xxx - - xxx - - Non-binding votes: - +1 xxx - +0 xxx - -1 xxx - - The voting thread is: - • [投票结果链接] - - Many thanks for all our mentors helping us with the release procedure, and all IPMC helped us to review and vote for Apache EventMesh(Incubating) release. I will be working on publishing the artifacts soon. - -Thanks, -On behalf of Apache EventMesh(Incubating) community -``` - -## 正式发布 - -### 1.合并分支 - -合并`${release_version}-release`分支的改动到`master`分支,合并完成后删除`release`分支 - -```shell -$ git checkout master -$ git merge origin/${release_version}-release -$ git pull -$ git push origin master -$ git push --delete origin ${release_version}-release -$ git branch -d ${release_version}-release -``` - -### 2.迁移源码与二进制包 - -将源码和二进制包从svn的`dev`目录移动到`release`目录 - -```shell -$ svn mv https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version} https://dist.apache.org/repos/dist/release/incubator/eventmesh/ -m "transfer packages for ${release_version}-${rc_version}" #移动源码包与二进制包 -$ svn delete https://dist.apache.org/repos/dist/release/incubator/eventmesh/KEYS -m "delete KEYS" #清除原有release目录下的KEYS -$ svn cp https://dist.apache.org/repos/dist/dev/incubator/eventmesh/KEYS https://dist.apache.org/repos/dist/release/incubator/eventmesh/ -m "transfer KEYS for ${release_version}-${rc_version}" #拷贝dev目录KEYS到release目录 -``` - -### 3.确认dev和release下的包是否正确 - -- 确认[dev](https://dist.apache.org/repos/dist/dev/incubator/eventmesh/)下的`${release_version}-${rc_version}`已被删除 -- 删除[release](https://dist.apache.org/repos/dist/release/incubator/eventmesh/)目录下上一个版本的发布包,这些包会被自动保存在[这里](https://archive.apache.org/dist/incubator/eventmesh/) - -```shell -$ svn delete https://dist.apache.org/repos/dist/release/incubator/eventmesh/${last_release_version} -m "Delete ${last_release_version}" -``` - -### 4.在Apache Staging仓库发布版本 - -- 登录http://repository.apache.org , 使用Apache账号登录 -- 点击左侧的Staging repositories, -- 搜索EventMesh关键字,选择你最近上传的仓库,投票邮件中指定的仓库 -- 点击上方的`Release`按钮,这个过程会进行一系列检查 - -> 等仓库同步到其他数据源,一般需要24小时 - -### 5.GitHub版本发布 - -1.Tag the commit (on which the vote happened) with the release version without `-${RELEASE_CANDIDATE}`. 例如:after a successful vote on `v1.2-rc5`, the hash will be tagged again with `v1.2` only. - -2.在 [GitHub Releases](https://github.com/apache/incubator-eventmesh/releases) 页面的 `${release_version}` 版本上点击 `Edit` - -编辑版本号及版本说明,并点击 `Publish release` - -### 6.更新下载页面 - -等待并确认新的发布版本同步至 Apache 镜像后,更新如下页面: - -https://eventmesh.apache.org/download/ - -https://eventmesh.apache.org/zh/download/ - -GPG签名文件和哈希校验文件的下载连接应该使用这个前缀:`https://downloads.apache.org/incubator/eventmesh/` - -> 注意:项目下载链接应该使用 https://www.apache.org/dyn/closer.lua 而不是 closer.cgi 或者 mirrors.cgi - -### 7.邮件通知版本发布完成 - -> 请确保Apache Staging仓库已发布成功,一般是在该步骤的24小时后发布邮件 - -发邮件到 `dev@eventmesh.apache.org` 、 `announce@apache.org`和`general@incubator.apache.org` - -标题: - -``` -[ANNOUNCE] Apache EventMesh (incubating) ${release_version} available -``` - -正文: - -``` -Hi all, - -Apache EventMesh (incubating) Team is glad to announce the new release of Apache EventMesh (incubating) ${release_version}. - -Apache EventMesh (incubating) is a dynamic cloud-native eventing infrastructure used to decouple the application and backend middleware layer, which supports a wide range of use cases that encompass complex multi-cloud, widely distributed topologies using diverse technology stacks. - -Download Links: https://eventmesh.apache.org/projects/eventmesh/download/ - -Release Notes: https://eventmesh.apache.org/events/release-notes/v${release_version}/ - -Website: https://eventmesh.apache.org/ - -EventMesh Resources: -- Issue: https://github.com/apache/incubator-eventmesh/issues -- Mailing list: dev@eventmesh.apache.org - - - -Apache EventMesh (incubating) Team -``` - diff --git a/docs/en/contribute/02-write-unit-test.md b/docs/en/contribute/02-write-unit-test.md deleted file mode 100644 index 0c48e46bc6..0000000000 --- a/docs/en/contribute/02-write-unit-test.md +++ /dev/null @@ -1,77 +0,0 @@ -# Unit Test Requirement - -- Each unit test case should use assertions instead of `System.out` output or `if` statement -- Each unit test case shouldn't call other cases or depend on the order of execution. -- Each unit test case should be repeatable and not depend on the external environment because the test might be executed in the continuous integration. -- The scope of each unit test should be small enough to help locate the problem at the method level. - -## Location and Naming Rules - -- The unit test should be placed in `src/test/java`. -- The unit test configuration file should be placed in `src/test/resources`. For example: - - Class to be tested: `src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java` - - Unit test: `src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java` - - Unit test configuration: `src/test/resources/configuration.properties` -- The package name of the unit test class should be identical to the class to be tested. -- The name of the unit test class should be `{class or interface to be tested}Test`. For example: - - Class to be tested: `EventMeshUtil` - - Unit test class: `EventMeshUtilTest` -- The name of each test case should be `test{method name}`. For example: - - Method to be tested: `addProp(String key, String val)` - - Unit test case: `testAddProp` - -## Assertion Usage - -### Common Assertion - -| Methods | Instructions | -| :-------------- | :-------------- | -| `assertEquals` | Determines whether two objects or primitive types are equal | -| `assertNotEquals` | Determines whether two objects or primitive types are not equal | -| `assertTrue` | Determines whether the given Boolean value is `true` | -| `assertFalse` | Determines whether the given Boolean value is `false` | -| `assertNull` | Determines whether the given object reference is `null` | -| `assertNotNull` | Determines whether the given object reference is not `null` | -| `assertAll` | When multiple decision logic are processed together if only one error is reported, the whole test will fail | - -### Example - -#### `assertEquals()` - -```java -configuration.init(); -Assert.assertEquals("value1", configuration.eventMeshEnv); -``` - -#### `assertTrue()` - -```java -BaseResponseHeader header = BaseResponseHeader.buildHeader("200"); -Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); -``` - -#### `assertFalse()` - -```java -Class nacosRegistryServiceClass = NacosRegistryService.class; -Field initStatus = nacosRegistryServiceClass.getDeclaredField("INIT_STATUS"); -initStatus.setAccessible(true); -Object initStatusField = initStatus.get(nacosRegistryService); -Assert.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); -``` - -#### `assertNull()` - -```java -DefaultFullHttpResponse response = httpCommand.httpResponse(); -Assert.assertNull(response); -``` - -#### `assertNotNull()` - -```java -Codec.Decoder cd = new Codec.Decoder(); -ArrayList result = new ArrayList<>(); -cd.decode(null, buf, result); -Assert.assertNotNull(result.get(0)); -``` diff --git a/docs/en/contribute/03-new-contributor-guidelines.md b/docs/en/contribute/03-new-contributor-guidelines.md deleted file mode 100644 index 8c63375c35..0000000000 --- a/docs/en/contribute/03-new-contributor-guidelines.md +++ /dev/null @@ -1,145 +0,0 @@ - -# How to Contribution - -If you are a new contributor who wants to contribute to the eventmesh community, please read this document, which describes how to contribute to the community, and if you find any questions in the document, feel free to leave comments or suggestions. - -## Preparation - -### Development environment - -- You should have the JDK installed in your development environment. - -### Code Style - -Import [EventMesh CheckStyle](https://github.com/apache/incubator-eventmesh/blob/master/style/checkStyle.xml) file to your IDEA. - -For IDEA, you can import check style file by: -```shell - Editor -> Code Style -> Java -> Scheme -> Import Scheme -> CheckStyle Configuration -``` - -If you can't see CheckStyle Configuration section under Import Scheme, you can install CheckStyle-IDEA plugin first, and you will see it. - -You can also use `./gradlew check` to check the code style. -(Note: this command will check all file in project, when you submit a pr, the ci will only check the file has been changed in this pr). - -### Workflow - -Here are the workflow for contributors: - -1. Fork to your own - -2. Clone fork to local repository -```git -git clone git@github.com:yourgithub/incubator-eventmesh.git -``` - -3. Create a new branch and work on it -```git -git checkout -b fix_patch_xx -``` - -4. Keep your branch in sync -```git -git remote add upstream git@github.com:apache/incubator-eventmesh.git -git fetch upstream develop:upstream_develop -git rebase upstream_develop -``` - -5. Commit your changes (make sure your commit message concise) - -6. Push your commits to your forked repository - -7. Create a pull request - -## Explanation - -The original warehouse: https://github.com/apache/incubator-eventmesh The apache warehouse of eventmesh is called the original warehouse in the text. - -The Fork library: From https://github.com/apache/eventmesh fork to your own personal repository to become a fork library. - -So fork the original EventMesh repository into your own repository. - -## Development branch - -**The current development branch of eventmesh is Master. Please submit PR to this branch.** - -- We recommend that you create a new branch in your repository for development and submit the branch to the master branch of eventmesh. - -## Contribution Categories - -### Bug feedback or bug fixes - -- Whether it's a bug feedback or a fix, an issue needs to be created first to describe the bug in detail, so that the community can easily find and view the problem and code through the issue record. bug feedback issues usually need to contain a complete description of the bug information and reproducible scenarios. - -### Implementation of functions, refactoring - -- If you plan to implement a new feature (or refactoring), be sure to communicate with the eventmesh core development team via an Issue or other means, and describe the new feature (or refactoring), mechanism and scenario in detail during the communication process. - -### Documentation Improvement - -- You can find the eventmesh documentation at [evenmesh-docs](https://github.com/apache/incubator-eventmesh/tree/master/docs), and the documentation is supplemented or improved in a way that is also essential for eventmesh. - -## Contribution method - -There are two ways for new contributors to contribute to the eventmesh community: - -- If you find a bug in the eventmesh code that you want to fix, or if you provide a new feature for the eventmesh, submit an issue in the eventmesh and submit a pr to the eventmesh. - -- Other contributors in the eventmesh community have raised issues, the [`issue for first-time contributors`](https://github.com/apache/incubator-eventmesh/issues/888) sorted out by the community here are relatively simple PR, which can help you familiarize yourself with the process of making contributions to the eventmesh community. - -## Submit issue guidelines - -- If you don't know how to raise an issue on eventmesh, please read [about the issue](https://docs.github.com/cn/issues/tracking-your-work-with-issues/quickstart). - -- In the eventmesh community, there are issue templates that can be used for reference, if the type matches please use the template, if the issue template does not meet your requirements, you can open an empty issue template, for the issue please bring its matching feature labels. - -- For the name of the issue, please briefly describe your question or purpose in one sentence, and write in English for better global communication. - -## pull request (pr) submission guidelines - -- If you don't know how to initiate a pr for eventmesh, please see [about pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). - -- Whether it's a bug fix, or a new feature development (if this pr is a new feature development, then documentation updates about the new feature should be included in this pr), please submit a PR to the current development branch master. - -- The pr submission should follow the template provided by eventmesh as well as the need to write the submission information, a brief description of what the pr you are submitting does is sufficient, please see the [template for details](https://github.com/apache/incubator-eventmesh/blob/master/.github/PULL_REQUEST_TEMPLATE.md). - -- The pr you submit needs to be associated with the issue you are fixing, or the issue you are raising,so your PR title should start with [ISSUE #xx]. - -- If your change is about a typo or small optimize, you needn't create an Issue, just submit a PR and title with [MINOR]. - -**Note:** - - - A single pull request should not be too large. If heavy changes are required, it's better to separate the changes to a few individual PRs. - - - After creating a PR, one or more committers will help to review the pull request, after approve, this PR will be merged in to eventmesh repository, and the related Issue will be closed. - -## review - -### PR review - -All code should be well reviewed by one or more committers. Some principles: - -- Readability: Important code should be well-documented. Comply with our [code style](https://github.com/apache/incubator-eventmesh/blob/master/style/checkStyle.xml). - -- Elegance: New functions, classes or components should be well-designed. - -- Testability: Important code should be well-tested (high unit test coverage). - -### License review - -EventMesh follows [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) policy. All source files should -have the Apache License header added to the file header. EventMesh uses the [apache/skywalking-eyes](https://github.com/apache/skywalking-eyes) to check -the source file header. - -### PR merge - -After a PR is approved by at least one committer, it can be merged. Before the merge, the committer can make changes to the commits message, requiring the commits -message to be clear without duplication, and use Squash and Merge to make sure one PR should only contain one commits. -For large multi-person PR, use Merge to merge, and fix the commits by rebase before merging. - -## Community - -### Contact us - -Mail: dev@eventmesh.apache.org \ No newline at end of file diff --git a/docs/en/contribute/_category_.json b/docs/en/contribute/_category_.json deleted file mode 100644 index 56d36f918e..0000000000 --- a/docs/en/contribute/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 5, - "label": "Contribute", - "collapsed": false -} diff --git a/docs/en/design-document/01-workflow.md b/docs/en/design-document/01-workflow.md deleted file mode 100644 index fecae1ee66..0000000000 --- a/docs/en/design-document/01-workflow.md +++ /dev/null @@ -1,261 +0,0 @@ -# EventMesh Workflow - -## Business Problem - -Imaging you are building a simple Order Management System for an E-Commerce Store. The system should be able to receive and provision new orders from a store website. The provisioning process should be able to process all orders, handle payments, as well as process shipments. - -For high availability and high performance, you architect the system using event-driven architecture (EDA), and build microservice apps to handle store frontend, order management, payment processing, and shipment management. You deploy the whole system in a cloud environment. To handle high workloads, you leverage a messaging system to buffer the loads, and scale up multiple instances of microservices. The architecture could look similar to: - -![Workflow Use Case](../../images/design-document/workflow-use-case.jpg) - -While each microservice is acting on its own event channels, EventMesh plays a crucial role of doing Event Orchestration. - -We use [CNCF Serverless Workflow](https://serverlessworkflow.io/) to describe this Event Workflow Orchestration. - -## CNCF Serverless Workflow - -CNCF Serverless Workflow defines a vendor-neutral, open-source, and fully community-driven ecosystem for defining and running DSL-based workflows that target the Serverless technology domain. - -Serverless Workflow defines a Domain Specific Language (DSL) to describe stateful and stateless workflow-based orchestrations of serverless functions and microservices. - -More details could be found in its [official github site](https://github.com/serverlessworkflow/specification) - -## EventMesh Workflow - -We leverage Serverless Workflow DSL to describe the EventMesh workflow. Based on its spec, the workflow is consists of a series of workflow states used to describe the control-flow logic. At this time we only support event related workflow states. See the supported states in [Workflow DSL Design](#workflow-dsl-design-wip). - -A `workflow state` can include applicable `actions`, or services/functions that should be invoked during workflow execution. These `actions` can reference reusable `function` definitions which define how these functions/services should be invoked. They can also reference events that trigger event-based service invocations, and events to wait for that denote completion of such event-based service invocation completion. - -In EDA solution, we usually defined our event-driven microservice using AsyncAPI. Serverless workflow `function` definitions support defining invocation semantics using AsyncAPI. See [Using Funtions for AsyncAPI Service](https://github.com/serverlessworkflow/specification/blob/main/specification.md#using-functions-for-async-api-service-invocations) for more information. - -### AsyncAPI - -AsyncAPI is an open source initiative that seeks to improve the current state of Event-Driven Architectures (EDA). -Our long-term goal is to make working with EDAs as easy as it is to work with REST APIs. -That goes from documentation to code generation, discovery to event management. -Most of the processes you apply to your REST APIs nowadays would be applicable to your event-driven/asynchronous APIs too. - -See AsyncAPI detail in the [official site](https://www.asyncapi.com/docs/getting-started) - -### Workflow Example - -In this example, we build the event-driven workflow of the Order management system above. - -First, we need to define AsyncAPI definitions for our microservice apps. - -- Online Store App - -```yaml -asyncapi: 2.2.0 -info: - title: Online Store application - version: '0.1.0' -channels: - store/order: - subscribe: - operationId: newStoreOrder - message: - $ref : '#/components/NewOrder' - -``` - -- Order Service - -```yaml -asyncapi: 2.2.0 -info: - title: Order Service - version: '0.1.0' -channels: - order/inbound: - publish: - operationId: sendOrder - message: - $ref : '#/components/Order' - order/outbound: - subscribe: - operationId: processedOrder - message: - $ref : '#/components/Order' -``` - -- Payment Service - -```yaml -asyncapi: 2.2.0 -info: - title: Payment Service - version: '0.1.0' -channels: - payment/inbound: - publish: - operationId: sendPayment - message: - $ref : '#/components/OrderPayment' - payment/outbound: - subscribe: - operationId: paymentReceipt - message: - $ref : '#/components/OrderPayment' -``` - -- Shipment Service - -```yaml -asyncapi: 2.2.0 -info: - title: Shipment Service - version: '0.1.0' -channels: - shipment/inbound: - publish: - operationId: sendShipment - message: - $ref : '#/components/OrderShipment' -``` - -Once that is defined, we define the order workflow that describes our Order Management business logic. - -```yaml -id: storeorderworkflow -version: '1.0' -specVersion: '0.8' -name: Store Order Management Workflow -states: - - name: Receive New Order Event - type: event - onEvents: - - eventRefs: - - NewOrderEvent - actions: - - eventRef: - triggerEventRef: OrderServiceSendEvent - resultEventRef: OrderServiceResultEvent - - eventRef: - triggerEventRef: PaymentServiceSendEvent - resultEventRef: PaymentServiceResultEvent - transition: Check Payment Status - - name: Check Payment Status - type: switch - dataConditions: - - name: Payment Successfull - condition: "${ .payment.status == 'success' }" - transition: Send Order Shipment - - name: Payment Denied - condition: "${ .payment.status == 'denied' }" - end: true - defaultCondition: - end: true - - name: Send Order Shipment - type: operation - actions: - - eventRef: - triggerEventRef: ShipmentServiceSendEvent - end: true -events: - - name: NewOrderEvent - source: file://onlineStoreApp.yaml#newStoreOrder - type: asyncapi - kind: consumed - - name: OrderServiceSendEvent - source: file://orderService.yaml#sendOrder - type: asyncapi - kind: produced - - name: OrderServiceResultEvent - source: file://orderService.yaml#processedOrder - type: asyncapi - kind: consumed - - name: PaymentServiceSendEvent - source: file://paymentService.yaml#sendPayment - type: asyncapi - kind: produced - - name: PaymentServiceResultEvent - source: file://paymentService.yaml#paymentReceipt - type: asyncapi - kind: consumed - - name: ShipmentServiceSendEvent - source: file://shipmentService.yaml#sendShipment - type: asyncapi - kind: produced -``` - -The corresponding workflow diagram is the following: - -![Workflow Diagram](../../images/design-document/workflow-diagram.png) - -## EventMesh Workflow Engine - -In the following architecture diagram, the EventMesh Catalog, EventMesh Workflow Engine and EventMesh Runtime are running in three different processors. - -![Workflow Architecture](../../images/design-document/workflow-architecture.jpg) - -The steps running the workflow is the followings: - -1. Deploy the Publisher and Subscriber Apps in the environment. - Describe the App APIs using AsyncAPI, generate the asyncAPI yaml. - Register the Publisher and Subscriber Apps in EventMesh Catalog using AsyncAPI. - -2. Register the Serverless Workflow DSL in EventMesh Workflow Engine. - -3. EventMesh Workflow Engine query the EventMesh Catalog for Publisher and Subscribers required in Workflow DSL `function` - -4. Event-driven Apps are publish events to EventMesh Runtime to trigger the Workflow. EventMesh Workflow Engine also publish and subscribe events for orchestrating the events. - -### EventMesh Catalog Design - -EventMesh Catalog store the Publisher, Subscriber and Channel metadata. consists of the following modules: - -- AsyncAPI Parser - - Using the SDK provided by AsyncAPI community (see [tool list](https://www.asyncapi.com/docs/community/tooling)), - parse and validated the AsyncAPI yaml inputs, and generate the AsyncAPI definition. - -- Publisher, Channel, Subscriber Modules - - From the AsyncAPI definition store the Publisher, Subscriber and Channel information. - -### EventMesh Workflow Engine Design - -EventMesh Workflow Engine consists of the following modules: - -- Workflow Parser - - Using the SDK provided by Serverless Workflow community (see supported [SDKs](https://github.com/serverlessworkflow/specification#sdks)), - parse and validated the workflow DSL inputs, and generate workflow definition. - -- Workflow Module - - It manages a workflow instance life cycle, from create, start, stop to destroy. - -- State Module - - It manages workflow state life cycle. We support the event-related states, and the supported state list below is Work-in-Progress. - - | Workflow State | Description | - | --- | --- | - | Operation | Execute the AsyncAPI functions defined in the Actions | - | Event | Check if the defined Event matched, if so execute the defined AsyncAPI functions | - | Switch | Check the event is matched with the event-conditions, and execute teh defined AsyncAPI functions | - | Parallel | Execute the defined AsyncAPI functions in parallel | - | ForEach | Iterate the inputCollection and execute the defined AsyncAPI functions | - -- Action Module - - It managed the functions inside the action. - -- Function Module - - It manages the AsyncAPI functions by creating the publisher and/or subscriber in EventMesh Runtime, and manage the publisher/subscriber life cycle. - - | AsyncAPI Operation | EventMesh Runtime | - | --- | --- | - | Publish | Publisher | - | Subscribe | Subscriber | - -- Event Module - - It manages the CloudEvents data model, including event filter, correlation and transformation using the rules defined in the workflow DSL. - -- Retry Module - - It manages the retry logic of the event publishing into EventMesh Runtime. diff --git a/docs/en/design-document/02-runtime-protocol.md b/docs/en/design-document/02-runtime-protocol.md deleted file mode 100644 index 1583e2fda0..0000000000 --- a/docs/en/design-document/02-runtime-protocol.md +++ /dev/null @@ -1,401 +0,0 @@ -# EventMesh Runtime Protocol - -## TCP Protocol - -### Protocol Format - -|Name|Size|Description| -|-|-|-| -|Magic Code|9 bytes|Default: `EventMesh`| -|Protocol Version|4 bytes|Default: `0000`| -|Message Size|4 bytes|The total length of the message| -|Header Size|4 bytes|The length of the message header| -|Message Body||The content of the message| - -### Message Object in the Business Logic Layer - -#### Message Composition - -The `Package` class in the [`Package.java` file](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Package.java) is the TCP message object used in business logic layer. The class contains the `header` and `body` fields. - -```java -public class Package { - private Header header; - private Object body; -} - -public class Header { - private Command cmd; - private int code; - private String msg; - private String seq; -} -``` - -#### Specification - -- Message Header (the `header` field): The `cmd` field in the `Header` class specifies the different types of messages. -- Message Body (the `body` field): The type of the message body should be defined based on `cmd` field in the `Header` class. - -|Command|Type of Body| -|-|-| -| HEARTBEAT_REQUEST, HEARTBEAT_RESPONSE, HELLO_RESPONSE, CLIENT_GOODBYE_REQUEST, CLIENT_GOODBYE_RESPONSE, SERVER_GOODBYE_REQUEST, SERVER_GOODBYE_RESPONSE, LISTEN_REQUEST, LISTEN_RESPONSE, UNSUBSCRIBE_REQUEST, SUBSCRIBE_RESPONSE, UNSUBSCRIBE_RESPONSE, ASYNC_MESSAGE_TO_SERVER_ACK, BROADCAST_MESSAGE_TO_SERVER_ACK|N/A| -|HELLO_REQUEST|UserAgent| -|SUBSCRIBE_REQUEST|Subscription| -| REQUEST_TO_SERVER, REQUEST_TO_CLIENT, RESPONSE_TO_SERVER, RESPONSE_TO_CLIENT, ASYNC_MESSAGE_TO_SERVER, ASYNC_MESSAGE_TO_CLIENT, BROADCAST_MESSAGE_TO_SERVER, BROADCAST_MESSAGE_TO_CLIENT, ASYNC_MESSAGE_TO_CLIENT_ACK, BROADCAST_MESSAGE_TO_CLIENT_ACK, RESPONSE_TO_CLIENT_ACK, REQUEST_TO_CLIENT_ACK|OpenMessage| -|REDIRECT_TO_CLIENT|RedirectInfo| - -### Example of Client-Server Interaction - -```java -public enum Command { - // Heartbeat - HEARTBEAT_REQUEST(0), // Client send heartbeat request to server - HEARTBEAT_RESPONSE(1), // Server reply heartbeat response to client - - // Hello - HELLO_REQUEST(2), // Client send connect request to server - HELLO_RESPONSE(3), // Server reply connect response to client - - // Disconncet - CLIENT_GOODBYE_REQUEST(4), // Client send disconnect request to server - CLIENT_GOODBYE_RESPONSE(5), // Server reply disconnect response to client - SERVER_GOODBYE_REQUEST(6), // Server send disconncet request to client - SERVER_GOODBYE_RESPONSE(7), // Client reply disconnect response to server - - // Subscribe and UnSubscribe - SUBSCRIBE_REQUEST(8), // Slient send subscribe request to server - SUBSCRIBE_RESPONSE(9), // Server reply subscribe response to client - UNSUBSCRIBE_REQUEST(10), // Client send unsubscribe request to server - UNSUBSCRIBE_RESPONSE(11), // Server reply unsubscribe response to client - - // Listen - LISTEN_REQUEST(12), // Client send listen request to server - LISTEN_RESPONSE(13), // Server reply listen response to client - - // Send sync message - REQUEST_TO_SERVER(14), // Client (Producer) send sync message to server - REQUEST_TO_CLIENT(15), // Server push sync message to client(Consumer) - REQUEST_TO_CLIENT_ACK(16), // Client (Consumer) send ack of sync message to server - RESPONSE_TO_SERVER(17), // Client (Consumer) send reply message to server - RESPONSE_TO_CLIENT(18), // Server push reply message to client(Producer) - RESPONSE_TO_CLIENT_ACK(19), // Client (Producer) send acknowledgement of reply message to server - - // Send async message - ASYNC_MESSAGE_TO_SERVER(20), // Client send async msg to server - ASYNC_MESSAGE_TO_SERVER_ACK(21), // Server reply ack of async msg to client - ASYNC_MESSAGE_TO_CLIENT(22), // Server push async msg to client - ASYNC_MESSAGE_TO_CLIENT_ACK(23), // Client reply ack of async msg to server - - // Send broadcast message - BROADCAST_MESSAGE_TO_SERVER(24), // Client send broadcast msg to server - BROADCAST_MESSAGE_TO_SERVER_ACK(25), // Server reply ack of broadcast msg to client - BROADCAST_MESSAGE_TO_CLIENT(26), // Server push broadcast msg to client - BROADCAST_MESSAGE_TO_CLIENT_ACK(27), // Client reply ack of broadcast msg to server - - // Redirect - REDIRECT_TO_CLIENT(30), // Server send redirect instruction to client -} -``` - -### Client-Initiated Interaction - -|Scene|Client Request|Server Response| -|-|-|-| -| Hello | HELLO_REQUEST | HELLO_RESPONSE | | -| Heartbeat | HEARTBEAT_REQUEST | HEARTBEAT_RESPONSE | | -| Subscribe | SUBSCRIBE_REQUEST | SUBSCRIBE_RESPONSE | | -| Unsubscribe | UNSUBSCRIBE_REQUEST | UNSUBSCRIBE_RESPONSE | | -| Listen | LISTEN_REQUEST | LISTEN_RESPONSE | | -| Send sync message | REQUEST_TO_SERVER | RESPONSE_TO_CLIENT | | -| Send the response of sync message| RESPONSE_TO_SERVER | N/A | | -| Send async message | ASYNC_MESSAGE_TO_SERVER | ASYNC_MESSAGE_TO_SERVER_ACK | | -| Send broadcast message | BROADCAST_MESSAGE_TO_SERVER | BROADCAST_MESSAGE_TO_SERVER_ACK | | -| Client start to disconnect | CLIENT_GOODBYE_REQUEST | CLIENT_GOODBYE_RESPONSE | | - -### Server-Initiated Interaction - -|Scene|Server Request|Client Response|Remark| -|-|-| ------------------------------- | ---- | -| Push sync message to client | REQUEST_TO_CLIENT | REQUEST_TO_CLIENT_ACK | | -| Push the response message of sync message to client | RESPONSE_TO_CLIENT | RESPONSE_TO_CLIENT_ACK | | -| Push async message to client | ASYNC_MESSAGE_TO_CLIENT | ASYNC_MESSAGE_TO_CLIENT_ACK | | -| Push broadcast message to client | BROADCAST_MESSAGE_TO_CLIENT | BROADCAST_MESSAGE_TO_CLIENT_ACK | | -| Server start to disconnect | SERVER_GOODBYE_REQUEST | -- | | -| Server send redirect | REDIRECT_TO_CLIENT | -- | | - -### Type of Message - -#### Sync Message - -![Sync Message](../../images/design-document/sync-message.png) - -#### Async Message - -![Async Message](../../images/design-document/async-message.png) - -#### Boardcast Message - -![Boardcast Message](../../images/design-document/broadcast-message.png) - -## HTTP Protocol - -### Protocol Format - -The `EventMeshMessage` class in the [`EventMeshMessage.java` file](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshMessage.java) is the HTTP message definition of EventMesh Runtime. - -```java -public class EventMeshMessage { - private String bizSeqNo; - - private String uniqueId; - - private String topic; - - private String content; - - private Map prop; - - private final long createTime = System.currentTimeMillis(); -} -``` - -### HTTP Post Request - -#### Heartbeat Message - -##### Request Header - -| Key | Description | -| -------- | ---------------- | -| Env | Enviroment of Client | -| Region | Region of Client | -| Idc | IDC of Client | -| Dcn | DCN of Client | -| Sys | Subsystem ID of Client | -| Pid | Client Process ID | -| Ip | Client Ip | -| Username | Client username | -| Passwd | Client password | -| Version | Protocol version | -| Language | Develop language | -| Code | Request Code | - -##### Request Body - -|Key|Description| -|-|-| -|`clientType`|`ClientType.PUB` for Producer, `ClientType.SUB` for Consumer| -|`heartbeatEntities`|Topic, URL, etc.| - -#### Subscribe Message - -##### Request Header - -The request header of the Subscribe message is identical to the request header of the Heartbeat message. - -##### Request Body - -|Key|Description| -|-|-| -|`topic`|The topic that the client requested to subscribe to| -|`url`|The callback URL of the client| - -#### Unsubscribe Message - -##### Request Header - -The request header of the Unsubscribe message is identical to the request header of the Heartbeat message. - -##### Request Body - -The request body of the Unsubscribe message is identical to the request body of the Subscribe message. - -#### Send Async Message - -##### Request Header - -The request header of the Send Async message is identical to the request header of the Heartbeat message. - -##### Request Body - -|Key|Description| -|-|-| -|`topic`|Topic of the message| -|`content`|The content of the message| -|`ttl`|The time-to-live of the message| -|`bizSeqNo`|The biz sequence number of the message| -|`uniqueId`|The unique ID of the message| - -### Client-Initiated Interaction - -|Scene|Client Request|Server Response|Remark| -|-|-|-|-| -| Heartbeat | HEARTBEAT(203) | SUCCESS(0) or EVENTMESH_HEARTBEAT_ERROR(19) | | -| Subscribe | SUBSCRIBE(206) | SUCCESS(0) or EVENTMESH_SUBSCRIBE_ERROR(17) | | -| Unsubscribe | UNSUBSCRIBE(207) | SUCCESS(0) or EVENTMESH_UNSUBSCRIBE_ERROR(18) | | -| Send async message | MSG_SEND_ASYNC(104) | SUCCESS(0) or EVENTMESH_SEND_ASYNC_MSG_ERR(14) | | - -### Server-Initiated Interaction - -|Scene|Client Request|Server Response|Remark| -|-|-|-|-| -|Push async message to the client|HTTP_PUSH_CLIENT_ASYNC(105)|`retCode`|The push is successful if the `retCode` is `0`| - -## gRPC Protocol - -### Protobuf - -The `eventmesh-protocol-gprc` module contains the [protobuf definition file](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-client.proto) of the Evenmesh client. The `gradle build` command generates the gRPC codes, which are located in `/build/generated/source/proto/main`. The generated gRPC codes are used in `eventmesh-sdk-java` module. - -### Data Model - -#### Message - -The message data model used by `publish()`, `requestReply()` and `broadcast()` APIs is defined as: - -```protobuf -message RequestHeader { - string env = 1; - string region = 2; - string idc = 3; - string ip = 4; - string pid = 5; - string sys = 6; - string username = 7; - string password = 8; - string language = 9; - string protocolType = 10; - string protocolVersion = 11; - string protocolDesc = 12; -} - -message SimpleMessage { - RequestHeader header = 1; - string producerGroup = 2; - string topic = 3; - string content = 4; - string ttl = 5; - string uniqueId = 6; - string seqNum = 7; - string tag = 8; - map properties = 9; -} - -message BatchMessage { - RequestHeader header = 1; - string producerGroup = 2; - string topic = 3; - - message MessageItem { - string content = 1; - string ttl = 2; - string uniqueId = 3; - string seqNum = 4; - string tag = 5; - map properties = 6; - } - - repeated MessageItem messageItem = 4; -} - -message Response { - string respCode = 1; - string respMsg = 2; - string respTime = 3; -} -``` - -#### Subscription - -The subscription data model used by `subscribe()` and `unsubscribe()` APIs is defined as: - -```protobuf -message Subscription { - RequestHeader header = 1; - string consumerGroup = 2; - - message SubscriptionItem { - enum SubscriptionMode { - CLUSTERING = 0; - BROADCASTING = 1; - } - - enum SubscriptionType { - ASYNC = 0; - SYNC = 1; - } - - string topic = 1; - SubscriptionMode mode = 2; - SubscriptionType type = 3; - } - - repeated SubscriptionItem subscriptionItems = 3; - string url = 4; -} -``` - -#### Heartbeat - -The heartbeat data model used by the `heartbeat()` API is defined as: - -```protobuf -message Heartbeat { - enum ClientType { - PUB = 0; - SUB = 1; - } - - RequestHeader header = 1; - ClientType clientType = 2; - string producerGroup = 3; - string consumerGroup = 4; - - message HeartbeatItem { - string topic = 1; - string url = 2; - } - - repeated HeartbeatItem heartbeatItems = 5; -} -``` - -### Service Definition - -#### Event Publisher Service - -```protobuf -service PublisherService { - // Async event publish - rpc publish(SimpleMessage) returns (Response); - - // Sync event publish - rpc requestReply(SimpleMessage) returns (Response); - - // Batch event publish - rpc batchPublish(BatchMessage) returns (Response); -} -``` - -#### Event Consumer Service - -```protobuf -service ConsumerService { - // The subscribed event will be delivered by invoking the webhook url in the Subscription - rpc subscribe(Subscription) returns (Response); - - // The subscribed event will be delivered through stream of Message - rpc subscribeStream(Subscription) returns (stream SimpleMessage); - - rpc unsubscribe(Subscription) returns (Response); -} -``` - -#### Client Hearthbeat Service - -```protobuf -service HeartbeatService { - rpc heartbeat(Heartbeat) returns (Response); -} -``` diff --git a/docs/en/design-document/03-stream.md b/docs/en/design-document/03-stream.md deleted file mode 100644 index 421faf3af3..0000000000 --- a/docs/en/design-document/03-stream.md +++ /dev/null @@ -1,118 +0,0 @@ -# EventMesh Stream - -## Overview of Event Streaming - -Event Streaming is an implementation of Pub/Sub architecture pattern,it consist of - -- Message or Event: Change of State. - -- Topic: Partition in messaging middle ware broker. - -- Consumer: Can subscribe to read events from broker topic. - -- Producer: Generate events - -Streaming of event is continuous flow of events in order to maintain order between events, events flow should be in a specific direction means from producers to consumers. - -## Requirements - -### Functional Requirements - -| Requirement ID | Requirement Description | Comments | -| -------------- | ----------------------- | -------- | -| F-1 | EventMesh users should be able to achieve Event Streaming functionality in EventMesh | Functionality | -| F-2 | EventMesh users can apply dynamic user specific logics for routing, filter, transformation etc | Functionality | - -## Design Details - -We are introduce EventMesh Stream component allow us to use programming model and binder abstractions -from Spring Cloud Stream natively within Apache Camel. - -[Spring-Cloud-Stream](https://spring.io/projects/spring-cloud-stream) Spring Cloud Stream is a framework for building -highly scalable event-driven microservices connected with shared messaging systems. - -[Apache Camel](https://camel.apache.org/) Camel is an Open Source integration framework that empowers you to quickly -and easily integrate various systems consuming or producing data. - -## Architecture - -![Stream Architecture](../../images/design-document/stream-architecture.png) - -## Design - -### EventMesh-Stream Component - -- Event -- Event Channel -- Event EndPoint -- Event Pipes & Filters -- Event Routes -- Event Converter - -#### Event - -> A event is the smallest unit for transmitting data in system. It structure divided into headers, body and attachments. - -#### Event Channel - -> A event channel is a logical channel in system, we are achieving by Spring Cloud Stream programming model, it has abstract functionality around messaging channels(As of now Spring `MessageChannel`). - -#### Event EndPoint - -> A event endpoint is the interface between an application and a messaging system. We can define two types of endpoint - -- Consumer endpoint - Appears at start of a route and read incoming events from an incoming channel. -- Producer endpoint - Appears at end of a route and write incoming events to an outgoing channel. - -#### Event Pipes & Filters - -> We can construct a route by creating chain of filters( Apache Camel `Processor`), where the output of one filter is fed into input for next filter in the pipeline. -The main advantage of the pipeline is that you can create complex event processing logic. - -#### Event Routes - -> A event router, is a type of filter on consumer and redirect them to the appropriate target endpoint based on a decision criteria. - -#### Event Converter - -> The event converter that modifies the contents of a event, translating it to a different format(i.e cloudevents -> Event (Camel) -> Binder Message(Spring Message) and vice versa). - -## EventMesh-Stream Component Interfaces - -### Component - -Component interface is the primary entry point, you can use Component object as a factory to create EndPoint objects. - -![Stream Component Interface](/images/design-document/stream-component-interface.png) - -### EndPoint - -EndPoint which is act as factories for creating Consumer, Producer and Event objects. - -- `createConsumer()` — Creates a consumer endpoint, which represents the source endpoint at the beginning of a route. -- `createProducer()` — Creates a producer endpoint, which represents the target endpoint at the end of a route. - -![Stream Component Routes](../../images/design-document/stream-component-routes.png) - -#### Producer - -User can create following types of producer -> Synchronous Producer-Processing thread blocks until the producer has finished the event processing. - -![Stream Sync Producer](../../images/design-document/stream-sync-producer.png) - -In future Producer Types: - -- Asynchronous Producer - Producer process the event in a sub-thread. - -#### Consumer - -User can create following types of consumer -> Event-driven consumer-the processing of an incoming request is initiated when message binder call a method in consumer. - -![Stream Event-Driven Consumer](../../images/design-document/stream-event-driven-consumer.png) - -In the Future - -- Scheduled poll consumer -- Custom polling consumer diff --git a/docs/en/design-document/04-schema-registry.md b/docs/en/design-document/04-schema-registry.md deleted file mode 100644 index 2cab152651..0000000000 --- a/docs/en/design-document/04-schema-registry.md +++ /dev/null @@ -1,134 +0,0 @@ -# EventMesh Schema Registry (OpenSchema) - -## Overview of Schema and Schema Registry - -### Schema - -A Schema stands for the description of serialization instances(string/stream/file/...) and has two properties. First, it is also in the format of serialization type. Second, it defines what requirements such serialized instances should satisfy. - -Besides describing a serialization instance, a Schema may also be used for validating whether an instance is legitimate. The reason is that it defines the ```type```(and other properties) of a serialized instance and inside keys. Taking JSON Schema for example, it could not only be referred when describing a JSON string, but also be used for validating whether a string satisfies properties defined in the schema[[1]](#References). - -Commonly, there are JSON Schema, Protobuf Schema, and Avro Schema. - -### Schema Registry - -Schema Registry is a server provides RESTful interfaces. It could receive and store Schemas from clients, as well as provide intrefaces for other clients to retrieve Schemas from it. - -It could be applied to validation process and (de-)serialization process. - -### Comparison of Schema Registry in Different Projects - -Project | Application -:---: | :--- -EMQ[[2]](#References) | Mainly in (de-)serialization process. Use "Schema Registry" and "Rule Matching" to transfer a message from one serialization format to another. -Pulsar[[3]](#References) | Mainly in validation process. Use "Schema Registry" to validate a message. -Confluentinc[[4]](#References) | In both validation and (de-)serialization process. - -## Overview of OpenSchema - -OpenSchema[[5]](#References) proposes a specification for data schema when exchanging the message and event in more and more modern cloud-native applications. It designs a RESTful interface for storing and retrieving such as Avro, JSON Schema, and Protobuf3 schemas from three aspects(subject/schema/compatibility). - -## Requirements(Goals) - -| Requirement ID | Requirement Description | Comments | -| :------------- | ------------------------------------------------------------ | ------------- | -| F-1 | In transmission, no message needs to contain schema information which bring efficiency. | Functionality | -| F-2 | The message content from producer could be validated whether serialized correctly according to schema. | Functionality | - -## Design Details - -### Architecture - -![OpenSchema](../../images/design-document/schema-registry-architecture.png) - -### Process of Transferring Messages under Schema Registry - -![Process](.././images/design-document/schema-registry-process.jpg) - -The highlevel process of messages transmission contains 10 steps as follows: - -- 1: Consumer subscribes "TOPIC" messages from EventMesh. -- 2: Producer registers a schema to EventMesh. -- 3: EventMesh registers a schema to Schema Registry. -- 4: Schema Registry returns the id of newly created schema; EventMesh caches such id and schema. -- 5: EventMesh returns the id of schema to Producer. -- 6: Producer patches the id in front of messages and send messages to EventMesh. -- 7: EventMesh validates the messages in the entry port and send it to EventStore; EventMesh retrieves messages from EventStore. -- 8: EventMesh unpatches the id and send it to Schema Registry(if such `` does not exists in local cache). -- 9: Schema Registry returns schema and EventMesh caches it. -- 10: EventMesh patches schema in front of messages and push it to consumer. - -## Current Progress - -### Status - -**Current state**: Developing - -**Discussion thread**: ISSUE #339 - -### Proposed Changes - -The proposal has two aspects. - -First is a separated Open Schema Registry, which includes storage and compatibility check for schema. -This proposal is under developing. - -Second is the integration of Open Schema in Eventmesh, which includes validation for schema. This proposal is to be developed. - -As for the first proposal, some developing statuses are as follows. - -#### Status Code and Exception Code - -No. | Status Code | Exception Code | Description | status ---- | :---: | :---: | :---: | :---: -1 | 401 | 40101 | Unauthorized Exception | ✔ -2 | 404 | 40401 | Schema Non- Exception | ✔ -3 | ^ | 40402 | Subject Non-exist Exception | ✔ -4 | ^ | 40403 | Version Non-exist Exception | ✔ -5 | 409 | 40901 | Compatibility Exception | ✔ -6 | 422 | 42201 | Schema Format Exception | ✔ -7 | ^ | 42202 | Subject Format Exception | ✔ -8 | ^ | 42203 | Version Format Exception | ✔ -9 | ^ | 42204 | Compatibility Format Exception | ✔ -10 | 500 | 50001 | Storage Service Exception | ✔ -11 | ^ | 50002 | Timeout Exception | ✔ - -#### API Development Status - -No. | Type | URL | response | exception | code | test ---- | --- | --- | --- | --- | --- | --- -1 | GET | /schemas/ids/{string: id} | `Schema.class` | 40101\40401\50001 | ✔ | ❌ -2 | GET | /schemas/ids/{string: id}/subjects | `SubjectAndVersion.class` | 40101\40401\50001 | ✔ | ❌ -3 | GET | /subjects | `List\` | 40101\50001 | ✔ | ❌ -4 | GET | /subjects/{string: subject}/versions | `List\` | 40101\40402\50001 | ✔ | ❌ -5 | DELETE | /subjects/(string: subject) | `List\` | 40101\40402\50001 | ✔ | ❌ -6 | GET | /subjects/(string: subject) | `Subject.class` | 40101\40402\50001 | ✔ | ❌ -7 | GET | /subjects/(string: subject)/versions/(version: version)/schema | `SubjectWithSchema.class` | 40101\40402\40403\50001 | ✔ | ❌ -8 | POST | /subjects/(string: subject)/versions | `SchemaIdResponse.class` | 40101\40901\42201\50001\50002 | - | ❌ -9 | POST | /subjects/(string: subject)/ | `Subject.class` | 40101\40901\42202\50001\50002 | ✔ | ❌ -10 | DELETE | /subjects/(string: subject)/versions/(version: version) | `int` | 40101\40402\40403\40901\50001| - | ❌ -11 | POST | /compatibility/subjects/(string: subject)/versions/(version: version) | `CompatibilityResultResponse.class` | 40101\40402\40403\42201\42203\50001| - | ❌ -12 | GET | /compatibility/(string: subject) | `Compatibility.class` | 40101\40402\50001 | ✔ | ❌ -13 | PUT | /compatibility/(string: subject) | `Compatibility.class` | 40101\40402\40901\42204\50001 | - | ❌ - -#### Overall Project Structure - -```SchemaController.java```+```SchemaService.java``` : ```OpenSchema 7.1.1~7.1.2 (API 1~2)``` - -```SubjectController.java```+```SubjectService.java``` : ```OpenSchema 7.2.1~7.2.8 (API 3~10)``` - -```CompatibilityController.java```+```CompatibilityService.java``` : ```OpenSchema 7.3.1~7.3.3 (API 11~13)``` + ```Check for Compatibility``` - -![Project Structure](../../images/design-document/schema-registry-project-structure.png) - -## References - -[1] [schema validator (github.com)](https://github.com/search?q=schema+validator) - -[2] [EMQ: Schema Registry](https://www.jianshu.com/p/33e0655c642b) - -[3] [Pulsar: Schema Registry](https://mp.weixin.qq.com/s/PaB66-Si00cX80py5ig5Mw) - -[4] [confluentinc/schema-registry](https://github.com/confluentinc/schema-registry) - -[5] [openmessaging/openschema](https://github.com/openmessaging/openschema) diff --git a/docs/en/design-document/05-metrics-export.md b/docs/en/design-document/05-metrics-export.md deleted file mode 100644 index bab18761e3..0000000000 --- a/docs/en/design-document/05-metrics-export.md +++ /dev/null @@ -1,47 +0,0 @@ -# EventMesh Metrics (OpenTelemetry and Prometheus) - -## Introduction - -[EventMesh(incubating)](https://github.com/apache/incubator-eventmesh) is a dynamic cloud-native eventing infrastructure. - -## An overview of OpenTelemetry - -OpenTelemetry is a collection of tools, APIs, and SDKs. You can use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior. - -## An overview of Prometheus - -Power your metrics and alerting with a leading open-source monitoring solution. - -- Dimensional data -- Powerful queries -- Great visualization -- Efficient storage -- Simple operation -- Precise alerting -- Many client libraries -- Many integrations - -## Requirements - -### Functional Requirements - -| Requirement ID | Requirement Description | Comments | -| :------------- | ------------------------------------------------------------ | ------------- | -| F-1 | EventMesh users should be able to observe HTTP metrics from Prometheus | Functionality | -| F-2 | EventMesh users should be able to observe TCP metrics from Prometheus | Functionality | - -## Design Details - -use the meter instrument provided by OpenTelemetry to observe the metrics exist in EventMesh then export to Prometheus. - -1、Initialize a meter instrument - -2、set the Prometheus server - -3、different metrics observer built - -## Appendix - -### References - - diff --git a/docs/en/design-document/06-cloudevents.md b/docs/en/design-document/06-cloudevents.md deleted file mode 100644 index 20a99d182a..0000000000 --- a/docs/en/design-document/06-cloudevents.md +++ /dev/null @@ -1,106 +0,0 @@ -# CloudEvents Integration - -## Introduction - -[CloudEvents](https://github.com/cloudevents/spec) is a specification for describing event data in common formats to provide interoperability across services, platforms and systems. - -As of May 2021, EventMesh contains the following major components: `eventmesh-runtime`, `eventmesh-sdk-java` and `eventmesh-connector-rocketmq`. -For a customer to use EventMesh, `eventmesh-runtime` can be deployed as microservices to transmit -customer's events between event producers and consumers. Customer's applications can then interact -with `eventmesh-runtime` using `eventmesh-sdk-java` to publish/subscribe for events on given topics. - -CloudEvents support has been a highly desired feature by EventMesh users. There are many reasons -for users to prefer using a SDK with CloudEvents support: - -- CloudEvents is a more widely accepted and supported way to describe events. `eventmesh-sdk-java` - currently uses the `LiteMessage` structure to describe events, which is less standardized. -- CloudEvents's Java SDK has a wider range of distribution methods. For example, EventMesh users - currently need to use the SDK tarball or build from source for every EventMesh release. With - CloudEvents support, it's easier for users to take a dependency on EventMesh's SDK using CloudEvents's public distributions (e.g. through a Maven configuration). -- CloudEvents's SDK supports multiple languages. Although EventMesh currently only supports a Java SDK, in future if more languages need to be supported, the extensions can be easier with experience on binding Java SDK with CloudEvents. - -## Requirements - -### Functional Requirements - -| Requirement ID | Requirement Description | Comments | -| -------------- | ----------------------- | -------- | -| F-1 | EventMesh users should be able to depend on a public SDK to publish/subscribe events in CloudEvents format | Functionality | -| F-2 | EventMesh users should continue to have access to existing EventMesh client features (e.g. load balancing) with an SDK that supports CloudEvent | Feature Parity | -| F-3 | EventMesh developers should be able to sync `eventmesh-sdk-java` and an SDK with CloudEvents support without much effort/pain | Maintainability | -| F-4 | EventMesh support pluggable protocols for developers integrate other protocols (e.g. CloudEvents\EventMesh Message\OpenMessage\MQTT ...) | Functionality | -| F-5 | EventMesh support the unified api for publish/subscribe events to/from event store | Functionality | - -### Performance Requirements - -| Requirement ID | Requirement Description | Comments | -| -------------- | ----------------------- | -------- | -| P-1 | Client side latency for SDK with CloudEvents support should be similar to current SDK | | - -## Design Details - -Binding with the CloudEvents Java SDK (similar to what Kafka already did, see Reference for more details) -should be an easy way to achieve the requirements. - -### Pluggable Protocols - -![Pluggable Protocols](../../images/design-document/cloudevents-pluggable-protocols.png) - -### Process of CloudEvents under EventMesh - -#### For TCP - -##### SDK side for publish - -- add the CloudEvents identifier in `package` header -- use `CloudEventBuilder` build the CloudEvent and put it into the `package` body - -##### SDK side for subscribe - -- add `convert` function under the `ReceiveMsgHook` interface, for converting the `package` body to the specific protocol with the identifier in `package` header -- different protocols should implement the `ReceiveMsgHook` interface - -##### Server side for publish - -- design the protocol convert api contains `decodeMessage` interface which convert the package's body to CloudEvent -- update `Session.upstreamMsg()` in `MessageTransferTask` change the input parameter Message to CloudEvent, the CloudEvent use the last step `decodeMessage` api convert -- update `SessionSender.send()` change the input parameter `Message` to `CloudEvent` -- update `MeshMQProducer` api support send `CloudEvents` in runtime -- support the implementation in `connector-plugin` for send `CloudEvents` to EventStore - -##### Server side for subscribe - -- support change the `RocketMessage` to `CloudEvent` in connector-plugin - -- overwrite the `AsyncMessageListener.consume()` function, change the input parameter `Message` to `CloudEvent` - -- update the `MeshMQPushConsumer.updateOffset()` implementation change the the input parameter `Message` to `CloudEvent` - -- update `DownStreamMsgContext` , change the input parameter `Message` to `CloudEvent`, update the `DownStreamMsgContext.ackMsg` - -#### For HTTP - -##### SDK side for publish - -- support `LiteProducer.publish(cloudEvent)` -- add the CloudEvents identifier in http request header - -##### SDK side for subscribe - -##### Server side for publish - -- support build the `HttpCommand.body` by pluggable protocol plugins according the protocol type in `HttpCommand` header -- support publish the CloudEvent in message processors - -##### Server side for subscribe - -- update the `EventMeshConsumer.subscribe()` - -- update `HandleMsgContext` , change the input parameter `Message` to `CloudEvent` -- update `AsyncHttpPushRequest.tryHTTPRequest()` - -## Appendix - -### References - -- diff --git a/docs/en/design-document/07-tracing.md b/docs/en/design-document/07-tracing.md deleted file mode 100644 index 1b191965da..0000000000 --- a/docs/en/design-document/07-tracing.md +++ /dev/null @@ -1,87 +0,0 @@ -# Distributed Tracing - -## Overview of OpenTelemetry - -OpenTelemetry is a collection of tools, APIs, and SDKs. You can use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior. - -## Requirements - -- set tracer -- different exporter -- start and end span in server - -## Design Details - -- SpanProcessor: BatchSpanProcessor - -- Exporter: log(default), would be changed from properties - -```java -// Configure the batch spans processor. This span processor exports span in batches. -BatchSpanProcessor batchSpansProcessor = - BatchSpanProcessor.builder(exporter) - .setMaxExportBatchSize(512) // set the maximum batch size to use - .setMaxQueueSize(2048) // set the queue size. This must be >= the export batch size - .setExporterTimeout( - 30, TimeUnit.SECONDS) // set the max amount of time an export can run before getting - // interrupted - .setScheduleDelay(5, TimeUnit.SECONDS) // set time between two different exports - .build(); -OpenTelemetrySdk.builder() - .setTracerProvider( - SdkTracerProvider.builder().addSpanProcessor(batchSpansProcessor).build()) - .build(); -``` - -1. When using the method 'init()' of the class "EventMeshHTTPServer", the class "AbstractHTTPServer” will get the tracer - -```java -super.openTelemetryTraceFactory = new OpenTelemetryTraceFactory(eventMeshHttpConfiguration); -super.tracer = openTelemetryTraceFactory.getTracer(this.getClass().toString()); -super.textMapPropagator = openTelemetryTraceFactory.getTextMapPropagator(); -``` - -2. then the trace in class "AbstractHTTPServer” will work. - -## Problems - -### How to set different exporter in class 'OpenTelemetryTraceFactory'? (Solved) - -After I get the exporter type from properties, how to deal with it. - -The 'logExporter' only needs to new it. - -But the 'zipkinExporter' needs to new and use the "getZipkinExporter()" method. - -## Solutions - -### Solution of different exporter - -Use reflection to get an exporter. - -First of all, different exporter must implement the interface 'EventMeshExporter'. - -Then we get the exporter name from the configuration and reflect to the class. - -```java -//different spanExporter -String exporterName = configuration.eventMeshTraceExporterType; -//use reflection to get spanExporter -String className = String.format("org.apache.eventmesh.runtime.exporter.%sExporter",exporterName); -EventMeshExporter eventMeshExporter = (EventMeshExporter) Class.forName(className).newInstance(); -spanExporter = eventMeshExporter.getSpanExporter(configuration); -``` - -Additional, this will surround with try catch.If the specified exporter cannot be obtained successfully, the default exporter log will be used instead - -#### Improvement of different exporter - -SPI (To be completed) - -## Appendix - -### References - - - - diff --git a/docs/en/design-document/08-spi.md b/docs/en/design-document/08-spi.md deleted file mode 100644 index 94da666e7f..0000000000 --- a/docs/en/design-document/08-spi.md +++ /dev/null @@ -1,113 +0,0 @@ -# Service Provider Interface - -## Introduction - -In order to improve scalability,EventMesh introduce the SPI(Service Provider Interface)mechanism, which can help to automatically find the concrete implementation -class of the extended interface at runtime and load it dynamically. In EventMesh, all extension modules are implemented by using plugin. -User can develop custom plugins by simply implementing extended interfaces, and select the plugin to be run at runtime by simply declare at configuration. - -## eventmesh-spi module - -The implementation of SPI is at eventmesh-spi module, there are three main classes `EventMeshSPI`, `EventMeshExtensionFactory` and `ExtensionClassLoader`. - -### EventMeshSPI - -EventMeshSPI is an SPI declaration annotation, all extended interface that want to be implemented should be declared by @EventMeshSPI. - -```java -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE}) -public @interface EventMeshSPI { - /** - * If true, the spi instance is singleton - */ - boolean isSingleton() default false; -} -``` - -Use annotation to declare the interface is an SPI extended interface can improve the readability of the code. -On the other hand, @EventMeshSPI contains a isSingleton attribute which used to declare whether the extension instance is a singleton. -If this attribute is true, that means the instance of this interface will be singleton. - -### EventMeshExtensionFactory - -EventMeshExtensionFactory is a factory used to get the SPI extension instance which contains a static method `getExtension(Class extensionType, String extensionName)`. - -```java -public enum EventMeshExtensionFactory { - /** - * @param extensionType extension plugin class type - * @param extensionName extension instance name - * @param the type of the plugin - * @return plugin instance - */ - public static T getExtension(Class extensionType, String extensionName) { - /* ... */ - } -} -``` - -If you want to get the extension instance, you should use EventMeshExtensionFactory. - -### ExtensionClassLoader - -ExtensionClassLoader is used to load extension instance classed, it has two subclass MetaInfExtensionClassLoader and JarExtensionClassLoader. - -```java -/** - * Load extension class - *
    - *
  • {@link MetaInfExtensionClassLoader}
  • - *
  • {@link JarExtensionClassLoader}
  • - *
- */ -public interface ExtensionClassLoader { - /** - * load - * - * @param extensionType extension type class - * @param extension type - * @return extension instance name to extension instance class - */ - Map> loadExtensionClass(Class extensionType); -} -``` - -MetaInfExtensionClassLoader used to load class from classPath, and JarExtensionClassLoader used to load class from extension jar on the plugin directory. -In the future, we might support the implementation to load from the maven repository. - -## SPI use case - -The following is an example of how to use the SPI to declare a plugin. - -First, we create an eventmesh-connector-api module, and define the extension interface MeshMQProducer, and we use @EventMeshSPI on the MeshMQProducer, -which indicates the MeshMQProducer is an SPI interface. - -```java -@EventMeshSPI(isSingleton = false) -public interface MeshMQProducer extends Producer { - /* ... */ -} -``` - -Then we create an eventmesh-connector-rocketmq module, which contains the concrete implementation named RocketMQProducerImpl. - -```java -public class RocketMQProducerImpl implements MeshMQProducer { - /* ... */ -} -``` - -At the same time, we need to create a file with the full qualified name of the SPI interface under the resource/META-INF/eventmesh directory -in the eventmesh-connector-rocketmq module. - -org.apache.eventmesh.api.producer.Producer - -The content of the file is the extension instance name and the corresponding instance full class name - -```properties -rocketmq=org.apache.eventmesh.connector.rocketmq.producer.RocketMQProducerImpl -``` - -At this point, an SPI expansion module is complete. We can use `EventMeshExtensionFactory.getExtension(MeshMQProducer.class, "rocketmq")` to get the `RocketMQProducerImpl` instance. diff --git a/docs/en/design-document/_category_.json b/docs/en/design-document/_category_.json deleted file mode 100644 index f9283e2f00..0000000000 --- a/docs/en/design-document/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 6, - "label": "Design Document", - "collapsed": false -} diff --git a/docs/en/instruction/01-store-with-docker.md b/docs/en/instruction/01-store-with-docker.md deleted file mode 100644 index e772db60b5..0000000000 --- a/docs/en/instruction/01-store-with-docker.md +++ /dev/null @@ -1,71 +0,0 @@ -# Guidelines of eventmesh-store with Docker - -## Dependencies - -``` -64-bit OS,we recommend Linux/Unix; -64-bit JDK 1.8+; -Gradle 7.0+, we recommend 7.0.* -4g+ available disk to deploy eventmesh-store -If you choose standalone mode, you could skip this file and go to the next step: Start Eventmesh-Runtime; if not, you could choose RocketMQ as the store layer. -``` - - -## Download - -Download the Binary code (recommended: 4.9.*) from [RocketMQ Official](https://rocketmq.apache.org/dowloading/releases/). Here we take 4.9.2 as an example. - -``` -unzip rocketmq-all-4.9.2-bin-release.zip -cd rocketmq-4.9.2/ -``` - - -## Deploy - -- #### Start Name Server - -``` -nohup sh bin/mqnamesrv & -tail -f ~/logs/rocketmqlogs/namesrv.log -``` - -- #### Start Broker - -``` -nohup sh bin/mqbroker -n localhost:9876 & -tail -f ~/logs/rocketmqlogs/broker.log -``` - -The deployment of eventmesh-store has finished, please go to the next step: [Start Eventmesh-Runtime](docs/en/instruction/02-runtime.md) - - - -## Deploy -Pull RocketMQ image from Docker Hub: - -```shell -#获取namesrv镜像 -sudo docker pull rocketmqinc/rocketmq-namesrv:4.5.0-alpine -#获取broker镜像 -sudo docker pull rocketmqinc/rocketmq-broker:4.5.0-alpine -``` - -Start namesrv and broker - -```shell -#运行namerv容器 -sudo docker run -d -p 9876:9876 -v `pwd`/data/namesrv/logs:/root/logs -v `pwd`/data/namesrv/store:/root/store --name rmqnamesrv rocketmqinc/rocketmq-namesrv:4.5.0-alpine sh mqnamesrv - -#运行broker容器 -sudo docker run -d -p 10911:10911 -p 10909:10909 -v `pwd`/data/broker/logs:/root/logs -v `pwd`/data/broker/store:/root/store --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq-broker:4.5.0-alpine sh mqbroker -c ../conf/broker.conf -``` - -Please note that the **rocketmq-broker ip** is **pod ip**. If you want to modify this ip, you can set it your custom value in **broker.conf**。 - - -By now, the deployment of eventmesh-store has finished, please go to the next step: [Start Eventmesh-Runtime Using Docker](docs/en/instruction/02-runtime-with-docker.md) - - -## Reference -For more details about RocketMQ,please refer to diff --git a/docs/en/instruction/01-store.md b/docs/en/instruction/01-store.md deleted file mode 100644 index d5b5eb9c19..0000000000 --- a/docs/en/instruction/01-store.md +++ /dev/null @@ -1,44 +0,0 @@ -# Guidelines of eventmesh-store - -## Dependencies - -``` -64-bit OS,we recommend Linux/Unix; -64-bit JDK 1.8+; -Gradle 7.0+, we recommend 7.0.* -4g+ available disk to deploy eventmesh-store -If you choose standalone mode, you could skip this file and go to the next step: Start Eventmesh-Runtime; if not, you could choose RocketMQ as the store layer. -``` - - -## Download - -Download the Binary code (recommended: 4.9.*) from [RocketMQ Official](https://rocketmq.apache.org/dowloading/releases/). Here we take 4.9.2 as an example. - -``` -unzip rocketmq-all-4.9.2-bin-release.zip -cd rocketmq-4.9.2/ -``` - - -## Deploy - -- #### Start Name Server - -``` -nohup sh bin/mqnamesrv & -tail -f ~/logs/rocketmqlogs/namesrv.log -``` - -- #### Start Broker - -``` -nohup sh bin/mqbroker -n localhost:9876 & -tail -f ~/logs/rocketmqlogs/broker.log -``` - -The deployment of eventmesh-store has finished, please go to the next step: [Start Eventmesh-Runtime](docs/en/instruction/02-runtime.md) - - -## Reference -For more details about RocketMQ,please refer to diff --git a/docs/en/instruction/02-runtime-with-docker.md b/docs/en/instruction/02-runtime-with-docker.md deleted file mode 100644 index 7da3e2a433..0000000000 --- a/docs/en/instruction/02-runtime-with-docker.md +++ /dev/null @@ -1,107 +0,0 @@ -# EventMesh Runtime (Docker) - -The documentation introduces the steps to install the latest release of EventMesh Runtime with Docker and connect to Apache RocketMQ. It's recommended to use a Linux-based system with [Docker Engine](https://docs.docker.com/engine/install/). Please follow the [Docker tutorial](https://docs.docker.com/get-started/) to get familiar with the basic concepts (registry, volume, etc.) and commands of Docker. - - -## Dependencies -``` -64-bit OS,we recommend Linux/Unix; -64-bit JDK 1.8+; -Gradle 7.0+, we recommend 7.0.* -4g+ available disk to deploy eventmesh-store -If you choose standalone mode, you could skip this file and go to the next step: Start Eventmesh-Runtime; if not, you could choose RocketMQ as the store layer. -``` - -## Pull EventMesh Image - -Download the pre-built image of [`eventmesh`](https://hub.docker.com/r/eventmesh/eventmesh) from Docker Hub with `docker pull`: - -```console -$ sudo docker pull eventmesh/eventmesh:v1.4.0 -``` - -To verify that the `eventmesh/eventmesh` image is successfully installed, list the downloaded images with `docker images`: - -```console -$ sudo docker images -eventmesh/eventmesh v1.4.0 6e2964599c78 2 weeks ago 937MB -``` - -## Edit Configuration - -Edit the `eventmesh.properties` to change the configuration (e.g. TCP port, client blacklist) of EventMesh Runtime. To integrate RocketMQ as a connector, these two configuration files should be created: `eventmesh.properties` and `rocketmq-client.properties`. - -```shell -sudo mkdir -p /data/eventmesh/rocketmq/conf -cd /data/eventmesh/rocketmq/conf -sudo touch eventmesh.properties -sudo touch rocketmq-client.properties -``` - -### `eventmesh.properties` - -The `eventmesh.properties` file contains the properties of EventMesh runtime environment and integrated plugins. Please refer to the [default configuration file](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-runtime/conf/eventmesh.properties) for the available configuration keys. - -```shell -sudo vim eventmesh.properties -``` - -| Configuration Key | Default Value | Description | -|-|-|-| -| `eventMesh.server.http.port` | 10105 | EventMesh HTTP server port | -| `eventMesh.server.tcp.port` | 10000 | EventMesh TCP server port | -| `eventMesh.server.grpc.port` | 10205 | EventMesh gRPC server port | - -### `rocketmq-client.properties` - -The `rocketmq-client.properties` file contains the properties of the Apache RocketMQ nameserver. - -```shell -sudo vim rocketmq-client.properties -``` - -Please refer to the [default configuration file](https://github.com/apache/incubator-eventmesh/blob/1.3.0/eventmesh-runtime/conf/rocketmq-client.properties) and change the value of `eventMesh.server.rocketmq.namesrvAddr` to the nameserver address of RocketMQ. - -| Configuration Key | Default Value | Description | -|-|-|-| -| `eventMesh.server.rocketmq.namesrvAddr` | `127.0.0.1:9876;127.0.0.1:9876` | The address of RocketMQ nameserver | - -## Run and Manage EventMesh Container - -Run an EventMesh container from the `eventmesh/eventmesh` image with the `docker run` command. The `-p` option of the command binds the container port with the host machine port. The `-v` option of the command mounts the configuration files from files in the host machine. - -```shell -sudo docker run -d -p 10000:10000 -p 10105:10105 \ --v /data/eventmesh/rocketmq/conf/eventmesh.properties:/data/app/eventmesh/conf/eventmesh.properties \ --v /data/eventmesh/rocketmq/conf/rocketmq-client.properties:/data/app/eventmesh/conf/rocketmq-client.properties \ -eventmesh/eventmesh:v1.4.0 -``` - -The `docker ps` command lists the details (id, name, status, etc.) of the running containers. The container id is the unique identifier of the container. - -```console -$ sudo docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - eventmesh/eventmesh:v1.4.0 "/bin/sh -c 'sh star…" About a minute ago Up About a minute 0.0.0.0:10000->10000/tcp, :::10000->10000/tcp, 0.0.0.0:10105->10105/tcp, :::10105->10105/tcp -``` - -To connect to the EventMesh container: - -```shell -sudo docker exec -it [container id or name] /bin/bash -``` - -To read the log of the EventMesh container: - -```shell -tail -f ../logs/eventmesh.out -``` - -To stop or remove the container: - -```shell -sudo docker stop [container id or name] - -sudo docker rm -f [container id or name] -``` - diff --git a/docs/en/instruction/02-runtime.md b/docs/en/instruction/02-runtime.md deleted file mode 100644 index 900f86864a..0000000000 --- a/docs/en/instruction/02-runtime.md +++ /dev/null @@ -1,107 +0,0 @@ -# EventMesh Runtime - -EventMesh Runtime is the core component of Apache EventMesh (Incubating). It is the middleware that transmits events between producers and consumers. The documentation introduces the step to install and start the latest release of EventMesh Runtime in the local or test environment. The EventMesh Runtime requires a Linux-based system with JDK (Java Development Kit) 8+. - -Here, we take JDK 8 as an example. JDK 8 could be installed with the system package manager or the [openjdk:8-jdk](https://hub.docker.com/_/openjdk) Docker image. - - -## 1 Run on your local machine - -### 1.1 Dependencies - -``` -64-bit OS,we recommend Linux/Unix; -64-bit JDK 1.8+; -Gradle 7.0+, we recommend 7.0.* -4g+ available disk to deploy eventmesh-store -If you choose standalone mode, you could skip this file and go to the next step: Start Eventmesh-Runtime; if not, you could choose RocketMQ as the store layer. -``` - -### 1.2 Download Source Code - -Gradle is the build automation tool used by Apache EventMesh (Incubating). Please refer to the [offical guide](https://docs.gradle.org/current/userguide/installation.html) to install the latest release of Gradle. - -Download and extract the source code of the latest release from [EventMesh download](https://eventmesh.apache.org/download). - -```console -wget https://dlcdn.apache.org/incubator/eventmesh/{version}-incubating/apache-eventmesh-{version}-incubating-source.tar.gz - -tar -xvzf apache-eventmesh-1.5.0-incubating-source.tar.gz -``` - -Build the source code with Gradle. - -```console -cd apache-eventmesh-1.5.0-incubating-source -gradle clean dist -``` - -Edit the `eventmesh.properties` to change the configuration (e.g. TCP port, client blacklist) of EventMesh Runtime. - -```console -cd dist -vim conf/eventmesh.properties -``` - -Execute the `start.sh` script to start the EventMesh Runtime server. - -```console -bash bin/start.sh -``` - -### 1.3 Build and Load Plugins - -Apache EventMesh (Incubating) introduces the SPI (Service Provider Interface) mechanism, which enables EventMesh to discover and load the plugins at runtime. The plugins could be installed with these methods: - -- Gradle Dependencies: Declare the plugins as the build dependencies in `eventmesh-starter/build.gradle`. - -```gradle -dependencies { - implementation project(":eventmesh-runtime") - - // Example: Load the RocketMQ plugin - implementation project(":eventmesh-connector-plugin:eventmesh-connector-rocketmq") -} -``` - -- Plugin directory: EventMesh loads the plugins in the `dist/plugin` directory based on `eventmesh.properties`. The `installPlugin` task of Gradle builds and moves the plugins into the `dist/plugin` directory. - -```console -gradle installPlugin -``` - - -## 2 Remote deployment -### 2.1 Dependencies - -``` -64-bit OS,we recommend Linux/Unix; -64-bit JDK 1.8+; -Gradle 7.0+, we recommend 7.0.* -4g+ available disk to deploy eventmesh-store -If you choose standalone mode, you could skip this file and go to the next step: Start Eventmesh-Runtime; if not, you could choose RocketMQ as the store layer. -``` - -### 2.2 Download -Download and extract the executable binaries of the latest release from [EventMesh download](https://eventmesh.apache.org/download). - -```console -wget https://github.com/apache/incubator-eventmesh/releases/download/v1.4.0/apache-eventmesh-1.4.0-incubating-bin.tar.gz - -tar -xvzf apache-eventmesh-1.5.0-incubating-bin.tar.gz -``` - -### 2.3 Deploy -Edit the `eventmesh.properties` to change the configuration (e.g. TCP port, client blacklist) of EventMesh Runtime. The executable binaries contain all plugins in the bundle, thus there's no need to build them from source code. - -```console -cd apache-eventmesh-1.5.0-incubating -vim conf/eventmesh.properties -``` - -Execute the `start.sh` script to start the EventMesh Runtime server. - -```console -bash bin/start.sh -``` - diff --git a/docs/en/instruction/03-demo.md b/docs/en/instruction/03-demo.md deleted file mode 100644 index 8545e05fb7..0000000000 --- a/docs/en/instruction/03-demo.md +++ /dev/null @@ -1,152 +0,0 @@ -# Run our demos - -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java) - -> EventMesh-sdk-java as the client,and comminucate with eventmesh-runtime,to finish the message sub and pub -> -> EventMesh-sdk-java support both async and broadcast. -> -> EventMesh-sdk-java support HTT, TCP and gRPC. - -The test demos of TCP, HTTP 和 GRPC are in the module **eventmesh-examples** - -## 1 TCP DEMO - -### 1.1 ASYNC - -- Start consumer to subscribe the topic (we have created the TEST-TOPIC-TCP-ASYNC by default, you can also create other topic to test) - -``` -Run the main method of org.apache.eventmesh.tcp.demo.sub.eventmeshmessage.AsyncSubscribe -``` - -- Start producer to publish async message - -``` -Run the main method of org.apache.eventmesh.tcp.demo.pub.eventmeshmessage.AsyncPublish -``` - -### 1.2 BROADCAST - -- Start subscriber to subscribe the topic (we have created the TEST-TOPIC-TCP-BROADCAST by default, you can also create other topic to test) - -``` -Run the main method of org.apache.eventmesh.tcp.demo.sub.eventmeshmessage.AsyncSubscribeBroadcast -``` - -- Start publisher to publish async message - -``` -Run the main method of org.apache.eventmesh.tcp.demo.pub.eventmeshmessage.AsyncPublishBroadcast -``` - -More information about EventMesh-TCP, please refer to [EventMesh TCP](docs/zh/sdk-java/03-tcp.md) - - -## 2 HTTP DEMO - - -### 2.1 ASYNC - -- The subscriber is a SpringBoot demo, so run this demo to start subscriber (we have created the topic TEST-TOPIC-HTTP-ASYNCT by default, you can also create other topic to test) - -``` -Run the main method of org.apache.eventmesh.http.demo.sub.SpringBootDemoApplication -``` - -- Start publisher to publish message - -``` -Run the main method of org.apache.eventmesh.http.demo.pub.eventmeshmessage.AsyncPublishInstance -``` -More information about EventMesh-HTTP, please refer to [EventMesh HTTP](docs/zh/sdk-java/02-http.md) - -## 3 GRPC DEMO - -### 3.1 ASYNC PUBLISH & WEBHOOK SUBSCRIBE - -- Start publisher to publish message (we have created the topic TEST-TOPIC-GRPC-ASYNC by default, you can also create other topic to test) - -``` -Run the main method of org.apache.eventmesh.grpc.pub.eventmeshmessage.AsyncPublishInstance -``` - -- Start webhook subscriber - -``` -Run the main method of org.apache.eventmesh.grpc.sub.app.SpringBootDemoApplication -``` - -### 3.2 SYNC PUBLISH & STREAM SUBSCRIBE - -- Start Request-Reply publisher to publish message (we have created the topic TEST-TOPIC-GRPC-RR by default, you can also create other topic to test) - -``` -Run the main method of org.apache.eventmesh.grpc.pub.eventmeshmessage.RequestReplyInstance -``` - -- Start stream subscriber - -``` -Run the main method of org.apache.eventmesh.grpc.sub.EventmeshAsyncSubscribe -``` - -### 3.3 PUBLISH BATCH MESSAGE - -- Start publisher to publish batch message (we have created the TEST-TOPIC-GRPC-ASYNC by default, you can also create other topic to test) - -``` -Run the main method of org.apache.eventmesh.grpc.pub.eventmeshmessage.BatchPublishInstance -``` - -More information about EventMesh-gRPC, please refer to [EventMesh gRPC](docs/zh/sdk-java/04-grpc.md) - -## 4 Run these demos by yourself - -Please refer to [EventMesh Store](docs/zh/instruction/01-store.md) and [EventMesh Runtime](docs/zh/instruction/02-runtime.md) to finish the necessary deployment before try our demo - -After finishing the deployment of store and runtime, you can run our demos in module `eventmesh-examples`: - -### TCP Sub - - ```shell - cd bin - sh tcp_eventmeshmessage_sub.sh - ``` - -### TCP Pub - - ```shell - cd bin - sh tcp_pub_eventmeshmessage.sh - ``` - -### TCP Sub Broadcast - - ```shell - cd bin - sh tcp_sub_eventmeshmessage_broadcast.sh - ``` - -### TCP Pub Broadcast - - ```shell - cd bin - sh tcp_pub_eventmeshmessage_broadcast.sh - ``` - -### HTTP Sub - - ```shell - cd bin - sh http_sub.sh - ``` - -### HTTP Pub - - ```shell - cd bin - sh http_pub_eventmeshmessage.sh - ``` - -You can review the log in the folder `/logs` diff --git a/docs/en/instruction/_category_.json b/docs/en/instruction/_category_.json deleted file mode 100644 index 690c6eb204..0000000000 --- a/docs/en/instruction/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 2, - "label": "Installation and Deployment", - "collapsed": false -} diff --git a/docs/en/introduction.md b/docs/en/introduction.md deleted file mode 100644 index 991f81e10e..0000000000 --- a/docs/en/introduction.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -sidebar_position: 0 ---- - -# Introduction to EventMesh - -[![CI status](https://img.shields.io/github/workflow/status/apache/incubator-eventmesh/Continuous%20Integration?logo=github&style=for-the-badge)](https://github.com/apache/incubator-eventmesh/actions/workflows/ci.yml) -[![CodeCov](https://img.shields.io/codecov/c/gh/apache/incubator-eventmesh/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/apache/incubator-eventmesh) -[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/incubator-eventmesh/context:java) -[![Total Alerts](https://img.shields.io/lgtm/alerts/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18&style=for-the-badge)](https://lgtm.com/projects/g/apache/incubator-eventmesh/alerts/) -[![License](https://img.shields.io/github/license/apache/incubator-eventmesh?style=for-the-badge)](https://www.apache.org/licenses/LICENSE-2.0.html) -[![GitHub Release](https://img.shields.io/github/v/release/apache/eventmesh?style=for-the-badge)](https://github.com/apache/incubator-eventmesh/releases) -[![Slack Status](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack&style=for-the-badge)](https://join.slack.com/t/apacheeventmesh/shared_invite/zt-16y1n77va-q~JepYy3RqpkygDYmQaQbw) - -**Apache EventMesh (Incubating)** is a dynamic event-driven application runtime used to decouple the application and backend middleware layer, which supports a wide range of use cases that encompass complex multi-cloud, widely distributed topologies using diverse technology stacks. - -## Features - -- **Communication Protocol**: EventMesh could communicate with clients with TCP, HTTP, or gRPC. -- **CloudEvents**: EventMesh supports the [CloudEvents](https://cloudevents.io) specification as the format of the events. CloudEvents is a specification for describing event data in common formats to provide interoperability across services, platforms, and systems. -- **Schema Registry**: EventMesh implements a schema registry that receives and stores schemas from clients and provides an interface for other clients to retrieve schemas. -- **Observability**: EventMesh exposed a range of metrics, such as the average latency of the HTTP protocol and the number of delivered messages. The metrics could be collected and analyzed with Prometheus or OpenTelemetry. -- **Event Workflow Orchestration**: EventMesh Workflow could receive an event and decide which command to trigger next based on the workflow definitions and the current workflow state. The workflow definition could be written with the [Serverless Workflow](https://serverlessworkflow.io) DSL. - -## Components - -Apache EventMesh (Incubating) consists of multiple components that integrate different middlewares and messaging protocols to enhance the functionalities of the application runtime. - -- **eventmesh-runtime**: The middleware that transmits events between producers and consumers, which supports cloud-native apps and microservices. -- **eventmesh-sdk-java**: The Java SDK that supports HTTP, TCP, and [gRPC](https://grpc.io) protocols. -- **eventmesh-connector-plugin**: The collection of plugins that connects middlewares such as [Apache Kafka](https://kafka.apache.org), [Apache RocketMQ](https://rocketmq.apache.org), [Apache Pulsar](https://pulsar.apache.org/), and [Redis](https://redis.io). -- **eventmesh-registry-plugin**: The collection of plugins that integrate service registries such as [Nacos](https://nacos.io) and [etcd](https://etcd.io). -- **eventmesh-security-plugin**: The collection of plugins that implement security mechanisms, such as ACL (access control list), authentication, and authorization. -- **eventmesh-protocol-plugin**: The collection of plugins that implement messaging protocols, such as [CloudEvents](https://cloudevents.io) and [MQTT](https://mqtt.org). -- **eventmesh-admin**: The control plane that manages clients, topics, and subscriptions. - -## Contributors - -Each contributor has played an important role in promoting the robust development of Apache EventMesh (Incubating). We sincerely appreciate all contributors who have contributed code and documents. The following is the list of contributors in EventMesh-related repositories. - -- [apache/incubator-eventmesh](https://github.com/apache/incubator-eventmesh/graphs/contributors) -- [apache/incubator-eventmesh-site](https://github.com/apache/incubator-eventmesh-site/graphs/contributors) diff --git a/docs/en/metrics-tracing/01-prometheus.md b/docs/en/metrics-tracing/01-prometheus.md deleted file mode 100644 index 1bc6e0e554..0000000000 --- a/docs/en/metrics-tracing/01-prometheus.md +++ /dev/null @@ -1,24 +0,0 @@ -# Observe Metrics with Prometheus - -## Prometheus - -[Prometheus](https://prometheus.io/docs/introduction/overview/) is an open-source system monitoring and alerting toolkit that collects and stores the metrics as time-series data. EventMesh exposes a collection of metrics data that could be scraped and analyzed by Prometheus. Please follow [the "First steps with Prometheus" tutorial](https://prometheus.io/docs/introduction/first_steps/) to download and install the latest release of Prometheus. - -## Edit Prometheus Configuration - -The `eventmesh-runtime/conf/prometheus.yml` configuration file specifies the port of the metrics HTTP endpoint. The default metrics port is `19090`. - -```properties -eventMesh.metrics.prometheus.port=19090 -``` - -Please refer to [the Prometheus configuration guide](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config) to add the EventMesh metrics as a scrape target in the configuration file. Here's the minimum configuration that creates a job with the name `eventmesh` and the endpoint `http://localhost:19090`: - -```yaml -scrape_configs: - - job_name: "eventmesh" - static_configs: - - targets: ["localhost:19090"] -``` - -Please navigate to the Prometheus dashboard (e.g. `http://localhost:9090`) to view the list of metrics exported by EventMesh, which are prefixed with `eventmesh_`. diff --git a/docs/en/metrics-tracing/02-zipkin.md b/docs/en/metrics-tracing/02-zipkin.md deleted file mode 100644 index f4d07252d7..0000000000 --- a/docs/en/metrics-tracing/02-zipkin.md +++ /dev/null @@ -1,38 +0,0 @@ -# Collect Trace with Zipkin - -## Zipkin - -Distributed tracing is a method used to profile and monitor applications built with microservices architecture. Distributed tracing helps pinpoint where failures occur and what causes poor performance. - -[Zipkin](https://zipkin.io) is a distributed tracing system that helps collect timing data needed to troubleshoot latency problems in service architectures. EventMesh exposes a collection of trace data that could be collected and analyzed by Zipkin. Please follow [the "Zipkin Quickstart" tutorial](https://zipkin.io/pages/quickstart.html) to download and install the latest release of Zipkin. - -## Configuration - -To enable the trace exporter of EventMesh Runtime, set the `eventMesh.server.trace.enabled` field in the `conf/eventmesh.properties` file to `true`. - -```conf -# Trace plugin -eventMesh.server.trace.enabled=true -eventMesh.trace.plugin=zipkin -``` - -To customize the behavior of the trace exporter such as timeout or export interval, edit the `exporter.properties` file. - -```conf -# Set the maximum batch size to use -eventmesh.trace.max.export.size=512 -# Set the queue size. This must be >= the export batch size -eventmesh.trace.max.queue.size=2048 -# Set the max amount of time an export can run before getting(TimeUnit=SECONDS) -eventmesh.trace.export.timeout=30 -# Set time between two different exports (TimeUnit=SECONDS) -eventmesh.trace.export.interval=5 -``` - -To send the exported trace data to Zipkin, edit the `eventmesh.trace.zipkin.ip` and `eventmesh.trace.zipkin.port` fields in the `conf/zipkin.properties` file to match the configuration of the Zipkin server. - -```conf -# Zipkin's IP and Port -eventmesh.trace.zipkin.ip=localhost -eventmesh.trace.zipkin.port=9411 -``` diff --git a/docs/en/metrics-tracing/_category_.json b/docs/en/metrics-tracing/_category_.json deleted file mode 100644 index 72c4414d12..0000000000 --- a/docs/en/metrics-tracing/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 4, - "label": "Metrics and Tracing", - "collapsed": false -} diff --git a/docs/en/roadmap.md b/docs/en/roadmap.md deleted file mode 100644 index f3c58aa348..0000000000 --- a/docs/en/roadmap.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Development Roadmap - -The development roadmap of Apache EventMesh (Incubating) is an overview of the planned features and milestones involved in the next several releases. The recent features and bug fixes are documented in the [release notes](https://eventmesh.apache.org/events/release-notes/v1.4.0). The order of the features listed below doesn't correspond to their priorities. - -## List of Features and Milestones - -| Status | Description | Reference | -|-------------------------------------------|---------------------------------| --- | -| **Implemented in 1.0.0** | Support HTTP | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.0.0** | Support TCP | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.0.0** | Support Pub/Sub Event | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.1.1** | Provide Java SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.1.1** | Support HTTPS | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.2.0** | Support RocketMQ as EventStore | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.2.0** | Support Heartbeat | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.3.0** | Integrate with OpenSchema | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.3.0** | Integrate with OpenTelemetry | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.3.0** | Support CloudEvents | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.4.0** | Support gRPC | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Provide Golang SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Support Nacos Registry | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Support Mesh Bridge | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Support Federal Government | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.6.0 (to be released)** | Integrate with Consul | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.6.0 (to be released)** | Support Webhook | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.6.0 (to be released)** | Support etcd | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Knative Eventing Infrastructure | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/790), [GSoC '22](https://issues.apache.org/jira/browse/COMDEV-463) | -| **In Progress** | Dashboard | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/700), [GSoC '22](https://issues.apache.org/jira/browse/COMDEV-465) | -| **In Progress** | Support Kafka as EventStore | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/676) | -| **In Progress** | Support Pulsar as EventStore | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/676) | -| **In Progress** | Support Dledger | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Workflow | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Support Redis | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Support Mesh Bridge | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Support Zookeeper | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| Planned | Provide NodeJS SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| Planned | Transaction Event | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/697) | -| Planned | Event Query Language (EQL) | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/778) | -| Planned | Metadata consistency persistent | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/817) | -| Planned | Rust SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/815) | -| Planned | WebAssembly Runtime | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/576) | -| Planned | Filter Chain | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/664) | - diff --git a/docs/en/sdk-java/02-http.md b/docs/en/sdk-java/02-http.md deleted file mode 100644 index bf2e5c6efa..0000000000 --- a/docs/en/sdk-java/02-http.md +++ /dev/null @@ -1,115 +0,0 @@ -# HTTP Protocol - -EventMesh SDK for Java implements the HTTP producer and consumer of asynchronous messages. Both the producer and consumer require an instance of `EventMeshHttpClientConfig` class that specifies the configuration of EventMesh HTTP client. The `liteEventMeshAddr`, `userName`, and `password` fields should match the `eventmesh.properties` file of EventMesh runtime. - -```java -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -public class HTTP { - public static void main(String[] args) throws Exception { - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr("localhost:10105") - .producerGroup("TEST_PRODUCER_GROUP") - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())) - .userName("eventmesh") - .password("password") - .build(); - /* ... */ - } -} -``` - -## HTTP Consumer - -The `EventMeshHttpConsumer` class implements the `heartbeat`, `subscribe`, and `unsubscribe` methods. The `subscribe` method accepts a list of `SubscriptionItem` that defines the topics to be subscribed and a callback URL. - -```java -import org.apache.eventmesh.client.http.consumer.EventMeshHttpConsumer; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import com.google.common.collect.Lists; - -public class HTTP { - final String url = "http://localhost:8080/callback"; - final List topicList = Lists.newArrayList( - new SubscriptionItem("eventmesh-async-topic", SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC) - ); - - public static void main(String[] args) throws Exception { - /* ... */ - eventMeshHttpConsumer = new EventMeshHttpConsumer(eventMeshClientConfig); - eventMeshHttpConsumer.heartBeat(topicList, url); - eventMeshHttpConsumer.subscribe(topicList, url); - /* ... */ - eventMeshHttpConsumer.unsubscribe(topicList, url); - } -} -``` - -The EventMesh runtime will send a POST request that contains the message in the [CloudEvents format](https://github.com/cloudevents/spec) to the callback URL. The [`SubController.java` file](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/controller/SubController.java) implements a Spring Boot controller that receives and parses the callback messages. - -## HTTP Producer - -The `EventMeshHttpProducer` class implements the `publish` method. The `publish` method accepts the message to be published and an optional timeout value. The message should be an instance of either of these classes: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` -- `io.openmessaging.api.Message` - -```java -import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.utils.JsonUtils; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class HTTP { - public static void main(String[] args) throws Exception { - /* ... */ - EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); - Map content = new HashMap<>(); - content.put("content", "testAsyncMessage"); - - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject("eventmesh-async-topic") - .withSource(URI.create("/")) - .withDataContentType("application/cloudevents+json") - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - eventMeshHttpProducer.publish(event); - } -} -``` - -## Using Curl Command - -You can also publish/subscribe event without eventmesh SDK. - -### Publish - -```shell -curl -H "Content-Type:application/json" -X POST -d '{"name": "admin", "pass":"12345678"}' http://127.0.0.1:10105/eventmesh/publish/TEST-TOPIC-HTTP-ASYNC -``` - -After you start the eventmesh runtime server, you can use the curl command publish the event to the specific topic with the HTTP POST method and the package body must be in JSON format. The publish url like (http://127.0.0.1:10105/eventmesh/publish/TEST-TOPIC-HTTP-ASYNC), and you will get the publish successful result. - -### Subscribe - -```shell -curl -H "Content-Type:application/json" -X POST -d '{"url": "http://127.0.0.1:8088/sub/test", "consumerGroup":"TEST-GROUP", "topic":[{"mode":"CLUSTERING","topic":"TEST-TOPIC-HTTP-ASYNC","type":"ASYNC"}]}' http://127.0.0.1:10105/eventmesh/subscribe/local -``` - -After you start the eventmesh runtime server, you can use the curl command to subscribe the specific topic list with the HTTP POST method, and the package body must be in JSON format. The subscribe url like (http://127.0.0.1:10105/eventmesh/subscribe/local), and you will get the subscribe successful result. You should pay attention to the `url` field in the package body, which means you need to set up an HTTP service at the specified URL, you can see the example in the `eventmesh-examples` module. - diff --git a/docs/en/sdk-java/03-tcp.md b/docs/en/sdk-java/03-tcp.md deleted file mode 100644 index 1643a41dca..0000000000 --- a/docs/en/sdk-java/03-tcp.md +++ /dev/null @@ -1,118 +0,0 @@ -# TCP Protocol - -EventMesh SDK for Java implements the TCP producer and consumer of synchronous, asynchronous, and broadcast messages. Both the producer and consumer require an instance of `EventMeshTCPClientConfig` class that specifies the configuration of EventMesh TCP client. The `host` and `port` fields should match the `eventmesh.properties` file of EventMesh runtime. - -```java -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import io.cloudevents.CloudEvent; - -public class AsyncSubscribe implements ReceiveMsgHook { - public static void main(String[] args) throws InterruptedException { - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - /* ... */ - } -} -``` - -## TCP Consumer - -The consumer should implement the `ReceiveMsgHook` class, which is defined in [`ReceiveMsgHook.java`](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java). - -```java -public interface ReceiveMsgHook { - Optional handle(ProtocolMessage msg); -} -``` - -The `EventMeshTCPClient` class implements the `subscribe` method. The `subscribe` method accepts the topic, the `SubscriptionMode`, and the `SubscriptionType`. The `handle` method will be invoked when the consumer receives a message from the topic it subscribes. If the `SubscriptionType` is `SYNC`, the return value of `handle` will be sent back to the producer. - -```java -import org.apache.eventmesh.client.tcp.EventMeshTCPClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import io.cloudevents.CloudEvent; - -public class TCPConsumer implements ReceiveMsgHook { - public static TCPConsumer handler = new TCPConsumer(); - private static EventMeshTCPClient client; - - public static void main(String[] args) throws Exception { - client = EventMeshTCPClientFactory.createEventMeshTCPClient( - eventMeshTcpClientConfig, - CloudEvent.class - ); - client.init(); - - client.subscribe( - "eventmesh-sync-topic", - SubscriptionMode.CLUSTERING, - SubscriptionType.SYNC - ); - - client.registerSubBusiHandler(handler); - client.listen(); - } - - @Override - public Optional handle(CloudEvent message) { - log.info("Messaged received: {}", message); - return Optional.of(message); - } -} -``` - -## TCP Producer - -### Asynchronous Producer - -The `EventMeshTCPClient` class implements the `publish` method. The `publish` method accepts the message to be published and an optional timeout value and returns the response message from the consumer. - -```java -/* ... */ -client = EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); -client.init(); - -CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); -client.publish(event, 1000); -``` - -### Synchronous Producer - -The `EventMeshTCPClient` class implements the `rr` method. The `rr` method accepts the message to be published and an optional timeout value and returns the response message from the consumer. - -```java -/* ... */ -client = EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); -client.init(); - -CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - -Package response = client.rr(event, 1000); -CloudEvent replyEvent = EventFormatProvider - .getInstance() - .resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(response.getBody().toString().getBytes(StandardCharsets.UTF_8)); -``` diff --git a/docs/en/sdk-java/04-grpc.md b/docs/en/sdk-java/04-grpc.md deleted file mode 100644 index 81f03a8d83..0000000000 --- a/docs/en/sdk-java/04-grpc.md +++ /dev/null @@ -1,174 +0,0 @@ -# gRPC Protocol - -EventMesh SDK for Java implements the gRPC producer and consumer of synchronous, asynchronous, and broadcast messages. Both the producer and consumer require an instance of `EventMeshGrpcClientConfig` class that specifies the configuration of EventMesh gRPC client. The `liteEventMeshAddr`, `userName`, and `password` fields should match the `eventmesh.properties` file of EventMesh runtime. - -```java -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import io.cloudevents.CloudEvent; - -public class CloudEventsAsyncSubscribe implements ReceiveMsgHook { - public static void main(String[] args) throws InterruptedException { - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr("localhost") - .serverPort(10205) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - /* ... */ - } -} -``` - -## gRPC Consumer - -### Stream Consumer - -The EventMesh runtime sends the message from producers to the stream consumer as a series of event streams. The consumer should implement the `ReceiveMsgHook` class, which is defined in [`ReceiveMsgHook.java`](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java). - -```java -public interface ReceiveMsgHook { - Optional handle(T msg) throws Throwable; - String getProtocolType(); -} -``` - -The `EventMeshGrpcConsumer` class implements the `registerListener`, `subscribe`, and `unsubscribe` methods. The `subscribe` method accepts a list of `SubscriptionItem` that defines the topics to be subscribed to. The `registerListener` accepts an instance of a class that implements the `ReceiveMsgHook`. The `handle` method will be invoked when the consumer receives a message from the topic it subscribes. If the `SubscriptionType` is `SYNC`, the return value of `handle` will be sent back to the producer. - -```java -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import io.cloudevents.CloudEvent; - -public class CloudEventsAsyncSubscribe implements ReceiveMsgHook { - public static CloudEventsAsyncSubscribe handler = new CloudEventsAsyncSubscribe(); - public static void main(String[] args) throws InterruptedException { - /* ... */ - SubscriptionItem subscriptionItem = new SubscriptionItem( - "eventmesh-async-topic", - SubscriptionMode.CLUSTERING, - SubscriptionType.ASYNC - ); - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - - eventMeshGrpcConsumer.init(); - eventMeshGrpcConsumer.registerListener(handler); - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - /* ... */ - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); - } - - @Override - public Optional handle(CloudEvent message) { - log.info("Messaged received: {}", message); - return Optional.empty(); - } - - @Override - public String getProtocolType() { - return EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME; - } -} -``` - -### Webhook Consumer - -The `subscribe` method of the `EventMeshGrpcConsumer` class accepts a list of `SubscriptionItem` that defines the topics to be subscribed and an optional callback URL. If the callback URL is provided, the EventMesh runtime will send a POST request that contains the message in the [CloudEvents format](https://github.com/cloudevents/spec) to the callback URL. The [`SubController.java` file](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/controller/SubController.java) implements a Spring Boot controller that receives and parses the callback messages. - -```java -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; - -@Component -public class SubService implements InitializingBean { - final String url = "http://localhost:8080/callback"; - - public void afterPropertiesSet() throws Exception { - /* ... */ - eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - eventMeshGrpcConsumer.init(); - - SubscriptionItem subscriptionItem = new SubscriptionItem( - "eventmesh-async-topic", - SubscriptionMode.CLUSTERING, - SubscriptionType.ASYNC - ); - - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem), url); - /* ... */ - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem), url); - } -} -``` - -## gRPC Producer - -### Asynchronous Producer - -The `EventMeshGrpcProducer` class implements the `publish` method. The `publish` method accepts the message to be published and an optional timeout value. The message should be an instance of either of these classes: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` - -```java -/* ... */ -EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); -eventMeshGrpcProducer.init(); - -Map content = new HashMap<>(); -content.put("content", "testAsyncMessage"); - -CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); -eventMeshGrpcProducer.publish(event); -``` - -### Synchronous Producer - -The `EventMeshGrpcProducer` class implements the `requestReply` method. The `requestReply` method accepts the message to be published and an optional timeout value. The method returns the message returned from the consumer. The message should be an instance of either of these classes: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` - -### Batch Producer - -The `EventMeshGrpcProducer` class overloads the `publish` method, which accepts a list of messages to be published and an optional timeout value. The messages in the list should be an instance of either of these classes: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` - -```java -/* ... */ -List cloudEventList = new ArrayList<>(); -for (int i = 0; i < 5; i++) { - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - - cloudEventList.add(event); -} - -eventMeshGrpcProducer.publish(cloudEventList); -/* ... */ -``` diff --git a/docs/en/sdk-java/_category_.json b/docs/en/sdk-java/_category_.json deleted file mode 100644 index e93d4cdd8a..0000000000 --- a/docs/en/sdk-java/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 3, - "label": "EventMesh SDK for Java", - "collapsed": false -} diff --git a/docs/en/sdk-java/intro.md b/docs/en/sdk-java/intro.md deleted file mode 100644 index 42b9c41942..0000000000 --- a/docs/en/sdk-java/intro.md +++ /dev/null @@ -1,29 +0,0 @@ -# Installation - -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java/badge.svg?style=for-the-badge)](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java) - -EventMesh SDK for Java is a collection of Java libraries to integrate EventMesh in a Java application. The SDK supports sending and receiving synchronous messages, asynchronous messages, and broadcast messages in TCP, HTTP, and gRPC protocols. The SDK implements EventMesh Message, CloudEvents, and OpenMessaging formats. The demo project is available in the [`eventmesh-example`](https://github.com/apache/incubator-eventmesh/tree/master/eventmesh-examples) module. - -## Gradle - -To install EventMesh SDK for Java with Gradle, declare `org.apache.eventmesh:eventmesh-sdk-java` as `implementation` in the dependencies block of the module's `build.gradle` file. - -```groovy -dependencies { - implementation 'org.apache.eventmesh:eventmesh-sdk-java:1.4.0' -} -``` - -## Maven - -To install EventMesh SDK for Java with Maven, declare `org.apache.eventmesh:eventmesh-sdk-java` as a dependency in the dependencies block of the project's `pom.xml` file. - -```xml - - - org.apache.eventmesh - eventmesh-sdk-java - 1.4.0 - - -``` diff --git a/docs/images/design-document/async-message.png b/docs/images/design-document/async-message.png deleted file mode 100644 index 4ad6ac4e03..0000000000 Binary files a/docs/images/design-document/async-message.png and /dev/null differ diff --git a/docs/images/design-document/broadcast-message.png b/docs/images/design-document/broadcast-message.png deleted file mode 100644 index 7c3be10c30..0000000000 Binary files a/docs/images/design-document/broadcast-message.png and /dev/null differ diff --git a/docs/images/design-document/cloudevents-pluggable-protocols.png b/docs/images/design-document/cloudevents-pluggable-protocols.png deleted file mode 100644 index 5b8b858f10..0000000000 Binary files a/docs/images/design-document/cloudevents-pluggable-protocols.png and /dev/null differ diff --git a/docs/images/design-document/schema-registry-architecture.png b/docs/images/design-document/schema-registry-architecture.png deleted file mode 100644 index 8de3fc3e05..0000000000 Binary files a/docs/images/design-document/schema-registry-architecture.png and /dev/null differ diff --git a/docs/images/design-document/schema-registry-process.jpg b/docs/images/design-document/schema-registry-process.jpg deleted file mode 100644 index f914a81f0d..0000000000 Binary files a/docs/images/design-document/schema-registry-process.jpg and /dev/null differ diff --git a/docs/images/design-document/schema-registry-project-structure.png b/docs/images/design-document/schema-registry-project-structure.png deleted file mode 100644 index c12ac2b3e4..0000000000 Binary files a/docs/images/design-document/schema-registry-project-structure.png and /dev/null differ diff --git a/docs/images/design-document/stream-architecture.png b/docs/images/design-document/stream-architecture.png deleted file mode 100644 index 50d2ff9100..0000000000 Binary files a/docs/images/design-document/stream-architecture.png and /dev/null differ diff --git a/docs/images/design-document/stream-component-interface.png b/docs/images/design-document/stream-component-interface.png deleted file mode 100644 index f8865f7d59..0000000000 Binary files a/docs/images/design-document/stream-component-interface.png and /dev/null differ diff --git a/docs/images/design-document/stream-component-routes.png b/docs/images/design-document/stream-component-routes.png deleted file mode 100644 index 98c8eb7509..0000000000 Binary files a/docs/images/design-document/stream-component-routes.png and /dev/null differ diff --git a/docs/images/design-document/stream-event-driven-consumer.png b/docs/images/design-document/stream-event-driven-consumer.png deleted file mode 100644 index 4be17f4746..0000000000 Binary files a/docs/images/design-document/stream-event-driven-consumer.png and /dev/null differ diff --git a/docs/images/design-document/stream-sync-producer.png b/docs/images/design-document/stream-sync-producer.png deleted file mode 100644 index bb8771cfe5..0000000000 Binary files a/docs/images/design-document/stream-sync-producer.png and /dev/null differ diff --git a/docs/images/design-document/sync-message.png b/docs/images/design-document/sync-message.png deleted file mode 100644 index b1c462fa51..0000000000 Binary files a/docs/images/design-document/sync-message.png and /dev/null differ diff --git a/docs/images/design-document/tcp-protocol.png b/docs/images/design-document/tcp-protocol.png deleted file mode 100644 index d3c1249d53..0000000000 Binary files a/docs/images/design-document/tcp-protocol.png and /dev/null differ diff --git a/docs/images/design-document/webhook/webhook-github-add.png b/docs/images/design-document/webhook/webhook-github-add.png deleted file mode 100644 index 55e19cb614..0000000000 Binary files a/docs/images/design-document/webhook/webhook-github-add.png and /dev/null differ diff --git a/docs/images/design-document/webhook/webhook-github-info.png b/docs/images/design-document/webhook/webhook-github-info.png deleted file mode 100644 index 978b64eb90..0000000000 Binary files a/docs/images/design-document/webhook/webhook-github-info.png and /dev/null differ diff --git a/docs/images/design-document/webhook/webhook-github-setting.png b/docs/images/design-document/webhook/webhook-github-setting.png deleted file mode 100644 index fa151313ce..0000000000 Binary files a/docs/images/design-document/webhook/webhook-github-setting.png and /dev/null differ diff --git a/docs/images/design-document/webhook/webhook-github-webhooks.png b/docs/images/design-document/webhook/webhook-github-webhooks.png deleted file mode 100644 index 978b64eb90..0000000000 Binary files a/docs/images/design-document/webhook/webhook-github-webhooks.png and /dev/null differ diff --git a/docs/images/design-document/workflow-architecture.jpg b/docs/images/design-document/workflow-architecture.jpg deleted file mode 100644 index 1bbb691c07..0000000000 Binary files a/docs/images/design-document/workflow-architecture.jpg and /dev/null differ diff --git a/docs/images/design-document/workflow-diagram.png b/docs/images/design-document/workflow-diagram.png deleted file mode 100644 index 0c2c825dcc..0000000000 Binary files a/docs/images/design-document/workflow-diagram.png and /dev/null differ diff --git a/docs/images/design-document/workflow-use-case.jpg b/docs/images/design-document/workflow-use-case.jpg deleted file mode 100644 index 124e7ec233..0000000000 Binary files a/docs/images/design-document/workflow-use-case.jpg and /dev/null differ diff --git a/docs/images/eventmesh-architecture.png b/docs/images/eventmesh-architecture.png deleted file mode 100644 index 5405afc593..0000000000 Binary files a/docs/images/eventmesh-architecture.png and /dev/null differ diff --git a/docs/images/eventmesh-bridge.png b/docs/images/eventmesh-bridge.png deleted file mode 100644 index b8d1220f20..0000000000 Binary files a/docs/images/eventmesh-bridge.png and /dev/null differ diff --git a/docs/images/eventmesh-orchestration.png b/docs/images/eventmesh-orchestration.png deleted file mode 100644 index 40b28208a5..0000000000 Binary files a/docs/images/eventmesh-orchestration.png and /dev/null differ diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico deleted file mode 100644 index b6b6c2c6ef..0000000000 Binary files a/docs/images/favicon.ico and /dev/null differ diff --git a/docs/images/incubator-logo.png b/docs/images/incubator-logo.png deleted file mode 100644 index 759252f001..0000000000 Binary files a/docs/images/incubator-logo.png and /dev/null differ diff --git a/docs/plugins/core-engines-configuration.md b/docs/plugins/core-engines-configuration.md new file mode 100644 index 0000000000..758efd9de9 --- /dev/null +++ b/docs/plugins/core-engines-configuration.md @@ -0,0 +1,135 @@ +# EventMesh Core Engines Configuration Guide + +EventMesh provides powerful core engines (`Filter`, `Transformer`, `Router`) to dynamically process messages. These engines are configured via **MetaStorage** (Governance Center, e.g., Nacos, Etcd), supporting on-demand loading and hot-reloading. + +## 0. Core Concepts + +Before configuration, it is important to understand the specific role of each engine in the message flow: + +* **Filter (The Gatekeeper)**: Decides **"Whether to pass"**. + * It inspects the message (CloudEvent) attributes. If the message matches the rules, it passes; otherwise, it is dropped. + * *Use Case*: Block debug logs from production traffic; Only subscribe to specific event types. + +* **Transformer (The Translator)**: Decides **"What it looks like"**. + * It modifies the message content (Payload or Metadata) according to templates or scripts. + * *Use Case*: Convert XML to JSON; Mask sensitive data (PII); Adapt legacy protocols to new standards. + +* **Router (The Dispatcher)**: Decides **"Where to go"**. + * It dynamically changes the destination (Topic) of the message. + * *Use Case*: Route traffic to a Canary/Gray release topic; Route high-priority orders to a dedicated queue. + +--- + +## 1. Overview + +The configuration is not in local property files but distributed via the MetaStorage. EventMesh listens to specific **Keys** based on client Groups. + +- **Data Source**: Configured via `eventMesh.metaStorage.plugin.type`. +- **Loading Mechanism**: Lazy loading & Hot-reloading. +- **Key Format**: `{EnginePrefix}-{GroupName}`. +- **Value Format**: JSON Array. + +| Engine | Prefix | Scope | Description | +| :--- | :--- | :--- | :--- | +| **Router** | `router-` | Pub Only | Routes messages to different topics. | +| **Filter** | `filter-` | Pub & Sub | Filters messages based on CloudEvent attributes. | +| **Transformer** | `transformer-` | Pub & Sub | Transforms message content (Payload/Header). | + +--- + +## 2. Router (Routing) + +**Scope**: Publish Only (Upstream) +**Key**: `router-{producerGroup}` + +Decides the target storage topic for a message sent by a producer. + +### Configuration Example (JSON) + +```json +[ + { + "topic": "original-topic", + "routerConfig": { + "targetTopic": "redirect-topic", + "expression": "data.type == 'urgent'" + } + } +] +``` + +* **topic**: The original topic the producer sends to. +* **targetTopic**: The actual topic to write to Storage. +* **expression**: Condition to trigger routing (e.g., SpEL). + +--- + +## 3. Filter (Filtering) + +**Scope**: Both Publish (Upstream) & Subscribe (Downstream) + +### A. Publish Side (Upstream) +**Key**: `filter-{producerGroup}` +**Effect**: Intercepts messages **before** they are sent to Storage. + +### B. Subscribe Side (Downstream) +**Key**: `filter-{consumerGroup}` +**Effect**: Intercepts messages **before** they are pushed to the Consumer. + +### Configuration Example (JSON) + +```json +[ + { + "topic": "test-topic", + "filterPattern": { + "source": ["app-a", "app-b"], + "type": [{"prefix": "com.example"}] + } + } +] +``` + +* **filterPattern**: Rules matching CloudEvent attributes. If a message doesn't match, it is dropped. + +--- + +## 4. Transformer (Transformation) + +**Scope**: Both Publish (Upstream) & Subscribe (Downstream) + +### A. Publish Side (Upstream) +**Key**: `transformer-{producerGroup}` +**Effect**: Modifies message content **before** sending to Storage. + +### B. Subscribe Side (Downstream) +**Key**: `transformer-{consumerGroup}` +**Effect**: Modifies message content **before** pushing to the Consumer. + +### Configuration Example (JSON) + +```json +[ + { + "topic": "raw-topic", + "transformerConfig": { + "transformerType": "template", + "template": "{\"id\": \"${id}\", \"new_content\": \"${data.content}\"}" + } + } +] +``` + +* **transformerType**: e.g., `original`, `template`. +* **template**: The transformation template definition. + +--- + +## 5. Verification + +1. **Publish Config**: Add the JSON config to your Governance Center (e.g., Nacos) with the Data ID `router-MyGroup`. +2. **Send Message**: Use EventMesh SDK to send a message from `MyGroup`. +3. **Observe**: + * For **Router**: Check if the message appears in the `targetTopic` in your MQ. + * For **Filter**: Check if blocked messages are skipped. + * For **Transformer**: Check if the message body in MQ (for Pub) or Consumer (for Sub) is modified. diff --git a/docs/zh/contribute/01-release.md b/docs/zh/contribute/01-release.md deleted file mode 100644 index 0810a75772..0000000000 --- a/docs/zh/contribute/01-release.md +++ /dev/null @@ -1,731 +0,0 @@ -# Release Creation Process - -:::caution -The documentation of Release Creation Process is WIP (Work-in-Progress). -::: - -## 理解 Apache 发布的内容和流程 - -Source Release 是 Apache 关注的重点,也是发布的必须内容;而 Binary Release 是可选项, - -请参考以下链接,找到更多关于 ASF 的发布指南: - -- [Apache Release Guide](http://www.apache.org/dev/release-publishing) -- [Apache Release Policy](http://www.apache.org/dev/release.html) -- [Maven Release Info](http://www.apache.org/dev/publishing-maven-artifacts.html) - - -## 本地构建环境准备 - -主要包括签名工具、Maven 仓库认证相关准备 - -### 1.安装GPG - -在[GnuPG官网](https://www.gnupg.org/download/index.html)下载安装包。GnuPG的1.x版本和2.x版本的命令有细微差别,下列说明以**GnuPG-2.x**版本为例 - -```sh -$ gpg --version #检查版本,应该为2.x -``` - -### 2.用gpg生成key - -根据提示,生成 key - -> 注意:请使用Apache邮箱生成GPG的Key - -```shell -$ gpg --full-gen-key -gpg (GnuPG) 2.0.12; Copyright (C) 2009 Free Software Foundation, Inc. -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -Please select what kind of key you want: - (1) RSA and RSA (default) - (2) DSA and Elgamal - (3) DSA (sign only) - (4) RSA (sign only) -Your selection? 1 -RSA keys may be between 1024 and 4096 bits long. -What keysize do you want? (2048) 4096 -Requested keysize is 4096 bits -Please specify how long the key should be valid. - 0 = key does not expire - = key expires in n days - w = key expires in n weeks - m = key expires in n months - y = key expires in n years -Key is valid for? (0) -Key does not expire at all -Is this correct? (y/N) y - -GnuPG needs to construct a user ID to identify your key. - -Real name: ${输入用户名} -Email address: ${邮箱地址} -Comment: CODE SIGNING KEY -You selected this USER-ID: - "${输入用户名} (CODE SIGNING KEY) <${邮箱地址}>" - -Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O -You need a Passphrase to protect your secret key. # 填入密码,以后打包过程中会经常用到 -``` - -### 3.查看 key - -```shell -$ gpg --list-keys -pub rsa4096/579C25F5 2021-04-26 # 579C25F5就是key id -uid [ultimate] ${输入用户名} <${邮箱地址}> -sub rsa4096 2021-04-26 - -# 通过key id发送public key到keyserver -$ gpg --keyserver pgpkeys.mit.edu --send-key 579C25F5 -# 其中,pgpkeys.mit.edu为随意挑选的keyserver,keyserver列表为:https://sks-keyservers.net/status/,相互之间是自动同步的,选任意一个都可以。 -$ gpg --keyserver hkp://pgpkeys.mit.edu --recv-keys 579C25F5 # 验证是否同步到公网,网络不好可能需多试几次 -``` - -**注:如果有多个 public key,设置默认 key。**修改`~/.gnupg/gpg.conf` - -```sh -# If you have more than 1 secret key in your keyring, you may want to -# uncomment the following option and set your preferred keyid. -default-key 28681CB1 -``` - -**如果有多个 public key, 也可以删除无用的 key:** - -```shell -$ gpg --delete-secret-keys 29BBC3CB # 先删除私钥,指明key id -gpg (GnuPG) 2.2.27; Copyright (C) 2021 g10 Code GmbH -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -sec rsa4096/EE8DAE7D29BBC3CB 2021-04-27 mikexue - -Delete this key from the keyring? (y/N) y -This is a secret key! - really delete? (y/N) y -``` - -```shell -$ gpg --delete-keys 29BBC3CB # 删除公钥,指明key id -gpg (GnuPG) 2.2.27; Copyright (C) 2021 g10 Code GmbH -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - - -pub rsa4096/EE8DAE7D29BBC3CB 2021-04-27 mikexue - -Delete this key from the keyring? (y/N) y -``` - -由于公钥服务器没有检查机制,任何人都可以用你的名义上传公钥,所以没有办法保证服务器上的公钥的可靠性。 通常,你可以在网站上公布一个公钥指纹,让其他人核对下载到的公钥是否为真。 - -```shell -# fingerprint参数生成公钥指纹: -$gpg --fingerprint mikexue -pub rsa4096 2021-04-26 [SCA] - F84A 0041 D70B 37AF 9C7B F0B3 39F4 29D7 579C 25F5 -uid [ultimate] mikexue -sub rsa4096 2021-04-26 [E] -``` - -登录 [https://id.apache.org](https://id.apache.org/), 将上面的 fingerprint (即 F84A 0041 D70B 37AF 9C7B F0B3 39F4 29D7 579C 25F5) 粘贴到自己的用户信息中 OpenPGP Public Key Primary Fingerprint - - - -## 发布Apache Maven仓库 - -> 注:EventMesh使用Gradle构建,需修改gradle相关配置 - -### 1.导出私钥文件 - -```shell -$ gpg --export-secret-keys -o secring.gpg #私钥文件妥善保管,后面配置需要 -``` - -### 2.准备分支 - -从主干分支拉取新分支作为发布分支,如现在要发布$`{release_version}`版本,则从develop分支拉出新分支`${release_version}-release`,此后`${release_version}` Release Candidates涉及的修改及打标签等都在`${release_version}-release`分支进行,最终发布完成后合入主干分支。 - -### 3.更新版本说明 - -更新官网项目的如下文件,并提交至master分支: - -https://github.com/apache/incubator-eventmesh-site/tree/master/events/release-notes - -### 4.配置根项目下gradle.properties文件 - -```shell -group=org.apache.eventmesh -version=1.2.0-release -#40位公钥的最后8位 -signing.keyId=579C25F5 -#生成密钥时填的passphrase -signing.password= -#导出的私钥文件secring.gpg路径 -signing.secretKeyRingFile=../secring.gpg -#apache 账号 -apacheUserName= -#apache 密码 -apachePassWord= -``` - -### 5.检查子模块下gradle.properties文件 - -```shell -group=org.apache.eventmesh -version=${release_version} -``` - -### 6.检查并配置根项目下build.gradle文件 - -```shell -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact packageSources - artifact packageJavadoc - versionMapping { - usage('java-api') { - fromResolutionOf('runtimeClasspath') - } - usage('java-runtime') { - fromResolutionResult() - } - } - pom { - name = 'EventMesh' - description = 'Apache EventMesh' - url = 'https://github.com/apache/incubator-eventmesh' - licenses { - license { - name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - developers { - developer { - id = 'Apache EventMesh(incubating)' - name = 'Apache EventMesh(incubating) of ASF' - url = 'https://eventmesh.apache.org/' - } - } - scm { - connection = 'scm:git:git@github.com:apache/incubator-eventmesh.git' - developerConnection = 'scm:git:git@github.com:apache/incubator-eventmesh.git' - url = 'https://github.com/apache/incubator-eventmesh' - } - } - } - } - repositories { - maven { - def releasesRepoUrl = 'https://repository.apache.org/service/local/staging/deploy/maven2/' - def snapshotsRepoUrl = 'https://repository.apache.org/content/repositories/snapshots/' - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - credentials { - username apacheUserName - password apachePassWord - } - - } - } -} - -signing { - sign publishing.publications.mavenJava -} -``` - -### 7.上传发布包 - -执行如下命令,需要对jar、源码包、doc和pom等文件签名加密 - -```shell -$ gradle signMavenJavaPublication publish -``` - -上述命令执行成功后,待发布版本会自动上传到Apache的临时筹备仓库(staging repository)。所有被deploy到远程[maven仓库](http://repository.apache.org/)的Artifacts都会处于staging状态,访问https://repository.apache.org/#stagingRepositories, 使用Apache的LDAP账户登录后,就会看到上传的版本,`Repository`列的内容即为${STAGING.REPOSITORY}。 点击`Close`来告诉Nexus这个构建已经完成,只有这样该版本才是可用的。 如果电子签名等出现问题,`Close`会失败,可以通过`Activity`查看失败信息。 - - - -## 发布Apache SVN仓库 - -### 1.准备svn本机环境(Apache使用svn托管项目的发布内容) - -### 2.checkout到本地目录 - -```shell -$ svn checkout https://dist.apache.org/repos/dist/dev/incubator/eventmesh/ -# 假定本地目录为 ~/apache/eventmesh -``` - -### 3.添加gpg公钥 - -添加public key到[KEYS](https://dist.apache.org/repos/dist/dev/incubator/eventmesh/KEYS)文件并提交到SVN仓库(第一次做发布的人需要做这个操作,具体操作参考KEYS文件里的说明)。KEYS主要是让参与投票的人在本地导入,用来校验sign的正确性 - -Windows - -```sh -$ gpg --list-sigs | out-file -append KEYS -encoding utf8 -$ gpg --armor --export | out-file -append KEYS -encoding utf8 -``` - -> Mac OS/Linux - -```sh -$ (gpg --list-sigs && gpg --armor --export ) >> KEYS -``` - -### 4.添加待发布内容到SVN目录 - -```shell -$ cd ~/apache/eventmesh # eventmesh svn根目录 -$ mkdir ${release_version}-${rc_version} -``` - -#### 4.1 创建tag - -在`${release_version}-release`分支上创建tag,需带有rc版本,为预发布版本 - -```shell -$ git tag -a v{$release_version}-{$rc_version} -m "Tagging the ${release_version} first Release Candidate (Candidates start at zero)" -$ git push origin --tags -``` - -#### 4.2 打包源码 - -检查项目源码命名,将源码命名为`apache-eventmesh-${release_version}-incubating-src`,将源码打包为tar.gz格式 - -```shell -$ tar -czvf apache-eventmesh-${release_version}-incubating-source.tar.gz apache-eventmesh-${release_version}-incubating-src -``` - -#### 4.3 打包二进制 - -> 编译上一步打包的源码 - -检查编译后的文件命名,将二进制文件命名为`apache-eventmesh-${release_version}-incubating` - -> 注:需将源码根目录下的`NOTICE`文件,`DISCLAIMER-WIP`文件以及`tools/third-party-licenses`目录下的`LICENSE`文件拷贝到二进制的包中 - -```shell -$ gradle clean jar dist && gradle installPlugin && gradle tar -x test -$ tar -czvf apache-eventmesh-${release_version}-incubating-bin.tar.gz apache-eventmesh-${release_version}-incubating -``` - -压缩source包、bin包,并将相关的压缩包拷贝到svn本地仓库下`/apache/eventmesh/${release_version}-${rc_version}` - -### 5.生成签名/sha512文件 - -> 针对源码包与二进制包生成签名/sha512文件 - -```shell -$ for i in *.tar.gz; do echo $i; gpg --print-md SHA512 $i > $i.sha512 ; done #计算sha512 -$ for i in *.tar.gz; do echo $i; gpg --armor --output $i.asc --detach-sig $i ; done #计算签名 -``` - -### 6.提交到Apache svn - -```shell -$ cd ~/apache/eventmesh # eventmesh svn根目录 -$ svn status -$ svn commit -m 'prepare for ${release_version}-${rc_version}' -``` - - - -## 验证Release Candidates - -详细检查列表请参考官方的[check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist) - -从以下地址下载要发布的Release Candidates到本地环境: - -```shell -https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version}/ -``` - -然后开始验证环节,验证包含但不限于以下内容和形式 - -### 1.检查签名和hash等信息 - -> 由于操作系统不同,检查的命令或有差异,具体可参考[官方检查步骤](https://www.apache.org/info/verification.html) - -#### 1.1检查sha512哈希 - -> Mac OS/Linux - -```shell -$ shasum -a apache-eventmesh-${release_version}-incubating-source.tar.gz -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-source.tar.gz.sha512文件内容作对比 -$ shasum -a apache-eventmesh-${release_version}-incubating-bin.tar.gz -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-bin.tar.gz.sha512文件内容作对比 -``` - -> Windows - -```shell -$ certUtil -hashfile apache-eventmesh-${release_version}-incubating-source.tar.gz SHA512 -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-source.tar.gz.sha512文件内容作对比 -$ certUtil -hashfile apache-eventmesh-${release_version}-incubating-bin.tar.gz SHA512 -#并将输出内容与 apache-eventmesh-${release_version}-${rc_version}-incubating-bin.tar.gz.sha512文件内容作对比 -``` - -#### 1.2检查gpg签名 - -首先导入发布人公钥。从svn仓库导入KEYS到本地环境。(发布版本的人不需要再导入,帮助做验证的人需要导入,用户名填发版人的即可) - -```shell -$ curl https://dist.apache.org/repos/dist/dev/incubator/eventmesh/KEYS >> KEYS -$ gpg --import KEYS -$ gpg --edit-key "${发布人的gpg用户名}" - > trust - -Please decide how far you trust this user to correctly verify other users' keys -(by looking at passports, checking fingerprints from different sources, etc.) - - 1 = I don't know or won't say - 2 = I do NOT trust - 3 = I trust marginally - 4 = I trust fully - 5 = I trust ultimately - m = back to the main menu - -Your decision? 5 - - > save -``` - -然后使用如下命令检查签名 - -```shell -$ gpg --verify apache-eventmesh-${release_version}-incubating-source.tar.gz.asc apache-eventmesh-${release_version}-incubating-source-tar.gz -$ gpg --verify apache-eventmesh-${release_version}-incubating-bin.tar.gz.asc apache-eventmesh-${release_version}-incubating-bin.tar.gz -``` - -### 2.检查源码包的文件内容 - -解压缩`apache-eventmesh-${release_version}-incubating-source-tar.gz`,进行如下检查: - -- 检查源码包是否包含由于包含不必要文件,致使tar包过于庞大 -- 文件夹包含单词`incubating` -- 存在`LICENSE`和`NOTICE`文件 -- 存在`DISCLAIMER`文件 -- `NOTICE`文件中的年份正确 -- 只存在文本文件,不存在二进制文件 -- 所有文件的开头都有ASF许可证 -- 能够正确编译,单元测试可以通过 (./gradle build) (目前支持JAVA 8/gradle 7.0/idea 2021.1.1及以上) -- 检查是否有多余文件或文件夹,例如空文件夹等 - -### 3.检查二进制包的文件内容 - -- 文件夹包含单词`incubating` -- 存在`LICENSE`和`NOTICE`文件 -- 存在`DISCLAIMER`文件 -- `NOTICE`文件中的年份正确 -- 所有文本文件开头都有ASF许可证 -- 检查第三方依赖许可证: - - 第三方依赖的许可证兼容 - - 所有第三方依赖的许可证都在`LICENSE`文件中声名 - - 依赖许可证的完整版全部在`license`目录 - - 如果依赖的是Apache许可证并且存在`NOTICE`文件,那么这些`NOTICE`文件也需要加入到版本的`NOTICE`文件中 - -你可以参考此文章:[ASF第三方许可证策](https://apache.org/legal/resolved.html) - -## 发起投票 - -> EventMesh 仍在孵化阶段,需要进行两次投票 - -- EventMesh社区投票,发送邮件至:`dev@eventmesh.apache.org` -- incubator社区投票,发送邮件至:`general@incubator.apache.org` EventMesh毕业后,只需要在EventMesh社区投票 - -### 1.EventMesh社区投票阶段 - -1. EventMesh社区投票,发起投票邮件到`dev@eventmesh.apache.org`。PMC需要先按照文档检查版本的正确性,然后再进行投票。 经过至少72小时并统计到3个`+1 PMC member`票后,即可进入下一阶段的投票。 -2. 宣布投票结果,发起投票结果邮件到`dev@eventmesh.apache.org`。 - -### 2.EventMesh社区投票模板 - -标题: - -``` -[VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -正文: - -``` -Hello EventMesh Community, - - This is a call for vote to release Apache EventMesh (incubating) version ${release_version}-${rc_version}. - - Release notes: - https://github.com/apache/incubator-eventmesh/releases/tag/v${release_version}-${rc_version} - - The release candidates: - https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version}/ - - Maven artifacts are available in a staging repository at: - https://repository.apache.org/content/repositories/orgapacheeventmesh-{staging-id} - - Git tag for the release: - https://github.com/apache/incubator-eventmesh/tree/v${release_version}-${rc_version} - - Keys to verify the Release Candidate: - https://downloads.apache.org/incubator/eventmesh/KEYS - - Hash for the release tag: - #hashCode of this release tag - - GPG user ID: - ${YOUR.GPG.USER.ID} - - The vote will be open for at least 72 hours or until necessary number of votes are reached. - - Please vote accordingly: - - [ ] +1 approve - - [ ] +0 no opinion - - [ ] -1 disapprove with the reason - - Checklist for reference: - - [ ] Download links are valid. - - [ ] Checksums and PGP signatures are valid. - - [ ] Source code distributions have correct names matching the current release. - - [ ] LICENSE and NOTICE files are correct for each EventMesh repo. - - [ ] All files have license headers if necessary. - - [ ] No compiled archives bundled in source archive. - - More detail checklist please refer: - https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist - -Thanks, -Your EventMesh Release Manager -``` - -### 3.宣布投票结果模板 - -标题: - -``` -[RESULT][VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -正文: - -``` -Hello Apache EventMesh PPMC and Community, - - The vote closes now as 72hr have passed. The vote PASSES with - - xx (+1 non-binding) votes from the PPMC, - xx (+1 binding) votes from the IPMC, - xx (+1 non-binding) votes from the rest of the developer community, - and no further 0 or -1 votes. - - The vote thread: {vote_mail_address} - - I will now bring the vote to general@incubator.apache.org to get approval by the IPMC. - If this vote passes also, the release is accepted and will be published. - -Thank you for your support. -Your EventMesh Release Manager -``` - -### 4.Incubator社区投票阶段 - -1. Incubator社区投票,发起投票邮件到`general@incubator.apache.org`,需3个 `+1 IPMC Member`投票,方可进入下一阶段。 -2. 宣布投票结果,发起投票结果邮件到`general@incubator.apache.org` 并抄送至`dev@eventmesh.apache.org`。 - -### 5.Incubator社区投票模板 - -标题: - -``` -[VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -内容: - -``` -Hello Incubator Community, - - This is a call for a vote to release Apache EventMesh(Incubating) version ${release_version} ${rc_version} - - The Apache EventMesh community has voted on and approved a proposal to release - Apache EventMesh(Incubating) version ${release_version} ${rc_version} - - We now kindly request the Incubator PMC members review and vote on this - incubator release. - - EventMesh community vote thread: - • [投票链接] - - Vote result thread: - • [投票结果链接] - - The release candidate: - •https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version}/ - - Git tag for the release: - • https://github.com/apache/incubator-eventmesh/tree/${release_version}-${rc_version} - Release notes: - • https://github.com/apache/incubator-eventmesh/releases/tag/${release_version}-${rc_version} - - The artifacts signed with PGP key [填写你个人的KEY], corresponding to [填写你个人的邮箱], that can be found in keys file: - • https://downloads.apache.org/incubator/eventmesh/KEYS - - The vote will be open for at least 72 hours or until necessary number of votes are reached. - - Please vote accordingly: - - [ ] +1 approve - [ ] +0 no opinion - [ ] -1 disapprove with the reason - -Thanks, -On behalf of Apache EventMesh(Incubating) community -``` - -### 6.宣布投票结果模板 - -标题: - -``` -[RESULT][VOTE] Release Apache EventMesh (incubating) ${release_version} ${rc_version} -``` - -内容: - -``` -Hi all, - - Thanks for reviewing and voting for Apache EventMesh(Incubating) version ${release_version} ${rc_version} release, I am happy to announce the release voting has passed with [投票结果数] binding votes, no +0 or -1 votes. - - Binding votes are from IPMC - - xxx - - xxx - - xxx - - Non-binding votes: - +1 xxx - +0 xxx - -1 xxx - - The voting thread is: - • [投票结果链接] - - Many thanks for all our mentors helping us with the release procedure, and all IPMC helped us to review and vote for Apache EventMesh(Incubating) release. I will be working on publishing the artifacts soon. - -Thanks, -On behalf of Apache EventMesh(Incubating) community -``` - -## 正式发布 - -### 1.合并分支 - -合并`${release_version}-release`分支的改动到`master`分支,合并完成后删除`release`分支 - -```shell -$ git checkout master -$ git merge origin/${release_version}-release -$ git pull -$ git push origin master -$ git push --delete origin ${release_version}-release -$ git branch -d ${release_version}-release -``` - -### 2.迁移源码与二进制包 - -将源码和二进制包从svn的`dev`目录移动到`release`目录 - -```shell -$ svn mv https://dist.apache.org/repos/dist/dev/incubator/eventmesh/${release_version}-${rc_version} https://dist.apache.org/repos/dist/release/incubator/eventmesh/ -m "transfer packages for ${release_version}-${rc_version}" #移动源码包与二进制包 -$ svn delete https://dist.apache.org/repos/dist/release/incubator/eventmesh/KEYS -m "delete KEYS" #清除原有release目录下的KEYS -$ svn cp https://dist.apache.org/repos/dist/dev/incubator/eventmesh/KEYS https://dist.apache.org/repos/dist/release/incubator/eventmesh/ -m "transfer KEYS for ${release_version}-${rc_version}" #拷贝dev目录KEYS到release目录 -``` - -### 3.确认dev和release下的包是否正确 - -- 确认[dev](https://dist.apache.org/repos/dist/dev/incubator/eventmesh/)下的`${release_version}-${rc_version}`已被删除 -- 删除[release](https://dist.apache.org/repos/dist/release/incubator/eventmesh/)目录下上一个版本的发布包,这些包会被自动保存在[这里](https://archive.apache.org/dist/incubator/eventmesh/) - -```shell -$ svn delete https://dist.apache.org/repos/dist/release/incubator/eventmesh/${last_release_version} -m "Delete ${last_release_version}" -``` - -### 4.在Apache Staging仓库发布版本 - -- 登录http://repository.apache.org , 使用Apache账号登录 -- 点击左侧的Staging repositories, -- 搜索EventMesh关键字,选择你最近上传的仓库,投票邮件中指定的仓库 -- 点击上方的`Release`按钮,这个过程会进行一系列检查 - -> 等仓库同步到其他数据源,一般需要24小时 - -### 5.GitHub版本发布 - -1.Tag the commit (on which the vote happened) with the release version without `-${RELEASE_CANDIDATE}`. 例如:after a successful vote on `v1.2-rc5`, the hash will be tagged again with `v1.2` only. - -2.在 [GitHub Releases](https://github.com/apache/incubator-eventmesh/releases) 页面的 `${release_version}` 版本上点击 `Edit` - -编辑版本号及版本说明,并点击 `Publish release` - -### 6.更新下载页面 - -等待并确认新的发布版本同步至 Apache 镜像后,更新如下页面: - -https://eventmesh.apache.org/download/ - -https://eventmesh.apache.org/zh/download/ - -GPG签名文件和哈希校验文件的下载连接应该使用这个前缀:`https://downloads.apache.org/incubator/eventmesh/` - -> 注意:项目下载链接应该使用 https://www.apache.org/dyn/closer.lua 而不是 closer.cgi 或者 mirrors.cgi - -### 7.邮件通知版本发布完成 - -> 请确保Apache Staging仓库已发布成功,一般是在该步骤的24小时后发布邮件 - -发邮件到 `dev@eventmesh.apache.org` 、 `announce@apache.org`和`general@incubator.apache.org` - -标题: - -``` -[ANNOUNCE] Apache EventMesh (incubating) ${release_version} available -``` - -正文: - -``` -Hi all, - -Apache EventMesh (incubating) Team is glad to announce the new release of Apache EventMesh (incubating) ${release_version}. - -Apache EventMesh (incubating) is a dynamic cloud-native eventing infrastructure used to decouple the application and backend middleware layer, which supports a wide range of use cases that encompass complex multi-cloud, widely distributed topologies using diverse technology stacks. - -Download Links: https://eventmesh.apache.org/projects/eventmesh/download/ - -Release Notes: https://eventmesh.apache.org/events/release-notes/v${release_version}/ - -Website: https://eventmesh.apache.org/ - -EventMesh Resources: -- Issue: https://github.com/apache/incubator-eventmesh/issues -- Mailing list: dev@eventmesh.apache.org - - - -Apache EventMesh (incubating) Team -``` - diff --git a/docs/zh/contribute/02-write-unit-test.md b/docs/zh/contribute/02-write-unit-test.md deleted file mode 100644 index 0c48e46bc6..0000000000 --- a/docs/zh/contribute/02-write-unit-test.md +++ /dev/null @@ -1,77 +0,0 @@ -# Unit Test Requirement - -- Each unit test case should use assertions instead of `System.out` output or `if` statement -- Each unit test case shouldn't call other cases or depend on the order of execution. -- Each unit test case should be repeatable and not depend on the external environment because the test might be executed in the continuous integration. -- The scope of each unit test should be small enough to help locate the problem at the method level. - -## Location and Naming Rules - -- The unit test should be placed in `src/test/java`. -- The unit test configuration file should be placed in `src/test/resources`. For example: - - Class to be tested: `src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java` - - Unit test: `src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java` - - Unit test configuration: `src/test/resources/configuration.properties` -- The package name of the unit test class should be identical to the class to be tested. -- The name of the unit test class should be `{class or interface to be tested}Test`. For example: - - Class to be tested: `EventMeshUtil` - - Unit test class: `EventMeshUtilTest` -- The name of each test case should be `test{method name}`. For example: - - Method to be tested: `addProp(String key, String val)` - - Unit test case: `testAddProp` - -## Assertion Usage - -### Common Assertion - -| Methods | Instructions | -| :-------------- | :-------------- | -| `assertEquals` | Determines whether two objects or primitive types are equal | -| `assertNotEquals` | Determines whether two objects or primitive types are not equal | -| `assertTrue` | Determines whether the given Boolean value is `true` | -| `assertFalse` | Determines whether the given Boolean value is `false` | -| `assertNull` | Determines whether the given object reference is `null` | -| `assertNotNull` | Determines whether the given object reference is not `null` | -| `assertAll` | When multiple decision logic are processed together if only one error is reported, the whole test will fail | - -### Example - -#### `assertEquals()` - -```java -configuration.init(); -Assert.assertEquals("value1", configuration.eventMeshEnv); -``` - -#### `assertTrue()` - -```java -BaseResponseHeader header = BaseResponseHeader.buildHeader("200"); -Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); -``` - -#### `assertFalse()` - -```java -Class nacosRegistryServiceClass = NacosRegistryService.class; -Field initStatus = nacosRegistryServiceClass.getDeclaredField("INIT_STATUS"); -initStatus.setAccessible(true); -Object initStatusField = initStatus.get(nacosRegistryService); -Assert.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); -``` - -#### `assertNull()` - -```java -DefaultFullHttpResponse response = httpCommand.httpResponse(); -Assert.assertNull(response); -``` - -#### `assertNotNull()` - -```java -Codec.Decoder cd = new Codec.Decoder(); -ArrayList result = new ArrayList<>(); -cd.decode(null, buf, result); -Assert.assertNotNull(result.get(0)); -``` diff --git a/docs/zh/contribute/03-new-contributor-guidelines.md b/docs/zh/contribute/03-new-contributor-guidelines.md deleted file mode 100644 index 8c63375c35..0000000000 --- a/docs/zh/contribute/03-new-contributor-guidelines.md +++ /dev/null @@ -1,145 +0,0 @@ - -# How to Contribution - -If you are a new contributor who wants to contribute to the eventmesh community, please read this document, which describes how to contribute to the community, and if you find any questions in the document, feel free to leave comments or suggestions. - -## Preparation - -### Development environment - -- You should have the JDK installed in your development environment. - -### Code Style - -Import [EventMesh CheckStyle](https://github.com/apache/incubator-eventmesh/blob/master/style/checkStyle.xml) file to your IDEA. - -For IDEA, you can import check style file by: -```shell - Editor -> Code Style -> Java -> Scheme -> Import Scheme -> CheckStyle Configuration -``` - -If you can't see CheckStyle Configuration section under Import Scheme, you can install CheckStyle-IDEA plugin first, and you will see it. - -You can also use `./gradlew check` to check the code style. -(Note: this command will check all file in project, when you submit a pr, the ci will only check the file has been changed in this pr). - -### Workflow - -Here are the workflow for contributors: - -1. Fork to your own - -2. Clone fork to local repository -```git -git clone git@github.com:yourgithub/incubator-eventmesh.git -``` - -3. Create a new branch and work on it -```git -git checkout -b fix_patch_xx -``` - -4. Keep your branch in sync -```git -git remote add upstream git@github.com:apache/incubator-eventmesh.git -git fetch upstream develop:upstream_develop -git rebase upstream_develop -``` - -5. Commit your changes (make sure your commit message concise) - -6. Push your commits to your forked repository - -7. Create a pull request - -## Explanation - -The original warehouse: https://github.com/apache/incubator-eventmesh The apache warehouse of eventmesh is called the original warehouse in the text. - -The Fork library: From https://github.com/apache/eventmesh fork to your own personal repository to become a fork library. - -So fork the original EventMesh repository into your own repository. - -## Development branch - -**The current development branch of eventmesh is Master. Please submit PR to this branch.** - -- We recommend that you create a new branch in your repository for development and submit the branch to the master branch of eventmesh. - -## Contribution Categories - -### Bug feedback or bug fixes - -- Whether it's a bug feedback or a fix, an issue needs to be created first to describe the bug in detail, so that the community can easily find and view the problem and code through the issue record. bug feedback issues usually need to contain a complete description of the bug information and reproducible scenarios. - -### Implementation of functions, refactoring - -- If you plan to implement a new feature (or refactoring), be sure to communicate with the eventmesh core development team via an Issue or other means, and describe the new feature (or refactoring), mechanism and scenario in detail during the communication process. - -### Documentation Improvement - -- You can find the eventmesh documentation at [evenmesh-docs](https://github.com/apache/incubator-eventmesh/tree/master/docs), and the documentation is supplemented or improved in a way that is also essential for eventmesh. - -## Contribution method - -There are two ways for new contributors to contribute to the eventmesh community: - -- If you find a bug in the eventmesh code that you want to fix, or if you provide a new feature for the eventmesh, submit an issue in the eventmesh and submit a pr to the eventmesh. - -- Other contributors in the eventmesh community have raised issues, the [`issue for first-time contributors`](https://github.com/apache/incubator-eventmesh/issues/888) sorted out by the community here are relatively simple PR, which can help you familiarize yourself with the process of making contributions to the eventmesh community. - -## Submit issue guidelines - -- If you don't know how to raise an issue on eventmesh, please read [about the issue](https://docs.github.com/cn/issues/tracking-your-work-with-issues/quickstart). - -- In the eventmesh community, there are issue templates that can be used for reference, if the type matches please use the template, if the issue template does not meet your requirements, you can open an empty issue template, for the issue please bring its matching feature labels. - -- For the name of the issue, please briefly describe your question or purpose in one sentence, and write in English for better global communication. - -## pull request (pr) submission guidelines - -- If you don't know how to initiate a pr for eventmesh, please see [about pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). - -- Whether it's a bug fix, or a new feature development (if this pr is a new feature development, then documentation updates about the new feature should be included in this pr), please submit a PR to the current development branch master. - -- The pr submission should follow the template provided by eventmesh as well as the need to write the submission information, a brief description of what the pr you are submitting does is sufficient, please see the [template for details](https://github.com/apache/incubator-eventmesh/blob/master/.github/PULL_REQUEST_TEMPLATE.md). - -- The pr you submit needs to be associated with the issue you are fixing, or the issue you are raising,so your PR title should start with [ISSUE #xx]. - -- If your change is about a typo or small optimize, you needn't create an Issue, just submit a PR and title with [MINOR]. - -**Note:** - - - A single pull request should not be too large. If heavy changes are required, it's better to separate the changes to a few individual PRs. - - - After creating a PR, one or more committers will help to review the pull request, after approve, this PR will be merged in to eventmesh repository, and the related Issue will be closed. - -## review - -### PR review - -All code should be well reviewed by one or more committers. Some principles: - -- Readability: Important code should be well-documented. Comply with our [code style](https://github.com/apache/incubator-eventmesh/blob/master/style/checkStyle.xml). - -- Elegance: New functions, classes or components should be well-designed. - -- Testability: Important code should be well-tested (high unit test coverage). - -### License review - -EventMesh follows [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) policy. All source files should -have the Apache License header added to the file header. EventMesh uses the [apache/skywalking-eyes](https://github.com/apache/skywalking-eyes) to check -the source file header. - -### PR merge - -After a PR is approved by at least one committer, it can be merged. Before the merge, the committer can make changes to the commits message, requiring the commits -message to be clear without duplication, and use Squash and Merge to make sure one PR should only contain one commits. -For large multi-person PR, use Merge to merge, and fix the commits by rebase before merging. - -## Community - -### Contact us - -Mail: dev@eventmesh.apache.org \ No newline at end of file diff --git a/docs/zh/contribute/_category_.json b/docs/zh/contribute/_category_.json deleted file mode 100644 index 56d36f918e..0000000000 --- a/docs/zh/contribute/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 5, - "label": "Contribute", - "collapsed": false -} diff --git a/docs/zh/desing-document/01-workflow.md b/docs/zh/desing-document/01-workflow.md deleted file mode 100644 index 444c09454d..0000000000 --- a/docs/zh/desing-document/01-workflow.md +++ /dev/null @@ -1,258 +0,0 @@ -# EventMesh工作流 - -## 业务场景 - -图中你正在构建一个简单的电商订单管理系统,系统能够接收和调配新的订单,调配流程需要处理所有的订单创建,付款处理以及发货处理。 - -为了实现高可用和高性能,你可以使用事件驱动架构(EDA)构建微服务应用去处理商店前端,订单管理,支付处理和发货管理。你可以在云上部署整个系统。要处理高并发,你可以利用消息系统缓冲,并扩展多个微服务实例。架构类似于: - -![Workflow Use Case](../../images/design-document/workflow-use-case.jpg) - -当每个微服务都在自己的事件通道上运行时,EventMesh在执行事件编排方面发挥着至关重要的作用。 - -我们使用 [CNCF Serverless工作流](https://serverlessworkflow.io/) 来描述此事件工作流编排。 - -## CNCF Serverless工作流 - -CNCF Serverless工作流定义了一个厂商中立、开源和完全社区驱动的生态系统,用于定义和运行针对Serverless技术领域的基于DSL的工作流。 - -Serverless工作流定义了一种领域特定语言(DSL)来描述有状态和无状态的基于工作流的serverless函数和微服务编排。 - -详见[官方github](https://github.com/serverlessworkflow/specification) - -## EventMesh工作流 - -我们利用Serverless工作流DSL来描述EventMesh工作流。根据其规范,工作流由一系列用于描述控制流逻辑的工作流状态组成。目前,我们仅支持与事件相关的工作流状态。请参见[工作流DSL设计](#workflow-dsl-design-wip)中支持的状态。 - -`工作流状态`可以包含通用的`操作`,或在工作流执行期间应调用的服务/函数。这些`操作`可以引用可复用的`函数`定义(应如何调用这些函数/服务),还可以引用触发基于事件的服务调用的事件,以及要等待的事件,这些事件表示这种基于事件的服务调用完成。 - -在EDA解决方案中,我们通常使用AsyncAPI定义事件驱动的微服务。Serverless工作流“函数”定义支持使用AsyncAPI定义调用语义。有关详细信息,请参见[Using Funtions for AsyncAPI Service](https://github.com/serverlessworkflow/specification/blob/main/specification.md#using-functions-for-async-api-service-invocations)。 - -### AsyncAPI - -AsyncAPI是一项开源计划,旨在改善事件驱动体系结构(EDA)的当前状态。我们的长期目标是让使用EDA和使用REST API一样容易。包括从文档到代码生成、发现到事件管理。现在应用于REST API的大多数流程也适用于事件驱动/异步API。 - -详见[AsyncAPI官网](https://www.asyncapi.com/docs/getting-started) - -### 工作流示例 - -在本示例中,我们构建了上面订单管理系统的事件驱动工作流。 - -首先,我们需要为我们的微服务应用定义AsyncAPI。 - -- 在线商店应用程序 - -```yaml -asyncapi: 2.2.0 -info: - title: Online Store application - version: '0.1.0' -channels: - store/order: - subscribe: - operationId: newStoreOrder - message: - $ref : '#/components/NewOrder' - -``` - -- 订单服务 - -```yaml -asyncapi: 2.2.0 -info: - title: Order Service - version: '0.1.0' -channels: - order/inbound: - publish: - operationId: sendOrder - message: - $ref : '#/components/Order' - order/outbound: - subscribe: - operationId: processedOrder - message: - $ref : '#/components/Order' -``` - -- 支付服务 - -```yaml -asyncapi: 2.2.0 -info: - title: Payment Service - version: '0.1.0' -channels: - payment/inbound: - publish: - operationId: sendPayment - message: - $ref : '#/components/OrderPayment' - payment/outbound: - subscribe: - operationId: paymentReceipt - message: - $ref : '#/components/OrderPayment' -``` - -- 物流服务 - -```yaml -asyncapi: 2.2.0 -info: - title: Shipment Service - version: '0.1.0' -channels: - shipment/inbound: - publish: - operationId: sendShipment - message: - $ref : '#/components/OrderShipment' -``` - -接下来,定义描述订单管理业务逻辑的订单工作流。 - -```yaml -id: storeorderworkflow -version: '1.0' -specVersion: '0.8' -name: Store Order Management Workflow -states: - - name: Receive New Order Event - type: event - onEvents: - - eventRefs: - - NewOrderEvent - actions: - - eventRef: - triggerEventRef: OrderServiceSendEvent - resultEventRef: OrderServiceResultEvent - - eventRef: - triggerEventRef: PaymentServiceSendEvent - resultEventRef: PaymentServiceResultEvent - transition: Check Payment Status - - name: Check Payment Status - type: switch - dataConditions: - - name: Payment Successfull - condition: "${ .payment.status == 'success' }" - transition: Send Order Shipment - - name: Payment Denied - condition: "${ .payment.status == 'denied' }" - end: true - defaultCondition: - end: true - - name: Send Order Shipment - type: operation - actions: - - eventRef: - triggerEventRef: ShipmentServiceSendEvent - end: true -events: - - name: NewOrderEvent - source: file://onlineStoreApp.yaml#newStoreOrder - type: asyncapi - kind: consumed - - name: OrderServiceSendEvent - source: file://orderService.yaml#sendOrder - type: asyncapi - kind: produced - - name: OrderServiceResultEvent - source: file://orderService.yaml#processedOrder - type: asyncapi - kind: consumed - - name: PaymentServiceSendEvent - source: file://paymentService.yaml#sendPayment - type: asyncapi - kind: produced - - name: PaymentServiceResultEvent - source: file://paymentService.yaml#paymentReceipt - type: asyncapi - kind: consumed - - name: ShipmentServiceSendEvent - source: file://shipmentService.yaml#sendShipment - type: asyncapi - kind: produced -``` - -对应的工作流图如下: - -![Workflow Diagram](../../images/design-document/workflow-diagram.png) - -## EventMesh工作流引擎 - -在下面的体系结构图中, EventMesh目录, EventMesh工作流引擎 和 EventMesh Runtime在三个不同的处理器中运行。 - -![Workflow Architecture](../../images/design-document/workflow-architecture.jpg) - -运行工作流的步骤如下: - -1. 在环境中部署发布者和订阅者应用程序。 - 使用AsyncAPI描述应用程序API,生成asyncAPI yaml。 - 使用AsyncAPI在EventMesh目录中注册发布者和订阅者应用程序。 - -2. 在EventMesh工作流引擎中注册Serverless工作流DSL。 - -3. 工作流引擎从EventMesh目录查询发布服务器和订阅服务器的需要的工作流DSL`函数`。 - -4. 事件驱动App将事件发布到EventMesh Runtime触发工作流。EventMesh工作流引擎发布和订阅事件、编排事件。 - -### EventMesh Catalog 设计 - -EventMesh目录存储发布者、订阅者和通道元数据。由以下模块组成: - -- AsyncAPI解析器 - - 使用AsyncAPI社区提供的SDK ([tool list](https://www.asyncapi.com/docs/community/tooling)), - 解析并验证AsyncAPI yaml输入,并生成AsyncAPI定义。 - -- 发布者, 通道, 订阅者模块 - - 从AsyncAPI定义存储发布者、订阅者和通道信息。 - -### EventMesh工作流引擎设计 - -工作流引擎由以下模块组成: - -- 工作流解析器 - - 使用Serverless Workflow社区提供的SDK([SDKs](https://github.com/serverlessworkflow/specification#sdks)), - 解析和验证工作流DSL输入,并生成工作流定义。 - -- 工作流模块 - - 管理工作流实例的生命周期,从创建、启动、停止到销毁。 - -- 状态模块 - - 管理工作流状态生命周期。支持与事件相关的状态,and the supported state list below is Work-in-Progress. - - | 工作流状态 | 描述 | - | --- | --- | - | Operation | 执行Actions中定义的AsyncAPI函数 | - | Event | 检查定义的事件是否匹配,如果匹配,执行定义的AsyncAPI函数 | - | Switch | 检查事件是否与事件条件匹配,并执行定义的AsyncAPI函数 | - | Parallel | 并行执行定义的AsyncAPI函数 | - | ForEach | 迭代输入集合并执行定义的AsyncAPI函数 | - -- 行为模块 - - 管理函数中的行为。 - -- 函数模块 - - 通过在EventMesh Runtime中创建发布者和/或订阅者来管理AsyncAPI函数,并管理发布者/订阅者生命周期。 - - | AsyncAPI 操作 | EventMesh Runtime | - | --- | --- | - | Publish | Publisher | - | Subscribe | Subscriber | - -- 事件模块 - - 使用工作流DSL中定义的规则管理CloudEvent数据模型,包括事件过滤器、关联和转换。 - -- 重试模块 - - 管理事件发布到EventMesh Runtime的重试逻辑。 diff --git a/docs/zh/desing-document/02-runtime-protocol.md b/docs/zh/desing-document/02-runtime-protocol.md deleted file mode 100644 index d5f155602f..0000000000 --- a/docs/zh/desing-document/02-runtime-protocol.md +++ /dev/null @@ -1,420 +0,0 @@ -# TCP协议文档 - -#### 1. 协议格式 - -![dataFlow](../../images/design-document/tcp-protocol.png) - -**消息组成详解:** - -``` -魔术字:9位,当前值为“EventMesh” - -通信协议版本号:4位,当前值为“0000” - -消息总长度值(length):4位,int类型 - -消息头长度值(headerLength):4位,int类型 - -消息头(header):长度 = headerLength - -消息体(body):长度 = length - headerLength - 4 - 4 -``` - -#### 2. 业务逻辑层 - -+ 消息组成 - -消息头(header)+ 消息体(body) - -```java -public class Package { - - private Header header; - private Object body; -} - - -public class Header { - - private Command cmd; - private int code; - private String msg; - private String seq; -} -``` - -+ 详解 - -消息头(header):类型为Header,Header中有Command字段,用于区分不同的消息类型 - -消息体(body):对于不同的消息类型,body的类型不同 - -| 消息命令字 | body类型 | -| ------------------------------------------------------------ | ------------ | -| HEARTBEAT_REQUEST, HEARTBEAT_RESPONSE, HELLO_RESPONSE, CLIENT_GOODBYE_REQUEST, CLIENT_GOODBYE_RESPONSE, SERVER_GOODBYE_REQUEST, SERVER_GOODBYE_RESPONSE, LISTEN_REQUEST, LISTEN_RESPONSE, UNSUBSCRIBE_REQUEST, SUBSCRIBE_RESPONSE, UNSUBSCRIBE_RESPONSE, ASYNC_MESSAGE_TO_SERVER_ACK, BROADCAST_MESSAGE_TO_SERVER_ACK | 无 | -| HELLO_REQUEST | UserAgent | -| SUBSCRIBE_REQUEST | Subscription | -| REQUEST_TO_SERVER, REQUEST_TO_CLIENT, RESPONSE_TO_SERVER, RESPONSE_TO_CLIENT, ASYNC_MESSAGE_TO_SERVER, ASYNC_MESSAGE_TO_CLIENT, BROADCAST_MESSAGE_TO_SERVER, BROADCAST_MESSAGE_TO_CLIENT, ASYNC_MESSAGE_TO_CLIENT_ACK, BROADCAST_MESSAGE_TO_CLIENT_ACK, RESPONSE_TO_CLIENT_ACK, REQUEST_TO_CLIENT_ACK | OpenMessage | -| REDIRECT_TO_CLIENT | RedirectInfo | - -#### 3. Client 与 Eventmesh-Runtime(Server)交互场景详解 - -```java -public enum Command { - - //心跳 - HEARTBEAT_REQUEST(0), //client发给server的心跳包 - HEARTBEAT_RESPONSE(1), //server回复client的心跳包 - - //握手 - HELLO_REQUEST(2), //client发给server的握手请求 - HELLO_RESPONSE(3), //server回复client的握手请求 - - //断连 - CLIENT_GOODBYE_REQUEST(4), //client主动断连时通知server - CLIENT_GOODBYE_RESPONSE(5), //server回复client的主动断连通知 - SERVER_GOODBYE_REQUEST(6), //server主动断连时通知client - SERVER_GOODBYE_RESPONSE(7), //client回复server的主动断连通知 - - //订阅管理 - SUBSCRIBE_REQUEST(8), //client发给server的订阅请求 - SUBSCRIBE_RESPONSE(9), //server回复client的订阅请求 - UNSUBSCRIBE_REQUEST(10), //client发给server的取消订阅请求 - UNSUBSCRIBE_RESPONSE(11), //server回复client的取消订阅请求 - - //监听 - LISTEN_REQUEST(12), //client发给server的启动监听请求 - LISTEN_RESPONSE(13), //server回复client的监听请求 - - //RR - REQUEST_TO_SERVER(14), //client将RR请求发送给server - REQUEST_TO_CLIENT(15), //server将RR请求推送给client - REQUEST_TO_CLIENT_ACK(16), //client收到RR请求后ACK给server - RESPONSE_TO_SERVER(17), //client将RR回包发送给server - RESPONSE_TO_CLIENT(18), //server将RR回包推送给client - RESPONSE_TO_CLIENT_ACK(19), //client收到回包后ACK给server - - //异步事件 - ASYNC_MESSAGE_TO_SERVER(20), //client将异步事件发送给server - ASYNC_MESSAGE_TO_SERVER_ACK(21), //server收到异步事件后ACK给client - ASYNC_MESSAGE_TO_CLIENT(22), //server将异步事件推送给client - ASYNC_MESSAGE_TO_CLIENT_ACK(23), //client收到异步事件后ACK给server - - //广播 - BROADCAST_MESSAGE_TO_SERVER(24), //client将广播消息发送给server - BROADCAST_MESSAGE_TO_SERVER_ACK(25), //server收到广播消息后ACK给client - BROADCAST_MESSAGE_TO_CLIENT(26), //server将广播消息推送给client - BROADCAST_MESSAGE_TO_CLIENT_ACK(27), //client收到广播消息后ACK给server - - //重定向指令 - REDIRECT_TO_CLIENT(30), //server将重定向指令推动给client -} -``` - -#### 4. Client发起交互 - -| 场景 | Client向Server发送消息命令字 | Server回复Client消息的命令字 | 说明 | -| -------------- | ---------------------------- | ------------------------------- | ---- | -| 握手 | HELLO_REQUEST | HELLO_RESPONSE | | -| 心跳 | HEARTBEAT_REQUEST | HEARTBEAT_RESPONSE | | -| 订阅 | SUBSCRIBE_REQUEST | SUBSCRIBE_RESPONSE | | -| 取消订阅 | UNSUBSCRIBE_REQUEST | UNSUBSCRIBE_RESPONSE | | -| 开始监听消息 | LISTEN_REQUEST | LISTEN_RESPONSE | | -| 发送RR请求 | REQUEST_TO_SERVER | RESPONSE_TO_CLIENT | | -| 发送RR回包 | RESPONSE_TO_SERVER | 无 | | -| 发送异步事件 | ASYNC_MESSAGE_TO_SERVER | ASYNC_MESSAGE_TO_SERVER_ACK | | -| 发送广播事件 | BROADCAST_MESSAGE_TO_SERVER | BROADCAST_MESSAGE_TO_SERVER_ACK | | -| 客户端主动断连 | CLIENT_GOODBYE_REQUEST | CLIENT_GOODBYE_RESPONSE | | - -#### 5. Server发起交互 - -| 场景 | Server向Client发送消息命令字 | Client回复Server消息命令字 | 说明 | -| ------------------ | ---------------------------- | ------------------------------- | ---- | -| 客户端接收RR请求 | REQUEST_TO_CLIENT | REQUEST_TO_CLIENT_ACK | | -| 客户端接收RR回包 | RESPONSE_TO_CLIENT | RESPONSE_TO_CLIENT_ACK | | -| 客户端接收异步事件 | ASYNC_MESSAGE_TO_CLIENT | ASYNC_MESSAGE_TO_CLIENT_ACK | | -| 客户端接收广播事件 | BROADCAST_MESSAGE_TO_CLIENT | BROADCAST_MESSAGE_TO_CLIENT_ACK | | -| 服务端主动断连 | SERVER_GOODBYE_REQUEST | 无 | | -| 服务端进行重定向 | REDIRECT_TO_CLIENT | 无 | | -| | | | | - -#### 6. 消息类型 - -+ 发送RR消息 - -![rr-msg](../../images/design-document/sync-message.png) - -+ 发送异步单播消息 - -![async-msg](../../images/design-document/async-message.png) - -+ 发送广播消息 - -![broadcast-msg](../../images/design-document/broadcast-message.png) - -## HTTP协议文档 - -Java类`LiteMessage`的`content`字段表示一个特殊的协议,因此,如果您要使用eventmesh-sdk-java的http-client,则只需设计协议的`content`即可。`LiteMessage`组成如下: - -```java -public class LiteMessage { - - private String bizSeqNo; - - private String uniqueId; - - private String topic; - - private String content; - - private Map prop; - - private long createTime = System.currentTimeMillis(); -} -``` - -#### 1. 消息发送方式与组成 - -**消息发送方式**:POST方式 - -**消息组成**:请求头(RequestHeader) + 请求体(RequestBody) - -+ 心跳消息 - -**RequestHeader** - -| Key | 说明 | -| -------- | ---------------- | -| Env | client所属环境 | -| Region | client所属区域 | -| Idc | client所属IDC | -| Dcn | client所在DCN | -| Sys | client所属子系统 | -| Pid | client进程号 | -| Ip | client Ip | -| Username | client 用户名 | -| Passwd | client 密码 | -| Version | 协议版本 | -| Language | 语言描述 | -| Code | 请求码 | - -**RequestBody** - -| Key | 说明 | -| ----------------- | ------------------------------ | -| clientType | 客户端类型 | -| heartbeatEntities | 心跳实体,包含topic、url等信息 | - -+ 订阅消息: - -**RequestHeader** - -与心跳消息一致 - -**RequestBody** - -| Key | 说明 | -| ----- | ----------------- | -| topic | 客户端订阅的topic | -| url | topic对应的url | - -+ 取消订阅消息: - -**RequestHeader** - -与心跳消息一致 - -**RequestBody** - -与订阅消息一致 - -+ 发送异步事件: - -**RequestHeader** - -与心跳消息一致 - -**RequestBody** - -| Key | 说明 | -| -------- | ----------------------- | -| topic | 客户端请求的topic | -| content | 客户端发送的topic的内容 | -| ttl | 客户端请求超时时间 | -| bizSeqNo | 客户端请求业务流水号 | -| uniqueId | 客户端请求消息唯一标识 | - -#### 2. Client发起交互 - -| 场景 | Client向Server发送消息请求码 | Server回复Client消息的响应码 | 说明 | -| ------------ | ---------------------------- | --------------------------------------- | ---- | -| 心跳 | HEARTBEAT(203) | SUCCESS(0)/EVENTMESH_HEARTBEAT_ERROR(19) | | -| 订阅 | SUBSCRIBE(206) | SUCCESS(0)/EVENTMESH_SUBSCRIBE_ERROR(17) | | -| 取消订阅 | UNSUBSCRIBE(207) | SUCCESS(0)/EVENTMESH_UNSUBSCRIBE_ERROR(18) | | -| 发送异步事件 | MSG_SEND_ASYNC(104) | SUCCESS(0)/EVENTMESH_SEND_ASYNC_MSG_ERR(14) | | - -#### 3. Server发起交互 - -| 场景 | Server向Client发送消息请求码 | Client回复Server消息响应码 | 说明 | -| ------------------ | ---------------------------- | -------------------------- | ---------------------- | -| 客户端接收异步事件 | HTTP_PUSH_CLIENT_ASYNC(105) | retCode | retCode值为0时代表成功 | - -## gRPC 协议文档 - -#### 1. protobuf - -在 `eventmesh-protocol-gprc` 模块有 Eventmesh gRPC 客户端的 protobuf 文件. the protobuf 文件路径是 `/src/main/proto/eventmesh-client.proto`. - -用gradle build 生成 gRPC 代码在 `/build/generated/source/proto/main`. 生成代码用于 `eventmesh-sdk-java` 模块. - -#### 2. gRPC 数据模型 - -+ 消息 - -以下消息数据模型用于 `publish()`, `requestReply()` 和 `broadcast()` APIs. - -``` -message RequestHeader { - string env = 1; - string region = 2; - string idc = 3; - string ip = 4; - string pid = 5; - string sys = 6; - string username = 7; - string password = 8; - string language = 9; - string protocolType = 10; - string protocolVersion = 11; - string protocolDesc = 12; -} - -message SimpleMessage { - RequestHeader header = 1; - string producerGroup = 2; - string topic = 3; - string content = 4; - string ttl = 5; - string uniqueId = 6; - string seqNum = 7; - string tag = 8; - map properties = 9; -} - -message BatchMessage { - RequestHeader header = 1; - string producerGroup = 2; - string topic = 3; - - message MessageItem { - string content = 1; - string ttl = 2; - string uniqueId = 3; - string seqNum = 4; - string tag = 5; - map properties = 6; - } - - repeated MessageItem messageItem = 4; -} - -message Response { - string respCode = 1; - string respMsg = 2; - string respTime = 3; -} -``` - -+ 订阅 - -以下订阅数据模型用于 `subscribe()` 和 `unsubscribe()` APIs. - -``` -message Subscription { - RequestHeader header = 1; - string consumerGroup = 2; - - message SubscriptionItem { - enum SubscriptionMode { - CLUSTERING = 0; - BROADCASTING = 1; - } - - enum SubscriptionType { - ASYNC = 0; - SYNC = 1; - } - - string topic = 1; - SubscriptionMode mode = 2; - SubscriptionType type = 3; - } - - repeated SubscriptionItem subscriptionItems = 3; - string url = 4; -} -``` - -+ 心跳 - -以下心跳数据模型用于 `heartbeat()` API. - -``` -message Heartbeat { - enum ClientType { - PUB = 0; - SUB = 1; - } - - RequestHeader header = 1; - ClientType clientType = 2; - string producerGroup = 3; - string consumerGroup = 4; - - message HeartbeatItem { - string topic = 1; - string url = 2; - } - - repeated HeartbeatItem heartbeatItems = 5; -} -``` - -#### 3. gRPC 服务接口 - -+ 事件生产端服务 APIs - -``` -service PublisherService { - # 异步事件生产 - rpc publish(SimpleMessage) returns (Response); - - # 同步事件生产 - rpc requestReply(SimpleMessage) returns (Response); - - # 批量事件生产 - rpc batchPublish(BatchMessage) returns (Response); -} -``` - -+ 事件消费端服务 APIs - -``` -service ConsumerService { - # 所消费事件通过 HTTP Webhook推送事件 - rpc subscribe(Subscription) returns (Response); - - # 所消费事件通过 TCP stream推送事件 - rpc subscribeStream(Subscription) returns (stream SimpleMessage); - - rpc unsubscribe(Subscription) returns (Response); -} -``` - -+ 客户端心跳服务 API - -``` -service HeartbeatService { - rpc heartbeat(Heartbeat) returns (Response); -} -``` diff --git a/docs/zh/desing-document/06-cloudevents.md b/docs/zh/desing-document/06-cloudevents.md deleted file mode 100644 index 2d53e6079e..0000000000 --- a/docs/zh/desing-document/06-cloudevents.md +++ /dev/null @@ -1,102 +0,0 @@ -# CloudEvents 集成 - -## 介绍 - -[CloudEvents](https://github.com/cloudevents/spec) 是一种描述事件数据的格式规范,它提供了跨服务、平台与系统的互操作性。 - -截止至 2021 年 5 月,EventMesh 包含了以下主要组件:`eventmesh-runtime`, `eventmesh-sdk-java` 和 `eventmesh-connector-rocketmq`。 - -对于使用 EventMesh 的用户,`eventmesh-runtime` 可以被部署为微服务来在生产者和消费者间传输用户的事件。 -用户的应用程序可以通过 `eventmesh-sdk-java` 来与 `eventmesh-runtime` 进行交互,即发布或订阅指定主题的事件。 - -EventMesh 的用户非常渴望能得到对 CloudEvents 的支持。有许多理由使得用户倾向于使用集成了 CloudEvents 支持的 SDK: - -- CloudEvents 是一种更为广泛接受和支持的描述事件的方式。目前,`eventmesh-sdk-java` 使用的是 `LiteMessage` 结构 - 来描述事件,其标准化程度较低。 -- CloudEvents 的 Java SDK 有更广泛的分发方式。比如,目前 EventMesh 的用户需要使用 SDK 的 tar 包,或对每个 EventMesh 的 - 发布版本从源码编译。有了 CloudEvents 的支持,用户可以更方便地通过 CloudEvents 的公开分发(比如,配置 Maven)来添加 - EventMesh SDK 依赖项。 -- CloudEvents 的 SDK 支持多种语言。尽管目前 EventMesh 只提供了 Java SDK,但在未来,如果要为更多语言提供支持,将 Java SDK - 与 CloudEvents 绑定的经验将使工作变得容易。 - -## 需求 - -### 功能需求 - -| 需求 ID | 需求描述 | 备注 | -| ------ | ------- | --- | -| F-1 | EventMesh 用户应能使用公共 SDK 依赖项来发布或订阅 CloudEvents 格式的事件 | 功能性 | -| F-2 | EventMesh 用户应能在提供了 CloudEvents 支持的 SDK 中继续使用现有的 EventMesh 客户端功能(如负载均衡) | 功能等价 | -| F-3 | EventMesh 的开发者应不需要付出特别多努力/痛苦来在 `eventmesh-sdk-java` 和提供了 CloudEvents 支持的 SDK 之间同步 | 可维护性 | -| F-4 | EventMesh 支持可插拔的协议,以便开发者整合其他协议(例如:CloudEvents / EventMesh MessageOpenMessage / MQTT...) | 功能性 | -| F-5 | EventMesh 支持统一的 API 以供从/向事件库发布或订阅事件 | 功能性 | - -### 性能需求 - -| 需求 ID | 需求描述 | 备注 | -| ------ | ------- | --- | -| P-1 | 提供了 CloudEvents 支持的 SDK 应具有与目前的 SDK 相近的客户端延迟 | | - -## 设计细节 - -与 CloudEvents 的 Java SDK 绑定(这与 Kafka 已经完成的工作类似,请在附录中的参考资料了解更多细节)是达成上述需求的一种简单方法。 - -### 可插拔协议 - -![可插拔协议](../../images/design-document/cloudevents-pluggable-protocols.png) - -### EventMesh 集成 CloudEvents 进度表 - -#### TCP - -##### SDK 端发布 - -- 在 `package` 首部中添加 CloudEvents 标识符 -- 使用 `CloudEventBuilder` 构造 CloudEvent,并将其放入 `package` 体中 - -##### SDK 端订阅 - -- 在 `ReceiveMsgHook` 接口下添加 `convert` 函数,其用于将 `package` 体转换为具有 `package` 首部标识符的特定协议 -- 不同协议应实现 `ReceiveMsgHook` 接口 - -##### 服务端发布 - -- 设计包含 `decodeMessage` 接口的协议转换 API,其可以把包体转换为 CloudEvent -- 更新 `MessageTransferTask` 下的 `Session.upstreamMsg()`,将入参 `Message` 改为 `CloudEvent`,这使用了 - 上一步的 `decodeMessage` API 来进行对 CloudEvent 的转换 -- 更新 `SessionSender.send()`,将入参 `Message` 改为 `CloudEvent` -- 更新 `MeshMQProducer` API,支持在运行时发送 `CloudEvents` -- 在 `connector-plugin` 中实现支持向 EventStore 中发送 `CloudEvents` - -##### 服务端订阅 - -- 支持将连接器插件中的 `RocketMessage` 改为 `CloudEvent -- 重写 `AsyncMessageListener.consume()` 函数,将入参 `Message` 改为 `CloudEvent` -- 更新 `MeshMQPushConsumer.updateOffset()`,将入参 `Message` 改为 `CloudEvent` -- 更新 `DownStreamMsgContext`,将入参 `Message` 改为 `CloudEvent`,更新 `DownStreamMsgContext.ackMsg` - -#### HTTP - -##### SDK 端发布 - -- 支持 `LiteProducer.publish(cloudEvent)` -- 在 http 请求头中添加 CloudEvents 标识符 - -##### SDK 端订阅 - -##### 服务端发布 - -- 支持根据 `HttpCommand` 首部中的协议类型,通过可插拔的协议插件构造 `HttpCommand.body` -- 支持在消息处理器中发布 CloudEvent - -##### 服务端订阅 - -- 更新 `EventMeshConsumer.subscribe()` -- 更新 `HandleMsgContext`, 将入参 `Message` 改为 `CloudEvent` -- 更新 `AsyncHttpPushRequest.tryHTTPRequest()` - -## 附录 - -### 参考资料 - -- diff --git a/docs/zh/desing-document/08-spi.md b/docs/zh/desing-document/08-spi.md deleted file mode 100644 index 5fb301f408..0000000000 --- a/docs/zh/desing-document/08-spi.md +++ /dev/null @@ -1,111 +0,0 @@ -# EventMesh SPI - -## 介绍 - -为了提高扩展性,EventMesh通过引入SPI(Service Provider Interface)机制,能够在运行时自动寻找扩展接口的具体实现类,动态加载。 -在EventMesh中,一切扩展点都利用SPI采用插件的实现方式,用户可以通过实现扩展接口,开发自定义的插件,在运行时通过简单的配置,声明式的选择所需要运行的插件。 - -## eventmesh-spi模块 - -SPI相关的代码位于eventmesh-spi模块下,其中主要包括EventMeshExtensionFactory, EventMeshSPI, ExtensionClassLoader这三个类。 - -### EventMeshSPI - -EventMeshSPI是SPI注解,所有需要采用SPI实现扩展的接口都需要使用@EventMeshSPI注解标记。 - -```java -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE}) -public @interface EventMeshSPI { - - /** - * If true, the spi instance is singleton - */ - boolean isSingleton() default false; - -} -``` - -这么做的原因是可以通过注解的方式声明接口为SPI扩展接口,提高代码的可读性。同时,@EventMeshSPI注解中包含一个isSingleton属性, -用来声明该扩展接口是否采用单例的实现方式,如果为true,那么该接口的实现类将会使用单例的实现方式,在一个JVM进程中全局唯一。 - -### EventMeshExtensionFactory - -EventMeshExtensionFactory是SPI实现类的获取工厂,包含一个静态方法`getExtension(Class extensionType, String extensionName)`, -接收扩展接口字节码对象和扩展实例名称,用于获取扩展接口的具体实现类。 - -```java -public enum EventMeshExtensionFactory { - ; - /** - * @param extensionType extension plugin class type - * @param extensionName extension instance name - * @param the type of the plugin - * @return plugin instance - */ - public static T getExtension(Class extensionType, String extensionName) { - } -} -``` - -所有需要获取扩展实现的地方都应该通过EventMeshExtensionFactory获取。 - -### ExtensionClassLoader - -ExtensionClassLoader是扩展接口实现类的加载接口,包含两个实现子类MetaInfExtensionClassLoader和JarExtensionClassLoader。 - -```java -/** - * Load extension class - *
    - *
  • {@link MetaInfExtensionClassLoader}
  • - *
  • {@link JarExtensionClassLoader}
  • - *
- */ -public interface ExtensionClassLoader { - - /** - * load - * - * @param extensionType extension type class - * @param extension type - * @return extension instance name to extension instance class - */ - Map> loadExtensionClass(Class extensionType); -} -``` - -MetaInfExtensionClassLoader用于从classPath直接加载实现类,JarExtensionClassLoader用于从配置目录下通过加载Jar包的方式加载实现类,未来可能还会提供通过从Maven仓库下加载实现类。 - -## SPI使用示例 - -下面以eventmesh-connector-plugin为例,介绍SPI具体的使用过程。 - -首先定义一个eventmesh-connector-api模块,并且定义扩展接口MeshMQProducer。在MeshMQProducer接口上使用@EventMeshSPI注解进行声明,表明该接口是一个SPI扩展接口 - -```java -@EventMeshSPI(isSingleton = false) -public interface MeshMQProducer extends Producer { -... -} -``` - -eventmesh-connector-rocketmq模块中包含采用rocketmq的具体实现方式RocketMQProducerImpl。 - -```java -public class RocketMQProducerImpl implements MeshMQProducer { -... -} -``` - -同时,还需要在eventmesh-connector-rocketmq模块中resource/META-INF/eventmesh目录下创建文件名为SPI接口全限定名的文件 -org.apache.eventmesh.api.producer.Producer - -文件内容为扩展实例名和对应的实例全类名 - -```properties -rocketmq=org.apache.eventmesh.connector.rocketmq.producer.RocketMQProducerImpl -``` - -至此,一个SPI扩展模块就完成了。在使用的时候只需要通过EventMeshExtensionFactory.getExtension(MeshMQProducer.class, “rocketmq”)就可以获取RocketMQProducerImpl实现类。 diff --git a/docs/zh/desing-document/_category_.json b/docs/zh/desing-document/_category_.json deleted file mode 100644 index 95b7eed067..0000000000 --- a/docs/zh/desing-document/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Documentation", - "collapsed": false -} diff --git a/docs/zh/desing-document/eventmesh-unit-test-rule.md b/docs/zh/desing-document/eventmesh-unit-test-rule.md deleted file mode 100644 index a346c835c8..0000000000 --- a/docs/zh/desing-document/eventmesh-unit-test-rule.md +++ /dev/null @@ -1,124 +0,0 @@ -# 单元测试准则 - -## 目录以及命名规则 - -+ 单元测试代码必须放在工程目录下:src/test/java - 测试的配置文件也必须放在: src/test/resources - 例: - 业务类: `src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java` - 对应被测试业务类: `src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java` - 测试配置文件: `src/test/resources/configuration.properties` - -+ 测试类所在的包名与被测试类所在的包名一致(如上所示) - -+ 测试类的命名规范: - 被测试(类、接口)名 + Test - 例: - 业务类名: `EventMeshUtil` - 对应被测试业务类名: `EventMeshUtilTest` - -+ 测试类用例命名规范: - test + 方法名, 使用test作为方法名的前缀 - 例: - 业务方法名: - ``` - public EventMeshMessage addProp(String key, String val) { - if (prop == null) { - prop = new HashMap<>(); - } - prop.put(key, val); - return this; - } - ``` - 对应被测试业务方法名: - ``` - public void testAddProp() { - EventMeshMessage message = createLiteMessage(); - message.addProp("key3", "value3"); - Assert.assertEquals(3L, message.getProp().size()); - Assert.assertEquals("value1", message.getProp("key1")); - } - ``` - -## 编码规范 - -+ 单元测试类中必须使用assert断言来进行验证, 不允许使用System.out, if判断验证来进行验证(可以使用log打印关键日志输出) -+ 增量代码要确保单元测试通过 -+ 单元测试要保证测试粒度足够小, 以助于精确定位问题, 一般都是方法级别 - 注:测试粒度小才能尽快定位到错误位置 -+ 保持单元测试之间的独立性, 为了保证单元测试稳定可靠且便于维护, 单元测试用例之间绝不能互相调用,也不能依赖执行的先后次序 -+ 单元测试必须可以重复执行的, 不受外界环境影响 - 注:单元测试通常放在持续集成中, 如果单个单元测试依赖外部环境, 那么很容易导致集成机制不可用 - -## 断言的使用 - -**所有的测试用例的结果验证都必须使用断言模式** - -### 常规断言 - -| 方法 | 说明 | 备注 | -| :-------------- | :---------------| ------------- | -| assertEquals | 判断两个对象或者两个原始类型是否相等 | | -| assertNotEquals | 判断两个对象或者两个原始类型是否不相等 | | -| assertTrue | 判断给定的布尔值是否为真 | | -| assertFalse | 判断给定的布尔值是否为假 | | -| assertNull | 判断给定的对象应用是否为空 | | -| assertNotNull | 判断给定的对象应用是否不为空 | | -| assertAll | 多个逻辑一起处理, 只要有一个报错, 整个测试就会失败 | | - -### 断言使用实例 - -+ assertEquals() -``` - configuration.init(); - Assert.assertEquals("value1", configuration.eventMeshEnv); -``` - -+ assertTrue() -``` - BaseResponseHeader header = BaseResponseHeader.buildHeader("200"); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); -``` - -+ assertFalse() -``` - Class nacosRegistryServiceClass = NacosRegistryService.class; - Field initStatus = nacosRegistryServiceClass.getDeclaredField("INIT_STATUS"); - initStatus.setAccessible(true); - Object initStatusField = initStatus.get(nacosRegistryService); - Assert.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); -``` - -+ assertNull() -``` - DefaultFullHttpResponse response = httpCommand.httpResponse(); - Assert.assertNull(response); -``` - -+ assertNotNull() -``` - Codec.Decoder cd = new Codec.Decoder(); - ArrayList result = new ArrayList<>(); - cd.decode(null, buf, result); - Assert.assertNotNull(result.get(0)); -``` - -+ 集合结果集中的每个对象都需要断言(以map为例) -``` - Map headerParam = new HashMap<>(); - headerParam.put(ProtocolKey.REQUEST_CODE, 200); - headerParam.put(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA); - headerParam.put(ProtocolKey.VERSION, "1.0"); - headerParam.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, "default cluster"); - headerParam.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, "127.0.0.1"); - headerParam.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, "DEV"); - headerParam.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, "IDC"); - header = PushMessageRequestHeader.buildHeader(headerParam); - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is(200)); - Assert.assertThat(header.toMap().get(ProtocolKey.LANGUAGE), is(Constants.LANGUAGE_JAVA)); - Assert.assertThat(header.toMap().get(ProtocolKey.VERSION), is(ProtocolVersion.V1)); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER), is("default cluster")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP), is("127.0.0.1")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV), is("DEV")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC), is("IDC")); -``` diff --git a/docs/zh/desing-document/https.md b/docs/zh/desing-document/https.md deleted file mode 100644 index a100ba3977..0000000000 --- a/docs/zh/desing-document/https.md +++ /dev/null @@ -1,32 +0,0 @@ -# HTTPS - -1.在eventmesh-runtime 中配置 - -``` -eventMesh.properties(添加如下配置) -eventMesh.server.useTls.enabled=true //默认值 false - - -config env varible --Dssl.server.protocol=TLSv1.1 //默认值 TLSv1.1 --Dssl.server.cer=sChat2.jks //把文件放到启动脚本start.sh 指定的conPath目录下 --Dssl.server.pass=sNetty -``` - -2.在eventmesh-sdk-java 中配置 - -``` -//创建producer -LiteClientConfig eventMeshHttpClientConfig = new eventMeshHttpClientConfig(); -... - -//设置开启TLS -eventMeshHttpClientConfig.setUseTls(true); -LiteProducer producer = new LiteProducer(eventMeshHttpClientConfig); - - -//配置环境变量 --Dssl.client.protocol=TLSv1.1 //默认值 TLSv1.1 --Dssl.client.cer=sChat2.jks //把文件放到应用指定的conPath目录下 --Dssl.client.pass=sNetty -``` diff --git a/docs/zh/desing-document/webhook.md b/docs/zh/desing-document/webhook.md deleted file mode 100644 index 617a602b05..0000000000 --- a/docs/zh/desing-document/webhook.md +++ /dev/null @@ -1,268 +0,0 @@ - - -## webhook使用流程 -#### 第一步:在eventmesh配置webhook相关信息并且启动 - -##### 配置说明 -``` -# 是否启动webhook admin服务 -eventMesh.webHook.admin.start=true - -# webhook事件配置存储模式。目前只支持file与nacos -eventMesh.webHook.operationMode=file -# 文件存储模式的文件存放路径,如果写上#{eventMeshHome},在eventMesh根目录 -eventMesh.webHook.fileMode.filePath= #{eventMeshHome}/webhook - -# nacos存储模式,配置命名规则是eventMesh.webHook.nacosMode.{nacos 原生配置key} 具体的配置请看 [nacos github api](https://github.com/alibaba/nacos/blob/develop/api/src/main/java/com/alibaba/nacos/api/SystemPropertyKeyConst.java) -## nacos的地址 -eventMesh.webHook.nacosMode.serverAddr=127.0.0.1:8848 - -# webhook eventcloud 发送模式。与eventMesh.connector.plugin.type 配置一样 -eventMesh.webHook.producer.connector=standalone -``` - -#### 第二步:添加webhook配置信息 -配置信息说明 -```java - /** - * 厂商调用的path。厂商事件调用地址、 [http or https ]://[域名 or IP 【厂商可以被调用】]:[端口]/webhook/[callbackPath] - * 比如:http://127.0.0.1:10504/webhook/test/event 需要把全完url填入厂商调用输入中 - * callbackPath 是唯一 - * manufacturer callback path - */ - private String callbackPath; - - /** - * 厂商的名字 - * manufacturer name ,like github - */ - private String manufacturerName; - - /** - * 厂商的事件名 - * webhook event name ,like rep-push - */ - private String manufacturerEventName; - - /** - * - * http header content type - */ - private String contentType = "application/json"; - - /** - * 说明 - * description of this WebHookConfig - */ - private String description; - - /** - * 有一些厂商使用验签方式, - * secret key ,for authentication - */ - private String secret; - - /** - * 有一些厂商使用验签方式,使用账户密码方式 - * userName ,for HTTP authentication - */ - private String userName; - - /** - * 有一些厂商使用验签方式,使用账户密码方式 - * password ,for HTTP authentication - */ - private String password; - - - - /** - * 事件发送到那个topic - * roll out event name ,like topic to mq - */ - private String cloudEventName; - - /** - * roll out data format -> CloudEvent serialization mode - * If HTTP protocol is used, the request header contentType needs to be marked - */ - private String dataContentType = "application/json";; - - /** - * source of event - */ - private String cloudEventSource; - - /** - * cloudEvent事件对象唯一标识符识别方式,uuid或者manufacturerEventId(厂商id) - * id of cloudEvent ,like uuid/manufacturerEventId - */ - private String cloudEventIdGenerateMode; - -``` - -##### 添加接口 -路径: /webhook/insertWebHookConfig -方法: POST -contentType: application/json - -输入参数: -| 字段 | 说明 | 类型 | 必须 | 默认值 | -| -- | -- | -- | -- | -- | -| callbackPath | 调用地址,唯一地址 | string | 是 | null | -| manufacturerName | 厂商名 | string | 是 | null | -| manufacturerEventName | 厂商事件名 | string | 是 | null | -| contentType | http connettype | string | 否 | application/json | -| description | 配置说明 | string | 否 | null | -| secret | 验签密钥 | string | 否 | null | -| userName | 用户名 | string | 否 | null | -| password | 用户密码 | string | 否 | null | -| cloudEventName | 事件名() | string | 是 | null | -| cloudEventSource | 事件来源可以填写 | string | 是 | null | -| cloudEventIdGenerateMode | cloudEvent事件对象唯一标识符识别方式,uuid或者manufacturerEventId(厂商id) | string | 否 | manufacturerEventId | - -列子: -```json - -{ - "callbackPath":"/webhook/github/eventmesh/all", - "manufacturerName":"github", - "manufacturerEventName":"all", - "secret":"eventmesh", - "cloudEventName":"github-eventmesh", - "cloudEventSource":"github" -} - -``` -输出参数:1 成功,0失败 - -##### 删除接口 -路径: /webhook/deleteWebHookConfig -方法: POST -contentType: application/json - -输入参数: -| 字段 | 说明 | 类型 | 必须 | 默认值 | -| -- | -- | -- | -- | -- | -| callbackPath | 调用地址,唯一地址 | string | 是 | null | - - -列子: - -```json - -{ - "callbackPath":"/webhook/github/eventmesh/all" -} - -``` - - -输出参数:1 成功,0失败 - -##### 通过callbackPath查询WebHookConfig -路径: /webhook/queryWebHookConfigById -方法: POST -contentType: application/json - -输入参数: -| 字段 | 说明 | 类型 | 必须 | 默认值 | -| -- | -- | -- | -- | -- | -| callbackPath | 调用地址,唯一地址 | string | 是 | null | - - -列子: - -```json - -{ - "callbackPath":"/webhook/github/eventmesh/all" -} - -``` - - -输出参数: -| 字段 | 说明 | 类型 | 必须 | 默认值 | -| -- | -- | -- | -- | -- | -| callbackPath | 调用地址,唯一地址 | string | 是 | null | -| manufacturerName | 厂商名 | string | 是 | null | -| manufacturerEventName | 厂商事件名 | string | 是 | null | -| contentType | http connettype | string | 否 | application/json | -| description | 配置说明 | string | 否 | null | -| secret | 验签密钥 | string | 否 | null | -| userName | 用户名 | string | 否 | null | -| password | 用户密码 | string | 否 | null | -| cloudEventName | 事件名() | string | 是 | null | -| cloudEventSource | 事件来源可以填写 | string | 是 | null | -| cloudEventIdGenerateMode | cloudEvent事件对象唯一标识符识别方式,uuid或者manufacturerEventId(厂商id) | string | 否 | manufacturerEventId | - - -##### 通过manufacturer查询WebHookConfig列表 -路径: /webhook/queryWebHookConfigByManufacturer -方法: POST -contentType: application/json - -输入参数: -| 字段 | 说明 | 类型 | 必须 | 默认值 | -| -- | -- | -- | -- | -- | -| manufacturerName | 厂商名 | string | 是 | null | - - -列子: - -```json - -{ - "manufacturerName":"github" -} - -``` - - -输出参数: -| 字段 | 说明 | 类型 | 必须 | 默认值 | -| -- | -- | -- | -- | -- | -| callbackPath | 调用地址,唯一地址 | string | 是 | null | -| manufacturerName | 厂商名 | string | 是 | null | -| manufacturerEventName | 厂商事件名 | string | 是 | null | -| contentType | http connettype | string | 否 | application/json | -| description | 配置说明 | string | 否 | null | -| secret | 验签密钥 | string | 否 | null | -| userName | 用户名 | string | 否 | null | -| password | 用户密码 | string | 否 | null | -| cloudEventName | 事件名() | string | 是 | null | -| cloudEventSource | 事件来源可以填写 | string | 是 | null | -| cloudEventIdGenerateMode | cloudEvent事件对象唯一标识符识别方式,uuid或者manufacturerEventId(厂商id) | string | 否 | manufacturerEventId | - - -#### 第三步:查看配置是否成功 -1. file存储模式。请到eventMesh.webHook.fileMode.filePath 目录下查看。文件名为callbackPath转移后的 -2. nacos存储模式。请到eventMesh.webHook.nacosMode.serverAddr 配置的nacos服务去看 - -#### 第四步:配置cloudevent的消费者 - - -#### 第五步:在厂商配置webhook相关信息 -> 厂商操作请看【厂商webhook操作说明】 - - -## 厂商webhook操作说明 -### github 注册 -#### 第一步:进入对应的项目 -#### 第二步:点击setting -![](../images/features/webhook/webhook-github-setting.png) -#### 第三步:点击Webhooks -![](../images/features/webhook/webhook-github-webhooks.png) -#### 第四步:点击 Add webhook -![](../images/features/webhook/webhook-github-add.png) -#### 第五步: 填写webhook信息 -![](../images/features/webhook/webhook-github-info.png) - -Payload URL: 服务地址以及pahts。[http or https ]://[域名 or IP 【厂商可以被调用】]:[端口]/webhook/[callbackPath] -Content type:http header content type -secret: 验签字符串 - - - - diff --git a/docs/zh/instruction/00-eclipse.md b/docs/zh/instruction/00-eclipse.md deleted file mode 100644 index 27ded49524..0000000000 --- a/docs/zh/instruction/00-eclipse.md +++ /dev/null @@ -1,33 +0,0 @@ -# eventMesh 导入Eclipse 快速入门说明 - -### 依赖 - -``` -64位JDK 1.8+; -Gradle至少为7.0, 推荐 7.0.* -eclipse 已安装gradle插件或者eclipse自带gradle插件 -``` - -### 下载源码 -git init - -git clone https://github.com/apache/incubator-eventmesh.git - -### 项目编译eclipse环境 - -打开命令行终端,运行gradlew cleanEclipse eclipse - -### 配置修改 -修改工程名称和settings.gradle 配置文件参数rootProject.name 参数一致 - -### 修改eclipse.init配置文件,配置lombok以1.18.8版本为例 --javaagent:lombok-1.18.8.jar --XBootclasspath/a:lombok-1.18.8.jar - -### 202106版本eclipse,eclipse.init增加配置参数 ---illegal-access=permit - - -### 导入gradle -打开eclipse,导入gradle项目到IDE里 - diff --git a/docs/zh/instruction/01-store-with-docker.md b/docs/zh/instruction/01-store-with-docker.md deleted file mode 100644 index cd3fc1ad69..0000000000 --- a/docs/zh/instruction/01-store-with-docker.md +++ /dev/null @@ -1,40 +0,0 @@ -# eventmesh-store 快速入门说明 - -## 依赖 - -``` -建议使用64位操作系统,建议使用Linux/Unix; -64位JDK 1.8+; -Gradle至少为7.0, 推荐7.0.* -4g+可用磁盘用于eventmesh-store服务器 -eventmesh在非standalone模式下,依赖RocketMQ作为存储层;若采用standalone模式,则可跳过该步,直接进行runtime的部署 -``` - -## 部署 -在命令行输入如下命令直接从 docker hub 上获取 RocketMQ 镜像: - -```shell -#获取 namesrv 镜像 -sudo docker pull rocketmqinc/rocketmq-namesrv:4.5.0-alpine -#获取 broker 镜像 -sudo docker pull rocketmqinc/rocketmq-broker:4.5.0-alpine -``` - -在命令行输入以下命令运行namerv容器和broker容器 - -```shell -#运行 namerv 容器 -sudo docker run -d -p 9876:9876 -v `pwd`/data/namesrv/logs:/root/logs -v `pwd`/data/namesrv/store:/root/store --name rmqnamesrv rocketmqinc/rocketmq-namesrv:4.5.0-alpine sh mqnamesrv - -#运行 broker 容器 -sudo docker run -d -p 10911:10911 -p 10909:10909 -v `pwd`/data/broker/logs:/root/logs -v `pwd`/data/broker/store:/root/store --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" rocketmqinc/rocketmq-broker:4.5.0-alpine sh mqbroker -c ../conf/broker.conf -``` - -请注意 **rocketmq-broker ip** 是 **pod ip**, 如果你想修改这个ip, 可以通过挂载容器中 **broker.conf** 文件的方式并修改文件中的 **brokerIP1** 配置项为自定义值 - - -至此eventmesh-store的部署已完成,请转至下一步完成eventmesh-runtime的部署 - - -## 参考 -关于RocketMQ的其他更多资料,请参考 diff --git a/docs/zh/instruction/01-store.md b/docs/zh/instruction/01-store.md deleted file mode 100644 index d8b5599f04..0000000000 --- a/docs/zh/instruction/01-store.md +++ /dev/null @@ -1,51 +0,0 @@ -# eventmesh-store 快速入门说明 - -## 依赖 - -``` -建议使用64位操作系统,建议使用Linux/Unix; -64位JDK 1.8+; -Gradle至少为7.0, 推荐7.0.* -4g+可用磁盘用于eventmesh-store服务器 -eventmesh在非standalone模式下,依赖RocketMQ作为存储层;若采用standalone模式,则可跳过该步,直接进行runtime的部署 -``` - - -## 下载 - -从[RocketMQ官方网站](https://rocketmq.apache.org/dowloading/releases/) 下载Binary代码(推荐使用4.9.*版本),这里以4.9.2为例 - -``` -unzip rocketmq-all-4.9.2-bin-release.zip -cd rocketmq-4.9.2/ -``` - - -## 部署 - -- #### 启动Name Server - -``` -nohup sh bin/mqnamesrv & -tail -f ~/logs/rocketmqlogs/namesrv.log -``` - -如果在看到The Name Server boot success...,则说明Name Server启动成功 - -- #### 启动Broker - -``` -nohup sh bin/mqbroker -n localhost:9876 & -tail -f ~/logs/rocketmqlogs/broker.log -``` - -如果在看到The broker boot success...,则说明Broker启动成功 - -至此eventmesh-store的部署已完成,请转至下一步完成eventmesh-runtime的部署 - - -## 参考 -关于RocketMQ的其他更多资料,请参考 - - - diff --git a/docs/zh/instruction/02-runtime-with-docker.md b/docs/zh/instruction/02-runtime-with-docker.md deleted file mode 100644 index 640bd59376..0000000000 --- a/docs/zh/instruction/02-runtime-with-docker.md +++ /dev/null @@ -1,149 +0,0 @@ -# 使用 Docker 快速入门 EventMesh(暂时只支持到1.4.0版本) - -本篇快速入门将详细介绍使用 docker 部署 EventMesh,以 RocketMQ 作为对接的中间件。 - -可选语言: [英文版本](../../en/instructions/eventmesh-runtime-quickstart-with-docker.md),[中文版本](02-runtime-with-docker.md)。 - -## 前提 - -1. 建议使用64位的 linux 系统; -2. 请预先安装 Docker Engine。 Docker 的安装过程可以参考 [docker 官方文档](https://docs.docker.com/engine/install/); -3. 建议掌握基础的 docker 概念和命令行,例如注册中心、挂载等等。不过这不是必须的,因为本次操作所需的命令都已为您列出; -4. 若您选择非standalone模式,请确保 [RocketMQ 已成功启动](https://rocketmq.apache.org/docs/quick-start/) 并且可以使用 ip 地址访问到;若您选择standalone模式,则无需启动 RocketMQ 。 - -## 获取 EventMesh 镜像 - -首先,你可以打开一个命令行,并且使用下面的 ```pull``` 命令从 [Docker Hub](https://registry.hub.docker.com/r/eventmesh/eventmesh/tags) 中下载[最新发布的 EventMesh](https://eventmesh.apache.org/events/release-notes/v1.3.0/) 。 - -```shell -sudo docker pull eventmesh/eventmesh:v1.4.0 -``` - -您可以使用以下命令列出并查看本地已有的镜像。 - -```shell -sudo docker images -``` - -如果终端显示如下所示的镜像信息,则说明 EventMesh 镜像已经成功下载到本地。 - -```shell -REPOSITORY TAG IMAGE ID CREATED SIZE -eventmesh/eventmesh v1.4.0 6e2964599c78 3 months ago 936.73 MB -``` - -## 创建配置文件 - -在根据 EventMesh 镜像运行对应容器之前,你需要创建两个配置文件,分别是:```eventMesh.properties``` 和 ```rocketmq-client.properties```。 - -首先,你需要使用下面的命令创建这两个文件。 - -```shell -sudo mkdir -p /data/eventmesh/rocketmq/conf -cd /data/eventmesh/rocketmq/conf -sudo touch eventmesh.properties -sudo touch rocketmq-client.properties -``` - -### 配置 eventMesh.properties - -这个配置文件中包含 EventMesh 运行时环境和集成进来的其他插件所需的参数。 - -使用下面的 ```vim``` 命令编辑 ```eventmesh.properties```。 - -```shell -sudo vim eventmesh.properties -``` - -你可以直接将 GitHub 仓库中的对应配置文件中的内容复制过来,链接为: 。 - -请检查配置文件里的默认端口是否已被占用,如果被占用请修改成未被占用的端口: - -| 属性 | 默认值 | 备注 | -|----------------------------|-------|----------------------------| -| eventMesh.server.http.port | 10105 | EventMesh http server port | -| eventMesh.server.tcp.port | 10000 | EventMesh tcp server port | -| eventMesh.server.grpc.port | 10205 | EventMesh grpc server port | - -### 配置 rocketmq-client.properties - -这个配置文件中包含 RocketMQ nameserver 的信息。 - -使用下面的 ```vim``` 命令编辑 ```rocketmq-client.properties```。 - -```shell -sudo vim rocketmq-client.properties -``` - -你可以直接将 GitHub 仓库中的对应配置文件中的内容复制过来,链接为: 。请注意,如果您正在运行的 namesetver 地址不是配置文件中的默认值,请将其修改为实际正在运行的nameserver地址。 - -请检查配置文件里的默认namesrvAddr是否已被占用,如果被占用请修改成未被占用的地址: - -| 属性 | 默认值 | 备注 | -|---------------------------------------|-------------------------------|----------------------------------| -| eventMesh.server.rocketmq.namesrvAddr | 127.0.0.1:9876;127.0.0.1:9876 | RocketMQ namesrv default address | - -## 运行 EventMesh - -现在你就可以开始根据下载好的 EventMesh 镜像运行容器了。 - -使用到的命令是 ```docker run```,有以下两点内容需要格外注意。 - -1. 绑定容器端口和宿主机端口:使用 ```docker run``` 的 ```-p``` 选项。 -2. 将宿主机中的两份配置文件挂在到容器中:使用 ```docker run``` 的 ```-v``` 选项。 - -综合一下,对应的启动命令为: - -```shell -sudo docker run -d \ - -p 10000:10000 -p 10105:10105 \ - -v /data/eventmesh/rocketmq/conf/eventMesh.properties:/data/app/eventmesh/conf/eventMesh.properties \ - -v /data/eventmesh/rocketmq/conf/rocketmq-client.properties:/data/app/eventmesh/conf/rocketmq-client.properties \ - eventmesh/eventmesh:v1.4.0 -``` - -如果运行命令之后看到新输出一行字符串,那么运行 EventMesh 镜像的容器就启动成功了。 - -接下来,你可以使用下面的命令查看容器的状态。 - -```shell -sudo docker ps -``` - -如果成功的话,你会看到终端打印出了如下所示容器的信息,其中就有运行 EventMesh 镜像的容器。 - -```shell -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -d1e1a335d4a9 eventmesh/eventmesh:v1.4.0 "/bin/sh -c 'sh star…" About a minute ago Up About a minute 0.0.0.0:10000->10000/tcp, :::10000->10000/tcp, 0.0.0.0:10105->10105/tcp, :::10105->10105/tcp focused_bartik -``` - -从这个信息中可以看出,```container id``` 是 ```d1e1a335d4a9```,```name``` 是 ```focused_bartik```,它们都可以用来唯一标识这个容器。**注意**:在你的电脑中,它们的值可能跟这里的不同。 - -## 管理 EventMesh 容器 - -在成功的运行了 EventMesh 容器后,你可以通过进入容器、查看日志、删除容器等方式管理容器。 - -**进入容器** 命令示例: - -```shell -sudo docker exec -it [your container id or name] /bin/bash -``` - -在容器中 **查看日志** 命令示例: - -```shell -cd ../logs -tail -f eventmesh.out -``` - -**删除容器** 命令示例: - -```shell -sudo docker rm -f [your container id or name] -``` - -## 探索更多 - -现在 EventMesh 已经通过容器运行了,你可以参考 [```eventmesh-examples``` 模块](https://github.com/apache/incubator-eventmesh/tree/master/eventmesh-examples) 编写并测试自己的代码了。 - -希望你享受这个过程并获得更多收获! diff --git a/docs/zh/instruction/02-runtime.md b/docs/zh/instruction/02-runtime.md deleted file mode 100644 index 845f1ccf63..0000000000 --- a/docs/zh/instruction/02-runtime.md +++ /dev/null @@ -1,114 +0,0 @@ -# Eventmesh-runtime 快速入门说明 - - -## 1 本地构建运行 - -### 1.1 依赖 - -``` -建议使用64位操作系统,建议使用Linux / Unix; -64位JDK 1.8+; -Gradle至少为7.0, 推荐 7.0.* -``` - -### 1.2 下载源码 - -在 [EventMesh download](https://eventmesh.apache.org/download) 页面选择1.5.0版本的 Source Code 进行下载并解压, 您将获得**apache-eventmesh-1.5.0-incubating-src** - - -### 1.3 本地启动 - -**1.3.1 项目结构说明:** - -- eventmesh-common : eventmesh公共类与方法模块 -- eventmesh-connector-api : eventmesh connector插件接口定义模块 -- eventmesh-connector-plugin : eventmesh connector插件模块 -- eventmesh-runtime : eventmesh运行时模块 -- eventmesh-sdk-java : eventmesh java客户端sdk -- eventmesh-starter : eventmesh本地启动运行项目入口 -- eventmesh-spi : eventmesh SPI加载模块 - -> 注:插件模块遵循 eventmesh 定义的SPI规范, 自定义的SPI接口需要使用注解 @EventMeshSPI 标识. -> 插件实例需要在对应模块中的 /main/resources/META-INF/eventmesh 下配置相关接口与实现类的映射文件,文件名为SPI接口全类名. -> 文件内容为插件实例名到插件实例的映射, 具体可以参考 eventmesh-connector-rocketmq 插件模块 - -**1.3.2 插件说明** - -***1.3.2.1 安装插件*** - -有两种方式安装插件 - -- classpath加载:本地开发可以通过在 eventmesh-starter 模块 build.gradle 中进行声明,例如声明使用 rocketmq 插件 - -```gradle - implementation project(":eventmesh-connector-plugin:eventmesh-connector-rocketmq") -``` - -- 文件加载:通过将插件安装到插件目录,EventMesh 在运行时会根据条件自动加载插件目录下的插件,可以通过执行以下命令安装插件 - -```shell -./gradlew clean jar dist && ./gradlew installPlugin -``` - -***1.3.2.2 使用插件*** - -EventMesh 会默认加载 dist/plugin 目录下的插件,可以通过`-DeventMeshPluginDir=your_plugin_directory`来改变插件目录。运行时需要使用的插件实例可以在 -`confPath`目录下面的`eventmesh.properties`中进行配置。例如通过以下设置声明在运行时使用rocketmq插件。 - -```properties -#connector plugin -eventMesh.connector.plugin.type=rocketmq -``` - -**1.3.3 配置VM启动参数** - -```properties --Dlog4j.configurationFile=eventmesh-runtime/conf/log4j2.xml --Deventmesh.log.home=eventmesh-runtime/logs --Deventmesh.home=eventmesh-runtime --DconfPath=eventmesh-runtime/conf -``` - -> 注:如果操作系统为Windows, 可能需要将文件分隔符换成\ - -**1.3.4 启动运行** - -``` -运行org.apache.eventmesh.starter.StartUp的主要方法 -``` - -## 2 远程部署 - -### 2.1 依赖 - -``` -建议使用64位操作系统,建议使用Linux / Unix; -64位JDK 1.8+; -Gradle至少为7.0, 推荐 7.0.* -``` - -### 2.2 下载 - -在 [EventMesh download](https://eventmesh.apache.org/download) 页面选择1.5.0版本的 Binary Distribution 进行下载, 您将获得**apache-eventmesh-1.5.0-incubating-bin.tar.gz** - - -### 2.3 部署 - -- 部署eventmesh-runtime - -```$ xslt -# 解压 apache-eventmesh-1.5.0-incubating-bin.tar.gz -tar -zxvf apache-eventmesh-1.5.0-incubating-bin.tar.gz -cd apache-eventmesh-1.5.0-incubating - -# 配置 eventMesh.properties -vim conf/eventMesh.properties - -# 启动EventMesh -cd bin -sh start.sh -``` - -如果看到"EventMeshTCPServer[port=10000] started....",则说明设置成功。 - - diff --git a/docs/zh/instruction/03-demo.md b/docs/zh/instruction/03-demo.md deleted file mode 100644 index 5a18196660..0000000000 --- a/docs/zh/instruction/03-demo.md +++ /dev/null @@ -1,178 +0,0 @@ -# 运行 eventmesh-sdk-java demo - -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java) - -> EventMesh-sdk-java作为客户端,与eventmesh-runtime通信,用于完成消息的发送和接收。 -> -> EventMesh-sdk-java支持异步消息和广播消息。异步消息表示生产者只发送消息,不关心回复消息。广播消息表示生产者发送一次消息,所有订阅广播主题的消费者都将收到消息 -> -> EventMesh-sdk-java支持HTTP,TCP 和 GRPC 协议。 - -TCP, HTTP 和 GRPC 示例都在**eventmesh-examples**模块下 - -### 1. TCP DEMO - -

异步消息

- -- 创建主题TEST-TOPIC-TCP-ASYNC,可以通过 rocketmq-console 或者 rocketmq tools 命令 - -- 启动消费者,订阅上一步骤已经创建的Topic - -``` -运行 org.apache.eventmesh.tcp.demo.sub.eventmeshmessage.AsyncSubscribe 的main方法 -``` - -- 启动发送端,发送消息 - -``` -运行 org.apache.eventmesh.tcp.demo.pub.eventmeshmessage.AsyncPublish 的main方法 -``` - -

广播消息

- -- 创建主题TEST-TOPIC-TCP-BROADCAST,可以通过 rocketmq-console 或者 rocketmq tools 命令 - -- 启动消费端,订阅上一步骤已经创建的Topic - -``` -运行 org.apache.eventmesh.tcp.demo.sub.eventmeshmessage.AsyncSubscribeBroadcast 的main方法 -``` - -- 启动发送端,发送广播消息 - -``` -运行 org.apache.eventmesh.tcp.demo.pub.eventmeshmessage.AsyncPublishBroadcast 的main方法 -``` - -更多关于TCP部分的内容,请参考 [EventMesh TCP](docs/zh/sdk-java/03-tcp.md) - -### 2. HTTP演示 - -> 对于HTTP,eventmesh-sdk-java对对于异步事件实现了发送与订阅 -> ->在演示中,Java类`LiteMessage`的`content`字段表示一个特殊的协议,因此,如果您要使用eventmesh-sdk-java的http-client,则只需设计协议的内容并在同一时间提供消费者的应用程序。 - -

异步事件

- -> 生产者将事件发送给下游即可,无需等待响应 - -- 创建主题TEST-TOPIC-HTTP-ASYNC,可以通过rocketmq-console或者rocketmq tools 命令 - -- 启动消费端,订阅Topic - - 异步事件消费端为spring boot demo,运行demo即可启动服务并完成Topic订阅 - -``` -运行 org.apache.eventmesh.http.demo.sub.SpringBootDemoApplication 的main方法 -``` - -- 启动发送端,发送消息 - -``` -运行 org.apache.eventmesh.http.demo.pub.eventmeshmessage.AsyncPublishInstance 的main方法 -``` -更多关于HTTP部分的内容,请参考 [EventMesh HTTP](docs/zh/sdk-java/02-http.md) - -### 3. GRPC 演示 - -> eventmesh-sdk-java 实现了 gRPC 协议. 它能异步和同步发送事件到 eventmesh-runtime. -> 它可以通过webhook和事件流方式订阅消费事件, 同时也支持 CNCF CloudEvents 协议. - -

异步事件发送 和 webhook订阅

- -> Async生产者 异步发送事件到 eventmesh-runtime, 不需要等待事件储存到 `event-store` -> 在webhook 消费者, 事件推送到消费者的http endpoint url。这个URL在消费者的 `Subscription` 模型定于. 这方法跟前面的Http eventmsh client类似。 - -- 在rocketmq 创建主题 TEST-TOPIC-GRPC-ASYNC -- 启动 publisher 发送事件 - -``` -运行 org.apache.eventmesh.grpc.pub.eventmeshmessage.AsyncPublishInstance 的main方法 -``` - -- 启动 webhook 消费者 - -``` -运行 org.apache.eventmesh.grpc.sub.app.SpringBootDemoApplication 的main方法 -``` - -

同步事件发送和事件流订阅

- -> 同步生产者 发送事件到 eventmesh-runtime, 同时等待事件储存到 `event-store` -> 在事件流消费者,事件以流的形式推送到 `ReceiveMsgHook` 客户端。 这方法类似 eventmesh client. - -- 在rocketmq 创建主题 TEST-TOPIC-GRPC-RR -- 启动 Request-Reply publisher 发送事件 - -``` -运行 org.apache.eventmesh.grpc.pub.eventmeshmessage.RequestReplyInstance 的main方法 -``` - -- 启动 stream subscriber - -``` -运行 org.apache.eventmesh.grpc.sub.EventmeshAsyncSubscribe 的main方法 -``` - -

批量事件发布

- -> 批量发布多个事件到 eventmesh-runtime. 这是异步操作 - -- 在rocketmq 创建主题 TEST-TOPIC-GRPC-ASYNC -- 启动 publisher 来批量发布事件 - -``` -运行 org.apache.eventmesh.grpc.pub.eventmeshmessage.BatchPublishInstance 的main方法 -``` - -更多关于 gRPC 部分的内容,请参考 [EventMesh gRPC](docs/zh/sdk-java/04-grpc.md) - -### 3.4 测试 - -请参考[EventMesh Store](docs/zh/instruction/01-store.md) 和 [EventMesh Runtime](docs/zh/instruction/02-runtime.md) 完成运行环境的部署 - -完成 store 和 runtime 的部署后,就可以在 eventmesh-examples 模块下运行我们的 demo 来体验 eventmesh 了: - - TCP Sub - - ```shell - cd bin - sh tcp_eventmeshmessage_sub.sh - ``` - - TCP Pub - - ```shell - cd bin - sh tcp_pub_eventmeshmessage.sh - ``` - - TCP Sub Broadcast - - ```shell - cd bin - sh tcp_sub_eventmeshmessage_broadcast.sh - ``` - - TCP Pub Broadcast - - ```shell - cd bin - sh tcp_pub_eventmeshmessage_broadcast.sh - ``` - - HTTP Sub - - ```shell - cd bin - sh http_sub.sh - ``` - - HTTP Pub - - ```shell - cd bin - sh http_pub_eventmeshmessage.sh - ``` - - 之后, 你可以在 `/logs` 目录下面看到不同模式的运行日志 diff --git a/docs/zh/instruction/_category_.json b/docs/zh/instruction/_category_.json deleted file mode 100644 index 06fd721fbd..0000000000 --- a/docs/zh/instruction/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Instructions", - "collapsed": false -} diff --git a/docs/zh/introduction.md b/docs/zh/introduction.md deleted file mode 100644 index 43c821dd61..0000000000 --- a/docs/zh/introduction.md +++ /dev/null @@ -1,49 +0,0 @@ -# Apache EventMesh (Incubating) - -[![CI status](https://github.com/apache/incubator-eventmesh/actions/workflows/ci.yml/badge.svg)](https://github.com/apache/incubator-eventmesh/actions/workflows/ci.yml) -[![CodeCov](https://codecov.io/gh/apache/incubator-eventmesh/branch/develop/graph/badge.svg)](https://codecov.io/gh/apache/incubator-eventmesh) -[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/apache/incubator-eventmesh/context:java) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/apache/incubator-eventmesh.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/apache/incubator-eventmesh/alerts/) -[![GitHub release](https://img.shields.io/badge/release-download-orange.svg)](https://github.com/apache/incubator-eventmesh/releases) -[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) - -## 什么是Event Mesh? - -EventMesh是一个动态的云原生事件驱动架构基础设施,用于分离应用程序和后端中间件层,它支持广泛的用例,包括复杂的混合云、使用了不同技术栈的分布式架构。 - -![architecture1](../images/eventmesh-define.png) - -**EventMesh架构:** - -![architecture1](../images/eventmesh-runtime.png) - -**EventMesh云原生结构:** - -![architecture2](../images/eventmesh-panels.png) - -Event Mesh允许将来自一个应用程序的事件动态路由到任何其他应用程序. Event Mesh的一般功能: - -* 事件驱动; -* 事件治理; -* 动态路由; -* 云原生 - -部件: - -* eventmesh-runtime:一种中间件,用于在事件生产者和消费者之间传输事件,支持云原生应用程序和微服务 -* eventmesh-sdk-java:当前支持HTTP、HHTTP、TCP和 [gRPC](https://grpc.io) 协议 - - -## 快速开始 - -1. 构建并部署 event-store(RocketMQ), 请参见[说明](instruction/01-store.md) -2. 构建并部署 eventmesh-runtime,请参见[说明](instruction/02-runtime.md) -3. 运行 eventmesh-sdk-java 演示,请参见[说明](instruction/03-demo.md) - -## 贡献 - -永远欢迎参与共建, 请参阅[贡献](../../03-new-contributor-guidelines.md)了解详细指南 - -您可以从发现和解决问题开始~ -[GitHub Issues](https://github.com/apache/incubator-eventmesh/issues) - diff --git a/docs/zh/metrics-tracing/01-prometheus.md b/docs/zh/metrics-tracing/01-prometheus.md deleted file mode 100644 index 067cd00abf..0000000000 --- a/docs/zh/metrics-tracing/01-prometheus.md +++ /dev/null @@ -1,46 +0,0 @@ -# 通过 Prometheus 观察 Metrics - -## 下载 Prometheus - -官网:https://prometheus.io/ - -本地下载Prometheus:https://prometheus.io/download/ - -选择自己电脑对应的版本下载并解压缩 - -![Prometheus-download](../../images/Prometheus-download.png) - -### 2、在prometheus.yml中添加配置 - -如果你是Prometheus的新手,可以直接复制eventmesh-runtime/conf/prometheus.yml替换 - -例如:这是win-64的下载后的样子: - -![prometheus-yml](../../images/prometheus-yml.png) - -替换红框中的文件 - -如果你十分了解Prometheus,可以自行配置,eventmesh默认的导出的端口为19090。 - -ps:如果需要更换端口的话,请修改eventmesh-runtime/conf/eventmesh.properties中的 - -```properties -#prometheusPort -eventMesh.metrics.prometheus.port=19090 -``` - -## 运行 Prometheus 和 EventMesh - -双击Prometheus.exe运行 - -运行eventmesh-starter(参考[eventmesh-runtime-quickstart](eventmesh-runtime-quickstart.md)) - -运行eventmesh-example(参考[eventmesh-sdk-java-quickstart](eventmesh-sdk-java-quickstart.md)) - -打开浏览器访问:http://localhost:9090/ - -### 输入想观察的 Metrics - -输入’**eventmesh_**‘ 就会出现相关的指标的提示 - -![promethus-search](../../images/promethus-search.png) diff --git a/docs/zh/metrics-tracing/02-zipkin.md b/docs/zh/metrics-tracing/02-zipkin.md deleted file mode 100644 index 913ee056cc..0000000000 --- a/docs/zh/metrics-tracing/02-zipkin.md +++ /dev/null @@ -1,49 +0,0 @@ -# 通过 Zipkin 观察 Trace - -### 1、下载和运行Zipkin - -请参考https://zipkin.io/pages/quickstart.html - - - -### 2、运行eventmesh - -运行eventmesh-starter(参考[eventmesh-runtime-quickstart](eventmesh-runtime-quickstart.md)) - -运行eventmesh-example(参考[eventmesh-sdk-java-quickstart](eventmesh-sdk-java-quickstart.md)) - - - -### 3、相关的设置 - -eventmesh-runtime/conf/eventmesh.properties中: - -默认的exporter是log,需要手动改成Zipkin - -```properties -#trace exporter -eventmesh.trace.exporter.type=Zipkin -``` -下面是关于Zipkin的各种配置 -```properties -#set the maximum batch size to use -eventmesh.trace.exporter.max.export.size=512 -#set the queue size. This must be >= the export batch size -eventmesh.trace.exporter.max.queue.size=2048 -#set the max amount of time an export can run before getting(TimeUnit=SECONDS) -eventmesh.trace.exporter.export.timeout=30 -#set time between two different exports(TimeUnit=SECONDS) -eventmesh.trace.exporter.export.interval=5 - -#zipkin -eventmesh.trace.export.zipkin.ip=localhost -eventmesh.trace.export.zipkin.port=9411 -``` - -以上都是相关的配置,如果你十分熟悉Zipkin的话可以自行修改。 - - - -### 4、观察 - -浏览器打开: **localhost:9411** diff --git a/docs/zh/metrics-tracing/_category_.json b/docs/zh/metrics-tracing/_category_.json deleted file mode 100644 index 72c4414d12..0000000000 --- a/docs/zh/metrics-tracing/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 4, - "label": "Metrics and Tracing", - "collapsed": false -} diff --git a/docs/zh/roadmap.md b/docs/zh/roadmap.md deleted file mode 100644 index a3d7695cca..0000000000 --- a/docs/zh/roadmap.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -sidebar_position: 1 ---- - -# EventMesh产品路线图 - -下表列出了EventMesh的新特性和bug修复情况,详情请参考 [release notes](https://eventmesh.apache.org/events/release-notes/v1.4.0). - -## List of Features and Milestones - -| Status | Description | Reference | -|-------------------------------------------|---------------------------------| --- | -| **Implemented in 1.0.0** | Support HTTP | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.0.0** | Support TCP | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.0.0** | Support Pub/Sub Event | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.1.1** | Provide Java SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.1.1** | Support HTTPS | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.2.0** | Support RocketMQ as EventStore | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.2.0** | Support Heartbeat | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.3.0** | Integrate with OpenSchema | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.3.0** | Integrate with OpenTelemetry | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.3.0** | Support CloudEvents | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.4.0** | Support gRPC | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Provide Golang SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Support Nacos Registry | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Support Mesh Bridge | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.5.0** | Support Federal Government | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.6.0 (to be released)** | Integrate with Consul | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.6.0 (to be released)** | Support Webhook | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **Implemented in 1.6.0 (to be released)** | Support etcd | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Knative Eventing Infrastructure | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/790), [GSoC '22](https://issues.apache.org/jira/browse/COMDEV-463) | -| **In Progress** | Dashboard | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/700), [GSoC '22](https://issues.apache.org/jira/browse/COMDEV-465) | -| **In Progress** | Support Kafka as EventStore | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/676) | -| **In Progress** | Support Pulsar as EventStore | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/676) | -| **In Progress** | Support Dledger | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Workflow | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Support Redis | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Support Mesh Bridge | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| **In Progress** | Support Zookeeper | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| Planned | Provide NodeJS SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/417) | -| Planned | Transaction Event | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/697) | -| Planned | Event Query Language (EQL) | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/778) | -| Planned | Metadata consistency persistent | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/817) | -| Planned | Rust SDK | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/815) | -| Planned | WebAssembly Runtime | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/576) | -| Planned | Filter Chain | [GitHub Issue](https://github.com/apache/incubator-eventmesh/issues/664) | - diff --git a/docs/zh/sdk-java/01-intro.md b/docs/zh/sdk-java/01-intro.md deleted file mode 100644 index cb4b87640c..0000000000 --- a/docs/zh/sdk-java/01-intro.md +++ /dev/null @@ -1,29 +0,0 @@ -# 安装 - -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java/badge.svg?style=for-the-badge)](https://maven-badges.herokuapp.com/maven-central/org.apache.eventmesh/eventmesh-sdk-java) - -EventMesh Java SDK 是在一个 Java 应用中集成 Eventmesh 所需的 Java 组件集合。SDK 支持使用 TCP、HTTP 和 gRPC 协议来发送和接收同步消息、异步消息和广播消息。SDK 实现了 EventMesh 消息、CloudEvents 和 OpenMessaging 形式。您可以在 [`eventmesh-example`](https://github.com/apache/incubator-eventmesh/tree/master/eventmesh-examples) 模块中查看示例项目。 - -## Gradle - -使用 Gradle 安装 EventMesh Java SDK,您需要在模块的 `build.gradle` 文件的依赖块中将 `org.apache.eventmesh:eventmesh-sdk-java` 声明为 `implementation`。 - -```groovy -dependencies { - implementation 'org.apache.eventmesh:eventmesh-sdk-java:1.4.0' -} -``` - -## Maven - -使用 Maven 安装 EventMesh Java SDK,您需要在项目 `pom.xml` 文件的依赖块中声明 `org.apache.eventmesh:eventmesh-sdk-java`。 - -```xml - - - org.apache.eventmesh - eventmesh-sdk-java - 1.4.0 - - -``` \ No newline at end of file diff --git a/docs/zh/sdk-java/02-http.md b/docs/zh/sdk-java/02-http.md deleted file mode 100644 index 45a6698da7..0000000000 --- a/docs/zh/sdk-java/02-http.md +++ /dev/null @@ -1,114 +0,0 @@ -# HTTP 协议 - -EventMesh Java SDK 实现了 HTTP 异步消息的生产者和消费者。二者都需要一个 `EventMeshHttpClientConfig` 类实例来指定 EventMesh HTTP 客户端的配置信息。其中的 `liteEventMeshAddr`、`userName` 和 `password` 字段需要和 EventMesh runtime `eventmesh.properties` 文件中的相匹配。 - -```java -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -public class HTTP { - public static void main(String[] args) throws Exception { - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr("localhost:10105") - .producerGroup("TEST_PRODUCER_GROUP") - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())) - .userName("eventmesh") - .password("password") - .build(); - /* ... */ - } -} -``` - -## HTTP 消费者 - -类 `EventMeshHttpConsumer` 实现了 `heartbeat`、`subscribe` 和 `unsubscribe` 方法。`subscribe` 方法接收一个 `SubscriptionItem` 对象的列表,其中定义了要订阅的话题和回调的 URL 地址。 - -```java -import org.apache.eventmesh.client.http.consumer.EventMeshHttpConsumer; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import com.google.common.collect.Lists; - -public class HTTP { - final String url = "http://localhost:8080/callback"; - final List topicList = Lists.newArrayList( - new SubscriptionItem("eventmesh-async-topic", SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC) - ); - - public static void main(String[] args) throws Exception { - /* ... */ - eventMeshHttpConsumer = new EventMeshHttpConsumer(eventMeshClientConfig); - eventMeshHttpConsumer.heartBeat(topicList, url); - eventMeshHttpConsumer.subscribe(topicList, url); - /* ... */ - eventMeshHttpConsumer.unsubscribe(topicList, url); - } -} -``` - -EventMesh runtime 将发送一个包含 [CloudEvents 格式](https://github.com/cloudevents/spec) 信息的 POST 请求到这个回调的 URL 地址。类 [SubController.java](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/controller/SubController.java) 实现了 Spring Boot controller,它将接收并解析回调信息。 - -## HTTP 生产者 - -类 `EventMeshHttpProducer` 实现了 `publish` 方法。`publish` 方法接收将被发布的消息和一个可选的 timeout 值。消息应是下列类的一个实例: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` -- `io.openmessaging.api.Message` - -```java -import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.utils.JsonUtils; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class HTTP { - public static void main(String[] args) throws Exception { - /* ... */ - EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); - Map content = new HashMap<>(); - content.put("content", "testAsyncMessage"); - - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject("eventmesh-async-topic") - .withSource(URI.create("/")) - .withDataContentType("application/cloudevents+json") - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - eventMeshHttpProducer.publish(event); - } -} -``` - -## 使用Curl 命令 - -也可以不通过Event Mesh SDK来体验事件的收发功能 - -### 事件发送 - -```shell -curl -H "Content-Type:application/json" -X POST -d '{"name": "admin", "pass":"12345678"}' http://127.0.0.1:10105/eventmesh/publish/TEST-TOPIC-HTTP-ASYNC -``` - -启动eventmesh运行时服务后,可以使用curl命令将事件用HTTP post方法发布到指定的主题,并且Body必须是JSON格式。发布事件的url类似于(http://127.0.0.1:10105/eventmesh/publish/TEST-TOPIC-HTTP-ASYNC),您将获得成功发布的结果。 - -### 事件订阅 - -```shell -curl -H "Content-Type:application/json" -X POST -d '{"url": "http://127.0.0.1:8088/sub/test", "consumerGroup":"TEST-GROUP", "topic":[{"mode":"CLUSTERING","topic":"TEST-TOPIC-HTTP-ASYNC","type":"ASYNC"}]}' http://127.0.0.1:10105/eventmesh/subscribe/local -``` - -启动eventmesh运行时服务器后,可以使用curl命令用HTTP post方法订阅指定的主题列表,并且Body必须是JSON格式。订阅url类似于(http://127.0.0.1:10105/eventmesh/subscribe/local),您将获得订阅成功的结果。你应该注意Body中的`url`字段,这意味着你需要在指定的url上启动HTTP服务实现监听,你可以在`eventmesh-examples`模块中看到这个例子。 \ No newline at end of file diff --git a/docs/zh/sdk-java/03-tcp.md b/docs/zh/sdk-java/03-tcp.md deleted file mode 100644 index 54f5eca556..0000000000 --- a/docs/zh/sdk-java/03-tcp.md +++ /dev/null @@ -1,118 +0,0 @@ -# TCP 协议 - -EventMesh Java SDK 实现了同步、异步和广播 TCP 消息的生产者和消费者。 二者都需要一个 `EventMeshHttpClientConfig` 类实例来指定 EventMesh TCP 客户端的配置信息。其中的 `host` 和 `port` 字段需要和 EventMesh runtime `eventmesh.properties` 文件中的相匹配。 - -```java -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import io.cloudevents.CloudEvent; - -public class AsyncSubscribe implements ReceiveMsgHook { - public static void main(String[] args) throws InterruptedException { - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - /* ... */ - } -} -``` - -## TCP 消费者 - -消费者应该实现 `ReceiveMsgHook` 类,其被定义在 [ReceiveMsgHook.java](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java)。 - -```java -public interface ReceiveMsgHook { - Optional handle(ProtocolMessage msg); -} -``` - -类 `EventMeshTCPClient` 实现了 `subscribe` 方法。该方法接收话题、`SubscriptionMode` 和 `SubscriptionType`。`handle` 方法将会在消费者从订阅的话题中收到消息时被调用。如果 `SubscriptionType` 是 `SYNC`,`handle` 的返回值将被发送回生产者。 - -```java -import org.apache.eventmesh.client.tcp.EventMeshTCPClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import io.cloudevents.CloudEvent; - -public class TCPConsumer implements ReceiveMsgHook { - public static TCPConsumer handler = new TCPConsumer(); - private static EventMeshTCPClient client; - - public static void main(String[] args) throws Exception { - client = EventMeshTCPClientFactory.createEventMeshTCPClient( - eventMeshTcpClientConfig, - CloudEvent.class - ); - client.init(); - - client.subscribe( - "eventmesh-sync-topic", - SubscriptionMode.CLUSTERING, - SubscriptionType.SYNC - ); - - client.registerSubBusiHandler(handler); - client.listen(); - } - - @Override - public Optional handle(CloudEvent message) { - log.info("Messaged received: {}", message); - return Optional.of(message); - } -} -``` - -## TCP 生产者 - -### 异步生产者 - -类 `EventMeshTCPClient` 实现了 `public` 方法。该方法接收将被发布的消息和一个可选的 timeout 值,并返回来自消费者的响应消息。 - -```java -/* ... */ -client = EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); -client.init(); - -CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); -client.publish(event, 1000); -``` - -### 同步生产者 - -类 `EventMeshTCPClient` 实现了 `rr` 方法。该方法接收将被发布的消息和一个可选的 timeout 值,并返回来自消费者的响应消息。 - -```java -/* ... */ -client = EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); -client.init(); - -CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - -Package response = client.rr(event, 1000); -CloudEvent replyEvent = EventFormatProvider - .getInstance() - .resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(response.getBody().toString().getBytes(StandardCharsets.UTF_8)); -``` \ No newline at end of file diff --git a/docs/zh/sdk-java/04-grpc.md b/docs/zh/sdk-java/04-grpc.md deleted file mode 100644 index b078187071..0000000000 --- a/docs/zh/sdk-java/04-grpc.md +++ /dev/null @@ -1,174 +0,0 @@ -# gRPC 协议 - -EventMesh Java SDK 实现了 gRPC 同步、异步和广播消息的生产者和消费者。二者都需要一个 `EventMeshHttpClientConfig` 类实例来指定 EventMesh gRPC 客户端的配置信息。其中的 `liteEventMeshAddr`、`userName` 和 `password` 字段需要和 EventMesh runtime `eventmesh.properties` 文件中的相匹配。 - -```java -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import io.cloudevents.CloudEvent; - -public class CloudEventsAsyncSubscribe implements ReceiveMsgHook { - public static void main(String[] args) throws InterruptedException { - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr("localhost") - .serverPort(10205) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - /* ... */ - } -} -``` - -## gRPC 消费者 - -### 流消费者 - -EventMesh runtime 会将来自生产者的信息作为一系列事件流向流消费者发送。消费者应实现 `ReceiveHook` 类,其被定义在 [ReceiveMsgHook.java](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java)。 - -```java -public interface ReceiveMsgHook { - Optional handle(T msg) throws Throwable; - String getProtocolType(); -} -``` - -类 `EventMeshGrpcConsumer` 实现了 `registerListener`、`subscribe` 和 `unsubscribe` 方法。`subscribe` 方法接收一个 `SubscriptionItem` 对象的列表,其中定义了要订阅的话题。`registerListener` 接收一个实现了 `ReceiveMsgHook` 的实例。`handle` 方法将会在消费者收到订阅的主题消息时被调用。如果 `SubscriptionType` 是 `SYNC`,`handle` 的返回值将被发送回生产者。 - -```java -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import io.cloudevents.CloudEvent; - -public class CloudEventsAsyncSubscribe implements ReceiveMsgHook { - public static CloudEventsAsyncSubscribe handler = new CloudEventsAsyncSubscribe(); - public static void main(String[] args) throws InterruptedException { - /* ... */ - SubscriptionItem subscriptionItem = new SubscriptionItem( - "eventmesh-async-topic", - SubscriptionMode.CLUSTERING, - SubscriptionType.ASYNC - ); - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - - eventMeshGrpcConsumer.init(); - eventMeshGrpcConsumer.registerListener(handler); - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - /* ... */ - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); - } - - @Override - public Optional handle(CloudEvent message) { - log.info("Messaged received: {}", message); - return Optional.empty(); - } - - @Override - public String getProtocolType() { - return EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME; - } -} -``` - -### Webhook 消费者 - -类 `EventMeshGrpcConsumer` 的 `subscribe` 方法接收一个 `SubscriptionItem` 对象的列表,其中定义了要订阅的主题和一个可选的 timeout 值。如果提供了回调 URL,EventMesh runtime 将向回调 URL 地址发送一个包含 [CloudEvents 格式](https://github.com/cloudevents/spec) 消息的 POST 请求。[SubController.java](https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/controller/SubController.java) 实现了一个接收并解析回调信息的 Spring Boot controller。 - -```java -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; - -@Component -public class SubService implements InitializingBean { - final String url = "http://localhost:8080/callback"; - - public void afterPropertiesSet() throws Exception { - /* ... */ - eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - eventMeshGrpcConsumer.init(); - - SubscriptionItem subscriptionItem = new SubscriptionItem( - "eventmesh-async-topic", - SubscriptionMode.CLUSTERING, - SubscriptionType.ASYNC - ); - - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem), url); - /* ... */ - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem), url); - } -} -``` - -## gRPC 生产者 - -### 异步生产者 - -类 `EventMeshGrpcProducer` 实现了 `publish` 方法。`publish` 方法接收将被发布的消息和一个可选的 timeout 值。消息应是下列类的一个实例: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` - -```java -/* ... */ -EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); -eventMeshGrpcProducer.init(); - -Map content = new HashMap<>(); -content.put("content", "testAsyncMessage"); - -CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); -eventMeshGrpcProducer.publish(event); -``` - -### 同步生产者 - -类 `EventMeshGrpcProducer` 实现了 `requestReply` 方法。`requestReply` 方法接收将被发布的消息和一个可选的 timeout 值。方法会返回消费者返回的消息。消息应是下列类的一个实例: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` - -### 批量生产者 - -类 `EventMeshGrpcProducer` 重写了 `publish` 方法,该方法接收一个将被发布的消息列表和一个可选的 timeout 值。列表中的消息应是下列类的一个实例: - -- `org.apache.eventmesh.common.EventMeshMessage` -- `io.cloudevents.CloudEvent` - -```java -/* ... */ -List cloudEventList = new ArrayList<>(); -for (int i = 0; i < 5; i++) { - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - - cloudEventList.add(event); -} - -eventMeshGrpcProducer.publish(cloudEventList); -/* ... */ -``` \ No newline at end of file diff --git a/docs/zh/sdk-java/_category_.json b/docs/zh/sdk-java/_category_.json deleted file mode 100644 index 9d0a27c562..0000000000 --- a/docs/zh/sdk-java/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "EventMesh SDK for Java", - "collapsed": false -} diff --git a/eventmesh-admin-server/.gitignore b/eventmesh-admin-server/.gitignore new file mode 100644 index 0000000000..b63da4551b --- /dev/null +++ b/eventmesh-admin-server/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/eventmesh-admin-server/bin/start-admin.sh b/eventmesh-admin-server/bin/start-admin.sh new file mode 100644 index 0000000000..1633036617 --- /dev/null +++ b/eventmesh-admin-server/bin/start-admin.sh @@ -0,0 +1,200 @@ +#!/bin/bash +# +# Licensed to 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. Apache Software Foundation (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. + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +# Server configuration may be inconsistent, add these configurations to avoid garbled code problems +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/customize/your/java/home/here" + +# Detect operating system. +OS=$(uname) + +function is_java8_or_11 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' || "$("$_java" -version 2>&1)" =~ 'java version "11' || "$("$_java" -version 2>&1)" =~ 'openjdk version "11' ]] || return 2 + return 0 +} + +function extract_java_version { + local _java="$1" + local version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{if ($1 == 1 && $2 == 8) print "8"; else if ($1 == 11) print "11"; else print "unknown"}') + echo "$version" +} + +# 0(not running), 1(is running) +#function is_proxyRunning { +# local _pid="$1" +# local pid=`ps ax | grep -i 'org.apache.eventmesh.runtime.boot.EventMeshStartup' |grep java | grep -v grep | awk '{print $1}'|grep $_pid` +# if [ -z "$pid" ] ; then +# return 0 +# else +# return 1 +# fi +#} + +function get_pid { + local ppid="" + if [ -f ${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file ]; then + ppid=$(cat ${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file) + # If the process does not exist, it indicates that the previous process terminated abnormally. + if [ ! -d /proc/$ppid ]; then + # Remove the residual file. + rm ${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file + echo -e "ERROR\t EventMesh process had already terminated unexpectedly before, please check log output." + ppid="" + fi + else + if [[ $OS =~ Msys ]]; then + # There is a Bug on Msys that may not be able to kill the identified process + ppid=`jps -v | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # Known problem: grep Java may not be able to accurately identify Java processes + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + if [ $DOCKER ]; then + # No need to exclude root user in Docker containers. + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_ADMIN_HOME | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | awk -F ' ' {'print $2'}) + else + # It is required to identify the process as accurately as possible on Linux. + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_ADMIN_HOME | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | grep -Ev "^root" | awk -F ' ' {'print $2'}) + fi + fi + fi + echo "$ppid"; +} + +#=========================================================================================== +# Locate Java Executable +#=========================================================================================== + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8_or_11 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" + JAVA_VERSION=$(extract_java_version "$TMP_JAVA_HOME/bin/java") +elif [[ -d "$JAVA_HOME" ]] && is_java8_or_11 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" + JAVA_VERSION=$(extract_java_version "$JAVA_HOME/bin/java") +elif is_java8_or_11 "$(which java)"; then + JAVA="$(which java)" + JAVA_VERSION=$(extract_java_version "$(which java)") +else + echo -e "ERROR\t Java 8 or 11 not found, operation abort." + exit 9; +fi + +echo "EventMesh using Java version: $JAVA_VERSION, path: $JAVA" + +EVENTMESH_ADMIN_HOME=$(cd "$(dirname "$0")/.." && pwd) +export EVENTMESH_ADMIN_HOME + +EVENTMESH_ADMIN_LOG_HOME="${EVENTMESH_ADMIN_HOME}/logs" +export EVENTMESH_ADMIN_LOG_HOME + +echo -e "EVENTMESH_ADMIN_HOME : ${EVENTMESH_ADMIN_HOME}\nEVENTMESH_ADMIN_LOG_HOME : ${EVENTMESH_ADMIN_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${EVENTMESH_ADMIN_LOG_HOME}" ]; then mkdir -p "${EVENTMESH_ADMIN_LOG_HOME}"; fi +} + +error_exit () +{ + echo -e "ERROR\t $1 !!" + exit 1 +} + +export JAVA_HOME + +#=========================================================================================== +# JVM Configuration +#=========================================================================================== +#if [ $1 = "prd" -o $1 = "benchmark" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms2048M -Xmx4096M -Xmn2048m -XX:SurvivorRatio=4" +#elif [ $1 = "sit" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms256M -Xmx512M -Xmn256m -XX:SurvivorRatio=4" +#elif [ $1 = "dev" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms128M -Xmx256M -Xmn128m -XX:SurvivorRatio=4" +#fi + +GC_LOG_FILE="${EVENTMESH_ADMIN_LOG_HOME}/eventmesh_admin_gc_%p.log" + +JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g" +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc" +if [[ "$JAVA_VERSION" == "8" ]]; then + # Set JAVA_OPT for Java 8 + JAVA_OPT="${JAVA_OPT} -Xloggc:${GC_LOG_FILE} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" + JAVA_OPT="${JAVA_OPT} -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +elif [[ "$JAVA_VERSION" == "11" ]]; then + # Set JAVA_OPT for Java 11 + XLOG_PARAM="time,level,tags:filecount=5,filesize=30m" + JAVA_OPT="${JAVA_OPT} -Xlog:gc*:${GC_LOG_FILE}:${XLOG_PARAM}" + JAVA_OPT="${JAVA_OPT} -Xlog:safepoint:${GC_LOG_FILE}:${XLOG_PARAM} -Xlog:ergo*=debug:${GC_LOG_FILE}:${XLOG_PARAM}" +fi +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${EVENTMESH_ADMIN_LOG_HOME} -XX:ErrorFile=${EVENTMESH_ADMIN_LOG_HOME}/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${EVENTMESH_ADMIN_HOME}/conf/log4j2.xml" +JAVA_OPT="${JAVA_OPT} -Deventmesh.log.home=${EVENTMESH_ADMIN_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${EVENTMESH_ADMIN_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -DconfigurationPath=${EVENTMESH_ADMIN_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" +JAVA_OPT="${JAVA_OPT} -DeventMeshPluginDir=${EVENTMESH_ADMIN_HOME}/plugin" + +#if [ -f "pid.file" ]; then +# pid=`cat pid.file` +# if ! is_proxyRunning "$pid"; then +# echo "proxy is running already" +# exit 9; +# else +# echo "err pid$pid, rm pid.file" +# rm pid.file +# fi +#fi + +pid=$(get_pid) +if [[ $pid == "ERROR"* ]]; then + echo -e "${pid}" + exit 9 +fi +if [ -n "$pid" ]; then + echo -e "ERROR\t The server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9 +fi + +make_logs_dir + +echo "Using Java version: $JAVA_VERSION, path: $JAVA" >> ${EVENTMESH_ADMIN_LOG_HOME}/eventmesh-admin.out + +EVENTMESH_ADMIN_MAIN=org.apache.eventmesh.admin.server.ExampleAdminServer +if [ $DOCKER ]; then + $JAVA $JAVA_OPT -classpath ${EVENTMESH_ADMIN_HOME}/conf:${EVENTMESH_ADMIN_HOME}/apps/*:${EVENTMESH_ADMIN_HOME}/lib/* $EVENTMESH_ADMIN_MAIN >> ${EVENTMESH_ADMIN_LOG_HOME}/eventmesh-admin.out +else + $JAVA $JAVA_OPT -classpath ${EVENTMESH_ADMIN_HOME}/conf:${EVENTMESH_ADMIN_HOME}/apps/*:${EVENTMESH_ADMIN_HOME}/lib/* $EVENTMESH_ADMIN_MAIN >> ${EVENTMESH_ADMIN_LOG_HOME}/eventmesh-admin.out 2>&1 & +echo $!>${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file +fi +exit 0 diff --git a/eventmesh-admin-server/bin/stop-admin.sh b/eventmesh-admin-server/bin/stop-admin.sh new file mode 100644 index 0000000000..207531d7fa --- /dev/null +++ b/eventmesh-admin-server/bin/stop-admin.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# +# Licensed to 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. Apache Software Foundation (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. + +# Detect operating system +OS=$(uname) + +EVENTMESH_ADMIN_HOME=`cd $(dirname $0)/.. && pwd` + +export EVENTMESH_ADMIN_HOME + +function get_pid { + local ppid="" + if [ -f ${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file ]; then + ppid=$(cat ${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file) + # If the process does not exist, it indicates that the previous process terminated abnormally. + if [ ! -d /proc/$ppid ]; then + # Remove the residual file and return an error status. + rm ${EVENTMESH_ADMIN_HOME}/bin/pid-admin.file + echo -e "ERROR\t EventMesh admin process had already terminated unexpectedly before, please check log output." + ppid="" + fi + else + if [[ $OS =~ Msys ]]; then + # There is a Bug on Msys that may not be able to kill the identified process + ppid=`jps -v | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # Known problem: grep Java may not be able to accurately identify Java processes + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + # It is required to identify the process as accurately as possible on Linux + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_ADMIN_HOME | grep -i "org.apache.eventmesh.admin.server.ExampleAdminServer" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "$ppid"; +} + +pid=$(get_pid) +if [[ $pid == "ERROR"* ]]; then + echo -e "${pid}" + exit 9 +fi +if [ -z "$pid" ];then + echo -e "ERROR\t No EventMesh admin server running." + exit 9 +fi + +kill ${pid} +echo "Send shutdown request to EventMesh admin(${pid}) OK" + +[[ $OS =~ Msys ]] && PS_PARAM=" -W " +stop_timeout=60 +for no in $(seq 1 $stop_timeout); do + if ps $PS_PARAM -p "$pid" 2>&1 > /dev/null; then + if [ $no -lt $stop_timeout ]; then + echo "[$no] server shutting down ..." + sleep 1 + continue + fi + + echo "shutdown server timeout, kill process: $pid" + kill -9 $pid; sleep 1; break; + echo "`date +'%Y-%m-%-d %H:%M:%S'` , pid : [$pid] , error message : abnormal shutdown which can not be closed within 60s" > ../logs/shutdown.error + else + echo "shutdown server ok!"; break; + fi +done + +if [ -f "pid-admin.file" ]; then + rm pid-admin.file +fi + + diff --git a/eventmesh-admin-server/build.gradle b/eventmesh-admin-server/build.gradle new file mode 100644 index 0000000000..fdfe1bffe8 --- /dev/null +++ b/eventmesh-admin-server/build.gradle @@ -0,0 +1,57 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-spi") + implementation project(":eventmesh-common") + implementation project(":eventmesh-registry:eventmesh-registry-api") + implementation project(":eventmesh-registry:eventmesh-registry-nacos") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api") + implementation "com.alibaba.nacos:nacos-client" + implementation("org.springframework.boot:spring-boot-starter-web") { + exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat" + } + implementation 'org.springframework.boot:spring-boot-starter-jetty' + implementation "io.grpc:grpc-core" + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty-shaded" + + // https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter + implementation "com.baomidou:mybatis-plus-boot-starter" + + // https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter + implementation "com.alibaba:druid-spring-boot-starter" + compileOnly 'com.mysql:mysql-connector-j' + compileOnly 'org.projectlombok:lombok' + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} + +configurations.implementation { + exclude group: "org.springframework.boot", module: "spring-boot-starter-logging" +} + +sourceSets { + main { + resources { + srcDirs = ['src/main/resources', 'conf'] + } + } +} + diff --git a/eventmesh-admin-server/conf/application.yaml b/eventmesh-admin-server/conf/application.yaml new file mode 100644 index 0000000000..7765d90ce8 --- /dev/null +++ b/eventmesh-admin-server/conf/application.yaml @@ -0,0 +1,58 @@ +# +# 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. +# + +spring: + datasource: + url: jdbc:mysql://localhost:3306/eventmesh?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true + username: //db_username + password: //db_password + driver-class-name: com.mysql.cj.jdbc.Driver + initialSize: 1 + minIdle: 1 + maxActive: 20 + maxWait: 10000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + poolPreparedStatements: false + maxPoolPreparedStatementPerConnectionSize: 20 + filters: stat + connectionProperties: "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000" +# secret keys +sysPubKey: +appPrivKey: + +mybatis-plus: + mapper-locations: classpath:mapper/*.xml + configuration: + map-underscore-to-camel-case: false + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +# http server port +server: + port: 8082 +event-mesh: + admin-server: + serviceName: DEFAULT_GROUP@@em_adm_server + # grpc server port + port: 8081 + adminServerList: + R1: http://localhost:8082;http://localhost:8082 + R2: http://localhost:8092;http://localhost:8092 + region: R1 \ No newline at end of file diff --git a/eventmesh-admin-server/conf/eventmesh-admin.properties b/eventmesh-admin-server/conf/eventmesh-admin.properties new file mode 100644 index 0000000000..30507ec02c --- /dev/null +++ b/eventmesh-admin-server/conf/eventmesh-admin.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +eventMesh.registry.plugin.type=nacos +eventMesh.registry.plugin.server-addr=localhost:8848 diff --git a/eventmesh-admin-server/conf/eventmesh.sql b/eventmesh-admin-server/conf/eventmesh.sql new file mode 100644 index 0000000000..4d11ab1585 --- /dev/null +++ b/eventmesh-admin-server/conf/eventmesh.sql @@ -0,0 +1,185 @@ +-- 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. + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + + +-- export eventmesh database +CREATE DATABASE IF NOT EXISTS `eventmesh` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */ /*!80016 DEFAULT ENCRYPTION='N' */; +USE `eventmesh`; + +-- export table eventmesh.event_mesh_data_source structure +CREATE TABLE IF NOT EXISTS `event_mesh_data_source` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `dataType` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `description` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `configuration` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `configurationClass` varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `region` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `createUid` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `updateUid` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- export table eventmesh.event_mesh_job_info structure +CREATE TABLE IF NOT EXISTS `event_mesh_job_info` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `jobID` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `jobDesc` varchar(50) COLLATE utf8_bin NOT NULL, + `taskID` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `transportType` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `sourceData` int NOT NULL DEFAULT '0', + `targetData` int NOT NULL DEFAULT '0', + `jobState` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `jobType` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `fromRegion` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `runningRegion` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `createUid` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `updateUid` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `jobID` (`jobID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- export table eventmesh.event_mesh_mysql_position structure +CREATE TABLE IF NOT EXISTS `event_mesh_mysql_position` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `jobID` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `serverUUID` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `address` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `position` bigint DEFAULT NULL, + `gtid` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `currentGtid` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `timestamp` bigint DEFAULT NULL, + `journalName` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `jobID` (`jobID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC; + +-- export table eventmesh.event_mesh_position_reporter_history structure +CREATE TABLE IF NOT EXISTS `event_mesh_position_reporter_history` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `job` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `record` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `address` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `job` (`job`), + KEY `address` (`address`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='record position reporter changes'; + +-- export table eventmesh.event_mesh_runtime_heartbeat structure +CREATE TABLE IF NOT EXISTS `event_mesh_runtime_heartbeat` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `adminAddr` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `runtimeAddr` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `jobID` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `reportTime` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'runtime local report time', + `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `jobID` (`jobID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- export table eventmesh.event_mesh_runtime_history structure +CREATE TABLE IF NOT EXISTS `event_mesh_runtime_history` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `job` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `address` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `address` (`address`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC COMMENT='record runtime task change history'; + +-- export table eventmesh.event_mesh_task_info structure +CREATE TABLE IF NOT EXISTS `event_mesh_task_info` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `taskID` varchar(50) COLLATE utf8_bin NOT NULL, + `taskName` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `taskDesc` varchar(50) COLLATE utf8_bin NOT NULL, + `taskState` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'taskstate', + `sourceRegion` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `targetRegion` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `createUid` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `updateUid` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `taskID` (`taskID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- export table eventmesh.event_mesh_verify structure +CREATE TABLE IF NOT EXISTS `event_mesh_verify` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `taskID` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `jobID` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `recordID` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `recordSig` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `connectorName` varchar(200) COLLATE utf8_bin DEFAULT NULL, + `connectorStage` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `position` text COLLATE utf8_bin DEFAULT NULL, + `createTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- eventmesh.event_mesh_weredis_position definition +CREATE TABLE `event_mesh_weredis_position` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `jobID` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '', + `address` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `clusterName` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `partitionName` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `masterReplid` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `host` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `replOffset` bigint(20) NOT NULL DEFAULT '-1', + `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `jobID` (`jobID`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC; + + +CREATE TABLE `event_mesh_monitor` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `taskID` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `jobID` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `address` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `transportType` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `connectorStage` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `totalReqNum` bigint DEFAULT NULL, + `totalTimeCost` bigint DEFAULT NULL, + `maxTimeCost` bigint DEFAULT NULL, + `avgTimeCost` bigint DEFAULT NULL, + `tps` double DEFAULT NULL, + `createTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; diff --git a/eventmesh-admin-server/conf/log4j2.xml b/eventmesh-admin-server/conf/log4j2.xml new file mode 100644 index 0000000000..acc6acb8ba --- /dev/null +++ b/eventmesh-admin-server/conf/log4j2.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eventmesh-admin-server/conf/mapper/EventMeshDataSourceMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshDataSourceMapper.xml new file mode 100644 index 0000000000..50e6ad82cc --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshDataSourceMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + id,dataType,description, + configuration,configurationClass,region, + createUid,updateUid,createTime,updateTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshJobInfoMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshJobInfoMapper.xml new file mode 100644 index 0000000000..a053d1c838 --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshJobInfoMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + id,jobID,jobDesc, + taskID,transportType,sourceData, + targetData,jobState,jobType, + fromRegion,runningRegion,createUid, + updateUid,createTime,updateTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshMonitorMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshMonitorMapper.xml new file mode 100644 index 0000000000..f77fb8ba77 --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshMonitorMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + id,taskID,jobID,address,transportType,connectorStage, + totalReqNum,totalTimeCost,maxTimeCost,avgTimeCost, + tps,createTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshMysqlPositionMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshMysqlPositionMapper.xml new file mode 100644 index 0000000000..9bcc7f42bb --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshMysqlPositionMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + id,jobID,serverUUID, + address,position,gtid, + currentGtid,timestamp,journalName, + createTime,updateTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshPositionReporterHistoryMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshPositionReporterHistoryMapper.xml new file mode 100644 index 0000000000..a9e4fe6f1b --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshPositionReporterHistoryMapper.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + id,job,record, + address,createTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshRuntimeHeartbeatMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshRuntimeHeartbeatMapper.xml new file mode 100644 index 0000000000..200b1bf54a --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshRuntimeHeartbeatMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + id,adminAddr,runtimeAddr, + jobID,reportTime,updateTime, + createTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshRuntimeHistoryMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshRuntimeHistoryMapper.xml new file mode 100644 index 0000000000..281cce30f9 --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshRuntimeHistoryMapper.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + id,job,address, + createTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshTaskInfoMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshTaskInfoMapper.xml new file mode 100644 index 0000000000..c3514fd945 --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshTaskInfoMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + id,taskID,taskName, + taskDesc,taskState,sourceRegion,targetRegion, + createUid,updateUid,createTime, + updateTime + + diff --git a/eventmesh-admin-server/conf/mapper/EventMeshVerifyMapper.xml b/eventmesh-admin-server/conf/mapper/EventMeshVerifyMapper.xml new file mode 100644 index 0000000000..45727498cc --- /dev/null +++ b/eventmesh-admin-server/conf/mapper/EventMeshVerifyMapper.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + id,taskID,jobID,recordID, + recordSig,connectorName,connectorStage, + position,createTime + + diff --git a/eventmesh-admin/gradle.properties b/eventmesh-admin-server/gradle.properties similarity index 100% rename from eventmesh-admin/gradle.properties rename to eventmesh-admin-server/gradle.properties diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/AdminServerProperties.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/AdminServerProperties.java new file mode 100644 index 0000000000..2e6d3c018a --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/AdminServerProperties.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server; + +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Getter; +import lombok.Setter; + +@ConfigurationProperties("event-mesh.admin-server") +@Getter +@Setter +public class AdminServerProperties { + + private int port; + private boolean enableSSL; + private String configurationPath; + private String configurationFile; + private String serviceName; + private Map adminServerList; + private String region; +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/AdminServerRuntimeException.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/AdminServerRuntimeException.java new file mode 100644 index 0000000000..e68d05100f --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/AdminServerRuntimeException.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server; + +import lombok.Getter; + +@Getter +public class AdminServerRuntimeException extends RuntimeException { + private final int code; + + public AdminServerRuntimeException(int code, String message) { + super(message); + this.code = code; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/ExampleAdminServer.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/ExampleAdminServer.java new file mode 100644 index 0000000000..d0f2111041 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/ExampleAdminServer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server; + +import org.apache.eventmesh.admin.server.constants.AdminServerConstants; +import org.apache.eventmesh.common.config.ConfigService; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@SpringBootApplication(scanBasePackages = "org.apache.eventmesh.admin.server", exclude = {DataSourceAutoConfiguration.class}) +public class ExampleAdminServer { + + public static void main(String[] args) throws Exception { + ConfigService.getInstance().setConfigPath(AdminServerConstants.EVENTMESH_CONF_HOME).setRootConfig(AdminServerConstants.EVENTMESH_CONF_FILE); + SpringApplication.run(ExampleAdminServer.class); + log.info("admin start success."); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/constants/AdminServerConstants.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/constants/AdminServerConstants.java new file mode 100644 index 0000000000..8ed079fd31 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/constants/AdminServerConstants.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.constants; + +public class AdminServerConstants { + public static final String CONF_ENV = "configurationPath"; + + public static final String EVENTMESH_CONF_HOME = System.getProperty(CONF_ENV, System.getenv(CONF_ENV)); + + public static final String EVENTMESH_CONF_FILE = "eventmesh-admin.properties"; +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/BaseServer.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/BaseServer.java new file mode 100644 index 0000000000..9bbe4ce305 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/BaseServer.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web; + +import org.apache.eventmesh.common.ComponentLifeCycle; +import org.apache.eventmesh.common.remote.payload.PayloadFactory; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class BaseServer implements ComponentLifeCycle { + + static { + PayloadFactory.getInstance().init(); + } + + @PostConstruct + public void init() throws Exception { + log.info("[{}] server starting at port [{}]", this.getClass().getSimpleName(), getPort()); + start(); + log.info("[{}] server started at port [{}]", this.getClass().getSimpleName(), getPort()); + } + + @PreDestroy + public void shutdown() throws Exception { + log.info("[{}] server will destroy", this.getClass().getSimpleName()); + stop(); + log.info("[{}] server has be destroy", this.getClass().getSimpleName()); + } + + public abstract int getPort(); +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/GrpcServer.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/GrpcServer.java new file mode 100644 index 0000000000..d2a0330355 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/GrpcServer.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web; + +import org.apache.eventmesh.admin.server.AdminServerProperties; +import org.apache.eventmesh.admin.server.web.service.AdminGrpcServer; + +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +import io.grpc.Server; +import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Controller +@Slf4j +public class GrpcServer extends BaseServer { + + @Autowired + AdminGrpcServer adminGrpcServer; + + @Autowired + AdminServerProperties properties; + + private Server server; + + @Override + public void start() throws Exception { + NettyServerBuilder serverBuilder = NettyServerBuilder.forPort(getPort()).addService(adminGrpcServer); + if (properties.isEnableSSL()) { + serverBuilder.sslContext(null); + } + server = serverBuilder.build(); + server.start(); + } + + @Override + public void stop() { + try { + if (server != null) { + server.shutdown(); + if (!server.awaitTermination(30, TimeUnit.SECONDS)) { + log.warn("[{}] server don't graceful stop in 30s, it will shutdown now", this.getClass().getSimpleName()); + server.shutdownNow(); + } + } + } catch (InterruptedException e) { + log.warn("destroy [{}] server fail", this.getClass().getSimpleName(), e); + } + } + + @Override + public int getPort() { + return properties.getPort(); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/HttpServer.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/HttpServer.java new file mode 100644 index 0000000000..0a20d8645e --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/HttpServer.java @@ -0,0 +1,183 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web; + +import org.apache.eventmesh.admin.server.web.db.service.EventMeshTaskInfoService; +import org.apache.eventmesh.admin.server.web.service.monitor.MonitorBizService; +import org.apache.eventmesh.admin.server.web.service.task.TaskBizService; +import org.apache.eventmesh.admin.server.web.service.verify.VerifyBizService; +import org.apache.eventmesh.common.remote.request.CreateTaskRequest; +import org.apache.eventmesh.common.remote.request.QueryTaskInfoRequest; +import org.apache.eventmesh.common.remote.request.QueryTaskMonitorRequest; +import org.apache.eventmesh.common.remote.request.ReportMonitorRequest; +import org.apache.eventmesh.common.remote.request.ReportVerifyRequest; +import org.apache.eventmesh.common.remote.request.TaskBachRequest; +import org.apache.eventmesh.common.remote.request.TaskIDRequest; +import org.apache.eventmesh.common.remote.response.CreateTaskResponse; +import org.apache.eventmesh.common.remote.response.HttpResponseResult; +import org.apache.eventmesh.common.remote.response.QueryTaskInfoResponse; +import org.apache.eventmesh.common.remote.response.QueryTaskMonitorResponse; +import org.apache.eventmesh.common.remote.response.SimpleResponse; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import lombok.extern.slf4j.Slf4j; + +@RestController +@RequestMapping("/eventmesh/admin") +@Slf4j +public class HttpServer { + + @Autowired + private TaskBizService taskService; + + @Autowired + private VerifyBizService verifyService; + + @Autowired + private MonitorBizService monitorService; + + @Autowired + private EventMeshTaskInfoService taskInfoService; + + @RequestMapping(value = "/createTask", method = RequestMethod.POST) + public String createOrUpdateTask(@RequestBody CreateTaskRequest task) { + log.info("receive http proto create task:{}", task); + CreateTaskResponse createTaskResponse = taskService.createTask(task); + log.info("receive http proto create task result:{}", createTaskResponse); + SimpleResponse simpleResponse = new SimpleResponse(); + simpleResponse.setData(createTaskResponse); + return JsonUtils.toJSONString(simpleResponse); + } + + + @RequestMapping(value = "/reportVerify", method = RequestMethod.POST) + public String reportVerify(@RequestBody ReportVerifyRequest request) { + log.info("receive http proto report verify request:{}", request); + boolean result = verifyService.reportVerifyRecord(request); + log.info("receive http proto report verify result:{}", result); + SimpleResponse simpleResponse = new SimpleResponse(); + simpleResponse.setData(result); + return JsonUtils.toJSONString(simpleResponse); + } + + @RequestMapping(value = "/reportMonitor", method = RequestMethod.POST) + public String reportMonitor(@RequestBody ReportMonitorRequest request) { + log.info("receive http proto report monitor request:{}", request); + boolean result = monitorService.reportMonitorRecord(request); + log.info("receive http proto report monitor result:{}", result); + SimpleResponse simpleResponse = new SimpleResponse(); + simpleResponse.setData(result); + return JsonUtils.toJSONString(simpleResponse); + } + + @RequestMapping(value = "/queryTaskMonitor", method = RequestMethod.POST) + public String queryTaskMonitor(@RequestBody QueryTaskMonitorRequest request) { + log.info("receive http proto query task monitor request:{}", request); + QueryTaskMonitorResponse result = monitorService.queryTaskMonitors(request); + log.info("receive http proto query task monitor result:{}", result); + SimpleResponse simpleResponse = new SimpleResponse(); + simpleResponse.setData(result); + return JsonUtils.toJSONString(simpleResponse); + } + + @RequestMapping(value = "/queryTaskInfo", method = RequestMethod.POST) + public HttpResponseResult queryTaskInfo(@RequestBody QueryTaskInfoRequest taskInfoRequest) { + log.info("receive http query task info request:{}", taskInfoRequest); + List taskInfosResponse = taskService.queryTaskInfo(taskInfoRequest); + log.info("receive http query task info taskInfosResponse:{}", taskInfoRequest); + if (taskInfosResponse.isEmpty()) { + return HttpResponseResult.failed("NOT FOUND"); + } + return HttpResponseResult.success(taskInfosResponse); + } + + @RequestMapping(value = "/deleteTask", method = RequestMethod.DELETE) + public HttpResponseResult deleteTask(@RequestBody TaskIDRequest taskIDRequest) { + log.info("receive need to delete taskID:{}", taskIDRequest.getTaskID()); + boolean result = taskService.deleteTaskByTaskID(taskIDRequest); + if (result) { + return HttpResponseResult.success(); + } else { + return HttpResponseResult.failed(); + } + } + + @RequestMapping(value = "/startTask", method = RequestMethod.POST) + public HttpResponseResult startTask(@RequestBody TaskIDRequest taskIDRequest) { + log.info("receive start task ID:{}", taskIDRequest.getTaskID()); + taskService.startTask(taskIDRequest); + return HttpResponseResult.success(); + } + + @RequestMapping(value = "/restartTask", method = RequestMethod.POST) + public HttpResponseResult restartTask(@RequestBody TaskIDRequest taskIDRequest) { + log.info("receive restart task ID:{}", taskIDRequest.getTaskID()); + taskService.restartTask(taskIDRequest); + return HttpResponseResult.success(); + } + + @RequestMapping(value = "/stopTask", method = RequestMethod.POST) + public HttpResponseResult stopTask(@RequestBody TaskIDRequest taskIDRequest) { + log.info("receive stop task ID:{}", taskIDRequest.getTaskID()); + taskService.stopTask(taskIDRequest); + return HttpResponseResult.success(); + } + + @RequestMapping(value = "/restartBatch", method = RequestMethod.POST) + public HttpResponseResult restartBatch(@RequestBody List taskBachRequestList) { + log.info("receive restart batch task IDs:{}", taskBachRequestList); + List errorNames = new ArrayList<>(); + taskService.restartBatchTask(taskBachRequestList, errorNames); + if (!errorNames.isEmpty()) { + return HttpResponseResult.failed(errorNames); + } + return HttpResponseResult.success(); + } + + @RequestMapping(value = "stopBatch", method = RequestMethod.POST) + public HttpResponseResult stopBatch(@RequestBody List taskBachRequestList) { + log.info("receive stop batch task IDs:{}", taskBachRequestList); + List errorNames = new ArrayList<>(); + taskService.stopBatchTask(taskBachRequestList, errorNames); + if (!errorNames.isEmpty()) { + return HttpResponseResult.failed(errorNames); + } + return HttpResponseResult.success(); + } + + @RequestMapping(value = "/startBatch", method = RequestMethod.POST) + public HttpResponseResult startBatch(@RequestBody List taskBachRequestList) { + log.info("receive start batch task IDs:{}", taskBachRequestList); + List errorNames = new ArrayList<>(); + taskService.startBatchTask(taskBachRequestList, errorNames); + if (!errorNames.isEmpty()) { + return HttpResponseResult.failed(errorNames); + } + return HttpResponseResult.success(); + } + +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/Request.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/Request.java new file mode 100644 index 0000000000..9484e986f1 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/Request.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web; + +public class Request { + private String uid; + private T data; + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/Response.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/Response.java new file mode 100644 index 0000000000..d573c3bac4 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/Response.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web; + +import org.apache.eventmesh.common.remote.exception.ErrorCode; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Response { + + private int code; + + private boolean success; + + private String desc; + + private T data; + + public static Response success() { + Response response = new Response<>(); + response.success = true; + response.code = ErrorCode.SUCCESS; + return response; + } + + public static Response success(T data) { + Response response = new Response<>(); + response.success = true; + response.data = data; + return response; + } + + public static Response fail(int code, String desc) { + Response response = new Response<>(); + response.success = false; + response.code = code; + response.desc = desc; + return response; + } + + public static Response fail(int code, String desc, T data) { + Response response = new Response<>(); + response.success = false; + response.code = code; + response.desc = desc; + response.data = data; + return response; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/ServerController.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/ServerController.java new file mode 100644 index 0000000000..5623cbad33 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/ServerController.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/eventmesh/admin") +public class ServerController { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/config/MybatisPlusConfig.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/config/MybatisPlusConfig.java new file mode 100644 index 0000000000..15d362bcd0 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/config/MybatisPlusConfig.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; + +@Configuration +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor paginationInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + pageInterceptor.setMaxLimit(500L); + interceptor.addInnerInterceptor(pageInterceptor); + return interceptor; + } + +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/DBThreadPool.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/DBThreadPool.java new file mode 100644 index 0000000000..277ea66656 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/DBThreadPool.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db; + +import org.apache.eventmesh.common.EventMeshThreadFactory; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PreDestroy; + +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class DBThreadPool { + + private final ThreadPoolExecutor executor = + new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, + Runtime.getRuntime().availableProcessors() * 2, 0L, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(1000), new EventMeshThreadFactory("admin-server-db"), + new ThreadPoolExecutor.DiscardOldestPolicy()); + + + private final ScheduledThreadPoolExecutor checkScheduledExecutor = + new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), new EventMeshThreadFactory("admin-server-check-scheduled"), + new ThreadPoolExecutor.DiscardOldestPolicy()); + + @PreDestroy + private void destroy() { + if (!executor.isShutdown()) { + try { + executor.shutdown(); + if (!executor.awaitTermination(30, TimeUnit.SECONDS)) { + log.info("wait handler thread pool shutdown timeout, it will shutdown immediately"); + executor.shutdownNow(); + } + } catch (InterruptedException e) { + log.warn("wait handler thread pool shutdown fail"); + } + } + + if (!checkScheduledExecutor.isShutdown()) { + try { + checkScheduledExecutor.shutdown(); + if (!checkScheduledExecutor.awaitTermination(30, TimeUnit.SECONDS)) { + log.info("wait scheduled thread pool shutdown timeout, it will shutdown immediately"); + checkScheduledExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + log.warn("wait scheduled thread pool shutdown fail"); + } + } + } + + public ThreadPoolExecutor getExecutors() { + return executor; + } + + public ScheduledThreadPoolExecutor getCheckExecutor() { + return checkScheduledExecutor; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/DruidDataSource.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/DruidDataSource.java new file mode 100644 index 0000000000..fb26d44d30 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/DruidDataSource.java @@ -0,0 +1,150 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db; + + +import org.apache.eventmesh.admin.server.web.utils.EncryptUtil; +import org.apache.eventmesh.admin.server.web.utils.ParamType; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.sql.SQLException; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import lombok.extern.slf4j.Slf4j; + +@Configuration +@ComponentScan +@Slf4j +public class DruidDataSource { + + @Value("${spring.datasource.url}") + private String dbUrl; + + @Value("${spring.datasource.username}") + private String username; + + @Value("${spring.datasource.password}") + private String password; + + @Value("${spring.datasource.driver-class-name}") + private String driverClassName; + + @Value("${spring.datasource.initialSize}") + private int initialSize; + + @Value("${spring.datasource.minIdle}") + private int minIdle; + + @Value("${spring.datasource.maxActive}") + private int maxActive; + + @Value("${spring.datasource.maxWait}") + private int maxWait; + + @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") + private int timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.minEvictableIdleTimeMillis}") + private int minEvictableIdleTimeMillis; + + @Value("${spring.datasource.validationQuery}") + private String validationQuery; + + @Value("${spring.datasource.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${spring.datasource.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${spring.datasource.testOnReturn}") + private boolean testOnReturn; + + @Value("${spring.datasource.poolPreparedStatements}") + private boolean poolPreparedStatements; + + @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}") + private int maxPoolPreparedStatementPerConnectionSize; + + @Value("${spring.datasource.filters}") + private String filters; + + @Value("{spring.datasource.connectionProperties}") + private String connectionProperties; + + @Value("${sysPubKey}") + private String sysPubKeyStr; + + @Value("${appPrivKey}") + private String appPrivKeyStr; + + + @Bean + @Primary + public DataSource dataSource() throws Exception { + try (com.alibaba.druid.pool.DruidDataSource datasource = new com.alibaba.druid.pool.DruidDataSource()) { + datasource.setUrl(this.dbUrl); + datasource.setUsername(username); + datasource.setPassword(rsaDecrypt(sysPubKeyStr, appPrivKeyStr, password)); + datasource.setDriverClassName(driverClassName); + datasource.setInitialSize(initialSize); + datasource.setMinIdle(minIdle); + datasource.setMaxActive(maxActive); + datasource.setMaxWait(maxWait); + datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + datasource.setValidationQuery(validationQuery); + datasource.setTestWhileIdle(testWhileIdle); + datasource.setTestOnBorrow(testOnBorrow); + datasource.setTestOnReturn(testOnReturn); + datasource.setPoolPreparedStatements(poolPreparedStatements); + datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); + try { + datasource.setFilters(filters); + } catch (SQLException e) { + log.error("druid configuration initialization filter", e); + } + datasource.setConnectionProperties(connectionProperties); + + return datasource; + } + } + + public static String rsaDecrypt(String sysPubKeyStr, String appPrivKeyStr, String encrtyptText) throws IOException { + if (StringUtils.isNotBlank(encrtyptText) && encrtyptText.length() > "{RSA}".length() && encrtyptText.startsWith("{RSA}")) { + String text = encrtyptText.startsWith("{RSA}") ? encrtyptText.substring("{RSA}".length()) : encrtyptText; + + try { + return EncryptUtil.decrypt(ParamType.STRING, sysPubKeyStr, ParamType.STRING, appPrivKeyStr, ParamType.STRING, text); + } catch (Exception e) { + throw new RuntimeException("decrypt error", e); + } + } else { + return encrtyptText; + } + } + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshDataSource.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshDataSource.java new file mode 100644 index 0000000000..e6e328984c --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshDataSource.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_data_source + */ +@TableName(value = "event_mesh_data_source") +@Data +public class EventMeshDataSource implements Serializable { + @TableId(type = IdType.AUTO) + private Integer id; + + private String dataType; + + private String description; + + private String configuration; + + private String configurationClass; + + private String region; + + private String createUid; + + private String updateUid; + + private Date createTime; + + private Date updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshJobInfo.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshJobInfo.java new file mode 100644 index 0000000000..a77eaaaca2 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshJobInfo.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_job_info + */ +@TableName(value = "event_mesh_job_info") +@Data +public class EventMeshJobInfo implements Serializable { + @TableId(type = IdType.AUTO) + private Integer id; + + private String jobID; + + private String jobDesc; + + private String taskID; + + private String transportType; + + private Integer sourceData; + + private Integer targetData; + + private String jobState; + + private String jobType; + + // job request from region + private String fromRegion; + + // job actually running region + private String runningRegion; + + private String createUid; + + private String updateUid; + + private Date createTime; + + private Date updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshMonitor.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshMonitor.java new file mode 100644 index 0000000000..0507464b5b --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshMonitor.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_monitor + */ +@TableName(value = "event_mesh_monitor") +@Data +public class EventMeshMonitor implements Serializable { + + @TableId(type = IdType.AUTO) + private Integer id; + + private String taskID; + private String jobID; + private String address; + private String transportType; + private String connectorStage; + private Long totalReqNum; + private Long totalTimeCost; + private Long maxTimeCost; + private Long avgTimeCost; + private Double tps; + private Date createTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshMysqlPosition.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshMysqlPosition.java new file mode 100644 index 0000000000..5e5d5745c1 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshMysqlPosition.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_mysql_position + */ +@TableName(value = "event_mesh_mysql_position") +@Data +public class EventMeshMysqlPosition implements Serializable { + @TableId(type = IdType.AUTO) + private Integer id; + + private String jobID; + + private String serverUUID; + + private String address; + + private Long position; + + private String gtid; + + private String currentGtid; + + private Long timestamp; + + private String journalName; + + private Date createTime; + + private Date updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshPositionReporterHistory.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshPositionReporterHistory.java new file mode 100644 index 0000000000..8518c38918 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshPositionReporterHistory.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_position_reporter_history + */ +@TableName(value = "event_mesh_position_reporter_history") +@Data +public class EventMeshPositionReporterHistory implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + private String job; + + private String record; + + private String address; + + private Date createTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshRuntimeHeartbeat.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshRuntimeHeartbeat.java new file mode 100644 index 0000000000..95e6c5e261 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshRuntimeHeartbeat.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_runtime_heartbeat + */ +@TableName(value = "event_mesh_runtime_heartbeat") +@Data +public class EventMeshRuntimeHeartbeat implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + private String adminAddr; + + private String runtimeAddr; + + private String jobID; + + private String reportTime; + + private Date updateTime; + + private Date createTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshRuntimeHistory.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshRuntimeHistory.java new file mode 100644 index 0000000000..ea7e10cbad --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshRuntimeHistory.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_runtime_history + */ +@TableName(value = "event_mesh_runtime_history") +@Data +public class EventMeshRuntimeHistory implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + private String job; + + private String address; + + private Date createTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshTaskInfo.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshTaskInfo.java new file mode 100644 index 0000000000..2d40f4a082 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshTaskInfo.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_task_info + */ +@TableName(value = "event_mesh_task_info") +@Data +public class EventMeshTaskInfo implements Serializable { + @TableId(type = IdType.AUTO) + private Integer id; + + private String taskID; + + private String taskName; + + private String taskDesc; + + private String taskState; + + private String sourceRegion; + + private String targetRegion; + + private String createUid; + + private String updateUid; + + private Date createTime; + + private Date updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshVerify.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshVerify.java new file mode 100644 index 0000000000..c5a6c35f8d --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshVerify.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_verify + */ +@TableName(value = "event_mesh_verify") +@Data +public class EventMeshVerify implements Serializable { + + @TableId(type = IdType.AUTO) + private Integer id; + + private String taskID; + + private String jobID; + + private String recordID; + + private String recordSig; + + private String connectorName; + + private String connectorStage; + + private String position; + + private Date createTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshWeredisPosition.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshWeredisPosition.java new file mode 100644 index 0000000000..2117230826 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/entity/EventMeshWeredisPosition.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * TableName event_mesh_weredis_position + */ +@TableName(value = "event_mesh_weredis_position") +@Data +public class EventMeshWeredisPosition implements Serializable { + @TableId(type = IdType.AUTO) + private Integer id; + + private String jobID; + + // connection run address + private String address; + + private String clusterName; + + private String partitionName; + + private String masterReplid; + + //weredis run host + private String host; + + private Long replOffset = -1L; + + private Date createTime; + + private Date updateTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshDataSourceMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshDataSourceMapper.java new file mode 100644 index 0000000000..c59e28428f --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshDataSourceMapper.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshDataSource; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * for table 'event_mesh_data_source' db operation + * 2024-05-09 15:52:49 + * entity.db.web.server.admin.eventmesh.apache.org.EventMeshDataSource + */ +@Mapper +public interface EventMeshDataSourceMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshJobInfoExtMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshJobInfoExtMapper.java new file mode 100644 index 0000000000..c04c4e3748 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshJobInfoExtMapper.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; + +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * etx operator for table event_mesh_job_info + */ +@Mapper +public interface EventMeshJobInfoExtMapper extends BaseMapper { + + @Insert("") + @Transactional(rollbackFor = Exception.class) + int saveBatch(@Param("jobs") List jobInfoList); +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshJobInfoMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshJobInfoMapper.java new file mode 100644 index 0000000000..39f8a4aed6 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshJobInfoMapper.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * for table 'event_mesh_job_info' db operation + * entity org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo + */ +@Mapper +public interface EventMeshJobInfoMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshMonitorMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshMonitorMapper.java new file mode 100644 index 0000000000..db77224637 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshMonitorMapper.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMonitor; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * event_mesh_monitor + * Entity org.apache.eventmesh.admin.server.web.db.entity.EventMeshMonitor + */ +@Mapper +public interface EventMeshMonitorMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshMysqlPositionMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshMysqlPositionMapper.java new file mode 100644 index 0000000000..f0a0467d76 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshMysqlPositionMapper.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMysqlPosition; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * for table `event_mesh_mysql_position` db operation + * 2024-05-14 17:15:03 + * entity.db.web.server.admin.eventmesh.apache.org.EventMeshMysqlPosition + */ +@Mapper +public interface EventMeshMysqlPositionMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshPositionReporterHistoryMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshPositionReporterHistoryMapper.java new file mode 100644 index 0000000000..adc6723b79 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshPositionReporterHistoryMapper.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshPositionReporterHistory; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * for table 'event_mesh_position_reporter_history' db operation + * 2024-05-14 17:15:03 + * entity.db.web.server.admin.eventmesh.apache.org.EventMeshPositionReporterHistory + */ +@Mapper +public interface EventMeshPositionReporterHistoryMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshRuntimeHeartbeatMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshRuntimeHeartbeatMapper.java new file mode 100644 index 0000000000..813769d2ab --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshRuntimeHeartbeatMapper.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHeartbeat; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * for table 'event_mesh_runtime_heartbeat' db operation + * 2024-05-14 17:15:03 + * entity.db.web.server.admin.eventmesh.apache.org.EventMeshRuntimeHeartbeat + */ +@Mapper +public interface EventMeshRuntimeHeartbeatMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshRuntimeHistoryMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshRuntimeHistoryMapper.java new file mode 100644 index 0000000000..5fc3a21f54 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshRuntimeHistoryMapper.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHistory; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * for table 'event_mesh_runtime_history' db operation + * 2024-05-14 17:15:03 + * entity.db.web.server.admin.eventmesh.apache.org.EventMeshRuntimeHistory + */ +@Mapper +public interface EventMeshRuntimeHistoryMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshTaskInfoMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshTaskInfoMapper.java new file mode 100644 index 0000000000..d1d472b8c4 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshTaskInfoMapper.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshTaskInfo; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * event_mesh_task_info + * Entity org.apache.eventmesh.admin.server.web.db.entity.EventMeshTaskInfo + */ +@Mapper +public interface EventMeshTaskInfoMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshVerifyMapper.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshVerifyMapper.java new file mode 100644 index 0000000000..b444d1e4b4 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/mapper/EventMeshVerifyMapper.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.mapper; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshVerify; + +import org.apache.ibatis.annotations.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * event_mesh_verify + * Entity org.apache.eventmesh.admin.server.web.db.entity.EventMeshVerify + */ +@Mapper +public interface EventMeshVerifyMapper extends BaseMapper { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshDataSourceService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshDataSourceService.java new file mode 100644 index 0000000000..29e2b8122e --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshDataSourceService.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshDataSource; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* +* for table 'event_mesh_data_source' db operation +* 2024-05-09 15:52:49 +*/ +public interface EventMeshDataSourceService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshJobInfoExtService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshJobInfoExtService.java new file mode 100644 index 0000000000..22fc5ae299 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshJobInfoExtService.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; + +import java.util.List; + +/** + * ext operator for table event_mesh_job + */ +public interface EventMeshJobInfoExtService { + int batchSave(List jobs); +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshJobInfoService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshJobInfoService.java new file mode 100644 index 0000000000..572e451ceb --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshJobInfoService.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * event_mesh_job_info + */ +public interface EventMeshJobInfoService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshMonitorService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshMonitorService.java new file mode 100644 index 0000000000..4180f82a97 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshMonitorService.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMonitor; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * event_mesh_monitor + */ +public interface EventMeshMonitorService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshMysqlPositionService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshMysqlPositionService.java new file mode 100644 index 0000000000..2bf34ab922 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshMysqlPositionService.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMysqlPosition; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* for table 'event_mesh_mysql_position' db operation +* 2024-05-14 17:15:03 +*/ +public interface EventMeshMysqlPositionService extends IService { +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshPositionReporterHistoryService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshPositionReporterHistoryService.java new file mode 100644 index 0000000000..976eec94ea --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshPositionReporterHistoryService.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshPositionReporterHistory; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* for table 'event_mesh_position_reporter_history' db operation +* 2024-05-14 17:15:03 +*/ +public interface EventMeshPositionReporterHistoryService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshRuntimeHeartbeatService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshRuntimeHeartbeatService.java new file mode 100644 index 0000000000..f0e5d1c61b --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshRuntimeHeartbeatService.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHeartbeat; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * for table 'event_mesh_runtime_heartbeat' db operation + * 2024-05-14 17:15:03 + */ +public interface EventMeshRuntimeHeartbeatService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshRuntimeHistoryService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshRuntimeHistoryService.java new file mode 100644 index 0000000000..1f6db0e12e --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshRuntimeHistoryService.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHistory; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * for table 'event_mesh_runtime_history' db operation + * 2024-05-14 17:15:03 + */ +public interface EventMeshRuntimeHistoryService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshTaskInfoService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshTaskInfoService.java new file mode 100644 index 0000000000..04da6a7952 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshTaskInfoService.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshTaskInfo; +import org.apache.eventmesh.common.remote.request.QueryTaskInfoRequest; +import org.apache.eventmesh.common.remote.response.QueryTaskInfoResponse; + +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * event_mesh_task_info + */ +public interface EventMeshTaskInfoService extends IService { + + List queryTaskInfo(QueryTaskInfoRequest taskInfoRequest); + + // boolean deleteTaskByTaskID(String taskID); + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshVerifyService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshVerifyService.java new file mode 100644 index 0000000000..97f2d7268e --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/EventMeshVerifyService.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshVerify; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * event_mesh_verify + */ +public interface EventMeshVerifyService extends IService { + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshDataSourceServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshDataSourceServiceImpl.java new file mode 100644 index 0000000000..f703425c94 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshDataSourceServiceImpl.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshDataSource; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshDataSourceMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshDataSourceService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * for table 'event_mesh_data_source' db operation + * 2024-05-09 15:52:49 + */ +@Service +public class EventMeshDataSourceServiceImpl extends ServiceImpl + implements EventMeshDataSourceService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshJobInfoExtServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshJobInfoExtServiceImpl.java new file mode 100644 index 0000000000..6cf0ebf6b2 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshJobInfoExtServiceImpl.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshJobInfoExtMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshJobInfoExtService; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class EventMeshJobInfoExtServiceImpl implements EventMeshJobInfoExtService { + @Autowired + EventMeshJobInfoExtMapper mapper; + + @Override + public int batchSave(List jobs) { + return mapper.saveBatch(jobs); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshJobInfoServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshJobInfoServiceImpl.java new file mode 100644 index 0000000000..4613e0809d --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshJobInfoServiceImpl.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshJobInfoMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshJobInfoService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * event_mesh_job_info + */ +@Service +public class EventMeshJobInfoServiceImpl extends ServiceImpl + implements EventMeshJobInfoService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshMonitorServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshMonitorServiceImpl.java new file mode 100644 index 0000000000..ebb4220000 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshMonitorServiceImpl.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMonitor; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshMonitorMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshMonitorService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * event_mesh_monitor + */ +@Service +public class EventMeshMonitorServiceImpl extends ServiceImpl + implements EventMeshMonitorService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshMysqlPositionServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshMysqlPositionServiceImpl.java new file mode 100644 index 0000000000..353443b78d --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshMysqlPositionServiceImpl.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMysqlPosition; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshMysqlPositionMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshMysqlPositionService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import lombok.extern.slf4j.Slf4j; + +/** + * for table 'event_mesh_mysql_position' db operation + * 2024-05-14 17:15:03 + */ +@Service +@Slf4j +public class EventMeshMysqlPositionServiceImpl extends ServiceImpl + implements EventMeshMysqlPositionService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshPositionReporterHistoryServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshPositionReporterHistoryServiceImpl.java new file mode 100644 index 0000000000..d546e412ba --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshPositionReporterHistoryServiceImpl.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshPositionReporterHistory; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshPositionReporterHistoryMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshPositionReporterHistoryService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * for table 'event_mesh_position_reporter_history' db operation + * 2024-05-14 17:15:03 + */ +@Service +public class EventMeshPositionReporterHistoryServiceImpl extends ServiceImpl + implements EventMeshPositionReporterHistoryService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshRuntimeHeartbeatServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshRuntimeHeartbeatServiceImpl.java new file mode 100644 index 0000000000..452569e3a6 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshRuntimeHeartbeatServiceImpl.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHeartbeat; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshRuntimeHeartbeatMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshRuntimeHeartbeatService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import lombok.extern.slf4j.Slf4j; + +/** + * for table 'event_mesh_runtime_heartbeat' db operation + * 2024-05-14 17:15:03 + */ +@Service +@Slf4j +public class EventMeshRuntimeHeartbeatServiceImpl extends ServiceImpl + implements EventMeshRuntimeHeartbeatService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshRuntimeHistoryServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshRuntimeHistoryServiceImpl.java new file mode 100644 index 0000000000..d39e868ce5 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshRuntimeHistoryServiceImpl.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHistory; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshRuntimeHistoryMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshRuntimeHistoryService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * for table 'event_mesh_runtime_history' db operation + * 2024-05-14 17:15:03 + */ +@Service +public class EventMeshRuntimeHistoryServiceImpl extends ServiceImpl + implements EventMeshRuntimeHistoryService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshTaskInfoServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshTaskInfoServiceImpl.java new file mode 100644 index 0000000000..91acb51a76 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshTaskInfoServiceImpl.java @@ -0,0 +1,323 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshDataSource; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMysqlPosition; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshTaskInfo; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshTaskInfoMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshDataSourceService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshJobInfoService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshMysqlPositionService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshTaskInfoService; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.request.QueryTaskInfoRequest; +import org.apache.eventmesh.common.remote.response.QueryTaskInfoResponse; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import lombok.extern.slf4j.Slf4j; + +/** + * event_mesh_task_info + */ +@Slf4j +@Service +public class EventMeshTaskInfoServiceImpl extends ServiceImpl + implements EventMeshTaskInfoService { + + @Autowired + private EventMeshTaskInfoMapper taskInfoMapper; + + @Autowired + private EventMeshJobInfoService jobInfoService; + + @Autowired + private EventMeshDataSourceService dataSourceService; + + @Autowired + private EventMeshMysqlPositionService mysqlPositionService; + + @Override + public List queryTaskInfo(QueryTaskInfoRequest taskInfoRequest) { + + log.info("receive query task info request:{}", taskInfoRequest); + + List queryTaskInfoResponseList = new ArrayList<>(); + + Integer currentPage = taskInfoRequest.getCurrentPage(); + Integer pageSize = taskInfoRequest.getPageSize(); + + // query by page + if (StringUtils.isEmpty(taskInfoRequest.getTaskID()) + && currentPage != null + && pageSize != null) { + + Page page = new Page<>(); + page.setCurrent(currentPage); + page.setSize(pageSize); + List eventMeshTaskInfoList = taskInfoMapper.selectPage(page, Wrappers.query() + .ne("taskState", TaskState.DELETE.name())).getRecords(); + queryTaskInfoResponseList = getQueryTaskInfoResponses(eventMeshTaskInfoList, queryTaskInfoResponseList); + + } + + if (StringUtils.isNotEmpty(taskInfoRequest.getTaskID()) || StringUtils.isNotEmpty(taskInfoRequest.getTaskID())) { + queryTaskInfoResponseList = eventMeshTaskInfoList(taskInfoRequest); + } + + // if (StringUtils.isNotEmpty(taskInfoRequest.getJobType())) { + // + // } + // + // if (StringUtils.isNotEmpty(taskInfoRequest.getSourceDataID())) { + // + // } + // + // if (StringUtils.isNotEmpty(taskInfoRequest.getTargetDataID())) { + // + // } + // + // if (StringUtils.isNotEmpty(taskInfoRequest.getIp())) { + // + // } + // + // if (StringUtils.isNotEmpty(taskInfoRequest.getSourceTableName())) { + // + // } + // + // if (StringUtils.isNotEmpty(taskInfoRequest.getTaskMathID())) { + // + // } + + log.info("query event mesh task info response result:{}", queryTaskInfoResponseList); + + return queryTaskInfoResponseList; + } + + @Transactional + private List eventMeshTaskInfoList(QueryTaskInfoRequest taskInfoRequest) { + + List eventMeshTaskInfoList = new ArrayList<>(); + + Page page = new Page<>(); + page.setCurrent(taskInfoRequest.getCurrentPage()); + page.setSize(taskInfoRequest.getPageSize()); + + if (StringUtils.isNotEmpty(taskInfoRequest.getTaskID())) { + eventMeshTaskInfoList = taskInfoMapper.selectPage(page, Wrappers.query() + .eq("taskID", taskInfoRequest.getTaskID()) + .ne("taskState", TaskState.DELETE.name())) + .getRecords(); + } + + if (StringUtils.isNotEmpty(taskInfoRequest.getTaskDesc())) { + eventMeshTaskInfoList = taskInfoMapper.selectPage(page, Wrappers.query() + .like("taskDesc", taskInfoRequest.getTaskDesc()) + .ne("jobState", JobState.DELETE.name())) + .getRecords(); + } + + List eventMeshTaskInfos = new ArrayList<>(); + + List queryTaskInfoResponse = getQueryTaskInfoResponses(eventMeshTaskInfoList, eventMeshTaskInfos); + log.info("query task info result queryTaskInfoResponse:{}", queryTaskInfoResponse); + + return queryTaskInfoResponse; + } + + private List getQueryTaskInfoResponses(List eventMeshTaskInfoList, + List eventMeshTaskInfos) { + + for (EventMeshTaskInfo meshTaskInfo : eventMeshTaskInfoList) { + QueryTaskInfoResponse eventMeshTaskInfo = initEventMeshTaskInfo(meshTaskInfo); + eventMeshTaskInfos.add(eventMeshTaskInfo); + } + + if (!eventMeshTaskInfoList.isEmpty()) { + List eventMeshJobInfoList = new ArrayList<>(); + for (QueryTaskInfoResponse eventMeshTaskInfo : eventMeshTaskInfos) { + List eventMeshJobInfos = jobInfoService.list(Wrappers.query() + .eq("taskID", eventMeshTaskInfo.getTaskID()) + .ne("jobState", JobState.DELETE.name())); + + for (EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfos) { + QueryTaskInfoResponse.EventMeshJobInfo eventMeshJobInfoCovert = initEventMeshJobInfo(eventMeshJobInfo); + eventMeshJobInfoList.add(eventMeshJobInfoCovert); + } + + if (!eventMeshJobInfoList.isEmpty()) { + for (QueryTaskInfoResponse.EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfoList) { + QueryTaskInfoResponse.EventMeshDataSource dataSource = covertEventMeshDataSource( + querySourceOrSinkData(eventMeshJobInfo.getSourceData())); + QueryTaskInfoResponse.EventMeshDataSource dataSink = covertEventMeshDataSource( + querySourceOrSinkData(eventMeshJobInfo.getTargetData())); + + EventMeshMysqlPosition eventMeshMysqlPosition = mysqlPositionService.getOne(Wrappers.query().eq( + "jobID", + eventMeshJobInfo.getJobID() + )); + + + QueryTaskInfoResponse.EventMeshMysqlPosition mysqlPosition = covertEventMeshMysqlPosition(eventMeshMysqlPosition); + + eventMeshJobInfo.setEventMeshMysqlPosition(mysqlPosition); + eventMeshJobInfo.setDataSource(dataSource); + eventMeshJobInfo.setDataSink(dataSink); + } + } + + // set job info to same taskID + eventMeshTaskInfo.setEventMeshJobInfoList(eventMeshJobInfoList); + } + } + + List queryTaskInfoResponse = new ArrayList<>(); + if (!eventMeshTaskInfos.isEmpty()) { + queryTaskInfoResponse.addAll(eventMeshTaskInfos); + } + + return queryTaskInfoResponse; + } + + /** + * QueryTaskInfoResponse.EventMeshDataSource covert + * + * @param eventMeshData EventMeshDataSource + * @return meshData + */ + private static QueryTaskInfoResponse.EventMeshDataSource covertEventMeshDataSource(EventMeshDataSource eventMeshData) { + QueryTaskInfoResponse.EventMeshDataSource meshData = new QueryTaskInfoResponse.EventMeshDataSource(); + if (ObjectUtils.isEmpty(eventMeshData)) { + return null; + } + meshData.setId(eventMeshData.getId()); + meshData.setDataType(eventMeshData.getDataType()); + meshData.setConfiguration(eventMeshData.getConfiguration()); + meshData.setConfigurationClass(eventMeshData.getConfigurationClass()); + meshData.setDescription(eventMeshData.getDescription()); + meshData.setRegion(eventMeshData.getRegion()); + meshData.setCreateUid(eventMeshData.getCreateUid()); + meshData.setUpdateUid(eventMeshData.getUpdateUid()); + meshData.setCreateTime(eventMeshData.getCreateTime()); + meshData.setUpdateTime(eventMeshData.getUpdateTime()); + return meshData; + } + + /** + * getSourceOrSinkData + * + * @param id id + * @return EventMeshDataSource + */ + private EventMeshDataSource querySourceOrSinkData(Integer id) { + return dataSourceService.getOne(Wrappers.query().eq( + "id", + id)); + } + + /** + * QueryTaskInfoResponse.EventMeshMysqlPosition + * + * @param mysqlPosition EventMeshMysqlPosition + * @return position + */ + private static QueryTaskInfoResponse.EventMeshMysqlPosition covertEventMeshMysqlPosition(EventMeshMysqlPosition mysqlPosition) { + QueryTaskInfoResponse.EventMeshMysqlPosition position = new QueryTaskInfoResponse.EventMeshMysqlPosition(); + if (ObjectUtils.isEmpty(mysqlPosition)) { + return null; + } + position.setId(mysqlPosition.getId()); + position.setJobID(mysqlPosition.getJobID()); + position.setServerUUID(mysqlPosition.getServerUUID()); + position.setAddress(mysqlPosition.getAddress()); + position.setPosition(mysqlPosition.getPosition()); + position.setGtid(mysqlPosition.getGtid()); + position.setCurrentGtid(mysqlPosition.getCurrentGtid()); + position.setTimestamp(mysqlPosition.getTimestamp()); + position.setJournalName(mysqlPosition.getJournalName()); + position.setCreateTime(mysqlPosition.getCreateTime()); + position.setUpdateTime(mysqlPosition.getUpdateTime()); + return position; + } + + /** + * EventMeshJobInfo covert + * + * @param eventMeshJobInfo EventMeshJobInfo + * @return QueryTaskInfoResponse.EventMeshJobInfo + */ + private static QueryTaskInfoResponse.EventMeshJobInfo initEventMeshJobInfo(EventMeshJobInfo eventMeshJobInfo) { + QueryTaskInfoResponse.EventMeshJobInfo eventMeshJobInfoCovert = new QueryTaskInfoResponse.EventMeshJobInfo(); + if (ObjectUtils.isEmpty(eventMeshJobInfo)) { + return null; + } + eventMeshJobInfoCovert.setId(eventMeshJobInfo.getId()); + eventMeshJobInfoCovert.setJobID(eventMeshJobInfo.getJobID()); + eventMeshJobInfoCovert.setJobDesc(eventMeshJobInfo.getJobDesc()); + eventMeshJobInfoCovert.setTaskID(eventMeshJobInfo.getTaskID()); + eventMeshJobInfoCovert.setTransportType(eventMeshJobInfo.getTransportType()); + eventMeshJobInfoCovert.setSourceData(eventMeshJobInfo.getSourceData()); + eventMeshJobInfoCovert.setTargetData(eventMeshJobInfo.getTargetData()); + eventMeshJobInfoCovert.setJobState(eventMeshJobInfo.getJobState()); + eventMeshJobInfoCovert.setJobType(eventMeshJobInfo.getJobType()); + eventMeshJobInfoCovert.setFromRegion(eventMeshJobInfo.getFromRegion()); + eventMeshJobInfoCovert.setRunningRegion(eventMeshJobInfo.getRunningRegion()); + eventMeshJobInfoCovert.setCreateUid(eventMeshJobInfo.getCreateUid()); + eventMeshJobInfoCovert.setUpdateUid(eventMeshJobInfo.getUpdateUid()); + eventMeshJobInfoCovert.setCreateTime(eventMeshJobInfo.getCreateTime()); + eventMeshJobInfoCovert.setUpdateTime(eventMeshJobInfo.getUpdateTime()); + return eventMeshJobInfoCovert; + } + + /** + * EventMeshTaskInfo covert + * + * @param meshTaskInfo EventMeshTaskInfo + * @return QueryTaskInfoResponse + */ + private static QueryTaskInfoResponse initEventMeshTaskInfo(EventMeshTaskInfo meshTaskInfo) { + QueryTaskInfoResponse eventMeshTaskInfo = new QueryTaskInfoResponse(); + eventMeshTaskInfo.setId(meshTaskInfo.getId()); + eventMeshTaskInfo.setTaskID(meshTaskInfo.getTaskID()); + eventMeshTaskInfo.setTaskDesc(meshTaskInfo.getTaskDesc()); + eventMeshTaskInfo.setTaskState(meshTaskInfo.getTaskState()); + eventMeshTaskInfo.setSourceRegion(meshTaskInfo.getSourceRegion()); + eventMeshTaskInfo.setTargetRegion(meshTaskInfo.getTargetRegion()); + eventMeshTaskInfo.setCreateUid(meshTaskInfo.getCreateUid()); + eventMeshTaskInfo.setUpdateUid(meshTaskInfo.getUpdateUid()); + eventMeshTaskInfo.setCreateTime(meshTaskInfo.getCreateTime()); + eventMeshTaskInfo.setUpdateTime(meshTaskInfo.getUpdateTime()); + return eventMeshTaskInfo; + } + +} \ No newline at end of file diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshVerifyServiceImpl.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshVerifyServiceImpl.java new file mode 100644 index 0000000000..5e49ba32ea --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/db/service/impl/EventMeshVerifyServiceImpl.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.db.service.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshVerify; +import org.apache.eventmesh.admin.server.web.db.mapper.EventMeshVerifyMapper; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshVerifyService; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * event_mesh_verify + */ +@Service +public class EventMeshVerifyServiceImpl extends ServiceImpl + implements EventMeshVerifyService { + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/BaseRequestHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/BaseRequestHandler.java new file mode 100644 index 0000000000..7f08f388c9 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/BaseRequestHandler.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.request.BaseRemoteRequest; +import org.apache.eventmesh.common.remote.response.BaseRemoteResponse; + +public abstract class BaseRequestHandler { + + public BaseRemoteResponse handlerRequest(T request, Metadata metadata) { + return handler(request, metadata); + } + + protected abstract S handler(T request, Metadata metadata); +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/RequestHandlerFactory.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/RequestHandlerFactory.java new file mode 100644 index 0000000000..9375fb537e --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/RequestHandlerFactory.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler; + +import org.apache.eventmesh.common.remote.request.BaseRemoteRequest; +import org.apache.eventmesh.common.remote.response.BaseRemoteResponse; + +import java.lang.reflect.ParameterizedType; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Component +public class RequestHandlerFactory implements ApplicationListener { + + private final Map> handlers = + new ConcurrentHashMap<>(); + + public BaseRequestHandler getHandler(String type) { + return handlers.get(type); + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public void onApplicationEvent(ContextRefreshedEvent event) { + Map beans = + event.getApplicationContext().getBeansOfType(BaseRequestHandler.class); + + for (BaseRequestHandler requestHandler : beans.values()) { + Class clazz = requestHandler.getClass(); + boolean skip = false; + while (!clazz.getSuperclass().equals(BaseRequestHandler.class)) { + if (clazz.getSuperclass().equals(Object.class)) { + skip = true; + break; + } + clazz = clazz.getSuperclass(); + } + if (skip) { + continue; + } + + Class c = (Class) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0]; + handlers.putIfAbsent(c.getSimpleName(), requestHandler); + } + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/FetchJobRequestHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/FetchJobRequestHandler.java new file mode 100644 index 0000000000..3392084c28 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/FetchJobRequestHandler.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.pojo.JobDetail; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.job.JobConnectorConfig; +import org.apache.eventmesh.common.remote.request.FetchJobRequest; +import org.apache.eventmesh.common.remote.response.FetchJobResponse; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.commons.lang3.StringUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class FetchJobRequestHandler extends BaseRequestHandler { + + @Autowired + JobInfoBizService jobInfoBizService; + + @Override + public FetchJobResponse handler(FetchJobRequest request, Metadata metadata) { + if (StringUtils.isBlank(request.getJobID())) { + return FetchJobResponse.failResponse(ErrorCode.BAD_REQUEST, "job id is empty"); + } + FetchJobResponse response = FetchJobResponse.successResponse(); + JobDetail detail = jobInfoBizService.getJobDetail(request.getJobID()); + if (detail == null) { + return response; + } + response.setId(detail.getJobID()); + JobConnectorConfig config = new JobConnectorConfig(); + config.setSourceConnectorConfig(JsonUtils.objectToMap(detail.getSourceDataSource().getConf())); + config.setSourceConnectorDesc(detail.getSourceConnectorDesc()); + config.setSinkConnectorConfig(JsonUtils.objectToMap(detail.getSinkDataSource().getConf())); + config.setSinkConnectorDesc(detail.getSinkConnectorDesc()); + response.setConnectorConfig(config); + response.setTransportType(detail.getTransportType()); + response.setState(detail.getState()); + response.setPosition(detail.getPositions()); + response.setType(detail.getJobType()); + return response; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/FetchPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/FetchPositionHandler.java new file mode 100644 index 0000000000..85ef0e6113 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/FetchPositionHandler.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.web.db.DBThreadPool; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.service.position.PositionBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.request.FetchPositionRequest; +import org.apache.eventmesh.common.remote.response.FetchPositionResponse; + +import org.apache.commons.lang3.StringUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class FetchPositionHandler extends BaseRequestHandler { + + @Autowired + DBThreadPool executor; + + @Autowired + PositionBizService positionBizService; + + @Override + protected FetchPositionResponse handler(FetchPositionRequest request, Metadata metadata) { + if (request.getDataSourceType() == null) { + return FetchPositionResponse.failResponse(ErrorCode.BAD_REQUEST, "illegal data type, it's empty"); + } + if (StringUtils.isBlank(request.getJobID())) { + return FetchPositionResponse.failResponse(ErrorCode.BAD_REQUEST, "illegal job id, it's empty"); + } + return FetchPositionResponse.successResponse(positionBizService.getPosition(request, metadata)); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportHeartBeatHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportHeartBeatHandler.java new file mode 100644 index 0000000000..26a9b430b7 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportHeartBeatHandler.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.web.db.DBThreadPool; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHeartbeat; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.service.heatbeat.RuntimeHeartbeatBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.request.ReportHeartBeatRequest; +import org.apache.eventmesh.common.remote.response.SimpleResponse; +import org.apache.eventmesh.common.utils.IPUtils; + +import org.apache.commons.lang3.StringUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class ReportHeartBeatHandler extends BaseRequestHandler { + + @Autowired + RuntimeHeartbeatBizService heartbeatBizService; + + @Autowired + DBThreadPool executor; + + @Override + protected SimpleResponse handler(ReportHeartBeatRequest request, Metadata metadata) { + if (StringUtils.isBlank(request.getJobID()) || StringUtils.isBlank(request.getAddress())) { + log.info("request [{}] id or reporter address is empty", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "request id or reporter address is empty"); + } + executor.getExecutors().execute(() -> { + EventMeshRuntimeHeartbeat heartbeat = new EventMeshRuntimeHeartbeat(); + heartbeat.setJobID(request.getJobID()); + heartbeat.setReportTime(request.getReportedTimeStamp()); + heartbeat.setAdminAddr(IPUtils.getLocalAddress()); + heartbeat.setRuntimeAddr(request.getAddress()); + try { + if (!heartbeatBizService.saveOrUpdateByRuntimeAddress(heartbeat)) { + log.warn("save or update heartbeat request [{}] fail", request); + } + } catch (Exception e) { + log.warn("save or update heartbeat request [{}] fail", request, e); + } + }); + + return SimpleResponse.success(); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportJobRequestHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportJobRequestHandler.java new file mode 100644 index 0000000000..c876014f63 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportJobRequestHandler.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.pojo.TaskDetail; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.admin.server.web.service.position.PositionBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.TransportType; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.request.RecordPositionRequest; +import org.apache.eventmesh.common.remote.request.ReportJobRequest; +import org.apache.eventmesh.common.remote.response.SimpleResponse; + +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + + +@Component +@Slf4j +public class ReportJobRequestHandler extends BaseRequestHandler { + + @Autowired + JobInfoBizService jobInfoBizService; + + @Autowired + PositionBizService positionBizService; + + @Override + public SimpleResponse handler(ReportJobRequest request, Metadata metadata) { + log.info("receive report job request:{}", request); + if (StringUtils.isBlank(request.getJobID())) { + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "illegal job id, it's empty"); + } + EventMeshJobInfo jobInfo = jobInfoBizService.getJobInfo(request.getJobID()); + if (jobInfo == null) { + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "illegal job id, not exist target job,jobID:" + request.getJobID()); + } + boolean recordResult = recordPosition(request, metadata, jobInfo); + boolean result = recordResult && jobInfoBizService.updateJobState(jobInfo.getJobID(), request.getState()); + if (result) { + return SimpleResponse.success(); + } else { + return SimpleResponse.fail(ErrorCode.INTERNAL_ERR, "update job failed."); + } + } + + private boolean recordPosition(ReportJobRequest request, Metadata metadata, EventMeshJobInfo jobInfo) { + if (!jobInfo.getJobState().equalsIgnoreCase(JobState.INIT.name()) || !JobState.RUNNING.name().equalsIgnoreCase(request.getState().name())) { + log.info("skip record position because of job state not from init change to running.jobID:{}", jobInfo.getJobID()); + return true; + } + + TaskDetail taskDetail = jobInfoBizService.getTaskDetail(jobInfo.getTaskID(), DataSourceType.MYSQL); + if (taskDetail.getFullTask() == null || taskDetail.getIncreaseTask() == null) { + log.info("skip record position because of not exist full and increase job.jobID:{}", jobInfo.getJobID()); + return true; + } + + List recordPositionList = + positionBizService.getPositionByJobID(taskDetail.getIncreaseTask().getJobID(), DataSourceType.MYSQL); + if (!recordPositionList.isEmpty()) { + log.info("skip record position because of increase job has exist position.jobID:{},position list size:{}", jobInfo.getJobID(), + recordPositionList.size()); + return true; + } + + RecordPositionRequest recordPositionRequest = new RecordPositionRequest(); + recordPositionRequest.setFullJobID(taskDetail.getFullTask().getJobID()); + recordPositionRequest.setIncreaseJobID(taskDetail.getIncreaseTask().getJobID()); + recordPositionRequest.setUpdateState(request.getState()); + recordPositionRequest.setAddress(request.getAddress()); + TransportType currentTransportType = TransportType.getTransportType(jobInfo.getTransportType()); + recordPositionRequest.setDataSourceType(currentTransportType.getSrc()); + return positionBizService.recordPosition(recordPositionRequest, metadata); + } + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportMonitorHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportMonitorHandler.java new file mode 100644 index 0000000000..a36939bb88 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportMonitorHandler.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.AdminServerProperties; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.admin.server.web.service.monitor.MonitorBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.request.ReportMonitorRequest; +import org.apache.eventmesh.common.remote.response.SimpleResponse; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class ReportMonitorHandler extends BaseRequestHandler { + + @Autowired + private MonitorBizService monitorService; + + @Autowired + JobInfoBizService jobInfoBizService; + + @Autowired + private AdminServerProperties properties; + + @Override + protected SimpleResponse handler(ReportMonitorRequest request, Metadata metadata) { + if (StringUtils.isAnyBlank(request.getTaskID(), request.getJobID(), request.getAddress())) { + log.info("report monitor request [{}] illegal", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "request task id,job id or address is none"); + } + + String jobID = request.getJobID(); + EventMeshJobInfo jobInfo = jobInfoBizService.getJobInfo(jobID); + if (jobInfo == null || StringUtils.isBlank(jobInfo.getFromRegion())) { + log.info("report monitor job info [{}] illegal", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "job info is null or fromRegion is blank,job id:" + jobID); + } + String fromRegion = jobInfo.getFromRegion(); + String transportType = jobInfo.getTransportType(); + if (StringUtils.isEmpty(request.getTransportType())) { + request.setTransportType(transportType); + } + String localRegion = properties.getRegion(); + log.info("report monitor request from region:{},localRegion:{},request:{}", fromRegion, localRegion, request); + if (fromRegion.equalsIgnoreCase(localRegion)) { + return monitorService.reportMonitorRecord(request) ? SimpleResponse.success() : + SimpleResponse.fail(ErrorCode.INTERNAL_ERR, "save monitor " + + "request fail"); + } else { + List adminServerList = Arrays.asList(properties.getAdminServerList().get(fromRegion).split(";")); + if (adminServerList == null || adminServerList.isEmpty()) { + throw new RuntimeException("No admin server available for region: " + fromRegion); + } + String targetUrl = adminServerList.get(new Random().nextInt(adminServerList.size())) + "/eventmesh/admin/reportMonitor"; + log.info("start transfer monitor request to from region admin server. from region:{}, targetUrl:{}", fromRegion, targetUrl); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.postForEntity(targetUrl, request, String.class); + if (!response.getStatusCode().is2xxSuccessful()) { + log.error("transfer monitor request to from region admin server error. from region:{}, targetUrl:{}", fromRegion, targetUrl); + return SimpleResponse.fail(ErrorCode.INTERNAL_ERR, + "save monitor request fail,code:" + response.getStatusCode() + ",msg:" + response.getBody()); + } + return SimpleResponse.success(); + } + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportPositionHandler.java new file mode 100644 index 0000000000..7a30bef80a --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportPositionHandler.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.web.db.DBThreadPool; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.pojo.JobDetail; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.admin.server.web.service.position.PositionBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.request.ReportPositionRequest; +import org.apache.eventmesh.common.remote.response.SimpleResponse; + +import org.apache.commons.lang3.StringUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class ReportPositionHandler extends BaseRequestHandler { + + @Autowired + private JobInfoBizService jobInfoBizService; + + @Autowired + private DBThreadPool executor; + + @Autowired + private PositionBizService positionBizService; + + @Override + protected SimpleResponse handler(ReportPositionRequest request, Metadata metadata) { + log.info("receive report position request:{}", request); + if (StringUtils.isBlank(request.getJobID())) { + log.info("request [{}] illegal job id", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "illegal job id, it's empty"); + } + if (request.getDataSourceType() == null) { + log.info("request [{}] illegal data type", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "illegal data type, it's empty"); + } + if (StringUtils.isBlank(request.getJobID())) { + log.info("request [{}] illegal job id", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "illegal job id, it's empty"); + } + if (request.getRecordPositionList() == null || request.getRecordPositionList().isEmpty()) { + log.info("request [{}] illegal record position", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "illegal record position list, it's empty"); + } + + positionBizService.isValidatePositionRequest(request.getDataSourceType()); + + executor.getExecutors().execute(() -> { + try { + boolean reported = positionBizService.reportPosition(request, metadata); + if (reported) { + if (log.isDebugEnabled()) { + log.debug("handle runtime [{}] report data type [{}] job [{}] position [{}] success", + request.getAddress(), request.getDataSourceType(), request.getJobID(), + request.getRecordPositionList()); + } + } else { + log.warn("handle runtime [{}] report data type [{}] job [{}] position [{}] fail", + request.getAddress(), request.getDataSourceType(), request.getJobID(), + request.getRecordPositionList()); + } + } catch (Exception e) { + log.warn("handle position request fail, request [{}]", request, e); + } finally { + try { + JobDetail detail = jobInfoBizService.getJobDetail(request.getJobID()); + if (detail != null && !detail.getState().equals(request.getState()) && !jobInfoBizService.updateJobState(request.getJobID(), + request.getState())) { + log.warn("update job [{}] old state [{}] to [{}] fail", request.getJobID(), detail.getState(), request.getState()); + } + } catch (Exception e) { + log.warn("update job id [{}] type [{}] state [{}] fail", request.getJobID(), + request.getDataSourceType(), request.getState(), e); + } + } + }); + return SimpleResponse.success(); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportVerifyHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportVerifyHandler.java new file mode 100644 index 0000000000..e7f1d1257f --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/handler/impl/ReportVerifyHandler.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.handler.impl; + +import org.apache.eventmesh.admin.server.AdminServerProperties; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.admin.server.web.service.verify.VerifyBizService; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.request.ReportVerifyRequest; +import org.apache.eventmesh.common.remote.response.SimpleResponse; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class ReportVerifyHandler extends BaseRequestHandler { + + @Autowired + private VerifyBizService verifyService; + + @Autowired + JobInfoBizService jobInfoBizService; + + @Autowired + private AdminServerProperties properties; + + @Override + protected SimpleResponse handler(ReportVerifyRequest request, Metadata metadata) { + if (StringUtils.isAnyBlank(request.getTaskID(), request.getJobID(), request.getRecordSig(), request.getRecordID(), + request.getConnectorStage())) { + log.info("report verify request [{}] illegal", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "request task id,job id, sign, record id or stage is none"); + } + + String jobID = request.getJobID(); + EventMeshJobInfo jobInfo = jobInfoBizService.getJobInfo(jobID); + if (jobInfo == null || StringUtils.isBlank(jobInfo.getFromRegion())) { + log.info("report verify job info [{}] illegal", request); + return SimpleResponse.fail(ErrorCode.BAD_REQUEST, "job info is null or fromRegion is blank,job id:" + jobID); + } + + String fromRegion = jobInfo.getFromRegion(); + String localRegion = properties.getRegion(); + log.info("report verify request from region:{},localRegion:{},request:{}", fromRegion, localRegion, request); + if (fromRegion.equalsIgnoreCase(localRegion)) { + return verifyService.reportVerifyRecord(request) ? SimpleResponse.success() : SimpleResponse.fail(ErrorCode.INTERNAL_ERR, "save verify " + + "request fail"); + } else { + log.info("start transfer report verify to from region admin server. from region:{}", fromRegion); + List adminServerList = Arrays.asList(properties.getAdminServerList().get(fromRegion).split(";")); + if (adminServerList == null || adminServerList.isEmpty()) { + throw new RuntimeException("No admin server available for region: " + fromRegion); + } + String targetUrl = adminServerList.get(new Random().nextInt(adminServerList.size())) + "/eventmesh/admin/reportVerify"; + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.postForEntity(targetUrl, request, String.class); + if (!response.getStatusCode().is2xxSuccessful()) { + return SimpleResponse.fail(ErrorCode.INTERNAL_ERR, + "save verify request fail,code:" + response.getStatusCode() + ",msg:" + response.getBody()); + } + return SimpleResponse.success(); + } + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/BinlogPosition.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/BinlogPosition.java new file mode 100644 index 0000000000..5bd8daab10 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/BinlogPosition.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.pojo; + + +import lombok.Data; + +@Data +public class BinlogPosition { + private String file; + private Long position; +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/JobDetail.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/JobDetail.java new file mode 100644 index 0000000000..0e2fa64878 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/JobDetail.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.pojo; + +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.TransportType; +import org.apache.eventmesh.common.remote.datasource.DataSource; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.Date; +import java.util.List; + +import lombok.Data; + +@Data +public class JobDetail { + private Integer id; + + private String jobID; + + private String jobDesc; + + private String taskID; + + private TaskState state; + + private JobType jobType; + + private Date createTime; + + private Date updateTime; + + private String createUid; + + private String updateUid; + + // job request from region + private String fromRegion; + + // job actually running region + private String runningRegion; + + private DataSource sourceDataSource; + + private String sourceConnectorDesc; + + private DataSource sinkDataSource; + + private String sinkConnectorDesc; + + private TransportType transportType; + + private List positions; +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/TaskDetail.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/TaskDetail.java new file mode 100644 index 0000000000..2b174209e2 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/pojo/TaskDetail.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.pojo; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; + +import lombok.Data; + +/** + * Description: + */ +@Data +public class TaskDetail { + + private EventMeshJobInfo fullTask; + + private EventMeshJobInfo increaseTask; + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/AdminGrpcServer.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/AdminGrpcServer.java new file mode 100644 index 0000000000..bc822ad6c3 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/AdminGrpcServer.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service; + +import org.apache.eventmesh.admin.server.AdminServerRuntimeException; +import org.apache.eventmesh.admin.server.web.handler.BaseRequestHandler; +import org.apache.eventmesh.admin.server.web.handler.RequestHandlerFactory; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.payload.PayloadUtil; +import org.apache.eventmesh.common.remote.request.BaseRemoteRequest; +import org.apache.eventmesh.common.remote.response.BaseRemoteResponse; +import org.apache.eventmesh.common.remote.response.SimpleResponse; + +import org.apache.commons.lang3.StringUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import io.grpc.stub.ServerCallStreamObserver; +import io.grpc.stub.StreamObserver; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class AdminGrpcServer extends AdminServiceGrpc.AdminServiceImplBase { + + @Autowired + RequestHandlerFactory handlerFactory; + + private Payload process(Payload value) { + if (value == null || StringUtils.isBlank(value.getMetadata().getType())) { + return PayloadUtil.from(SimpleResponse.fail(ErrorCode.BAD_REQUEST, "bad request: type not exists")); + } + try { + BaseRequestHandler handler = handlerFactory.getHandler(value.getMetadata().getType()); + if (handler == null) { + return PayloadUtil.from(SimpleResponse.fail(ErrorCode.BAD_REQUEST, "not match any request handler")); + } + BaseRemoteResponse response = handler.handlerRequest((BaseRemoteRequest) PayloadUtil.parse(value), value.getMetadata()); + if (response == null) { + log.warn("received request type [{}] handler [{}], then replay empty response", value.getMetadata().getType(), + handler.getClass().getName()); + response = SimpleResponse.success(); + } + return PayloadUtil.from(response); + } catch (Exception e) { + log.warn("process payload {} fail", value.getMetadata().getType(), e); + if (e instanceof AdminServerRuntimeException) { + return PayloadUtil.from(SimpleResponse.fail(((AdminServerRuntimeException) e).getCode(), e.getMessage())); + } + return PayloadUtil.from(SimpleResponse.fail(ErrorCode.INTERNAL_ERR, "admin server internal err")); + } + } + + public StreamObserver invokeBiStream(StreamObserver responseObserver) { + return new StreamObserver() { + @Override + public void onNext(Payload value) { + Payload payload = process(value); + if (payload == null) { + return; + } + responseObserver.onNext(payload); + } + + @Override + public void onError(Throwable t) { + if (responseObserver instanceof ServerCallStreamObserver) { + if (!((ServerCallStreamObserver) responseObserver).isCancelled()) { + log.warn("admin gRPC server fail", t); + } + } + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + }; + } + + public void invoke(Payload request, StreamObserver responseObserver) { + responseObserver.onNext(process(request)); + responseObserver.onCompleted(); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/AdminServer.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/AdminServer.java new file mode 100644 index 0000000000..fd7582800d --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/AdminServer.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service; + +import org.apache.eventmesh.admin.server.AdminServerProperties; +import org.apache.eventmesh.admin.server.AdminServerRuntimeException; +import org.apache.eventmesh.common.ComponentLifeCycle; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.registry.RegisterServerInfo; +import org.apache.eventmesh.registry.RegistryFactory; +import org.apache.eventmesh.registry.RegistryService; + +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.PostConstruct; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class AdminServer implements ComponentLifeCycle, ApplicationListener { + private final RegistryService registryService; + + private final RegisterServerInfo adminServeInfo; + + private final CommonConfiguration configuration; + + public AdminServer(AdminServerProperties properties) { + configuration = + ConfigService.getInstance().buildConfigInstance(CommonConfiguration.class); + if (configuration == null) { + throw new AdminServerRuntimeException(ErrorCode.STARTUP_CONFIG_MISS, "common configuration file miss"); + } + this.adminServeInfo = new RegisterServerInfo(); + + adminServeInfo.setHealth(true); + adminServeInfo.setAddress(IPUtils.getLocalAddress() + ":" + properties.getPort()); + String name = Constants.ADMIN_SERVER_REGISTRY_NAME; + if (StringUtils.isNotBlank(properties.getServiceName())) { + name = properties.getServiceName(); + } + adminServeInfo.setServiceName(name); + registryService = RegistryFactory.getInstance(configuration.getEventMeshRegistryPluginType()); + } + + @Override + @PostConstruct + public void start() { + if (configuration.isEventMeshRegistryPluginEnabled()) { + registryService.init(); + } + } + + @Override + public void stop() { + if (configuration.isEventMeshRegistryPluginEnabled()) { + registryService.unRegister(adminServeInfo); + try { + Thread.sleep(3000); + } catch (InterruptedException ignore) { + log.warn("interrupted when sleep"); + Thread.currentThread().interrupt(); + } + registryService.shutdown(); + } + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + if (configuration.isEventMeshRegistryPluginEnabled()) { + log.info("application is started and registry plugin is enabled, it's will register admin self"); + registryService.register(adminServeInfo); + } + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/datasource/DataSourceBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/datasource/DataSourceBizService.java new file mode 100644 index 0000000000..4d2d670100 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/datasource/DataSourceBizService.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.datasource; + +import org.apache.eventmesh.admin.server.AdminServerRuntimeException; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshDataSource; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshDataSourceService; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.request.CreateOrUpdateDataSourceReq; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class DataSourceBizService { + + @Autowired + private EventMeshDataSourceService dataSourceService; + + public EventMeshDataSource createDataSource(CreateOrUpdateDataSourceReq dataSource) { + EventMeshDataSource entity = new EventMeshDataSource(); + entity.setConfiguration(JsonUtils.toJSONString(dataSource.getConfig())); + entity.setConfigurationClass(dataSource.getConfigClass()); + entity.setDataType(dataSource.getType().name()); + entity.setCreateUid(dataSource.getOperator()); + entity.setUpdateUid(dataSource.getOperator()); + entity.setRegion(dataSource.getRegion()); + entity.setDescription(dataSource.getDesc()); + if (dataSourceService.save(entity)) { + return entity; + } + throw new AdminServerRuntimeException(ErrorCode.BAD_DB_DATA, "save data source fail"); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/heatbeat/RuntimeHeartbeatBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/heatbeat/RuntimeHeartbeatBizService.java new file mode 100644 index 0000000000..95dff6e5b3 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/heatbeat/RuntimeHeartbeatBizService.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.heatbeat; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHeartbeat; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHistory; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshRuntimeHeartbeatService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshRuntimeHistoryService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import lombok.extern.slf4j.Slf4j; + +/** + * for table 'event_mesh_runtime_heartbeat' db operation 2024-05-14 17:15:03 + */ +@Service +@Slf4j +public class RuntimeHeartbeatBizService { + + @Autowired + EventMeshRuntimeHistoryService historyService; + + @Autowired + EventMeshRuntimeHeartbeatService heartbeatService; + + public boolean saveOrUpdateByRuntimeAddress(EventMeshRuntimeHeartbeat entity) { + EventMeshRuntimeHeartbeat old = heartbeatService.getOne(Wrappers.query().eq( + "runtimeAddr", + entity.getRuntimeAddr())); + if (old == null) { + return heartbeatService.save(entity); + } else { + if (Long.parseLong(old.getReportTime()) >= Long.parseLong(entity.getReportTime())) { + log.info("update heartbeat record ignore, current report time late than db, job [{}], remote [{}]", entity.getJobID(), + entity.getRuntimeAddr()); + return true; + } + try { + return heartbeatService.update(entity, Wrappers.update().eq("updateTime", + old.getUpdateTime())); + } finally { + if (old.getJobID() != null && !old.getJobID().equals(entity.getJobID())) { + EventMeshRuntimeHistory history = new EventMeshRuntimeHistory(); + history.setAddress(old.getAdminAddr()); + history.setJob(old.getJobID()); + try { + historyService.save(history); + } catch (Exception e) { + log.warn("save runtime job changed history fail", e); + } + + log.info("runtime [{}] changed job, old job [{}], now [{}]", entity.getRuntimeAddr(), old.getJobID(), + entity.getJobID()); + } + } + } + } +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/job/JobInfoBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/job/JobInfoBizService.java new file mode 100644 index 0000000000..c200d9801a --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/job/JobInfoBizService.java @@ -0,0 +1,302 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.job; + +import org.apache.eventmesh.admin.server.AdminServerProperties; +import org.apache.eventmesh.admin.server.AdminServerRuntimeException; +import org.apache.eventmesh.admin.server.web.db.DBThreadPool; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshDataSource; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshRuntimeHeartbeat; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshDataSourceService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshJobInfoExtService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshJobInfoService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshRuntimeHeartbeatService; +import org.apache.eventmesh.admin.server.web.pojo.JobDetail; +import org.apache.eventmesh.admin.server.web.pojo.TaskDetail; +import org.apache.eventmesh.admin.server.web.service.datasource.DataSourceBizService; +import org.apache.eventmesh.admin.server.web.service.position.PositionBizService; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.TransportType; +import org.apache.eventmesh.common.remote.datasource.DataSource; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.common.remote.request.CreateOrUpdateDataSourceReq; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.time.Duration; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import lombok.extern.slf4j.Slf4j; + +/** + * for table 'event_mesh_job_info' db operation + */ +@Service +@Slf4j +public class JobInfoBizService { + + @Autowired + private EventMeshJobInfoService jobInfoService; + + @Autowired + private EventMeshJobInfoExtService jobInfoExtService; + + @Autowired + private DataSourceBizService dataSourceBizService; + + @Autowired + private EventMeshDataSourceService dataSourceService; + + @Autowired + private PositionBizService positionBizService; + + @Autowired + private AdminServerProperties properties; + + @Autowired + EventMeshRuntimeHeartbeatService heartbeatService; + + private final long heatBeatPeriod = Duration.ofMillis(5000).toMillis(); + + @Autowired + DBThreadPool executor; + + @PostConstruct + public void init() { + log.info("init check job info scheduled task."); + executor.getCheckExecutor().scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + checkJobInfo(); + } + }, 10, 10, TimeUnit.SECONDS); + } + + public boolean updateJobState(String jobID, TaskState state) { + if (jobID == null || state == null) { + return false; + } + EventMeshJobInfo jobInfo = new EventMeshJobInfo(); + jobInfo.setJobState(state.name()); + return jobInfoService.update(jobInfo, Wrappers.update().eq("jobID", jobID).ne("jobState", JobState.DELETE.name())); + } + + public boolean updateJobState(String jobID, JobState state) { + if (jobID == null || state == null) { + return false; + } + EventMeshJobInfo jobInfo = new EventMeshJobInfo(); + jobInfo.setJobState(state.name()); + return jobInfoService.update(jobInfo, Wrappers.update().eq("jobID", jobID).ne("jobState", JobState.DELETE.name())); + } + + @Transactional + public List createJobs(List jobs) { + if (jobs == null || jobs.isEmpty() || jobs.stream().anyMatch(job -> StringUtils.isBlank(job.getTaskID()))) { + log.warn("when create jobs, task id is empty or jobs config is empty "); + return null; + } + List entityList = new LinkedList<>(); + + for (JobDetail job : jobs) { + // if running region not equal with admin region continue + if (!job.getRunningRegion().equals(properties.getRegion())) { + continue; + } + EventMeshJobInfo entity = new EventMeshJobInfo(); + entity.setJobState(TaskState.INIT.name()); + entity.setTaskID(job.getTaskID()); + entity.setJobType(job.getJobType().name()); + entity.setJobDesc(job.getJobDesc()); + String jobID = UUID.randomUUID().toString(); + entity.setJobID(jobID); + entity.setTransportType(job.getTransportType().name()); + entity.setCreateUid(job.getCreateUid()); + entity.setUpdateUid(job.getUpdateUid()); + entity.setFromRegion(job.getFromRegion()); + entity.setRunningRegion(job.getRunningRegion()); + CreateOrUpdateDataSourceReq source = new CreateOrUpdateDataSourceReq(); + source.setType(job.getTransportType().getSrc()); + source.setOperator(job.getCreateUid()); + source.setRegion(job.getSourceDataSource().getRegion()); + source.setDesc(job.getSourceConnectorDesc()); + Config sourceConfig = job.getSourceDataSource().getConf(); + source.setConfig(sourceConfig); + source.setConfigClass(job.getSourceDataSource().getConfClazz().getName()); + EventMeshDataSource createdSource = dataSourceBizService.createDataSource(source); + entity.setSourceData(createdSource.getId()); + + CreateOrUpdateDataSourceReq sink = new CreateOrUpdateDataSourceReq(); + sink.setType(job.getTransportType().getDst()); + sink.setOperator(job.getCreateUid()); + sink.setRegion(job.getSinkDataSource().getRegion()); + sink.setDesc(job.getSinkConnectorDesc()); + Config sinkConfig = job.getSinkDataSource().getConf(); + sink.setConfig(sinkConfig); + sink.setConfigClass(job.getSinkDataSource().getConfClazz().getName()); + EventMeshDataSource createdSink = dataSourceBizService.createDataSource(sink); + entity.setTargetData(createdSink.getId()); + + entityList.add(entity); + } + int changed = jobInfoExtService.batchSave(entityList); + if (changed != entityList.size()) { + throw new AdminServerRuntimeException(ErrorCode.INTERNAL_ERR, String.format("create [%d] jobs of not match expect [%d]", + changed, jobs.size())); + } + return entityList; + } + + + public JobDetail getJobDetail(String jobID) { + if (jobID == null) { + return null; + } + EventMeshJobInfo job = jobInfoService.getOne(Wrappers.query().eq("jobID", jobID)); + if (job == null) { + return null; + } + JobDetail detail = new JobDetail(); + detail.setTaskID(job.getTaskID()); + detail.setJobID(job.getJobID()); + EventMeshDataSource source = dataSourceService.getById(job.getSourceData()); + EventMeshDataSource target = dataSourceService.getById(job.getTargetData()); + if (source != null) { + if (!StringUtils.isBlank(source.getConfiguration())) { + try { + DataSource sourceDataSource = new DataSource(); + Class configClass = Class.forName(source.getConfigurationClass()); + sourceDataSource.setConf((Config) JsonUtils.parseObject(source.getConfiguration(), configClass)); + detail.setSourceDataSource(sourceDataSource); + } catch (Exception e) { + log.warn("parse source config id [{}] fail", job.getSourceData(), e); + throw new AdminServerRuntimeException(ErrorCode.BAD_DB_DATA, "illegal source data source config"); + } + } + detail.setSourceConnectorDesc(source.getDescription()); + if (source.getDataType() != null) { + detail.setPositions(positionBizService.getPositionByJobID(job.getJobID(), + DataSourceType.getDataSourceType(source.getDataType()))); + + } + } + if (target != null) { + if (!StringUtils.isBlank(target.getConfiguration())) { + try { + DataSource sinkDataSource = new DataSource(); + Class configClass = Class.forName(target.getConfigurationClass()); + sinkDataSource.setConf((Config) JsonUtils.parseObject(target.getConfiguration(), configClass)); + detail.setSinkDataSource(sinkDataSource); + } catch (Exception e) { + log.warn("parse sink config id [{}] fail", job.getSourceData(), e); + throw new AdminServerRuntimeException(ErrorCode.BAD_DB_DATA, "illegal target data sink config"); + } + } + detail.setSinkConnectorDesc(target.getDescription()); + } + + TaskState state = TaskState.fromIndex(job.getJobState()); + if (state == null) { + throw new AdminServerRuntimeException(ErrorCode.BAD_DB_DATA, "illegal job state in db"); + } + detail.setState(state); + detail.setTransportType(TransportType.getTransportType(job.getTransportType())); + detail.setJobType(JobType.fromIndex(job.getJobType())); + detail.setJobDesc(job.getJobDesc()); + return detail; + } + + public EventMeshJobInfo getJobInfo(String jobID) { + if (jobID == null) { + return null; + } + return jobInfoService.getOne(Wrappers.query().eq("jobID", jobID)); + } + + public List getJobsByTaskID(String taskID) { + if (taskID == null) { + return null; + } + return jobInfoService.list(Wrappers.query().eq("taskID", taskID)); + } + + public void checkJobInfo() { + List eventMeshJobInfoList = jobInfoService.list(Wrappers.query().eq("jobState", JobState.RUNNING.name())); + log.info("start check job info.to check job size:{}", eventMeshJobInfoList.size()); + for (EventMeshJobInfo jobInfo : eventMeshJobInfoList) { + String jobID = jobInfo.getJobID(); + if (StringUtils.isEmpty(jobID)) { + continue; + } + List heartbeatList = heartbeatService.list((Wrappers.query().eq("jobID", jobID))); + if (heartbeatList == null || heartbeatList.size() == 0) { + continue; + } + // if last heart beat update time have delay three period.print job heart beat delay warn + long currentTimeStamp = System.currentTimeMillis(); + if (currentTimeStamp - heartbeatList.get(0).getUpdateTime().getTime() > 3 * heatBeatPeriod) { + log.warn("current job heart heart has delay.jobID:{},currentTimeStamp:{},last update time:{}", jobID, currentTimeStamp, + heartbeatList.get(0).getUpdateTime()); + } + } + } + + public TaskDetail getTaskDetail(String taskID, DataSourceType dataSourceType) { + TaskDetail taskDetail = new TaskDetail(); + List jobInfoList = getJobsByTaskID(taskID); + if (jobInfoList == null || jobInfoList.size() == 0) { + return taskDetail; + } + for (EventMeshJobInfo jobInfo : jobInfoList) { + TransportType currentTransportType = TransportType.getTransportType(jobInfo.getTransportType()); + JobType jobType = JobType.fromIndex(jobInfo.getJobType()); + if (currentTransportType.getSrc().equals(dataSourceType)) { + if (jobType.name().equalsIgnoreCase(JobType.FULL.name())) { + taskDetail.setFullTask(jobInfo); + } + if (jobType.name().equalsIgnoreCase(JobType.INCREASE.name())) { + taskDetail.setIncreaseTask(jobInfo); + } + } + } + return taskDetail; + } + + +} + + + + diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/monitor/MonitorBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/monitor/MonitorBizService.java new file mode 100644 index 0000000000..3377334144 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/monitor/MonitorBizService.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.monitor; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMonitor; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshMonitorService; +import org.apache.eventmesh.common.remote.request.QueryTaskMonitorRequest; +import org.apache.eventmesh.common.remote.request.ReportMonitorRequest; +import org.apache.eventmesh.common.remote.response.QueryTaskMonitorResponse; +import org.apache.eventmesh.common.remote.task.TaskMonitor; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class MonitorBizService { + + @Autowired + private EventMeshMonitorService monitorService; + + public boolean reportMonitorRecord(ReportMonitorRequest request) { + EventMeshMonitor monitor = new EventMeshMonitor(); + monitor.setTaskID(request.getTaskID()); + monitor.setJobID(request.getJobID()); + monitor.setAddress(request.getAddress()); + monitor.setTransportType(request.getTransportType()); + monitor.setConnectorStage(request.getConnectorStage()); + monitor.setTotalReqNum(request.getTotalReqNum()); + monitor.setTotalTimeCost(request.getTotalTimeCost()); + monitor.setMaxTimeCost(request.getMaxTimeCost()); + monitor.setAvgTimeCost(request.getAvgTimeCost()); + monitor.setTps(request.getTps()); + return monitorService.save(monitor); + } + + public QueryTaskMonitorResponse queryTaskMonitors(QueryTaskMonitorRequest request) { + if (StringUtils.isBlank(request.getTaskID())) { + throw new RuntimeException("task id is empty"); + } + long limit = request.getLimit(); + if (limit <= 0) { + log.info("query task monitor limit:{},use default value:{}", limit, 10); + limit = 10; + } + + Page queryPage = new Page<>(); + queryPage.setCurrent(1); + queryPage.setSize(limit); + queryPage.addOrder(OrderItem.desc("createTime")); + + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("taskID", request.getTaskID()); + if (StringUtils.isNotEmpty(request.getJobID())) { + queryWrapper.eq("jobID", request.getJobID()); + } + List eventMeshMonitors = monitorService.list(queryPage, queryWrapper); + List taskMonitorList = new ArrayList<>(); + if (eventMeshMonitors != null) { + log.info("query event mesh monitor size:{}", eventMeshMonitors.size()); + if (log.isDebugEnabled()) { + log.debug("query event mesh monitor content:{}", JsonUtils.toJSONString(eventMeshMonitors)); + } + for (EventMeshMonitor eventMeshMonitor : eventMeshMonitors) { + TaskMonitor monitor = new TaskMonitor(); + monitor.setTaskID(eventMeshMonitor.getTaskID()); + monitor.setJobID(eventMeshMonitor.getJobID()); + monitor.setAddress(eventMeshMonitor.getAddress()); + monitor.setTransportType(eventMeshMonitor.getTransportType()); + monitor.setConnectorStage(eventMeshMonitor.getConnectorStage()); + monitor.setTotalReqNum(eventMeshMonitor.getTotalReqNum()); + monitor.setTotalTimeCost(eventMeshMonitor.getTotalTimeCost()); + monitor.setMaxTimeCost(eventMeshMonitor.getMaxTimeCost()); + monitor.setAvgTimeCost(eventMeshMonitor.getAvgTimeCost()); + monitor.setTps(eventMeshMonitor.getTps()); + monitor.setCreateTime(eventMeshMonitor.getCreateTime()); + taskMonitorList.add(monitor); + } + } + QueryTaskMonitorResponse queryTaskMonitorResponse = new QueryTaskMonitorResponse(); + queryTaskMonitorResponse.setTaskMonitors(taskMonitorList); + return queryTaskMonitorResponse; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IFetchPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IFetchPositionHandler.java new file mode 100644 index 0000000000..2c039062f3 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IFetchPositionHandler.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.request.FetchPositionRequest; + +import java.util.List; + +/** + * IFetchPositionHandler + */ +public interface IFetchPositionHandler { + + List handler(FetchPositionRequest request, Metadata metadata); +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IRecordPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IRecordPositionHandler.java new file mode 100644 index 0000000000..fa38e14320 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IRecordPositionHandler.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.request.RecordPositionRequest; + +/** + * IRecordPositionHandler + */ +public interface IRecordPositionHandler { + + boolean handler(RecordPositionRequest request, Metadata metadata); + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IReportPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IReportPositionHandler.java new file mode 100644 index 0000000000..75f392e395 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/IReportPositionHandler.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.request.ReportPositionRequest; + +/** + * IReportPositionHandler + */ +public interface IReportPositionHandler { + + boolean handler(ReportPositionRequest request, Metadata metadata); +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionBizService.java new file mode 100644 index 0000000000..0c4cd7a423 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionBizService.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position; + +import org.apache.eventmesh.admin.server.AdminServerRuntimeException; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.request.FetchPositionRequest; +import org.apache.eventmesh.common.remote.request.RecordPositionRequest; +import org.apache.eventmesh.common.remote.request.ReportPositionRequest; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class PositionBizService { + + @Autowired + PositionHandlerFactory factory; + + // called isValidateReportRequest before call this + public List getPosition(FetchPositionRequest request, Metadata metadata) { + if (request == null) { + return null; + } + isValidatePositionRequest(request.getDataSourceType()); + IFetchPositionHandler handler = factory.getHandler(request.getDataSourceType()); + return handler.handler(request, metadata); + } + + public void isValidatePositionRequest(DataSourceType type) { + if (type == null) { + throw new AdminServerRuntimeException(ErrorCode.BAD_REQUEST, "data source type is null"); + } + IReportPositionHandler handler = factory.getHandler(type); + if (handler == null) { + throw new AdminServerRuntimeException(ErrorCode.BAD_REQUEST, + String.format("illegal data base type [%s], it not match any report position handler", type)); + } + } + + // called isValidateReportRequest before call this + public boolean reportPosition(ReportPositionRequest request, Metadata metadata) { + if (request == null) { + return false; + } + isValidatePositionRequest(request.getDataSourceType()); + IReportPositionHandler handler = factory.getHandler(request.getDataSourceType()); + return handler.handler(request, metadata); + } + + public List getPositionByJobID(String jobID, DataSourceType type) { + if (jobID == null || type == null) { + return null; + } + isValidatePositionRequest(type); + PositionHandler handler = factory.getHandler(type); + FetchPositionRequest request = new FetchPositionRequest(); + request.setJobID(jobID); + return handler.handler(request, null); + } + + public boolean recordPosition(RecordPositionRequest request, Metadata metadata) { + isValidatePositionRequest(request.getDataSourceType()); + IRecordPositionHandler handler = factory.getHandler(request.getDataSourceType()); + return handler.handler(request, metadata); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionHandler.java new file mode 100644 index 0000000000..9cbaf3fad6 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionHandler.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position; + +import org.apache.eventmesh.common.remote.datasource.DataSourceType; + +public abstract class PositionHandler implements IReportPositionHandler, IFetchPositionHandler, IRecordPositionHandler { + + protected abstract DataSourceType getSourceType(); +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionHandlerFactory.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionHandlerFactory.java new file mode 100644 index 0000000000..c2065f80f4 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/PositionHandlerFactory.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position; + +import org.apache.eventmesh.common.remote.datasource.DataSourceType; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class PositionHandlerFactory implements ApplicationListener { + + private final Map handlers = + new ConcurrentHashMap<>(); + + public PositionHandler getHandler(DataSourceType type) { + return handlers.get(type); + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + Map beans = + event.getApplicationContext().getBeansOfType(PositionHandler.class); + + for (PositionHandler handler : beans.values()) { + DataSourceType type = handler.getSourceType(); + if (handlers.containsKey(type)) { + log.warn("data source type [{}] handler already exists", type); + continue; + } + handlers.put(type, handler); + } + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/impl/HttpPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/impl/HttpPositionHandler.java new file mode 100644 index 0000000000..a58fa31c07 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/impl/HttpPositionHandler.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position.impl; + +import org.apache.eventmesh.admin.server.web.db.service.EventMeshPositionReporterHistoryService; +import org.apache.eventmesh.admin.server.web.service.position.PositionHandler; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.request.FetchPositionRequest; +import org.apache.eventmesh.common.remote.request.RecordPositionRequest; +import org.apache.eventmesh.common.remote.request.ReportPositionRequest; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class HttpPositionHandler extends PositionHandler { + + @Autowired + EventMeshPositionReporterHistoryService historyService; + + @Override + protected DataSourceType getSourceType() { + return DataSourceType.HTTP; + } + + @Override + public boolean handler(ReportPositionRequest request, Metadata metadata) { + log.info("receive http position report request:{}", request); + // mock wemq postion report store + return true; + } + + @Override + public List handler(FetchPositionRequest request, Metadata metadata) { + // mock http position fetch request + List recordPositionList = new ArrayList<>(); + return recordPositionList; + } + + @Override + public boolean handler(RecordPositionRequest request, Metadata metadata) { + return true; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/impl/MysqlPositionHandler.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/impl/MysqlPositionHandler.java new file mode 100644 index 0000000000..8545078d80 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/position/impl/MysqlPositionHandler.java @@ -0,0 +1,351 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.position.impl; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshMysqlPosition; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshPositionReporterHistory; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshMysqlPositionService; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshPositionReporterHistoryService; +import org.apache.eventmesh.admin.server.web.pojo.BinlogPosition; +import org.apache.eventmesh.admin.server.web.pojo.JobDetail; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.admin.server.web.service.position.PositionHandler; +import org.apache.eventmesh.admin.server.web.utils.JdbcUtils; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceFullConfig; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.offset.canal.CanalRecordOffset; +import org.apache.eventmesh.common.remote.offset.canal.CanalRecordPartition; +import org.apache.eventmesh.common.remote.request.FetchPositionRequest; +import org.apache.eventmesh.common.remote.request.RecordPositionRequest; +import org.apache.eventmesh.common.remote.request.ReportPositionRequest; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.LockSupport; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Component; + +import com.alibaba.druid.pool.DruidDataSource; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class MysqlPositionHandler extends PositionHandler { + private static final int RETRY_TIMES = 3; + private static final String SQL_SELECT_RDB_VERSION = "select version() as rdb_version"; + private static final String SQL_SHOW_BINLOG_POSITION = "SHOW MASTER STATUS"; + private static final String SQL_SELECT_SERVER_UUID_IN_MARIADB = "SELECT @@global.server_id as server_uuid"; + private static final String SQL_SHOW_SERVER_UUID_IN_MYSQL = "SELECT @@server_uuid as server_uuid"; + private static final String SQL_SELECT_GTID_IN_MARIADB = "SELECT @@global.gtid_binlog_pos as gtid"; + private static final String SQL_SELECT_GTID_IN_MYSQL = "SELECT @@gtid_executed as gtid"; + + private final long retryPeriod = Duration.ofMillis(500).toNanos(); + + @Autowired + EventMeshMysqlPositionService positionService; + + @Autowired + EventMeshPositionReporterHistoryService historyService; + + @Autowired + JobInfoBizService jobInfoBizService; + + @Override + protected DataSourceType getSourceType() { + return DataSourceType.MYSQL; + } + + private boolean isNotForward(EventMeshMysqlPosition now, EventMeshMysqlPosition old) { + if (StringUtils.isNotBlank(old.getJournalName()) && old.getJournalName().equals(now.getJournalName()) + && old.getPosition() >= now.getPosition()) { + log.info("job [{}] report position [{}] by runtime [{}] less than db position [{}] journal name [{}] by [{}]", now.getJobID(), + now.getPosition(), now.getAddress(), now.getJournalName(), old.getPosition(), old.getAddress()); + return true; + } + return false; + } + + public boolean saveOrUpdateByJob(EventMeshMysqlPosition position) { + for (int i = 0; i < RETRY_TIMES; i++) { + EventMeshMysqlPosition old = positionService.getOne(Wrappers.query().eq("jobId", position.getJobID())); + if (old == null) { + try { + return positionService.save(position); + } catch (DuplicateKeyException e) { + log.warn("current insert position fail, it will retry in 500ms"); + LockSupport.parkNanos(retryPeriod); + continue; + } catch (Exception e) { + log.warn("insert position fail catch unknown exception", e); + return false; + } + } + + if (isNotForward(position, old)) { + return true; + } + try { + if (!positionService.update(position, + Wrappers.update().eq("updateTime", old.getUpdateTime()).eq("jobID", old.getJobID()))) { + log.warn("update position [{}] fail, maybe current update. it will retry in 500ms", position); + LockSupport.parkNanos(retryPeriod); + continue; + } + return true; + } finally { + if (old.getAddress() != null && !old.getAddress().equals(position.getAddress())) { + EventMeshPositionReporterHistory history = new EventMeshPositionReporterHistory(); + history.setRecord(JsonUtils.toJSONString(position)); + history.setJob(old.getJobID()); + history.setAddress(old.getAddress()); + log.info("job [{}] position reporter changed old [{}], now [{}]", position.getJobID(), old, position); + try { + historyService.save(history); + } catch (Exception e) { + log.warn("save job [{}] mysql position reporter changed history fail, now reporter [{}], old [{}]", position.getJobID(), + position.getAddress(), old.getAddress(), e); + } + } + } + } + return false; + } + + @Override + public boolean handler(ReportPositionRequest request, Metadata metadata) { + try { + List recordPositionList = request.getRecordPositionList(); + RecordPosition recordPosition = recordPositionList.get(0); + if (recordPosition == null || recordPosition.getRecordPartition() == null || recordPosition.getRecordOffset() == null) { + log.warn("report mysql position, but record-partition/partition/offset is null"); + return false; + } + if (!(recordPosition.getRecordPartition() instanceof CanalRecordPartition)) { + log.warn("report mysql position, but record partition class [{}] not match [{}]", + recordPosition.getRecordPartition().getRecordPartitionClass(), CanalRecordPartition.class); + return false; + } + if (!(recordPosition.getRecordOffset() instanceof CanalRecordOffset)) { + log.warn("report mysql position, but record offset class [{}] not match [{}]", + recordPosition.getRecordOffset().getRecordOffsetClass(), CanalRecordOffset.class); + return false; + } + EventMeshMysqlPosition position = new EventMeshMysqlPosition(); + position.setJobID(request.getJobID()); + position.setAddress(request.getAddress()); + CanalRecordOffset offset = (CanalRecordOffset) recordPosition.getRecordOffset(); + if (offset != null) { + position.setPosition(offset.getOffset()); + position.setGtid(offset.getGtid()); + position.setCurrentGtid(offset.getCurrentGtid()); + } + CanalRecordPartition partition = (CanalRecordPartition) recordPosition.getRecordPartition(); + if (partition != null) { + position.setServerUUID(partition.getServerUUID()); + position.setTimestamp(partition.getTimeStamp()); + position.setJournalName(partition.getJournalName()); + } + if (!saveOrUpdateByJob(position)) { + log.warn("update job position fail [{}]", request); + return false; + } + return true; + } catch (Exception e) { + log.warn("save position job [{}] fail", request.getJobID(), e); + } + + return false; + } + + @Override + public List handler(FetchPositionRequest request, Metadata metadata) { + List positionList = positionService.list(Wrappers.query().eq("jobID", request.getJobID())); + List recordPositionList = new ArrayList<>(); + for (EventMeshMysqlPosition position : positionList) { + CanalRecordPartition partition = new CanalRecordPartition(); + partition.setTimeStamp(position.getTimestamp()); + partition.setJournalName(position.getJournalName()); + partition.setServerUUID(position.getServerUUID()); + RecordPosition recordPosition = new RecordPosition(); + recordPosition.setRecordPartition(partition); + CanalRecordOffset offset = new CanalRecordOffset(); + offset.setOffset(position.getPosition()); + offset.setGtid(position.getGtid()); + offset.setCurrentGtid(position.getCurrentGtid()); + recordPosition.setRecordOffset(offset); + recordPositionList.add(recordPosition); + } + return recordPositionList; + } + + @Override + public boolean handler(RecordPositionRequest request, Metadata metadata) { + try { + String fullJobID = request.getFullJobID(); + String increaseJobID = request.getIncreaseJobID(); + log.info("start record full job position to increase job position,full jobID:{}, increase jobID:{}.", fullJobID, increaseJobID); + JobDetail fullJobDetail = jobInfoBizService.getJobDetail(fullJobID); + CanalSourceConfig canalSourceConfig = (CanalSourceConfig) fullJobDetail.getSourceDataSource().getConf(); + CanalSourceFullConfig canalSourceFullConfig = JsonUtils.mapToObject(canalSourceConfig.getSourceConfig(), CanalSourceFullConfig.class); + try (DruidDataSource druidDataSource = JdbcUtils.createDruidDataSource(canalSourceFullConfig.getSourceConnectorConfig().getUrl(), + canalSourceFullConfig.getSourceConnectorConfig().getUserName(), canalSourceFullConfig.getSourceConnectorConfig().getPassWord())) { + + DataSourceType dataSourceType = checkRDBDataSourceType(druidDataSource); + + ReportPositionRequest reportPositionRequest = new ReportPositionRequest(); + reportPositionRequest.setJobID(increaseJobID); + reportPositionRequest.setDataSourceType(DataSourceType.MYSQL); + reportPositionRequest.setAddress(request.getAddress()); + + RecordPosition recordPosition = new RecordPosition(); + CanalRecordOffset recordOffset = new CanalRecordOffset(); + BinlogPosition binlogPosition = queryBinlogPosition(druidDataSource); + String gtid = queryGTID(druidDataSource, dataSourceType); + recordOffset.setOffset(binlogPosition.getPosition()); + recordOffset.setGtid(gtid); + recordPosition.setRecordOffset(recordOffset); + + CanalRecordPartition recordPartition = new CanalRecordPartition(); + String serverUUID = queryServerUUID(druidDataSource, dataSourceType); + recordPartition.setJournalName(binlogPosition.getFile()); + recordPartition.setServerUUID(serverUUID); + recordPosition.setRecordPartition(recordPartition); + + List recordPositions = new ArrayList<>(); + recordPositions.add(recordPosition); + + reportPositionRequest.setRecordPositionList(recordPositions); + log.info("start store increase task position,jobID:{},request:{}", increaseJobID, reportPositionRequest); + handler(reportPositionRequest, metadata); + } + return true; + } catch (Exception e) { + log.error("record full job position to increase job position failed.", e); + return false; + } + } + + private DataSourceType checkRDBDataSourceType(DruidDataSource druidDataSource) { + try { + log.info("execute sql '{}' start.", SQL_SELECT_RDB_VERSION); + try (PreparedStatement preparedStatement = druidDataSource.getConnection().prepareStatement(SQL_SELECT_RDB_VERSION)) { + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + log.info("execute sql '{}' result:{}", SQL_SELECT_RDB_VERSION, resultSet); + String rdbVersion = resultSet.getString("rdb_version"); + if (StringUtils.isNotBlank(rdbVersion)) { + if (rdbVersion.toLowerCase().contains(DataSourceType.MariaDB.getName().toLowerCase())) { + return DataSourceType.MariaDB; + } + } + } + } + } catch (Exception e) { + log.warn("select rdb version failed,data source:{}", druidDataSource, e); + throw new RuntimeException("select rdb version failed"); + } + return DataSourceType.MYSQL; + } + + private BinlogPosition queryBinlogPosition(DruidDataSource druidDataSource) { + BinlogPosition binlogPosition = new BinlogPosition(); + try { + log.info("execute sql '{}' start.", SQL_SHOW_BINLOG_POSITION); + try (PreparedStatement preparedStatement = druidDataSource.getConnection().prepareStatement(SQL_SHOW_BINLOG_POSITION)) { + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + log.info("execute sql '{}' result:{}", SQL_SELECT_RDB_VERSION, resultSet); + String fileName = resultSet.getString("File"); + Long position = resultSet.getLong("Position"); + binlogPosition.setFile(fileName); + binlogPosition.setPosition(position); + } + } + } catch (Exception e) { + log.warn("show binlog position failed,data source:{}", druidDataSource, e); + throw new RuntimeException("show binlog position failed"); + } + return binlogPosition; + } + + private String queryServerUUID(DruidDataSource druidDataSource, DataSourceType dataSourceType) { + String serverUUID = ""; + try { + String queryServerUUIDSql; + if (DataSourceType.MariaDB.equals(dataSourceType)) { + queryServerUUIDSql = SQL_SELECT_SERVER_UUID_IN_MARIADB; + } else { + queryServerUUIDSql = SQL_SHOW_SERVER_UUID_IN_MYSQL; + } + log.info("execute sql '{}' start.", queryServerUUIDSql); + try (PreparedStatement preparedStatement = druidDataSource.getConnection().prepareStatement(queryServerUUIDSql)) { + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + log.info("execute sql '{}' result:{}", queryServerUUIDSql, resultSet); + serverUUID = resultSet.getString("server_uuid"); + log.info("execute sql '{}',query server_uuid result:{}", queryServerUUIDSql, serverUUID); + return serverUUID; + } + } + } catch (Exception e) { + log.warn("select server_uuid failed,data source:{}", druidDataSource, e); + throw new RuntimeException("select server_uuid failed"); + } + return serverUUID; + } + + private String queryGTID(DruidDataSource druidDataSource, DataSourceType dataSourceType) { + String gitd = ""; + try { + String queryGTIDSql; + if (DataSourceType.MariaDB.equals(dataSourceType)) { + queryGTIDSql = SQL_SELECT_GTID_IN_MARIADB; + } else { + queryGTIDSql = SQL_SELECT_GTID_IN_MYSQL; + } + log.info("execute sql '{}' start.", queryGTIDSql); + try (PreparedStatement preparedStatement = druidDataSource.getConnection().prepareStatement(queryGTIDSql)) { + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + log.info("execute sql '{}' result:{}", queryGTIDSql, resultSet); + gitd = resultSet.getString("gtid"); + log.info("execute sql '{}',select gitd result:{}", queryGTIDSql, gitd); + return gitd; + } + } + } catch (Exception e) { + log.warn("select gtid failed,data source:{}", druidDataSource, e); + // when db server not open gitd mode, ignore gtid query exception + //throw new RuntimeException("select gtid failed"); + } + return gitd; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/task/TaskBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/task/TaskBizService.java new file mode 100644 index 0000000000..d3c7087d47 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/task/TaskBizService.java @@ -0,0 +1,360 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.task; + +import org.apache.eventmesh.admin.server.AdminServerProperties; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshJobInfo; +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshTaskInfo; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshTaskInfoService; +import org.apache.eventmesh.admin.server.web.pojo.JobDetail; +import org.apache.eventmesh.admin.server.web.service.job.JobInfoBizService; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.datasource.DataSource; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.request.CreateTaskRequest; +import org.apache.eventmesh.common.remote.request.QueryTaskInfoRequest; +import org.apache.eventmesh.common.remote.request.TaskBachRequest; +import org.apache.eventmesh.common.remote.request.TaskIDRequest; +import org.apache.eventmesh.common.remote.response.CreateTaskResponse; +import org.apache.eventmesh.common.remote.response.QueryTaskInfoResponse; +import org.apache.eventmesh.common.remote.response.SimpleResponse; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class TaskBizService { + + @Autowired + private EventMeshTaskInfoService taskInfoService; + + @Autowired + private JobInfoBizService jobInfoService; + + @Autowired + private AdminServerProperties properties; + + private static final String TYPE = "type"; + + private static final String DESC = "desc"; + + private static final String CONF_CLAZZ = "confClazz"; + + private static final String CONF = "conf"; + + private static final String REGION = "region"; + + @Transactional + public CreateTaskResponse createTask(CreateTaskRequest req) { + String taskID = req.getTaskId(); + if (StringUtils.isEmpty(taskID)) { + taskID = UUID.randomUUID().toString(); + req.setTaskId(taskID); + } + + String targetRegion = req.getTargetRegion(); + String remoteResponse = ""; + // not from other admin && target not equals with self region + if (!req.isFlag() && !properties.getRegion().equals(targetRegion)) { + List adminServerList = Arrays.asList(properties.getAdminServerList().get(targetRegion).split(";")); + if (adminServerList == null || adminServerList.isEmpty()) { + throw new RuntimeException("No admin server available for region: " + targetRegion); + } + String targetUrl = adminServerList.get(new Random().nextInt(adminServerList.size())) + "/eventmesh/admin/createTask"; + + RestTemplate restTemplate = new RestTemplate(); + req.setFlag(true); + ResponseEntity response = restTemplate.postForEntity(targetUrl, req, String.class); + if (!response.getStatusCode().is2xxSuccessful()) { + throw new RuntimeException("Failed to create task on admin server: " + targetUrl); + } + remoteResponse = response.getBody(); + } + + String finalTaskID = taskID; + List jobs = req.getJobs().stream().map(x -> { + JobDetail job = null; + try { + job = parse(x); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + job.setTaskID(finalTaskID); + job.setCreateUid(req.getUid()); + job.setUpdateUid(req.getUid()); + return job; + }).collect(Collectors.toList()); + + EventMeshTaskInfo taskInfo = new EventMeshTaskInfo(); + taskInfo.setTaskID(finalTaskID); + taskInfo.setTaskName(req.getTaskName()); + taskInfo.setTaskDesc(req.getTaskDesc()); + taskInfo.setTaskState(TaskState.INIT.name()); + taskInfo.setCreateUid(req.getUid()); + taskInfo.setSourceRegion(req.getSourceRegion()); + taskInfo.setTargetRegion(req.getTargetRegion()); + List eventMeshJobInfoList = jobInfoService.createJobs(jobs); + taskInfoService.save(taskInfo); + return buildCreateTaskResponse(finalTaskID, eventMeshJobInfoList, remoteResponse); + } + + private JobDetail parse(CreateTaskRequest.JobDetail src) throws ClassNotFoundException { + JobDetail dst = new JobDetail(); + dst.setJobDesc(src.getJobDesc()); + dst.setTransportType(src.getTransportType()); + dst.setSourceConnectorDesc(src.getSourceConnectorDesc()); + try { + dst.setSourceDataSource(mapToDataSource(src.getSourceDataSource())); + dst.setSinkDataSource(mapToDataSource(src.getSinkDataSource())); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Failed to map data source", e); + } + dst.setSinkConnectorDesc(src.getSinkConnectorDesc()); + // full/increase/check + dst.setJobType(src.getJobType()); + dst.setFromRegion(src.getFromRegion()); + dst.setRunningRegion(src.getRunningRegion()); + return dst; + } + + private DataSource mapToDataSource(Map dataMap) throws ClassNotFoundException { + DataSource dataSource = new DataSource(); + dataSource.setType(DataSourceType.fromString(dataMap.get(TYPE).toString())); + dataSource.setDesc((String) dataMap.get(DESC)); + dataSource.setConfClazz((Class) Class.forName(dataMap.get(CONF_CLAZZ).toString())); + dataSource.setConf(JsonUtils.parseObject(JsonUtils.toJSONString(dataMap.get(CONF)), dataSource.getConfClazz())); + dataSource.setRegion((String) dataMap.get(REGION)); + return dataSource; + } + + private CreateTaskResponse buildCreateTaskResponse(String taskId, List eventMeshJobInfoList, String remoteResponse) { + CreateTaskResponse createTaskResponse = new CreateTaskResponse(); + createTaskResponse.setTaskId(taskId); + List jobDetailList = new ArrayList<>(); + if (!eventMeshJobInfoList.isEmpty()) { + for (EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfoList) { + CreateTaskRequest.JobDetail jobDetail = new CreateTaskRequest.JobDetail(); + jobDetail.setJobId(eventMeshJobInfo.getJobID()); + jobDetail.setRunningRegion(eventMeshJobInfo.getRunningRegion()); + jobDetailList.add(jobDetail); + } + } + if (!StringUtils.isEmpty(remoteResponse)) { + SimpleResponse response = JsonUtils.parseObject(remoteResponse, SimpleResponse.class); + CreateTaskResponse remoteCreateTaskResponse = JsonUtils.convertValue(response.getData(), CreateTaskResponse.class); + jobDetailList.addAll(remoteCreateTaskResponse.getJobIdList()); + } + createTaskResponse.setJobIdList(jobDetailList); + return createTaskResponse; + } + + /** + * start task + * @param taskIDRequest id + */ + @Transactional + public void startTask(TaskIDRequest taskIDRequest) { + try { + EventMeshTaskInfo taskInfoServiceOne = taskInfoService.getOne(Wrappers.query() + .eq("taskID", taskIDRequest.getTaskID())); + + if (Objects.isNull(taskInfoServiceOne)) { + throw new EventMeshException("task not found"); + } + + if (TaskState.DELETE.name().equals(taskInfoServiceOne.getTaskState())) { + throw new EventMeshException("task already deleted"); + } + + // update task state + taskInfoService.update(Wrappers.update() + .eq("id", taskInfoServiceOne.getId()) + .set("taskState", TaskState.RUNNING.name())); + + List eventMeshJobInfos = jobInfoService.getJobsByTaskID(taskIDRequest.getTaskID()); + + for (EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfos) { + // update job state by jonID + jobInfoService.updateJobState(eventMeshJobInfo.getJobID(), JobState.RUNNING); + } + + // todo: start task job eventmesh-runtime-v2 schedule ? + + } catch (Exception e) { + log.info("start task exception:{}", e.getMessage()); + throw new EventMeshException("start task exception"); + } + } + + @Transactional + public boolean deleteTaskByTaskID(TaskIDRequest taskIDRequest) { + try { + EventMeshTaskInfo taskInfoServiceOne = taskInfoService.getOne(Wrappers.query() + .eq("taskID", taskIDRequest.getTaskID())); + + if (Objects.isNull(taskInfoServiceOne)) { + throw new EventMeshException("task not found"); + } + + if (!TaskState.DELETE.name().equals(taskInfoServiceOne.getTaskState())) { + // update task state to delete + taskInfoService.update(Wrappers.update() + .eq("id", taskInfoServiceOne.getId()) + .set("taskState", TaskState.DELETE.name())); + } + List eventMeshJobInfos = jobInfoService.getJobsByTaskID(taskInfoServiceOne.getTaskID()); + for (EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfos) { + // update job state to delete + jobInfoService.updateJobState(eventMeshJobInfo.getJobID(), JobState.DELETE); + } + // todo: data source config need delete? + + } catch (RuntimeException e) { + log.error("delete task failed:{}", e.getMessage()); + throw new EventMeshException("delete task failed"); + } + return true; + } + + public List queryTaskInfo(QueryTaskInfoRequest taskInfoRequest) { + return taskInfoService.queryTaskInfo(taskInfoRequest); + } + + @Transactional + public void restartTask(TaskIDRequest taskIDRequest) { + try { + EventMeshTaskInfo taskInfoServiceOne = taskInfoService.getOne(Wrappers.query() + .eq("taskID", taskIDRequest.getTaskID()) + .ne("taskState", TaskState.DELETE.name())); + + if (Objects.isNull(taskInfoServiceOne)) { + throw new EventMeshException("task not found"); + } + if (!TaskState.RUNNING.name().equals(taskInfoServiceOne.getTaskState())) { + taskInfoService.update(Wrappers.update() + .eq("id", taskInfoServiceOne.getId()) + .set("taskState", TaskState.RUNNING.name())); + } + List eventMeshJobInfos = jobInfoService.getJobsByTaskID(taskInfoServiceOne.getTaskID()); + for (EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfos) { + // update job state to restart + jobInfoService.updateJobState(eventMeshJobInfo.getJobID(), JobState.RUNNING); + } + // todo: start task job eventmesh-runtime-v2 schedule? + + } catch (RuntimeException e) { + log.error("restart task filed:{}", e.getMessage()); + throw new EventMeshException("restart task filed"); + } + } + + @Transactional + public void stopTask(TaskIDRequest taskIDRequest) { + try { + EventMeshTaskInfo taskInfoServiceOne = taskInfoService.getOne(Wrappers.query() + .eq("taskID", taskIDRequest.getTaskID())); + + if (Objects.isNull(taskInfoServiceOne)) { + throw new EventMeshException("task not found"); + } + if (!TaskState.PAUSE.name().equals(taskInfoServiceOne.getTaskState())) { + taskInfoService.update(Wrappers.update() + .eq("id", taskInfoServiceOne.getId()) + .set("taskState", TaskState.PAUSE.name())); + } + + List eventMeshJobInfos = jobInfoService.getJobsByTaskID(taskInfoServiceOne.getTaskID()); + for (EventMeshJobInfo eventMeshJobInfo : eventMeshJobInfos) { + // update job state to pause + jobInfoService.updateJobState(eventMeshJobInfo.getJobID(), JobState.PAUSE); + } + + // todo: stop task job eventmesh-runtime-v2 schedule? + + } catch (RuntimeException e) { + log.error("stop task filed:{}", e.getMessage()); + throw new EventMeshException("stop task filed"); + } + } + + @Transactional + public void restartBatchTask(List taskIDRequestList, List errorNames) { + for (TaskBachRequest task : taskIDRequestList) { + try { + TaskIDRequest taskIDRequest = new TaskIDRequest(); + taskIDRequest.setTaskID(task.getTaskID()); + startTask(taskIDRequest); + } catch (RuntimeException e) { + log.error("restart batch task failed:{}", e.getMessage()); + errorNames.add(task.getTaskName()); + } + } + } + + @Transactional + public void stopBatchTask(List taskIDRequestList, List errorNames) { + for (TaskBachRequest task : taskIDRequestList) { + try { + TaskIDRequest taskIDRequest = new TaskIDRequest(); + taskIDRequest.setTaskID(task.getTaskID()); + stopTask(taskIDRequest); + } catch (RuntimeException e) { + log.error("stop batch task failed:{}", e.getMessage()); + errorNames.add(task.getTaskName()); + } + } + } + + @Transactional + public void startBatchTask(List taskIDRequestList, List errorNames) { + for (TaskBachRequest task : taskIDRequestList) { + try { + TaskIDRequest taskIDRequest = new TaskIDRequest(); + taskIDRequest.setTaskID(task.getTaskID()); + restartTask(taskIDRequest); + } catch (RuntimeException e) { + log.error("start batch task failed:{}", e.getMessage()); + errorNames.add(task.getTaskName()); + } + } + } + +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/verify/VerifyBizService.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/verify/VerifyBizService.java new file mode 100644 index 0000000000..e4f08b30cc --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/service/verify/VerifyBizService.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.service.verify; + +import org.apache.eventmesh.admin.server.web.db.entity.EventMeshVerify; +import org.apache.eventmesh.admin.server.web.db.service.EventMeshVerifyService; +import org.apache.eventmesh.common.remote.request.ReportVerifyRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class VerifyBizService { + + @Autowired + private EventMeshVerifyService verifyService; + + public boolean reportVerifyRecord(ReportVerifyRequest request) { + EventMeshVerify verify = new EventMeshVerify(); + verify.setRecordID(request.getRecordID()); + verify.setRecordSig(request.getRecordSig()); + verify.setPosition(request.getPosition()); + verify.setTaskID(request.getTaskID()); + verify.setJobID(request.getJobID()); + verify.setConnectorName(request.getConnectorName()); + verify.setConnectorStage(request.getConnectorStage()); + return verifyService.save(verify); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/Base64.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/Base64.java new file mode 100644 index 0000000000..f85807b7f9 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/Base64.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.utils; + +public class Base64 { + private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray(); + private static byte[] codes = new byte[256]; + + public Base64() { + } + + public static char[] encode(byte[] data) { + char[] out = new char[(data.length + 2) / 3 * 4]; + int i = 0; + + for (int index = 0; i < data.length; index += 4) { + boolean quad = false; + boolean trip = false; + int val = 255 & data[i]; + val <<= 8; + if (i + 1 < data.length) { + val |= 255 & data[i + 1]; + trip = true; + } + + val <<= 8; + if (i + 2 < data.length) { + val |= 255 & data[i + 2]; + quad = true; + } + + out[index + 3] = alphabet[quad ? val & 63 : 64]; + val >>= 6; + out[index + 2] = alphabet[trip ? val & 63 : 64]; + val >>= 6; + out[index + 1] = alphabet[val & 63]; + val >>= 6; + out[index + 0] = alphabet[val & 63]; + i += 3; + } + + return out; + } + + public static byte[] decode(char[] data) { + int tempLen = data.length; + + int len; + for (len = 0; len < data.length; ++len) { + if (data[len] > 255 || codes[data[len]] < 0) { + --tempLen; + } + } + + len = tempLen / 4 * 3; + if (tempLen % 4 == 3) { + len += 2; + } + + if (tempLen % 4 == 2) { + ++len; + } + + byte[] out = new byte[len]; + int shift = 0; + int accum = 0; + int index = 0; + + for (int ix = 0; ix < data.length; ++ix) { + int value = data[ix] > 255 ? -1 : codes[data[ix]]; + if (value >= 0) { + accum <<= 6; + shift += 6; + accum |= value; + if (shift >= 8) { + shift -= 8; + out[index++] = (byte) (accum >> shift & 255); + } + } + } + + if (index != out.length) { + throw new Error("Miscalculated data length (wrote " + index + " instead of " + out.length + ")"); + } else { + return out; + } + } + + static { + int i; + for (i = 0; i < 256; ++i) { + codes[i] = -1; + } + + for (i = 65; i <= 90; ++i) { + codes[i] = (byte) (i - 65); + } + + for (i = 97; i <= 122; ++i) { + codes[i] = (byte) (26 + i - 97); + } + + for (i = 48; i <= 57; ++i) { + codes[i] = (byte) (52 + i - 48); + } + + codes[43] = 62; + codes[47] = 63; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/Base64Utils.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/Base64Utils.java new file mode 100644 index 0000000000..9c9a258671 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/Base64Utils.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +public class Base64Utils { + private static final int CACHE_SIZE = 1024; + + public Base64Utils() { + } + + public static byte[] decode(String base64) throws Exception { + return Base64.decode(base64.toCharArray()); + } + + public static String encode(byte[] bytes) throws Exception { + return new String(Base64.encode(bytes)); + } + + public static String encodeFile(String filePath) throws Exception { + byte[] bytes = fileToByte(filePath); + return encode(bytes); + } + + public static void decodeToFile(String filePath, String base64) throws Exception { + byte[] bytes = decode(base64); + byteArrayToFile(bytes, filePath); + } + + public static byte[] fileToByte(String filePath) throws Exception { + byte[] data = new byte[0]; + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + byte[] cache = new byte[1024]; + int nread; + + while ((nread = in.read(cache)) != -1) { + out.write(cache, 0, nread); + out.flush(); + } + + out.close(); + in.close(); + data = out.toByteArray(); + } + + return data; + } + + public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { + InputStream in = new ByteArrayInputStream(bytes); + File destFile = new File(filePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] cache = new byte[1024]; + + int nread; + while ((nread = ((InputStream) in).read(cache)) != -1) { + ((OutputStream) out).write(cache, 0, nread); + ((OutputStream) out).flush(); + } + + ((OutputStream) out).close(); + ((InputStream) in).close(); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/EncryptUtil.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/EncryptUtil.java new file mode 100644 index 0000000000..06c8bbc330 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/EncryptUtil.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +public class EncryptUtil { + public EncryptUtil() { + } + + private static byte[] hexStringToBytes(String hexString) { + if (hexString != null && !hexString.equals("")) { + hexString = hexString.toUpperCase(); + int length = hexString.length() / 2; + char[] hexChars = hexString.toCharArray(); + byte[] d = new byte[length]; + + for (int i = 0; i < length; ++i) { + int pos = i * 2; + d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); + } + + return d; + } else { + return null; + } + } + + public static String byteToHexString(byte[] b) { + String a = ""; + + for (int i = 0; i < b.length; ++i) { + String hex = Integer.toHexString(b[i] & 255); + if (hex.length() == 1) { + hex = '0' + hex; + } + + a = a + hex; + } + + return a; + } + + private static byte charToByte(char c) { + return (byte) "0123456789ABCDEF".indexOf(c); + } + + private static String readFileContent(String filePath) { + File file = new File(filePath); + BufferedReader reader = null; + StringBuffer key = new StringBuffer(); + + try { + IOException e; + try { + reader = new BufferedReader(new FileReader(file)); + e = null; + + String tempString; + while ((tempString = reader.readLine()) != null) { + if (!tempString.startsWith("--")) { + key.append(tempString); + } + } + + reader.close(); + } catch (IOException ioException) { + e = ioException; + e.printStackTrace(); + } + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + } + + } + + return key.toString(); + } + + public static String decrypt(String sysPubKeyFile, String appPrivKeyFile, String encStr) throws Exception { + String pubKeyBase64 = readFileContent(sysPubKeyFile); + String privKeyBase64 = readFileContent(appPrivKeyFile); + byte[] encBin = hexStringToBytes(encStr); + byte[] pubDecBin = RSAUtils.decryptByPublicKeyBlock(encBin, pubKeyBase64); + byte[] privDecBin = RSAUtils.decryptByPrivateKeyBlock(pubDecBin, privKeyBase64); + return new String(privDecBin); + } + + public static String decrypt(ParamType pubKeyType, String sysPubKey, ParamType privKeyType, String appPrivKey, ParamType passwdType, + String passwd) throws Exception { + String pubKeyBase64 = pubKeyType == ParamType.FILE ? readFileContent(sysPubKey) : sysPubKey; + String privKeyBase64 = privKeyType == ParamType.FILE ? readFileContent(appPrivKey) : appPrivKey; + String passwdContent = passwdType == ParamType.FILE ? readFileContent(passwd) : passwd; + byte[] encBin = hexStringToBytes(passwdContent); + byte[] pubDecBin = RSAUtils.decryptByPublicKeyBlock(encBin, pubKeyBase64); + byte[] privDecBin = RSAUtils.decryptByPrivateKeyBlock(pubDecBin, privKeyBase64); + return new String(privDecBin); + } + + public static String encrypt(String appPubKeyFile, String sysPrivKeyFile, String passwd) throws Exception { + String pubKeyBase64 = readFileContent(appPubKeyFile); + String privKeyBase64 = readFileContent(sysPrivKeyFile); + byte[] pubEncBin = RSAUtils.encryptByPublicKeyBlock(passwd.getBytes(), pubKeyBase64); + byte[] privEncBin = RSAUtils.encryptByPrivateKeyBlock(pubEncBin, privKeyBase64); + return byteToHexString(privEncBin); + } + + public static String encrypt(ParamType pubKeyType, String appPubKey, ParamType privKeyType, String sysPrivKey, String passwd) throws Exception { + String pubKeyBase64 = pubKeyType == ParamType.FILE ? readFileContent(appPubKey) : appPubKey; + String privKeyBase64 = privKeyType == ParamType.FILE ? readFileContent(sysPrivKey) : sysPrivKey; + byte[] pubEncBin = RSAUtils.encryptByPublicKeyBlock(passwd.getBytes(), pubKeyBase64); + byte[] privEncBin = RSAUtils.encryptByPrivateKeyBlock(pubEncBin, privKeyBase64); + return byteToHexString(privEncBin); + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/JdbcUtils.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/JdbcUtils.java new file mode 100644 index 0000000000..c012806e2e --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/JdbcUtils.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.utils; + +import com.alibaba.druid.pool.DruidDataSource; + +public class JdbcUtils { + + public static DruidDataSource createDruidDataSource(String url, String userName, String passWord) { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl(url); + dataSource.setUsername(userName); + dataSource.setPassword(passWord); + dataSource.setInitialSize(5); + dataSource.setMinIdle(5); + dataSource.setMaxActive(20); + dataSource.setMaxWait(60000); + dataSource.setTimeBetweenEvictionRunsMillis(60000); + dataSource.setMinEvictableIdleTimeMillis(300000); + dataSource.setValidationQuery("SELECT 1"); + dataSource.setTestWhileIdle(true); + dataSource.setTestOnBorrow(false); + dataSource.setTestOnReturn(false); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(20); + return dataSource; + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/ParamType.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/ParamType.java new file mode 100644 index 0000000000..ed58a49b89 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/ParamType.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.utils; + +public enum ParamType { + FILE, + STRING; + + private ParamType() { + } +} diff --git a/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/RSAUtils.java b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/RSAUtils.java new file mode 100644 index 0000000000..9353eb3f17 --- /dev/null +++ b/eventmesh-admin-server/src/main/java/org/apache/eventmesh/admin/server/web/utils/RSAUtils.java @@ -0,0 +1,255 @@ +/* + * 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. + */ + +package org.apache.eventmesh.admin.server.web.utils; + +import java.io.ByteArrayOutputStream; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.Cipher; + +public class RSAUtils { + public static final String KEY_ALGORITHM = "RSA"; + public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; + private static final String PUBLIC_KEY = "RSAPublicKey"; + private static final String PRIVATE_KEY = "RSAPrivateKey"; + private static final int MAX_ENCRYPT_BLOCK = 117; + private static final int MAX_DECRYPT_BLOCK = 128; + + public RSAUtils() { + } + + public static Map genKeyPair() throws Exception { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); + keyPairGen.initialize(1024); + KeyPair keyPair = keyPairGen.generateKeyPair(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + Map keyMap = new HashMap(2); + keyMap.put("RSAPublicKey", publicKey); + keyMap.put("RSAPrivateKey", privateKey); + return keyMap; + } + + public static String sign(byte[] data, String privateKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Signature signature = Signature.getInstance("MD5withRSA"); + signature.initSign(privateK); + signature.update(data); + return Base64Utils.encode(signature.sign()); + } + + public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicK = keyFactory.generatePublic(keySpec); + Signature signature = Signature.getInstance("MD5withRSA"); + signature.initVerify(publicK); + signature.update(data); + return signature.verify(Base64Utils.decode(sign)); + } + + public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(2, privateK); + int inputLen = encryptedData.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + + for (int i = 0; inputLen - offSet > 0; offSet = i * 128) { + byte[] cache; + if (inputLen - offSet > 128) { + cache = cipher.doFinal(encryptedData, offSet, 128); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + + out.write(cache, 0, cache.length); + ++i; + } + + byte[] decryptedData = out.toByteArray(); + out.close(); + return decryptedData; + } + + public static byte[] decryptByPrivateKeyBlock(byte[] encryptedData, String privateKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(2, privateK); + int inputLen = encryptedData.length; + int offSet = 0; + byte[] cache = cipher.doFinal(encryptedData, offSet, inputLen); + return cache; + } + + public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key publicK = keyFactory.generatePublic(x509KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(2, publicK); + int inputLen = encryptedData.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + + for (int i = 0; inputLen - offSet > 0; offSet = i * 128) { + byte[] cache; + if (inputLen - offSet > 128) { + cache = cipher.doFinal(encryptedData, offSet, 128); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + + out.write(cache, 0, cache.length); + ++i; + } + + byte[] decryptedData = out.toByteArray(); + out.close(); + return decryptedData; + } + + public static byte[] decryptByPublicKeyBlock(byte[] encryptedData, String publicKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key publicK = keyFactory.generatePublic(x509KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(2, publicK); + int inputLen = encryptedData.length; + int offSet = 0; + byte[] cache = cipher.doFinal(encryptedData, offSet, inputLen); + return cache; + } + + public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key publicK = keyFactory.generatePublic(x509KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(1, publicK); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + + for (int i = 0; inputLen - offSet > 0; offSet = i * 117) { + byte[] cache; + if (inputLen - offSet > 117) { + cache = cipher.doFinal(data, offSet, 117); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + + out.write(cache, 0, cache.length); + ++i; + } + + byte[] encryptedData = out.toByteArray(); + out.close(); + return encryptedData; + } + + public static byte[] encryptByPublicKeyBlock(byte[] data, String publicKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key publicK = keyFactory.generatePublic(x509KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(1, publicK); + int inputLen = data.length; + int offSet = 0; + byte[] cache = cipher.doFinal(data, offSet, inputLen); + return cache; + } + + public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(1, privateK); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + + for (int i = 0; inputLen - offSet > 0; offSet = i * 117) { + byte[] cache; + if (inputLen - offSet > 117) { + cache = cipher.doFinal(data, offSet, 117); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + + out.write(cache, 0, cache.length); + ++i; + } + + byte[] encryptedData = out.toByteArray(); + out.close(); + return encryptedData; + } + + public static byte[] encryptByPrivateKeyBlock(byte[] data, String privateKey) throws Exception { + byte[] keyBytes = Base64Utils.decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(1, privateK); + int inputLen = data.length; + int offSet = 0; + byte[] cache = cipher.doFinal(data, offSet, inputLen); + return cache; + } + + public static String getPrivateKey(Map keyMap) throws Exception { + Key key = (Key) keyMap.get("RSAPrivateKey"); + return Base64Utils.encode(key.getEncoded()); + } + + public static String getPublicKey(Map keyMap) throws Exception { + Key key = (Key) keyMap.get("RSAPublicKey"); + return Base64Utils.encode(key.getEncoded()); + } +} diff --git a/eventmesh-admin-server/src/main/resources/META-INF/spring.factories b/eventmesh-admin-server/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..0d9e9bae6e --- /dev/null +++ b/eventmesh-admin-server/src/main/resources/META-INF/spring.factories @@ -0,0 +1,19 @@ +# +# 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. +# + +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.apache.eventmesh.admin.server.AdminServerProperties \ No newline at end of file diff --git a/eventmesh-admin/README.md b/eventmesh-admin/README.md deleted file mode 100644 index 69db9bb59a..0000000000 --- a/eventmesh-admin/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# EventMesh Administration Module - -EventMesh Administration Module for EventMesh. It manages Admin Service, Configurations such as topics/subscriptions management.It works as a control plane and provide some interface to manage the eventmesh-runtime module and other configurations. - -## Administration Client Manager APIs - -### POST /topicManage -- Create a new topic if does not exist -- Exposed POST endpoint to create a new topic if it does not exist. - * Url - http://localhost:8081/topicManage - * sample request payload - ```json - { - "name": "mytopic1" - } - ``` - - Sample response - - ```json - { - "topic": "mytopic1", - "created_time": "2021-09-03", - } - ``` -### DELETE /topicManage/(string: topic) -- Delete a specific topic. -- Exposed DELETE endpoint to remove a specific topic - * URL - - ```url - http://localhost:8081/topicManage/mytopic1 - ``` - - * Response - - - ```json - { - "topic": "mytopic1", - } - ``` - -### GET /topicManage -- Retrieve a list of topics -- Exposed GET endpoint to retrieve all topics - * URL - - ```url - http://localhost:8081/topicManage - ``` - * Response - - ```json - ["mytopic1", "mytopic2"] - ``` diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/build.gradle b/eventmesh-admin/eventmesh-admin-rocketmq/build.gradle deleted file mode 100644 index 1217b33818..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - - -dependencies { - compileOnly project(":eventmesh-common") - - implementation "org.apache.httpcomponents:httpclient" - implementation "com.fasterxml.jackson.core:jackson-databind" - implementation "com.fasterxml.jackson.core:jackson-core" - implementation "com.fasterxml.jackson.core:jackson-annotations" - - implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") - - testImplementation project(":eventmesh-connector-plugin:eventmesh-connector-api") -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/gradle.properties b/eventmesh-admin/eventmesh-admin-rocketmq/gradle.properties deleted file mode 100644 index 7c28639929..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/gradle.properties +++ /dev/null @@ -1,17 +0,0 @@ -# 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. -# - -rocketmq_version=4.9.3 \ No newline at end of file diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/Constants.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/Constants.java deleted file mode 100644 index 6547f9e3ee..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/Constants.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq; - -public class Constants { - - public static final String TOPIC_MANAGE_PATH = "/topicManage"; -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/controller/AdminController.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/controller/AdminController.java deleted file mode 100644 index 9b85b4521c..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/controller/AdminController.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.controller; - -import static org.apache.eventmesh.admin.rocketmq.Constants.TOPIC_MANAGE_PATH; - -import org.apache.eventmesh.admin.rocketmq.handler.TopicsHandler; - -import java.io.IOException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpServer; - -public class AdminController { - - private static final Logger logger = LoggerFactory.getLogger(AdminController.class); - - public AdminController() { - } - - public void run(HttpServer server) throws IOException { - - server.createContext(TOPIC_MANAGE_PATH, new TopicsHandler()); - - logger.info("EventMesh-Admin Controller server context created successfully"); - } -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/handler/TopicsHandler.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/handler/TopicsHandler.java deleted file mode 100644 index ed9fbcadeb..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/handler/TopicsHandler.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.handler; - -import static org.apache.eventmesh.admin.rocketmq.Constants.TOPIC_MANAGE_PATH; - -import org.apache.eventmesh.admin.rocketmq.request.TopicCreateRequest; -import org.apache.eventmesh.admin.rocketmq.response.TopicResponse; -import org.apache.eventmesh.admin.rocketmq.util.JsonUtils; -import org.apache.eventmesh.admin.rocketmq.util.NetUtils; -import org.apache.eventmesh.admin.rocketmq.util.RequestMapping; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -public class TopicsHandler implements HttpHandler { - private static final Logger logger = LoggerFactory.getLogger(TopicsHandler.class); - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - - // create a new topic - if (RequestMapping.postMapping(TOPIC_MANAGE_PATH, httpExchange)) { - createTopicHandler(httpExchange); - return; - } - - OutputStream out = httpExchange.getResponseBody(); - httpExchange.sendResponseHeaders(500, 0); - String result = String.format("Please check your request url"); - logger.error(result); - out.write(result.getBytes()); - return; - } - - public void createTopicHandler(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String params = NetUtils.parsePostBody(httpExchange); - TopicCreateRequest topicCreateRequest = - JsonUtils.toObject(params, TopicCreateRequest.class); - String topic = topicCreateRequest.getName(); - - if (StringUtils.isBlank(topic)) { - result = "Create topic failed. Parameter topic not found."; - logger.error(result); - out.write(result.getBytes()); - return; - } - - //TBD: A new rocketmq service will be implemented for creating topics - TopicResponse topicResponse = null; - if (topicResponse != null) { - logger.info("create a new topic: {}", topic); - httpExchange.getResponseHeaders().add("Content-Type", "application/json"); - httpExchange.sendResponseHeaders(200, 0); - result = JsonUtils.toJson(topicResponse); - logger.info(result); - out.write(result.getBytes()); - return; - } else { - httpExchange.sendResponseHeaders(500, 0); - result = String.format("create topic failed! Server side error"); - logger.error(result); - out.write(result.getBytes()); - return; - } - } catch (Exception e) { - httpExchange.getResponseHeaders().add("Content-Type", "application/json"); - httpExchange.sendResponseHeaders(500, 0); - result = String.format("create topic failed! Server side error"); - logger.error(result); - out.write(result.getBytes()); - return; - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - } - -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/request/TopicCreateRequest.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/request/TopicCreateRequest.java deleted file mode 100644 index 7adaa77cd2..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/request/TopicCreateRequest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.request; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonInclude(JsonInclude.Include.NON_EMPTY) -@JsonIgnoreProperties(ignoreUnknown = true) -public class TopicCreateRequest { - - private String name; - - @JsonCreator - public TopicCreateRequest(@JsonProperty("name") String topic) { - super(); - this.name = topic; - } - - @JsonProperty("name") - public String getName() { - return this.name; - } - - @JsonProperty("name") - public void setName(String name) { - this.name = name; - } - -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/response/TopicResponse.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/response/TopicResponse.java deleted file mode 100644 index 41b6e6a9b2..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/response/TopicResponse.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.response; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class TopicResponse { - - private String topic; - private String createdTime; - - @JsonCreator - public TopicResponse(@JsonProperty("topic") String topic, - @JsonProperty("created_time") String createdTime) { - super(); - this.topic = topic; - this.createdTime = createdTime; - } - - @JsonProperty("topic") - public String getTopic() { - return this.topic; - } - - @JsonProperty("topic") - public void setTopic(String topic) { - this.topic = topic; - } - - @JsonProperty("created_time") - public String getCreatedTime() { - return createdTime; - } - - @JsonProperty("created_time") - public void setCreatedTime(String createdTime) { - this.createdTime = createdTime; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("TopicResponse {topic=" + this.topic + ","); - sb.append("created_time=" + this.createdTime + "}"); - return sb.toString(); - } - -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/JsonUtils.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/JsonUtils.java deleted file mode 100644 index 6fbd31a2dd..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/JsonUtils.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.util; - -import java.io.IOException; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; - -public class JsonUtils { - - private static ObjectMapper objectMapper; - - static { - objectMapper = new ObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - } - - public static byte[] serialize(String topic, Class data) throws JsonProcessingException { - if (data == null) { - return null; - } - return objectMapper.writeValueAsBytes(data); - } - - public static String toJson(Object obj) throws JsonProcessingException { - if (obj == null) { - return null; - } - return objectMapper.writeValueAsString(obj); - } - - public static T toObject(String json, Class clazz) throws JsonProcessingException { - return objectMapper.readValue(json, clazz); - } - - public static T deserialize(Class clazz, byte[] bytes) throws IOException { - if (bytes == null || bytes.length == 0) { - return null; - } - - return objectMapper.readValue(bytes, clazz); - } - - public static T deserialize(Class clazz, String json) throws IOException { - if (json == null || json.length() == 0) { - return null; - } - - return objectMapper.readValue(json, clazz); - } - - public static JsonNode getJsonNode(String json) throws IOException { - if (json == null || json.length() == 0) { - return null; - } - - return objectMapper.readTree(json); - } -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/NetUtils.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/NetUtils.java deleted file mode 100644 index 7a16bf74f8..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/NetUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.util; - -import org.apache.eventmesh.admin.rocketmq.HttpMethod; - -import org.apache.http.Consts; - -import java.io.IOException; -import java.io.InputStreamReader; - -import com.sun.net.httpserver.HttpExchange; - -public class NetUtils { - - public static String parsePostBody(HttpExchange exchange) - throws IOException { - StringBuilder body = new StringBuilder(); - if (HttpMethod.POST.name().equalsIgnoreCase(exchange.getRequestMethod()) - || HttpMethod.PUT.name().equalsIgnoreCase(exchange.getRequestMethod())) { - try (InputStreamReader reader = - new InputStreamReader(exchange.getRequestBody(), Consts.UTF_8)) { - char[] buffer = new char[256]; - int read; - while ((read = reader.read(buffer)) != -1) { - body.append(buffer, 0, read); - } - } - } - return body.toString(); - } -} - diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/RequestMapping.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/RequestMapping.java deleted file mode 100644 index 6a67e05813..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/RequestMapping.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.util; - -import org.apache.eventmesh.admin.rocketmq.HttpMethod; - -import com.sun.net.httpserver.HttpExchange; - -public class RequestMapping { - - public static boolean postMapping(String value, HttpExchange httpExchange) { - if (HttpMethod.POST.name().equalsIgnoreCase(httpExchange.getRequestMethod())) { - String requestUri = httpExchange.getRequestURI().getPath(); - UrlMappingPattern matcher = new UrlMappingPattern(value); - return matcher.matches(requestUri); - } - return false; - } - - public static boolean getMapping(String value, HttpExchange httpExchange) { - if (HttpMethod.GET.name().equalsIgnoreCase(httpExchange.getRequestMethod())) { - String requestUri = httpExchange.getRequestURI().getPath(); - UrlMappingPattern matcher = new UrlMappingPattern(value); - return matcher.matches(requestUri); - } - return false; - } - - public static boolean putMapping(String value, HttpExchange httpExchange) { - if (HttpMethod.PUT.name().equalsIgnoreCase(httpExchange.getRequestMethod())) { - String requestUri = httpExchange.getRequestURI().getPath(); - UrlMappingPattern matcher = new UrlMappingPattern(value); - return matcher.matches(requestUri); - } - return false; - } - - public static boolean deleteMapping(String value, HttpExchange httpExchange) { - if (HttpMethod.DELETE.name().equalsIgnoreCase(httpExchange.getRequestMethod())) { - String requestUri = httpExchange.getRequestURI().getPath(); - UrlMappingPattern matcher = new UrlMappingPattern(value); - return matcher.matches(requestUri); - } - return false; - } - -} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/UrlMappingPattern.java b/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/UrlMappingPattern.java deleted file mode 100644 index 09d0eb3d67..0000000000 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/util/UrlMappingPattern.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.admin.rocketmq.util; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class UrlMappingPattern { - - private static final String URL_PARAMETER_REGEX = "\\{(\\w*?)\\}"; - - private static final String URL_PARAMETER_MATCH_REGEX = - "\\([%\\\\w-.\\\\~!\\$&'\\\\(\\\\)\\\\*\\\\+,;=:\\\\[\\\\]@]+?\\)"; - - private static final Pattern URL_PARAMETER_PATTERN = Pattern.compile(URL_PARAMETER_REGEX); - - private static final String URL_FORMAT_REGEX = "(?:\\.\\{format\\})$"; - - private static final String URL_FORMAT_MATCH_REGEX = "(?:\\\\.\\([\\\\w%]+?\\))?"; - - private static final String URL_QUERY_STRING_REGEX = "(?:\\?.*?)?$"; - - private String urlMappingPattern; - - private Pattern compiledUrlMappingPattern; - - private List paramNames = new ArrayList(); - - public UrlMappingPattern(String pattern) { - super(); - setUrlMappingPattern(pattern); - compile(); - } - - public String getMappingPattern() { - return getUrlMappingPattern().replaceFirst(URL_FORMAT_REGEX, ""); - } - - private String getUrlMappingPattern() { - return urlMappingPattern; - } - - public Map extractPathParameterValues(String url) { - Matcher matcher = compiledUrlMappingPattern.matcher(url); - if (matcher.matches()) { - return extractParameters(matcher); - } - return null; - } - - public boolean matches(String url) { - return (extractPathParameterValues(url) != null); - } - - public void compile() { - acquireParamNames(); - String parsedPattern = - getUrlMappingPattern().replaceFirst(URL_FORMAT_REGEX, URL_FORMAT_MATCH_REGEX); - parsedPattern = parsedPattern.replaceAll(URL_PARAMETER_REGEX, URL_PARAMETER_MATCH_REGEX); - this.compiledUrlMappingPattern = Pattern.compile(parsedPattern + URL_QUERY_STRING_REGEX); - } - - private void acquireParamNames() { - Matcher m = URL_PARAMETER_PATTERN.matcher(getUrlMappingPattern()); - while (m.find()) { - paramNames.add(m.group(1)); - } - } - - private Map extractParameters(Matcher matcher) { - Map values = new HashMap(); - for (int i = 0; i < matcher.groupCount(); i++) { - String value = matcher.group(i + 1); - - if (value != null) { - values.put(paramNames.get(i), value); - } - } - return values; - } - - private void setUrlMappingPattern(String pattern) { - this.urlMappingPattern = pattern; - } - - public List getParamNames() { - return Collections.unmodifiableList(paramNames); - } -} diff --git a/eventmesh-common/build.gradle b/eventmesh-common/build.gradle index 5033b3aabb..21b6e63d44 100644 --- a/eventmesh-common/build.gradle +++ b/eventmesh-common/build.gradle @@ -15,6 +15,8 @@ * limitations under the License. */ +def grpcVersion = '1.68.0' + dependencies { api "com.google.guava:guava" api "org.slf4j:slf4j-api" @@ -23,33 +25,42 @@ dependencies { api "org.apache.commons:commons-text" api "org.apache.commons:commons-lang3" - implementation "org.apache.logging.log4j:log4j-api" - implementation "org.apache.logging.log4j:log4j-core" - implementation "org.apache.logging.log4j:log4j-slf4j-impl" + api "com.jayway.jsonpath:json-path" + + api "io.cloudevents:cloudevents-core" + api "io.cloudevents:cloudevents-json-jackson" + + api "com.alibaba.fastjson2:fastjson2" + + runtimeOnly "org.apache.logging.log4j:log4j-core" + runtimeOnly "org.apache.logging.log4j:log4j-slf4j2-impl" - implementation 'com.github.seancfoley:ipaddress:5.3.3' + implementation 'com.github.seancfoley:ipaddress' implementation "com.lmax:disruptor" api "com.fasterxml.jackson.core:jackson-databind" api "com.fasterxml.jackson.core:jackson-core" api "com.fasterxml.jackson.core:jackson-annotations" + api "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" + api "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" implementation "org.apache.httpcomponents:httpclient" implementation "io.netty:netty-all" + compileOnly 'com.mysql:mysql-connector-j' - implementation "io.grpc:grpc-protobuf:1.17.1" - implementation "io.grpc:grpc-stub:1.17.1" + implementation "io.grpc:grpc-protobuf:${grpcVersion}" + implementation "io.grpc:grpc-stub:${grpcVersion}" implementation "javax.annotation:javax.annotation-api:1.3.2" - implementation "com.github.stefanbirkner:system-rules" + testImplementation "org.junit-pioneer:junit-pioneer" - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' testImplementation "org.apache.commons:commons-lang3" @@ -58,7 +69,7 @@ dependencies { testImplementation "org.slf4j:slf4j-api" testImplementation "org.apache.logging.log4j:log4j-api" testImplementation "org.apache.logging.log4j:log4j-core" - testImplementation "org.apache.logging.log4j:log4j-slf4j-impl" + testImplementation "org.apache.logging.log4j:log4j-slf4j2-impl" testImplementation "com.lmax:disruptor" @@ -73,6 +84,5 @@ dependencies { testImplementation "org.assertj:assertj-core" testImplementation "org.mockito:mockito-core" - testImplementation "org.powermock:powermock-module-junit4" - testImplementation "org.powermock:powermock-api-mockito2" + testImplementation "org.mockito:mockito-junit-jupiter" } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/AbstractComponent.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/AbstractComponent.java new file mode 100644 index 0000000000..375b6cb1d3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/AbstractComponent.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractComponent implements ComponentLifeCycle { + private final AtomicBoolean started = new AtomicBoolean(false); + private final AtomicBoolean stopped = new AtomicBoolean(false); + + @Override + public void start() throws Exception { + if (!started.compareAndSet(false, true)) { + log.info("component [{}] has started", this.getClass()); + return; + } + log.info("component [{}] will start", this.getClass()); + run(); + log.info("component [{}] started successfully", this.getClass()); + } + + @Override + public void stop() throws Exception { + if (!stopped.compareAndSet(false, true)) { + log.info("component [{}] has stopped", this.getClass()); + return; + } + log.info("component [{}] will stop", this.getClass()); + shutdown(); + log.info("component [{}] stopped successfully", this.getClass()); + } + + protected abstract void run() throws Exception; + + protected abstract void shutdown() throws Exception; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/ComponentLifeCycle.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ComponentLifeCycle.java new file mode 100644 index 0000000000..76fdd548d0 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ComponentLifeCycle.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +/** + * LifeCycle of EventMesh Component + */ +public interface ComponentLifeCycle { + + void start() throws Exception; + + void stop() throws Exception; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/Constants.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/Constants.java index 9c13e75ad0..2460129e75 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/Constants.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/Constants.java @@ -17,14 +17,23 @@ package org.apache.eventmesh.common; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + public class Constants { - public static final String DEFAULT_CHARSET = "UTF-8"; + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + + public static final String DATE_FORMAT_INCLUDE_MILLISECONDS = "yyyy-MM-dd HH:mm:ss.SSS"; + + public static final String DATE_FORMAT_DEFAULT = "yyyy-MM-dd HH:mm:ss"; - public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + public static final String DATA_CONTENT_TYPE = "datacontenttype"; public static final String LANGUAGE_JAVA = "JAVA"; + public static final String CONNECT_SERVER_CONFIG_FILE_NAME = "server-config.yml"; + public static final String HTTP_PROTOCOL_PREFIX = "http://"; public static final String HTTPS_PROTOCOL_PREFIX = "https://"; @@ -99,10 +108,16 @@ public class Constants { public static final String PRODUCER_GROUP = "producerGroup"; + public static final String PRODUCER_TOKEN = "producerToken"; + + public static final String CONSUMER_TOKEN = "consumerToken"; + public static final String INSTANCE_NAME = "instanceName"; public static final String ACCESS_POINTS = "ACCESS_POINTS"; + public static final String CLIENT_ADDRESS = "clientAddress"; + public static final String REGION = "REGION"; public static final String MESSAGE_MODEL = "MESSAGE_MODEL"; @@ -113,4 +128,85 @@ public class Constants { public static final String OPERATION_TIMEOUT = "OPERATION_TIMEOUT"; + public static final String CLOUD_EVENTS_PROTOCOL_NAME = "cloudevents"; + + public static final String EM_MESSAGE_PROTOCOL_NAME = "eventmeshmessage"; + + public static final String OPEN_MESSAGE_PROTOCOL_NAME = "openmessage"; + + // delimiter define + public static final String COMMA = ","; + + public static final String VERTICAL_LINE = "|"; + + public static final String COLON = ":"; + + public static final String HYPHEN = "-"; + + public static final String DOT = "."; + + public static final String POUND = "#"; + + public static final String ASTERISK = "*"; + + public static final String UNDER_LINE = "_"; + + public static final String UNKNOWN = "unknown"; + + public static final String LEFT_PARENTHESIS = "("; + + public static final String RIGHT_PARENTHESIS = ")"; + + public static final String LINE_BREAK = "\n"; + + public static final String TAB = "\t"; + + public static final String AT = "@"; + + public static final String QUESTION_MARK = "?"; + + public static final String AND = "&"; + + public static final String EQ = "="; + + public static final String EMPTY = ""; + + public static final int SUCCESS_CODE = 200; + + public static final String SINK = "Sink"; + + public static final String SOURCE = "Source"; + + // protocol desc + public static final String PROTOCOL_DESC_GRPC_CLOUD_EVENT = "grpc-cloud-event"; + + public static final String PROTOCOL_DESC_HTTP = "http"; + + public static final String PROTOCOL_DESC_TCP = "tcp"; + + /** + * GRPC PROTOCOL + */ + public static final String PROTOCOL_GRPC = "grpc"; + + /** + * application/cloudevents+json Content-type + */ + public static final String CONTENT_TYPE_CLOUDEVENTS_JSON = "application/cloudevents+json"; + + public static final String HTTP = "HTTP"; + + public static final String TCP = "TCP"; + + public static final String GRPC = "GRPC"; + + public static final String ADMIN = "ADMIN"; + + public static final String OS_NAME_KEY = "os.name"; + + public static final String OS_WIN_PREFIX = "win"; + + public static final String DEFAULT = "default"; + + public static final String ADMIN_SERVER_REGISTRY_NAME = "DEFAULT_GROUP@@em_adm_server"; } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshDateFormat.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshDateFormat.java new file mode 100644 index 0000000000..c25862ec96 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshDateFormat.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.text.SimpleDateFormat; + +public class EventMeshDateFormat extends SimpleDateFormat { + + public EventMeshDateFormat(final String pattern) { + super(pattern); + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshMessage.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshMessage.java index 8fecc700fe..9175ca45d2 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshMessage.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshMessage.java @@ -38,15 +38,13 @@ public class EventMeshMessage { private String content; - private Map prop; + @Builder.Default + private Map prop = new HashMap<>(); @Builder.Default private final long createTime = System.currentTimeMillis(); public EventMeshMessage addProp(String key, String val) { - if (prop == null) { - prop = new HashMap<>(); - } prop.put(key, val); return this; } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshThreadFactory.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshThreadFactory.java new file mode 100644 index 0000000000..d18ec5a048 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/EventMeshThreadFactory.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.annotation.Nonnull; + +import lombok.Getter; + +public class EventMeshThreadFactory implements ThreadFactory { + + @Getter + private final String threadNamePrefix; + private final AtomicInteger threadIndex; + private final boolean daemon; + private final Integer priority; + + public EventMeshThreadFactory(final String threadNamePrefix, final AtomicInteger threadIndex, final boolean daemon, + final Integer priority) { + this.threadNamePrefix = threadNamePrefix; + this.threadIndex = threadIndex; + this.daemon = daemon; + this.priority = priority; + } + + public EventMeshThreadFactory(final String threadNamePrefix, final AtomicInteger threadIndex, + final boolean daemon) { + this(threadNamePrefix, threadIndex, daemon, null); + } + + public EventMeshThreadFactory(final String threadNamePrefix, final boolean daemon, final Integer priority) { + this(threadNamePrefix, new AtomicInteger(0), daemon, priority); + } + + public EventMeshThreadFactory(final String threadNamePrefix, final boolean daemon) { + this(threadNamePrefix, new AtomicInteger(0), daemon); + } + + public EventMeshThreadFactory(final String threadNamePrefix) { + this(threadNamePrefix, new AtomicInteger(0), false); + } + + /** + * Constructs a new {@code Thread}. Implementations may also initialize priority, name, daemon status, {@code ThreadGroup}, etc. + * + * @param runnable a runnable to be executed by new thread instance + * @return constructed thread, or {@code null} if the request to create a thread is rejected + */ + @Override + public Thread newThread(@Nonnull final Runnable runnable) { + + StringBuilder threadName = new StringBuilder(threadNamePrefix); + if (threadIndex != null) { + threadName.append("-").append(threadIndex.incrementAndGet()); + } + Thread thread = new Thread(runnable, threadName.toString()); + thread.setDaemon(daemon); + if (priority != null) { + thread.setPriority(priority); + } + + return thread; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/MetricsConstants.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/MetricsConstants.java new file mode 100644 index 0000000000..d1c74c90c3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/MetricsConstants.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + + +public class MetricsConstants { + + private MetricsConstants() { + + } + + public static final String UNKOWN = "unkown"; + + public static final String LABEL_PROCESSOR = "processor"; + + public static final String CLIENT_ADDRESS = "client.address"; + + public static final String RPC_SYSTEM = "rpc.system"; + + public static final String RPC_SERVICE = "rpc.service"; + + //GRPC-https://opentelemetry.io/docs/reference/specification/metrics/semantic_conventions/rpc-metrics/ + public static final String GRPC_NET_PEER_PORT = "net.peer.port"; + + public static final String GRPC_NET_PEER_NAME = "net.peer.name"; + + public static final String GRPC_NET_SOCK_PEER_ADDR = "net.sock.peer.addr"; + + public static final String GRPC_NET_SOCK_PEER_PORT = "net.sock.peer.port"; + + // HTTP https://opentelemetry.io/docs/reference/specification/metrics/semantic_conventions/http-metrics/ + + public static final String HTTP_HTTP_SCHEME = "http.scheme"; + + public static final String HTTP_HTTP_FLAVOR = "http.flavor"; + + public static final String HTTP_NET_HOST_NAME = "net.host.name"; + + public static final String HTTP_NET_HOST_PORT = "net.host.port"; + + //TCP + public static final String TCP_NET_HOST_NAME = "net.host.name"; + + public static final String TCP_NET_HOST_PORT = "net.host.port"; + + + public static final String CLIENT_PROTOCOL_TYPE = "client.protocol.type"; + + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/Pair.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/Pair.java new file mode 100644 index 0000000000..25b2a6f3c4 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/Pair.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +public class Pair { + + private Left left; + + private Right right; + + public Pair(Left left, Right right) { + this.left = left; + this.right = right; + } + + public Left getLeft() { + return left; + } + + public void setLeft(Left left) { + this.left = left; + } + + public Right getRight() { + return right; + } + + public void setRight(Right right) { + this.right = right; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/ResetCountDownLatch.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ResetCountDownLatch.java new file mode 100644 index 0000000000..bb6a01f976 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ResetCountDownLatch.java @@ -0,0 +1,178 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +/** + * ResetCountDownLatch can reset + * + * @see java.util.concurrent.CountDownLatch + */ +public class ResetCountDownLatch { + + private final RestSync restSync; + + public ResetCountDownLatch(int count) { + this.restSync = new RestSync(count); + } + + /** + * Causes the current thread to wait until the latch has counted down to zero, unless the thread is {@linkplain Thread#interrupt interrupted}. + * + *

If the current count is zero then this method returns immediately. + * + *

If the current count is greater than zero then the current + * thread becomes disabled for thread scheduling purposes and lies dormant until one of two things happen: + *

    + *
  • The count reaches zero due to invocations of the + * {@link #countDown} method; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + *
+ * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @throws InterruptedException if the current thread is interrupted while waiting + */ + public void await() throws InterruptedException { + restSync.acquireSharedInterruptibly(1); + } + + /** + * Causes the current thread to wait until the latch has counted down to zero, unless the thread is {@linkplain Thread#interrupt interrupted}, or + * the specified waiting time elapses. + * + *

If the current count is zero then this method returns immediately + * with the value {@code true}. + * + *

If the current count is greater than zero then the current + * thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happen: + *

    + *
  • The count reaches zero due to invocations of the + * {@link #countDown} method; or + *
  • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + *
  • The specified waiting time elapses. + *
+ * + *

If the count reaches zero then the method returns with the + * value {@code true}. + * + *

If the current thread: + *

    + *
  • has its interrupted status set on entry to this method; or + *
  • is {@linkplain Thread#interrupt interrupted} while waiting, + *
+ * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + *

If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if the count reached zero and {@code false} if the waiting time elapsed before the count reached zero + * @throws InterruptedException if the current thread is interrupted while waiting + */ + public boolean await(long timeout, TimeUnit unit) + throws InterruptedException { + return restSync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Decrements the count of the latch, releasing all waiting threads if the count reaches zero. + * + *

If the current count is greater than zero then it is decremented. + * If the new count is zero then all waiting threads are re-enabled for thread scheduling purposes. + * + *

If the current count equals zero then nothing happens. + */ + public void countDown() { + restSync.releaseShared(1); + } + + /** + * Returns the current count. + * + *

This method is typically used for debugging and testing purposes. + * + * @return the current count + */ + public int getCount() { + return restSync.getCount(); + } + + /** + * Reset the CountDownLatch + */ + public void reset() { + restSync.reset(); + } + + /** + * Synchronization control For ResetCountDownLatch. Uses AQS state to represent count. + */ + private static final class RestSync extends AbstractQueuedSynchronizer { + + private final int initCount; + + RestSync(int count) { + if (count < 0) { + throw new IllegalArgumentException("count must be greater than or equal to 0"); + } + this.initCount = count; + setState(count); + } + + protected void reset() { + setState(initCount); + } + + int getCount() { + return getState(); + } + + @Override + protected int tryAcquireShared(int acquires) { + return (getState() == 0) ? 1 : -1; + } + + @Override + protected boolean tryReleaseShared(int releases) { + for (;;) { + int count = getState(); + if (count == 0) { + return false; + } + int nextCount = count - 1; + if (compareAndSetState(count, nextCount)) { + return nextCount == 0; + } + } + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadPoolFactory.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadPoolFactory.java index 8b6e4379d2..6f9d8a6ba4 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadPoolFactory.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadPoolFactory.java @@ -18,75 +18,48 @@ package org.apache.eventmesh.common; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import com.google.common.util.concurrent.ThreadFactoryBuilder; +public abstract class ThreadPoolFactory { -public class ThreadPoolFactory { + private ThreadPoolFactory() { + } public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, final String threadName) { return createThreadPoolExecutor(core, max, threadName, true); } public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, final String threadName, - final boolean isDaemon) { + final boolean isDaemon) { return createThreadPoolExecutor(core, max, new LinkedBlockingQueue<>(1000), threadName, isDaemon); } public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, BlockingQueue blockingQueue, - final String threadName, final boolean isDaemon) { + final String threadName, final boolean isDaemon) { return new ThreadPoolExecutor(core, max, 10 * 1000, TimeUnit.MILLISECONDS, blockingQueue, - new ThreadFactoryBuilder().setNameFormat(threadName).setDaemon(isDaemon).build() - ); - } - - public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, ThreadFactory threadFactory) { - return createThreadPoolExecutor(core, max, new LinkedBlockingQueue<>(1000), threadFactory); + new EventMeshThreadFactory(threadName, isDaemon)); } public static ThreadPoolExecutor createThreadPoolExecutor(int core, int max, BlockingQueue blockingQueue, - ThreadFactory threadFactory) { + ThreadFactory threadFactory) { return new ThreadPoolExecutor(core, max, 10 * 1000, TimeUnit.MILLISECONDS, blockingQueue, threadFactory); } public static ScheduledExecutorService createSingleScheduledExecutor(final String threadName) { - return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { - private AtomicInteger ai = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, threadName + ai.incrementAndGet()); - thread.setDaemon(true); - return thread; - } - }); - } - - public static ScheduledExecutorService createScheduledExecutor(int core, final String threadName) { - return createScheduledExecutor(core, threadName, true); - } - - public static ScheduledExecutorService createScheduledExecutor(int core, final String threadName, - final boolean isDaemon) { - return Executors.newScheduledThreadPool(core, new ThreadFactory() { - private AtomicInteger ai = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, threadName + ai.incrementAndGet()); - thread.setDaemon(isDaemon); - return thread; - } - }); + return Executors.newSingleThreadScheduledExecutor(new EventMeshThreadFactory(threadName, true)); } public static ScheduledExecutorService createScheduledExecutor(int core, ThreadFactory threadFactory) { return Executors.newScheduledThreadPool(core, threadFactory); } + + public static ExecutorService createSingleExecutor(final String threadName) { + return Executors.newSingleThreadExecutor(new EventMeshThreadFactory(threadName)); + } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadWrapper.java new file mode 100644 index 0000000000..b24402c5fe --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/ThreadWrapper.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class ThreadWrapper implements Runnable { + + private final AtomicBoolean started = new AtomicBoolean(false); + protected Thread thread; + protected final ResetCountDownLatch waiter = new ResetCountDownLatch(1); + protected volatile AtomicBoolean hasWakeup = new AtomicBoolean(false); + protected boolean isDaemon = false; + protected volatile boolean isRunning = false; + + public ThreadWrapper() { + + } + + public abstract String getThreadName(); + + public void start() { + + if (!started.compareAndSet(false, true)) { + log.warn("Start thread:{} fail", getThreadName()); + return; + } + this.thread = new Thread(this, getThreadName()); + this.thread.setDaemon(isDaemon); + this.thread.start(); + this.isRunning = true; + log.info("Start thread:{} success", getThreadName()); + } + + public void await() { + if (hasWakeup.compareAndSet(true, false)) { + return; + } + // reset count + waiter.reset(); + try { + waiter.await(); + } catch (InterruptedException e) { + log.error("Thread[{}] Interrupted", getThreadName(), e); + } finally { + hasWakeup.set(false); + } + } + + public void await(long timeout) { + await(timeout, TimeUnit.MILLISECONDS); + } + + public void await(long timeout, TimeUnit timeUnit) { + if (hasWakeup.compareAndSet(true, false)) { + return; + } + // reset count + waiter.reset(); + try { + waiter.await(timeout, timeUnit == null ? TimeUnit.MILLISECONDS : timeUnit); + } catch (InterruptedException e) { + log.error("Thread[{}] Interrupted", getThreadName(), e); + } finally { + hasWakeup.set(false); + } + } + + public void wakeup() { + if (hasWakeup.compareAndSet(false, true)) { + waiter.countDown(); + } + } + + public void shutdownImmediately() { + shutdown(true); + } + + public void shutdown() { + shutdown(false); + } + + private void shutdown(final boolean interruptThread) { + if (!started.compareAndSet(true, false)) { + return; + } + this.isRunning = false; + // wakeup the thread to run + wakeup(); + + try { + if (interruptThread) { + this.thread.interrupt(); + } + if (!this.isDaemon) { + // wait main thread to wait this thread finish + this.thread.join(TimeUnit.SECONDS.toMillis(60)); + } + } catch (InterruptedException e) { + log.error("Thread[{}] Interrupted", getThreadName(), e); + } + } + + public void setDaemon(boolean daemon) { + isDaemon = daemon; + } + + public boolean isStated() { + return this.started.get(); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/CommonConfiguration.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/CommonConfiguration.java index fe88d58486..b2f0ebbb0c 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/CommonConfiguration.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/CommonConfiguration.java @@ -17,163 +17,117 @@ package org.apache.eventmesh.common.config; +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.collections4.CollectionUtils; -import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Optional; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import com.google.common.base.Preconditions; +import org.assertj.core.util.Strings; -import lombok.Getter; +import lombok.Data; +import lombok.NoArgsConstructor; +@Data +@NoArgsConstructor +@Config(prefix = "eventMesh") public class CommonConfiguration { - public String eventMeshEnv = "P"; - public String eventMeshIDC = "FT"; - public String eventMeshCluster = "LS"; - public String eventMeshName = ""; - public String sysID = "5477"; - public String eventMeshConnectorPluginType = "rocketmq"; - public String eventMeshSecurityPluginType = "security"; - public String eventMeshRegistryPluginType = "namesrv"; - public List eventMeshMetricsPluginType; - public String eventMeshTracePluginType; - public String namesrvAddr = ""; - public String eventMeshRegistryPluginUsername = ""; - public String eventMeshRegistryPluginPassword = ""; - public Integer eventMeshRegisterIntervalInMills = 10 * 1000; - public Integer eventMeshFetchRegistryAddrInterval = 10 * 1000; - public String eventMeshServerIp = null; - public boolean eventMeshServerSecurityEnable = false; - public boolean eventMeshServerRegistryEnable = false; - public boolean eventMeshServerTraceEnable = false; - - @Getter - protected ConfigurationWrapper configurationWrapper; - - public String eventMeshWebhookOrigin = "eventmesh." + eventMeshIDC; - - public CommonConfiguration(ConfigurationWrapper configurationWrapper) { - this.configurationWrapper = configurationWrapper; - } - - public void init() { - - if (configurationWrapper != null) { - eventMeshEnv = checkNotEmpty(ConfKeys.KEYS_EVENTMESH_ENV); - - sysID = checkNumeric(ConfKeys.KEYS_EVENTMESH_SYSID); - - eventMeshCluster = checkNotEmpty(ConfKeys.KEYS_EVENTMESH_SERVER_CLUSTER); - - eventMeshName = checkNotEmpty(ConfKeys.KEYS_EVENTMESH_SERVER_NAME); - - eventMeshIDC = checkNotEmpty(ConfKeys.KEYS_EVENTMESH_IDC); - - eventMeshServerIp = get(ConfKeys.KEYS_EVENTMESH_SERVER_HOST_IP, IPUtils::getLocalAddress); - - eventMeshConnectorPluginType = checkNotEmpty(ConfKeys.KEYS_ENENTMESH_CONNECTOR_PLUGIN_TYPE); - eventMeshServerSecurityEnable = Boolean.parseBoolean(get(ConfKeys.KEYS_EVENTMESH_SECURITY_ENABLED, () -> "false")); + @ConfigField(field = "sysid", beNumber = true, notEmpty = true) + private String sysID = "5477"; - eventMeshSecurityPluginType = checkNotEmpty(ConfKeys.KEYS_ENENTMESH_SECURITY_PLUGIN_TYPE); + @ConfigField(field = "server.env", notEmpty = true) + private String eventMeshEnv = "P"; - eventMeshServerRegistryEnable = Boolean.parseBoolean(get(ConfKeys.KEYS_EVENTMESH_REGISTRY_ENABLED, () -> "false")); + @ConfigField(field = "server.idc", notEmpty = true) + private String eventMeshIDC = "FT"; - eventMeshRegistryPluginType = checkNotEmpty(ConfKeys.KEYS_ENENTMESH_REGISTRY_PLUGIN_TYPE); + @ConfigField(field = "server.name", notEmpty = true) + private String eventMeshName = ""; - namesrvAddr = checkNotEmpty(ConfKeys.KEYS_EVENTMESH_REGISTRY_PULGIN_SERVER_ADDR); + @ConfigField(field = "server.cluster", notEmpty = true) + private String eventMeshCluster = "LS"; - eventMeshRegistryPluginUsername = - Optional.ofNullable(configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REGISTRY_PULGIN_USERNAME)).orElse(""); + @ConfigField(field = "server.hostIp", reload = true) + private String eventMeshServerIp = null; - eventMeshRegistryPluginPassword = - Optional.ofNullable(configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REGISTRY_PULGIN_PASSWORD)).orElse(""); + @ConfigField(field = "metaStorage.plugin.server-addr", notEmpty = true) + private String metaStorageAddr = ""; - String metricsPluginType = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_METRICS_PLUGIN_TYPE); - if (StringUtils.isNotEmpty(metricsPluginType)) { - eventMeshMetricsPluginType = Arrays.stream(metricsPluginType.split(",")) - .filter(StringUtils::isNotBlank) - .map(String::trim) - .collect(Collectors.toList()); - } + @ConfigField(field = "metaStorage.plugin.type", notEmpty = true) + private String eventMeshMetaStoragePluginType = "nacos"; - eventMeshServerTraceEnable = Boolean.parseBoolean(get(ConfKeys.KEYS_EVENTMESH_TRACE_ENABLED, () -> "false")); - if (eventMeshServerTraceEnable) { - eventMeshTracePluginType = checkNotEmpty(ConfKeys.KEYS_EVENTMESH_TRACE_PLUGIN_TYPE); - } - } - } + @ConfigField(field = "metaStorage.plugin.username") + private String eventMeshMetaStoragePluginUsername = ""; - private String checkNotEmpty(String key) { - String value = configurationWrapper.getProp(key); - if (value != null) { - value = StringUtils.deleteWhitespace(value); - } - Preconditions.checkState(StringUtils.isNotEmpty(value), key + " is invalidated"); - return value; - } + @ConfigField(field = "metaStorage.plugin.password") + private String eventMeshMetaStoragePluginPassword = ""; - private String checkNumeric(String key) { - String value = configurationWrapper.getProp(key); - if (value != null) { - value = StringUtils.deleteWhitespace(value); - } - Preconditions.checkState(StringUtils.isNotEmpty(value) && StringUtils.isNumeric(value), key + " is invalidated"); - return value; - } + @ConfigField(field = "metaStorage.plugin.enabled") + private boolean eventMeshServerMetaStorageEnable = false; - private String get(String key, Supplier defaultValueSupplier) { - String value = configurationWrapper.getProp(key); - if (value != null) { - value = StringUtils.deleteWhitespace(value); - } - return StringUtils.isEmpty(value) ? defaultValueSupplier.get() : value; - } + @ConfigField(field = "trace.plugin", notEmpty = true) + private String eventMeshTracePluginType; - static class ConfKeys { - public static final String KEYS_EVENTMESH_ENV = "eventMesh.server.env"; + @ConfigField(field = "metrics.plugin", notEmpty = true) + private List eventMeshMetricsPluginType; - public static final String KEYS_EVENTMESH_IDC = "eventMesh.server.idc"; + @ConfigField(field = "security.plugin.type", notEmpty = true) + private String eventMeshSecurityPluginType = "security"; - public static final String KEYS_EVENTMESH_SYSID = "eventMesh.sysid"; + @ConfigField(field = "storage.plugin.type", notEmpty = true) + private String eventMeshStoragePluginType = "standalone"; - public static final String KEYS_EVENTMESH_SERVER_CLUSTER = "eventMesh.server.cluster"; + @ConfigField(field = "security.validation.type.token", notEmpty = true) + private boolean eventMeshSecurityValidateTypeToken = false; - public static final String KEYS_EVENTMESH_SERVER_NAME = "eventMesh.server.name"; + @ConfigField(field = "server.trace.enabled") + private boolean eventMeshServerTraceEnable = false; - public static final String KEYS_EVENTMESH_SERVER_HOST_IP = "eventMesh.server.hostIp"; + @ConfigField(field = "server.security.enabled") + private boolean eventMeshServerSecurityEnable = false; - public static final String KEYS_EVENTMESH_SERVER_REGISTER_INTERVAL = - "eventMesh.server.registry.registerIntervalInMills"; + @ConfigField(field = "security.publickey") + private String eventMeshSecurityPublickey = ""; - public static final String KEYS_EVENTMESH_SERVER_FETCH_REGISTRY_ADDR_INTERVAL = - "eventMesh.server.registry.fetchRegistryAddrIntervalInMills"; + @ConfigField(field = "server.provide.protocols", reload = true) + private List eventMeshProvideServerProtocols; - public static final String KEYS_ENENTMESH_CONNECTOR_PLUGIN_TYPE = "eventMesh.connector.plugin.type"; + @ConfigField(reload = true) + private String meshGroup; - public static final String KEYS_EVENTMESH_SECURITY_ENABLED = "eventMesh.server.security.enabled"; + @ConfigField(field = "server.retry.plugin.type") + private String eventMeshRetryPluginType = Constants.DEFAULT; - public static final String KEYS_ENENTMESH_SECURITY_PLUGIN_TYPE = "eventMesh.security.plugin.type"; + @ConfigField(field = "registry.plugin.server-addr", notEmpty = true) + private String registryAddr = ""; - public static final String KEYS_EVENTMESH_REGISTRY_ENABLED = "eventMesh.registry.plugin.enabled"; + @ConfigField(field = "registry.plugin.type", notEmpty = true) + private String eventMeshRegistryPluginType = "nacos"; - public static final String KEYS_ENENTMESH_REGISTRY_PLUGIN_TYPE = "eventMesh.registry.plugin.type"; + @ConfigField(field = "registry.plugin.username") + private String eventMeshRegistryPluginUsername = ""; - public static final String KEYS_EVENTMESH_REGISTRY_PULGIN_SERVER_ADDR = "eventMesh.registry.plugin.server-addr"; + @ConfigField(field = "registry.plugin.password") + private String eventMeshRegistryPluginPassword = ""; - public static final String KEYS_EVENTMESH_REGISTRY_PULGIN_USERNAME = "eventMesh.registry.plugin.username"; + @ConfigField(field = "registry.plugin.enabled") + private boolean eventMeshRegistryPluginEnabled = false; - public static final String KEYS_EVENTMESH_REGISTRY_PULGIN_PASSWORD = "eventMesh.registry.plugin.password"; + public void reload() { - public static final String KEYS_EVENTMESH_METRICS_PLUGIN_TYPE = "eventMesh.metrics.plugin"; + if (Strings.isNullOrEmpty(this.eventMeshServerIp)) { + this.eventMeshServerIp = IPUtils.getLocalAddress(); + } - public static final String KEYS_EVENTMESH_TRACE_ENABLED = "eventMesh.server.trace.enabled"; + if (CollectionUtils.isEmpty(eventMeshProvideServerProtocols)) { + this.eventMeshProvideServerProtocols = Collections.singletonList(HTTP); + } - public static final String KEYS_EVENTMESH_TRACE_PLUGIN_TYPE = "eventMesh.trace.plugin"; + meshGroup = String.join("-", this.eventMeshEnv, this.eventMeshIDC, this.eventMeshCluster, this.sysID); } -} \ No newline at end of file +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/Config.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/Config.java new file mode 100644 index 0000000000..6c6d726525 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/Config.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Record information about the configuration class to be converted + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +@Repeatable(Config.Configs.class) +public @interface Config { + + String field() default ""; + + String path() default ""; + + String prefix() default ""; + + String hump() default "."; + + boolean removePrefix() default true; + + boolean monitor() default false; + + String reloadMethodName() default "reload"; + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @interface Configs { + + Config[] value(); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigField.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigField.java new file mode 100644 index 0000000000..aecdf23003 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigField.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import org.apache.eventmesh.common.config.convert.ConvertValue.DefaultConverter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Record information about the field in the configuration class to be converted + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD}) +public @interface ConfigField { + + /** + * @return The key name of the configuration file + */ + String field() default ""; + + /** + * Note : When reload is true, the class must have a reload method + * + * @return Whether to reload. This parameter is used when other fields are associated + */ + boolean reload() default false; + + /** + * In some special cases, used to specify the converter class of the field + * + * @return field converter + */ + Class converter() default DefaultConverter.class; + + /** + * if the configuration filed is empty, try to read from env, by field + * + * @return Whether to try to read from env if the configuration filed is empty + */ + boolean findEnv() default false; + + /** + * If it cannot be null but is null, an exception is thrown + * + * @return Whether the field can be null + */ + boolean notNull() default false; + + /** + * If it cannot be empty but is empty, an exception is thrown + * + * @return Whether the field can be empty + */ + boolean notEmpty() default false; + + /** + * If it's not a number, an exception is thrown + * + * @return Whether the field must be number + */ + boolean beNumber() default false; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigInfo.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigInfo.java new file mode 100644 index 0000000000..a180f0f6ba --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigInfo.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import java.lang.reflect.Field; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ConfigInfo { + + public static final String HUMP_SPOT = "spot"; + public static final String HUMP_ROD = "rod"; + + private String path; + private String field; + private String prefix; + private String hump; + private boolean monitor; + private boolean removePrefix; + + private Class clazz; + private Object object; + private String filePath; + + private String reloadMethodName; + + Field objectField; + Object instance; + + private String resourceUrl; +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigMonitorService.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigMonitorService.java new file mode 100644 index 0000000000..5c4000b60c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigMonitorService.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import org.apache.eventmesh.common.ThreadPoolFactory; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ConfigMonitorService { + + private static final long TIME_INTERVAL = 30 * 1000L; + + private final List configInfoList = new ArrayList<>(); + + private final ScheduledExecutorService configLoader = ThreadPoolFactory.createSingleScheduledExecutor("eventMesh-configLoader"); + + { + configLoader.scheduleAtFixedRate(this::load, TIME_INTERVAL, TIME_INTERVAL, TimeUnit.MILLISECONDS); + } + + public void monitor(ConfigInfo configInfo) { + configInfoList.add(configInfo); + } + + public void load() { + for (ConfigInfo configInfo : configInfoList) { + try { + Object object = ConfigService.getInstance().getConfig(configInfo); + if (configInfo.getObject().equals(object)) { + continue; + } + + Field field = configInfo.getObjectField(); + boolean isAccessible = field.isAccessible(); + try { + field.setAccessible(true); + field.set(configInfo.getInstance(), object); + } finally { + field.setAccessible(isAccessible); + } + + configInfo.setObject(object); + log.info("config reload success: {}", object); + } catch (Exception e) { + log.error("config reload failed", e); + } + } + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigService.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigService.java new file mode 100644 index 0000000000..3f3f609a1f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigService.java @@ -0,0 +1,205 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import static org.apache.eventmesh.common.utils.ReflectUtils.lookUpFieldByParentClass; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.net.URL; +import java.util.Objects; +import java.util.Properties; + +import org.assertj.core.util.Strings; + +import lombok.Getter; + +public class ConfigService { + + private static final ConfigService INSTANCE = new ConfigService(); + + public static final String CLASS_PATH_PREFIX = "classPath://"; + public static final String FILE_PATH_PREFIX = "file://"; + + /** + * Unified configuration Properties corresponding to eventmesh.properties + */ + private Properties properties = new Properties(); + + @Getter + private String rootPath; + + private static final ConfigMonitorService configMonitorService = new ConfigMonitorService(); + + private String configPath; + + public static ConfigService getInstance() { + return INSTANCE; + } + + private ConfigService() { + } + + public ConfigService setConfigPath(String configPath) { + if (StringUtils.isNotBlank(configPath) && !configPath.endsWith(File.separator)) { + configPath = configPath + File.separator; + } + this.configPath = configPath; + return this; + } + + public void setRootConfig(String path) throws Exception { + ConfigInfo configInfo = new ConfigInfo(); + rootPath = path; + configInfo.setPath(rootPath); + properties = this.getConfig(configInfo); + } + + public Properties getRootConfig() { + return this.properties; + } + + public T buildConfigInstance(Class clazz) { + + Config[] configArray = clazz.getAnnotationsByType(Config.class); + Config config = configArray.length == 0 ? null : configArray[0]; + ConfigInfo configInfo = new ConfigInfo(); + configInfo.setClazz(clazz); + configInfo.setPath(config == null ? null : config.path()); + configInfo.setHump(config == null ? ConfigInfo.HUMP_SPOT : config.hump()); + configInfo.setPrefix(config == null ? null : config.prefix()); + configInfo.setMonitor(config != null && config.monitor()); + configInfo.setReloadMethodName(config == null ? null : config.reloadMethodName()); + + try { + return this.getConfig(configInfo); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void populateConfigForObject(Object object) throws IllegalAccessException, NoSuchFieldException, IOException { + Class clazz = object.getClass(); + Config[] configArray = clazz.getAnnotationsByType(Config.class); + if (configArray.length == 0) { + return; + } + + for (Config config : configArray) { + populateConfig(object, clazz, config); + } + } + + @SuppressWarnings("unchecked") + public T getConfig(ConfigInfo configInfo) throws IOException { + Object object; + + String path = configInfo.getPath(); + if (StringUtils.isBlank(path)) { + object = FileLoad.getPropertiesFileLoad().getConfig(properties, configInfo); + return (T) object; + } + + String filePath; + String resourceUrl = null; + if (path.startsWith(CLASS_PATH_PREFIX)) { + resourceUrl = "/" + path.substring(CLASS_PATH_PREFIX.length()); + URL fileURL = getClass().getResource(resourceUrl); + if (fileURL == null) { + throw new RuntimeException("file is not exists"); + } + filePath = fileURL.getPath(); + } else { + filePath = path.startsWith(FILE_PATH_PREFIX) ? path.substring(FILE_PATH_PREFIX.length()) : this.configPath + path; + } + filePath = normalizeFilePath(filePath); + if (filePath.contains(".jar")) { + try (final InputStream inputStream = getClass().getResourceAsStream(Objects.requireNonNull(resourceUrl))) { + if (inputStream == null) { + throw new RuntimeException("file is not exists"); + } + } + } else { + File file = new File(filePath); + if (!file.exists()) { + throw new RuntimeException("file is not exists"); + } + } + + String suffix = path.substring(path.lastIndexOf('.') + 1); + configInfo.setFilePath(filePath); + configInfo.setResourceUrl(resourceUrl); + object = FileLoad.getFileLoad(suffix).getConfig(configInfo); + return (T) object; + } + + private String normalizeFilePath(String filePath) { + if (System.getProperty("os.name").toLowerCase().contains("win")) { + if (filePath.startsWith("/")) { + filePath = filePath.substring(1); + } + } + return filePath; + } + + private void populateConfig(Object object, Class clazz, Config config) + throws NoSuchFieldException, IOException, IllegalAccessException { + ConfigInfo configInfo = new ConfigInfo(); + configInfo.setField(config.field()); + configInfo.setMonitor(config.monitor()); + configInfo.setReloadMethodName(config.reloadMethodName()); + + Field field = null; + try { + field = clazz.getDeclaredField(configInfo.getField()); + } catch (NoSuchFieldException e) { + field = lookUpFieldByParentClass(clazz, configInfo.getField()); + if (field == null) { + throw e; + } + } + configInfo.setClazz(field.getType()); + + Config configType = field.getType().getAnnotation(Config.class); + if (configType != null && !Strings.isNullOrEmpty(configType.prefix())) { + configInfo.setPrefix(configType.prefix()); + configInfo.setPath(configType.path()); + configInfo.setHump(configType.hump()); + } + + Object configObject = this.getConfig(configInfo); + + try { + field.setAccessible(true); + field.set(object, configObject); + } finally { + field.setAccessible(false); + } + if (configInfo.isMonitor()) { + configInfo.setObjectField(field); + configInfo.setInstance(object); + configInfo.setObject(configObject); + configMonitorService.monitor(configInfo); + } + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigurationWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigurationWrapper.java deleted file mode 100644 index b24426c92b..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/ConfigurationWrapper.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.config; - -import org.apache.eventmesh.common.file.FileChangeContext; -import org.apache.eventmesh.common.file.FileChangeListener; -import org.apache.eventmesh.common.file.WatchFileManager; - -import org.apache.commons.lang3.StringUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.Map.Entry; -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Preconditions; - -public class ConfigurationWrapper { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final String directoryPath; - - private final String fileName; - - private final Properties properties = new Properties(); - - private final String file; - - private final boolean reload; - - private final FileChangeListener fileChangeListener = new FileChangeListener() { - @Override - public void onChanged(FileChangeContext changeContext) { - load(); - } - - @Override - public boolean support(FileChangeContext changeContext) { - return changeContext.getWatchEvent().context().toString().contains(fileName); - } - }; - - public ConfigurationWrapper(String directoryPath, String fileName, boolean reload) { - this.directoryPath = directoryPath - .replace('/', File.separator.charAt(0)) - .replace('\\', File.separator.charAt(0)); - this.fileName = fileName; - this.file = (directoryPath + File.separator + fileName) - .replace('/', File.separator.charAt(0)) - .replace('\\', File.separator.charAt(0)); - this.reload = reload; - init(); - } - - private void init() { - load(); - if (this.reload) { - WatchFileManager.registerFileChangeListener(directoryPath, fileChangeListener); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - logger.info("Configuration reload task closed"); - WatchFileManager.deregisterFileChangeListener(directoryPath); - })); - } - } - - private void load() { - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - logger.info("loading config: {}", file); - properties.load(reader); - } catch (IOException e) { - logger.error("loading properties [{}] error", file, e); - } - } - - public String getProp(String key) { - return StringUtils.isEmpty(key) ? null : properties.getProperty(key, null); - } - - public int getIntProp(String configKey, int defaultValue) { - String configValue = StringUtils.deleteWhitespace(getProp(configKey)); - if (StringUtils.isEmpty(configValue)) { - return defaultValue; - } - Preconditions.checkState(StringUtils.isNumeric(configValue), - String.format("key:%s, value:%s error", configKey, configValue)); - return Integer.parseInt(configValue); - } - - public boolean getBoolProp(String configKey, boolean defaultValue) { - String configValue = StringUtils.deleteWhitespace(getProp(configKey)); - if (StringUtils.isEmpty(configValue)) { - return defaultValue; - } - return Boolean.parseBoolean(configValue); - } - - private String removePrefix(String key, String prefix, boolean removePrefix) { - return removePrefix ? key.replace(prefix, "") : key; - } - - public Properties getPropertiesByConfig(String prefix, boolean removePrefix) { - Properties properties = new Properties(); - prefix = prefix.endsWith(".") ? prefix : prefix + "."; - for (Entry entry : this.properties.entrySet()) { - String key = (String) entry.getKey(); - if (key.startsWith(prefix)) { - properties.put(removePrefix(key, prefix, removePrefix), entry.getValue()); - } - } - return properties; - } - - @SuppressWarnings("unchecked") - public T getPropertiesByConfig(String prefix, Class clazz, boolean removePrefix) { - ObjectMapper objectMapper = new ObjectMapper(); - return (T) objectMapper.convertValue(getPropertiesByConfig(prefix, removePrefix), clazz); - } - -} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/FileLoad.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/FileLoad.java new file mode 100644 index 0000000000..4f8c6687b8 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/FileLoad.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.convert.Convert; + +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.Properties; + +import org.yaml.snakeyaml.Yaml; + +/** + * load config from file + */ +public interface FileLoad { + + PropertiesFileLoad PROPERTIES_FILE_LOAD = new PropertiesFileLoad(); + + YamlFileLoad YAML_FILE_LOAD = new YamlFileLoad(); + + static FileLoad getFileLoad(String fileType) { + if (StringUtils.equals("properties", fileType)) { + return PROPERTIES_FILE_LOAD; + } else if (StringUtils.equals("yaml", fileType)) { + return YAML_FILE_LOAD; + } + return PROPERTIES_FILE_LOAD; + } + + static PropertiesFileLoad getPropertiesFileLoad() { + return PROPERTIES_FILE_LOAD; + } + + static YamlFileLoad getYamlFileLoad() { + return YAML_FILE_LOAD; + } + + T getConfig(ConfigInfo configInfo) throws IOException; + + class PropertiesFileLoad implements FileLoad { + + private final Convert convert = new Convert(); + + @SuppressWarnings("unchecked") + @Override + public T getConfig(ConfigInfo configInfo) throws IOException { + final Properties properties = new Properties(); + if (StringUtils.isNotBlank(configInfo.getResourceUrl())) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + Objects.requireNonNull(getClass().getResourceAsStream(configInfo.getResourceUrl())), Constants.DEFAULT_CHARSET))) { + properties.load(reader); + } + } else { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(Files.newInputStream(Paths.get(configInfo.getFilePath())), Constants.DEFAULT_CHARSET))) { + properties.load(reader); + } + } + + if (Objects.isNull(configInfo.getClazz())) { + return (T) properties; + } + + return (T) convert.doConvert(configInfo, properties); + } + + @SuppressWarnings("unchecked") + public T getConfig(Properties properties, ConfigInfo configInfo) { + return (T) convert.doConvert(configInfo, properties); + } + } + + class YamlFileLoad implements FileLoad { + + @SuppressWarnings("unchecked") + @Override + public T getConfig(ConfigInfo configInfo) throws IOException { + Yaml yaml = new Yaml(); + try (InputStream input = Files.newInputStream(Paths.get(configInfo.getFilePath())); + Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8)) { + return (T) yaml.loadAs(reader, configInfo.getClazz()); + } + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/Config.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/Config.java new file mode 100644 index 0000000000..d4bdee7778 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/Config.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector; + +public abstract class Config { +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/Constants.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/Constants.java new file mode 100644 index 0000000000..817efb6d3a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/Constants.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector; + +public class Constants { + + public static final String ENV_TARGET = "connectorTarget"; + + public static final String ENV_PORT = "connectorPort"; + + public static final String ENV_SOURCE_CONFIG_FILE = "sourceConnectorConf"; + + public static final String ENV_SINK_CONFIG_FILE = "sinkConnectorConf"; + + public static final int DEFAULT_ATTEMPT = 3; + + public static final int DEFAULT_PORT = 8080; + + // ======================== Source Constants ======================== + /** + * Default capacity + */ + public static final int DEFAULT_CAPACITY = 1024; + + /** + * Default poll batch size + */ + public static final int DEFAULT_POLL_BATCH_SIZE = 10; + + /** + * Default poll timeout (unit: ms) + */ + public static final long DEFAULT_POLL_TIMEOUT = 5000L; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/PollConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/PollConfig.java new file mode 100644 index 0000000000..cf3f06be91 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/PollConfig.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector; + +import lombok.Data; + +/** + * Source Poll Config + */ +@Data +public class PollConfig { + + /** + * Capacity of the poll queue + */ + private int capacity = Constants.DEFAULT_CAPACITY; + + /** + * Max batch size of the poll + */ + private int maxBatchSize = Constants.DEFAULT_POLL_BATCH_SIZE; + + /** + * Max wait time of the poll + */ + private long maxWaitTime = Constants.DEFAULT_POLL_TIMEOUT; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/PubSubConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/PubSubConfig.java new file mode 100644 index 0000000000..be83d51127 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/PubSubConfig.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector; + +import lombok.Data; + +@Data +public class PubSubConfig { + + private String meshAddress; + + private String subject; + + private String idc; + + private String env; + + private String group; + + private String appId; + + private String userName; + + private String passWord; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/SinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/SinkConfig.java new file mode 100644 index 0000000000..4ef68291d3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/SinkConfig.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public abstract class SinkConfig extends Config { + + private PubSubConfig pubSubConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/SourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/SourceConfig.java new file mode 100644 index 0000000000..f7bc42970c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/SourceConfig.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector; + +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public abstract class SourceConfig extends Config { + + private PubSubConfig pubSubConfig; + + private OffsetStorageConfig offsetStorageConfig; + + // Polling configuration, e.g. capacity, batch size, wait time, etc. + private PollConfig pollConfig = new PollConfig(); + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/dingtalk/DingDingSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/dingtalk/DingDingSinkConfig.java new file mode 100644 index 0000000000..3482d5665c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/dingtalk/DingDingSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.dingtalk; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class DingDingSinkConfig extends SinkConfig { + + private SinkConnectorConfig sinkConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/dingtalk/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/dingtalk/SinkConnectorConfig.java new file mode 100644 index 0000000000..1dfcd76640 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/dingtalk/SinkConnectorConfig.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.dingtalk; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String appKey; + + private String appSecret; + + private String openConversationId; + + private String robotCode; + + private String coolAppCode; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/FileSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/FileSinkConfig.java new file mode 100644 index 0000000000..7de6daa51e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/FileSinkConfig.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.file; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FileSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + + private Integer flushSize = 1000; + + private boolean hourlyFlushEnabled = false; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/FileSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/FileSourceConfig.java new file mode 100644 index 0000000000..06bc4c1745 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/FileSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.file; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FileSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/SinkConnectorConfig.java new file mode 100644 index 0000000000..ee42a17759 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/SinkConnectorConfig.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.file; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String topic; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/SourceConnectorConfig.java new file mode 100644 index 0000000000..786d8fa743 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/file/SourceConnectorConfig.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.file; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String filePath; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpRetryConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpRetryConfig.java new file mode 100644 index 0000000000..319732a875 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpRetryConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.http; + +import lombok.Data; + +@Data +public class HttpRetryConfig { + // maximum number of retries, default 2, minimum 0 + private int maxRetries = 2; + + // retry interval, default 1000ms + private int interval = 1000; + + // Default value is false, indicating that only requests with network-level errors will be retried. + // If set to true, all failed requests will be retried, including network-level errors and non-2xx responses. + private boolean retryOnNonSuccess = false; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpSinkConfig.java new file mode 100644 index 0000000000..3c429f3355 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.http; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HttpSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpSourceConfig.java new file mode 100644 index 0000000000..476dfb10de --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.http; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HttpSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpWebhookConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpWebhookConfig.java new file mode 100644 index 0000000000..96b9e09826 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/HttpWebhookConfig.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.http; + +import lombok.Data; + +@Data +public class HttpWebhookConfig { + + private boolean activate = false; + + // Path to display/export callback data + private String exportPath = "/export"; + + private int port; + + // timeunit: ms + private int serverIdleTimeout = 5000; + + // max size of the storage queue + private int maxStorageSize = 5000; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/SinkConnectorConfig.java new file mode 100644 index 0000000000..65fc8fe72d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/SinkConnectorConfig.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.http; + + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String[] urls; + + // keepAlive, default true + private boolean keepAlive = true; + + // timeunit: ms, default 60000ms + private int keepAliveTimeout = 60 * 1000; // Keep units consistent + + // timeunit: ms, default 5000ms, recommended scope: 5000ms - 10000ms + private int connectionTimeout = 5000; + + // timeunit: ms, default 5000ms + private int idleTimeout = 5000; + + // maximum number of HTTP/1 connections a client will pool, default 50 + private int maxConnectionPoolSize = 50; + + // retry config + private HttpRetryConfig retryConfig = new HttpRetryConfig(); + + // webhook config + private HttpWebhookConfig webhookConfig = new HttpWebhookConfig(); + + private String deliveryStrategy = "ROUND_ROBIN"; + + private boolean skipDeliverException = false; + + // managed pipelining param, default true + private boolean isParallelized = true; + + private int parallelism = 2; + + + /** + * Fill default values if absent (When there are multiple default values for a field) + * + * @param config SinkConnectorConfig + */ + public static void populateFieldsWithDefaults(SinkConnectorConfig config) { + /* + * set default values for idleTimeout + * recommended scope: common(5s - 10s), webhook(15s - 30s) + */ + final int commonHttpIdleTimeout = 5000; + final int webhookHttpIdleTimeout = 15000; + + // Set default values for idleTimeout + if (config.getIdleTimeout() == 0) { + int idleTimeout = config.webhookConfig.isActivate() ? webhookHttpIdleTimeout : commonHttpIdleTimeout; + config.setIdleTimeout(idleTimeout); + } + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/SourceConnectorConfig.java new file mode 100644 index 0000000000..2c091e321a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/http/SourceConnectorConfig.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.http; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String path = "/"; + + private int port; + + // timeunit: ms, default 5000ms + private int idleTimeout = 5000; + + /** + *

    + *
  • The maximum size allowed for form attributes when Content-Type is application/x-www-form-urlencoded or multipart/form-data
  • + *
  • Default is 1MB (1024 * 1024 bytes).
  • + *
  • If you receive a "size exceed allowed maximum capacity" error, you can increase this value.
  • + *
  • Note: This applies only when handling form data submissions.
  • + *
+ */ + private int maxFormAttributeSize = 1024 * 1024; + + // max size of the queue, default 1000 + private int maxStorageSize = 1000; + + // batch size, default 10 + private int batchSize = 10; + + // protocol, default CloudEvent + private String protocol = "Common"; + + // extra config, e.g. GitHub secret + private Map extraConfig = new HashMap<>(); + + // data consistency enabled, default true + private boolean dataConsistencyEnabled = true; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/KnativeSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/KnativeSinkConfig.java new file mode 100644 index 0000000000..aff7c275a5 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/KnativeSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.knative; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class KnativeSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/KnativeSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/KnativeSourceConfig.java new file mode 100644 index 0000000000..644161d915 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/KnativeSourceConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.knative; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class KnativeSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/SinkConnectorConfig.java new file mode 100644 index 0000000000..076bd68756 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/SinkConnectorConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.knative; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + public String emurl; + + public String serviceAddr; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/SourceConnectorConfig.java new file mode 100644 index 0000000000..98e7815520 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/knative/SourceConnectorConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.knative; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + public String emurl; + + public String serviceAddr; + +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/lark/LarkSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/lark/LarkSinkConfig.java new file mode 100644 index 0000000000..a9235129a0 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/lark/LarkSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.lark; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class LarkSinkConfig extends SinkConfig { + + public SinkConnectorConfig sinkConnectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/lark/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/lark/SinkConnectorConfig.java new file mode 100644 index 0000000000..a4895b8b2e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/lark/SinkConnectorConfig.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.lark; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName = "larkSink"; + + /** + * Can not be blank + */ + private String appId; + + /** + * Can not be blank + */ + private String appSecret; + + /** + * The value is {@code open_id/user_id/union_id/email/chat_id}. + * Recommend to use open_id. + */ + private String receiveIdType = "open_id"; + + /** + * Can not be blank.And it needs to correspond to {@code receiveIdType} + */ + private String receiveId; + + /** + * When sinking CouldEvent to lark, choose to call + */ + private String sinkAsync = "true"; + + private String maxRetryTimes = "3"; + + private String retryDelayInMills = "1000"; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpRetryConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpRetryConfig.java new file mode 100644 index 0000000000..44889f9ffa --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpRetryConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mcp; + +import lombok.Data; + +@Data +public class McpRetryConfig { + // maximum number of retries, default 2, minimum 0 + private int maxRetries = 2; + + // retry interval, default 1000ms + private int interval = 1000; + + // Default value is false, indicating that only requests with network-level errors will be retried. + // If set to true, all failed requests will be retried, including network-level errors and non-2xx responses. + private boolean retryOnNonSuccess = false; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpSinkConfig.java new file mode 100644 index 0000000000..ce645513c5 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mcp; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class McpSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpSourceConfig.java new file mode 100644 index 0000000000..320cc3761f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/McpSourceConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mcp; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class McpSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/SinkConnectorConfig.java new file mode 100644 index 0000000000..54a02fb6b5 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/SinkConnectorConfig.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mcp; + + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String[] urls; + + // keepAlive, default true + private boolean keepAlive = true; + + // timeunit: ms, default 60000ms + private int keepAliveTimeout = 60 * 1000; // Keep units consistent + + // timeunit: ms, default 5000ms, recommended scope: 5000ms - 10000ms + private int connectionTimeout = 5000; + + // timeunit: ms, default 5000ms + private int idleTimeout = 5000; + + // maximum number of HTTP/1 connections a client will pool, default 50 + private int maxConnectionPoolSize = 50; + + // retry config + private McpRetryConfig retryConfig = new McpRetryConfig(); + + private String deliveryStrategy = "ROUND_ROBIN"; + + private boolean skipDeliverException = false; + + // managed pipelining param, default true + private boolean isParallelized = true; + + private int parallelism = 2; + + + /** + * Fill default values if absent (When there are multiple default values for a field) + * + * @param config SinkConnectorConfig + */ + public static void populateFieldsWithDefaults(SinkConnectorConfig config) { + /* + * set default values for idleTimeout + * recommended scope: common(5s - 10s), webhook(15s - 30s) + */ + final int commonHttpIdleTimeout = 5000; + + // Set default values for idleTimeout + if (config.getIdleTimeout() == 0) { + config.setIdleTimeout(commonHttpIdleTimeout); + } + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/SourceConnectorConfig.java new file mode 100644 index 0000000000..18808942e0 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mcp/SourceConnectorConfig.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mcp; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String path = "/"; + + private int port; + + // timeunit: ms, default 5000ms + private int idleTimeout = 5000; + + /** + *
    + *
  • The maximum size allowed for form attributes when Content-Type is application/x-www-form-urlencoded or multipart/form-data
  • + *
  • Default is 1MB (1024 * 1024 bytes).
  • + *
  • If you receive a "size exceed allowed maximum capacity" error, you can increase this value.
  • + *
  • Note: This applies only when handling form data submissions.
  • + *
+ */ + private int maxFormAttributeSize = 1024 * 1024; + + // max size of the queue, default 1000 + private int maxStorageSize = 1000; + + // batch size, default 10 + private int batchSize = 10; + + // protocol, default CloudEvent + private String protocol = "Mcp"; + + // extra config, e.g. GitHub secret + private Map extraConfig = new HashMap<>(); + + // data consistency enabled, default true + private boolean dataConsistencyEnabled = false; + + private String forwardPath; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/KafkaSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/KafkaSinkConfig.java new file mode 100644 index 0000000000..973eed11ff --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/KafkaSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.kafka; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class KafkaSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/KafkaSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/KafkaSourceConfig.java new file mode 100644 index 0000000000..bf44a82710 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/KafkaSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.kafka; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class KafkaSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/SinkConnectorConfig.java new file mode 100644 index 0000000000..e7584319cb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/SinkConnectorConfig.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.kafka; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName = "kafkaSink"; + private String topic = "TopicTest"; + private String ack = "all"; + private String bootstrapServers = "127.0.0.1:9092"; + private String keyConverter = "org.apache.kafka.common.serialization.StringSerializer"; + private String valueConverter = "org.apache.kafka.common.serialization.StringSerializer"; + private String maxRequestSize = "1048576"; + private String bufferMemory = "33554432"; + private String batchSize = "16384"; + private String lingerMs = "0"; + private String requestTimeoutMs = "30000"; + private String maxInFightRequestsPerConnection = "5"; + private String retries = "0"; + private String compressionType = "none"; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/SourceConnectorConfig.java new file mode 100644 index 0000000000..eb7406f664 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/kafka/SourceConnectorConfig.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.kafka; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName = "kafkaSource"; + private String topic = "TopicTest"; + private String bootstrapServers = "127.0.0.1:9092"; + private String groupID = "kafkaSource"; + private String keyConverter = "org.apache.kafka.common.serialization.StringDeserializer"; + private String valueConverter = "org.apache.kafka.common.serialization.StringDeserializer"; + private String autoCommitIntervalMS = "1000"; + private String enableAutoCommit = "false"; + private String sessionTimeoutMS = "10000"; + private String maxPollRecords = "1000"; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/PulsarSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/PulsarSinkConfig.java new file mode 100644 index 0000000000..8cbfd5fb2c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/PulsarSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.pulsar; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PulsarSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/PulsarSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/PulsarSourceConfig.java new file mode 100644 index 0000000000..43eb2ca854 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/PulsarSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.pulsar; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PulsarSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/SinkConnectorConfig.java new file mode 100644 index 0000000000..b66f1a5324 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/SinkConnectorConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.pulsar; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String serviceUrl; + + private String topic; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/SourceConnectorConfig.java new file mode 100644 index 0000000000..9f8fbce2d2 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/pulsar/SourceConnectorConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.pulsar; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String serviceUrl; + + private String topic; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/RabbitMQSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/RabbitMQSinkConfig.java new file mode 100644 index 0000000000..8dcb8ad50c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/RabbitMQSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rabbitmq; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RabbitMQSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/RabbitMQSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/RabbitMQSourceConfig.java new file mode 100644 index 0000000000..c268c1005a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/RabbitMQSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rabbitmq; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RabbitMQSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/SinkConnectorConfig.java new file mode 100644 index 0000000000..a6f633f943 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/SinkConnectorConfig.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rabbitmq; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String host; + + private int port; + + private String username; + + private String passwd; + + private String virtualHost; + + private String exchangeType; + + private String exchangeName; + + private String routingKey; + + private String queueName; + + private boolean autoAck; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/SourceConnectorConfig.java new file mode 100644 index 0000000000..29a041338f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rabbitmq/SourceConnectorConfig.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rabbitmq; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String host; + + private int port; + + private String username; + + private String passwd; + + private String virtualHost; + + private String exchangeType; + + private String exchangeName; + + private String routingKey; + + private String queueName; + + private boolean autoAck; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/RocketMQSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/RocketMQSinkConfig.java new file mode 100644 index 0000000000..d7c08e8b79 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/RocketMQSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rocketmq; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RocketMQSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/RocketMQSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/RocketMQSourceConfig.java new file mode 100644 index 0000000000..5c531d91c7 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/RocketMQSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rocketmq; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RocketMQSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/SinkConnectorConfig.java new file mode 100644 index 0000000000..93472f7a4c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/SinkConnectorConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rocketmq; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String nameServer; + + private String topic; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/SourceConnectorConfig.java new file mode 100644 index 0000000000..641d1873bb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/mq/rocketmq/SourceConnectorConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.mq.rocketmq; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String nameserver; + + private String topic; + + private long commitOffsetIntervalMs = 5 * 1000; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/offset/OffsetStorageConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/offset/OffsetStorageConfig.java new file mode 100644 index 0000000000..60448d3691 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/offset/OffsetStorageConfig.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.offset; + +import org.apache.eventmesh.common.remote.datasource.DataSourceType; + +import java.util.Map; + +import lombok.Data; + +@Data +public class OffsetStorageConfig { + + private String offsetStorageType; + + private String offsetStorageAddr; + + private Map extensions; + + private DataSourceType dataSourceType; + + private DataSourceType dataSinkType; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/OpenFunctionSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/OpenFunctionSinkConfig.java new file mode 100644 index 0000000000..151ff68834 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/OpenFunctionSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.openfunction; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class OpenFunctionSinkConfig extends SinkConfig { + + public SinkConnectorConfig sinkConnectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/OpenFunctionSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/OpenFunctionSourceConfig.java new file mode 100644 index 0000000000..e3a6123ed9 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/OpenFunctionSourceConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.openfunction; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class OpenFunctionSourceConfig extends SourceConfig { + + public SourceConnectorConfig sourceConnectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/SinkConnectorConfig.java new file mode 100644 index 0000000000..b8bc937390 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/SinkConnectorConfig.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.openfunction; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String target; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/SourceConnectorConfig.java new file mode 100644 index 0000000000..09dbdea14c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/openfunction/SourceConnectorConfig.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.openfunction; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/PravegaSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/PravegaSinkConfig.java new file mode 100644 index 0000000000..a94766c20c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/PravegaSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.pravega; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PravegaSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/PravegaSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/PravegaSourceConfig.java new file mode 100644 index 0000000000..105d3474ee --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/PravegaSourceConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.pravega; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PravegaSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/SinkConnectorConfig.java new file mode 100644 index 0000000000..7f56ea57a8 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/SinkConnectorConfig.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.pravega; + +import java.net.URI; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private URI controllerURI; + + private String scope; + + private int clientPoolSize; + + private int queueSize; + + private boolean authEnabled; + + private String username; + + private String password; + + private boolean tlsEnable; + + private String truststore; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/SourceConnectorConfig.java new file mode 100644 index 0000000000..da0f8c5f13 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/pravega/SourceConnectorConfig.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.pravega; + +import java.net.URI; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private URI controllerURI; + + private String scope; + + private int clientPoolSize; + + private int queueSize; + + private boolean authEnabled; + + private String username; + + private String password; + + private boolean tlsEnable; + + private String truststore; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/prometheus/PrometheusSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/prometheus/PrometheusSourceConfig.java new file mode 100644 index 0000000000..3393e4a193 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/prometheus/PrometheusSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.prometheus; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PrometheusSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/prometheus/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/prometheus/SourceConnectorConfig.java new file mode 100644 index 0000000000..1df3fe18cb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/prometheus/SourceConnectorConfig.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.prometheus; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String connectorId; + + private String address; + + private String api; + + private Long initTime; + + private String query; + + private Integer interval; + + private String step; +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/JdbcConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/JdbcConfig.java new file mode 100644 index 0000000000..fc784fc187 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/JdbcConfig.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb; + +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; + +import java.util.Set; + +import lombok.Data; + +@Data +public class JdbcConfig { + private String url; + + private String dbAddress; + + private int dbPort; + + private String userName; + + private String passWord; + + private Set databases; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalMySQLType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalMySQLType.java new file mode 100644 index 0000000000..b5107ccbf3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalMySQLType.java @@ -0,0 +1,191 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import java.util.HashMap; +import java.util.Map; + +import com.mysql.cj.MysqlType; + +public enum CanalMySQLType { + BIT("BIT"), + TINYINT("TINYINT"), + SMALLINT("SMALLINT"), + MEDIUMINT("MEDIUMINT"), + INT("INT"), + BIGINT("BIGINT"), + DECIMAL("DECIMAL"), + FLOAT("FLOAT"), + DOUBLE("DOUBLE"), + DATE("DATE"), + DATETIME("DATETIME"), + TIMESTAMP("TIMESTAMP"), + TIME("TIME"), + YEAR("YEAR"), + CHAR("CHAR"), + VARCHAR("VARCHAR"), + BINARY("BINARY"), + VARBINARY("VARBINARY"), + TINYBLOB("TINYBLOB"), + BLOB("BLOB"), + MEDIUMBLOB("MEDIUMBLOB"), + LONGBLOB("LONGBLOB"), + TINYTEXT("TINYTEXT"), + TEXT("TEXT"), + MEDIUMTEXT("MEDIUMTEXT"), + LONGTEXT("LONGTEXT"), + ENUM("ENUM"), + SET("SET"), + JSON("JSON"), + GEOMETRY("GEOMETRY"), + // MysqlType not include the following type + POINT("POINT"), + LINESTRING("LINESTRING"), + POLYGON("POLYGON"), + MULTIPOINT("MULTIPOINT"), + GEOMETRY_COLLECTION("GEOMETRYCOLLECTION"), + GEOM_COLLECTION("GEOMCOLLECTION"), + MULTILINESTRING("MULTILINESTRING"), + MULTIPOLYGON("MULTIPOLYGON"); + + private final String codeKey; + private final MysqlType mysqlType; + + CanalMySQLType(String codeKey) { + this.codeKey = codeKey; + this.mysqlType = MysqlType.getByName(codeKey); + } + + private static final Map TYPES = new HashMap<>(); + + static { + CanalMySQLType[] values = values(); + for (CanalMySQLType tableType : values) { + TYPES.put(tableType.codeKey, tableType); + } + } + + public String genPrepareStatement4Insert() { + switch (this) { + case GEOMETRY: + case GEOM_COLLECTION: + case GEOMETRY_COLLECTION: + return "ST_GEOMFROMTEXT(?)"; + case POINT: + return "ST_PointFromText(?)"; + case LINESTRING: + return "ST_LineStringFromText(?)"; + case POLYGON: + return "ST_PolygonFromText(?)"; + case MULTIPOINT: + return "ST_MultiPointFromText(?)"; + case MULTILINESTRING: + return "ST_MultiLineStringFromText(?)"; + case MULTIPOLYGON: + return "ST_MultiPolygonFromText(?)"; + default: + return "?"; + } + } + + public static CanalMySQLType valueOfCode(String code) { + CanalMySQLType type = TYPES.get(code.toUpperCase()); + if (type != null) { + return type; + } + switch (MysqlType.getByName(code)) { + case BOOLEAN: + case TINYINT: + case TINYINT_UNSIGNED: + return TINYINT; + case SMALLINT: + case SMALLINT_UNSIGNED: + return SMALLINT; + case INT: + case INT_UNSIGNED: + return INT; + case BIGINT: + case BIGINT_UNSIGNED: + return BIGINT; + case MEDIUMINT: + case MEDIUMINT_UNSIGNED: + return MEDIUMINT; + case DECIMAL: + case DECIMAL_UNSIGNED: + return DECIMAL; + case FLOAT: + case FLOAT_UNSIGNED: + return FLOAT; + case DOUBLE: + case DOUBLE_UNSIGNED: + return DOUBLE; + case BIT: + return BIT; + case BINARY: + return BINARY; + case VARBINARY: + return VARBINARY; + case TINYBLOB: + return TINYBLOB; + case MEDIUMBLOB: + return MEDIUMBLOB; + case LONGBLOB: + return LONGBLOB; + case BLOB: + return BLOB; + case CHAR: + return CHAR; + case VARCHAR: + return VARCHAR; + case TINYTEXT: + return TINYTEXT; + case MEDIUMTEXT: + return MEDIUMTEXT; + case LONGTEXT: + return LONGTEXT; + case TEXT: + return TEXT; + case DATE: + return DATE; + case TIME: + return TIME; + case TIMESTAMP: + return TIMESTAMP; + case DATETIME: + return DATETIME; + case YEAR: + return YEAR; + case JSON: + return JSON; + case ENUM: + return ENUM; + case SET: + return SET; + case GEOMETRY: + return GEOMETRY; + case NULL: + case UNKNOWN: + default: + throw new UnsupportedOperationException("Unsupported mysql columnType " + code); + } + } + + public MysqlType getMysqlType() { + return mysqlType; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkConfig.java new file mode 100644 index 0000000000..c535c7f52a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkConfig.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import java.util.Map; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSinkConfig extends SinkConfig { + + // used to convert canal full/increment/check connector config + private Map sinkConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkFullConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkFullConfig.java new file mode 100644 index 0000000000..dca16b100c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkFullConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSinkFullConfig extends SinkConfig { + private SinkConnectorConfig sinkConnectorConfig; + private String zeroDate; + private int parallel = 2; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkIncrementConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkIncrementConfig.java new file mode 100644 index 0000000000..aeb9d5a0e2 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSinkIncrementConfig.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.remote.job.SyncMode; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSinkIncrementConfig extends CanalSinkConfig { + + // batchSize + private Integer batchSize = 50; + + // enable batch + private Boolean useBatch = true; + + // sink thread size for single channel + private Integer poolSize = 5; + + // sync mode: field/row + private SyncMode syncMode = SyncMode.ROW; + + private boolean isGTIDMode = false; + + private boolean isMariaDB = true; + + // skip sink process exception + private Boolean skipException = false; + + public SinkConnectorConfig sinkConnectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceCheckConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceCheckConfig.java new file mode 100644 index 0000000000..f326301d7d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceCheckConfig.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSourceCheckConfig extends SourceConfig { + private SourceConnectorConfig sourceConnectorConfig; + private List startPosition; + private int parallel; + private int flushSize; + private int executePeriod = 3600; + private Integer pagePerSecond = 1; + private Integer recordPerSecond = 100; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceConfig.java new file mode 100644 index 0000000000..db17fbe75d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceConfig.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import java.util.Map; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSourceConfig extends SourceConfig { + + // used to convert canal full/increment/check connector config + private Map sourceConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceFullConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceFullConfig.java new file mode 100644 index 0000000000..53988ca055 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceFullConfig.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSourceFullConfig extends SourceConfig { + private SourceConnectorConfig sourceConnectorConfig; + private List startPosition; + private int parallel = 2; + private int flushSize = 20; + private Integer pagePerSecond = 1; + private Integer recordPerSecond = 100; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceIncrementConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceIncrementConfig.java new file mode 100644 index 0000000000..7f73727140 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/CanalSourceIncrementConfig.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.remote.job.SyncConsistency; +import org.apache.eventmesh.common.remote.job.SyncMode; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalSourceIncrementConfig extends CanalSourceConfig { + + private String destination; + + private Long canalInstanceId = 1L; + + private String desc = "canalSourceInstance"; + + private boolean ddlSync = false; + + private boolean filterTableError = false; + + private Long slaveId; + + private Short clientId = 1; + + private String serverUUID; + + private boolean isMariaDB = true; + + private boolean isGTIDMode = true; + + private Integer batchSize = 10000; + + private Long batchTimeout = -1L; + + private String tableFilter; + + private String fieldFilter; + + private List recordPositions; + + // ================================= channel parameter + // ================================ + + // enable remedy + private Boolean enableRemedy = false; + + // sync mode: field/row + private SyncMode syncMode = SyncMode.ROW; + + // sync consistency + private SyncConsistency syncConsistency = SyncConsistency.BASE; + + // ================================= system parameter + // ================================ + + // Column name of the bidirectional synchronization mark + private String needSyncMarkTableColumnName; + + // Column value of the bidirectional synchronization mark + private String needSyncMarkTableColumnValue; + + private SourceConnectorConfig sourceConnectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/JobRdbFullPosition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/JobRdbFullPosition.java new file mode 100644 index 0000000000..42ba889bbd --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/JobRdbFullPosition.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import java.math.BigDecimal; + +import lombok.Data; +import lombok.ToString; + +@Data +@ToString +public class JobRdbFullPosition { + private String jobId; + private String schema; + private String tableName; + private String primaryKeyRecords; + private long maxCount; + private long handledRecordCount = 0; + private boolean finished; + private BigDecimal percent; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbColumnDefinition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbColumnDefinition.java new file mode 100644 index 0000000000..94c0135c3e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbColumnDefinition.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import java.sql.JDBCType; + +import lombok.Data; + +@Data +public class RdbColumnDefinition { + protected String name; + protected JDBCType jdbcType; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbDBDefinition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbDBDefinition.java new file mode 100644 index 0000000000..ab3ed336f8 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbDBDefinition.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import java.util.Set; + +import lombok.Data; + +/** + * Description: as class name + */ +@Data +public class RdbDBDefinition { + private String schemaName; + private Set tables; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbTableDefinition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbTableDefinition.java new file mode 100644 index 0000000000..c281035578 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/RdbTableDefinition.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import lombok.Data; + +/** + * Description: as class name + */ +@Data +public class RdbTableDefinition { + protected String schemaName; + protected String tableName; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/SinkConnectorConfig.java new file mode 100644 index 0000000000..761cdba4bb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/SinkConnectorConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.rdb.JdbcConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Configuration parameters for a sink connector. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SinkConnectorConfig extends JdbcConfig { + private String connectorName; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/SourceConnectorConfig.java new file mode 100644 index 0000000000..9a95696a0d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/SourceConnectorConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal; + +import org.apache.eventmesh.common.config.connector.rdb.JdbcConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Represents the configuration for a database connector. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SourceConnectorConfig extends JdbcConfig { + private String connectorName; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/Constants.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/Constants.java new file mode 100644 index 0000000000..8c51c7255b --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/Constants.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal.mysql; + +public class Constants { + public static final String MySQLQuot = "`"; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/MySQLColumnDef.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/MySQLColumnDef.java new file mode 100644 index 0000000000..cdc9adf33f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/MySQLColumnDef.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalMySQLType; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbColumnDefinition; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class MySQLColumnDef extends RdbColumnDefinition { + private CanalMySQLType type; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/MySQLTableDef.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/MySQLTableDef.java new file mode 100644 index 0000000000..4266a96060 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/canal/mysql/MySQLTableDef.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.canal.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; + +import java.util.List; +import java.util.Map; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Description: + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MySQLTableDef extends RdbTableDefinition { + private List primaryKeys; + private Map columnDefinitions; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcConfig.java new file mode 100644 index 0000000000..1b46a76c99 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcConfig.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.jdbc; + +import java.util.Properties; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents the configuration for a JDBC connection. + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +public class JdbcConfig { + + private String databaseName; + + // The hostname of the database server. + private String hostname; + + // The port number of the database server. + private int port; + + // The username for the database connection. + private String user; + + // The password for the database connection. + private String password; + + private String initialStatements; + + private int connectTimeout; + + // e.g jdbc:mysql://127.0.0.1:3306 + private String url; + + /** + * Converts the JdbcConfig object to a Properties object containing the user and password. + * + * @return The Properties object representing the JdbcConfig. + */ + public Properties asProperties() { + Properties props = new Properties(); + props.put("user", this.user); + props.put("password", this.password); + return props; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcSinkConfig.java new file mode 100644 index 0000000000..83711c68be --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcSinkConfig.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.jdbc; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class JdbcSinkConfig extends SinkConfig { + + private boolean supportUpsert = true; + + private boolean supportDelete = true; + + public SinkConnectorConfig sinkConnectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcSourceConfig.java new file mode 100644 index 0000000000..553a0581a2 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/JdbcSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.jdbc; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class JdbcSourceConfig extends SourceConfig { + + private SourceConnectorConfig sourceConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/MysqlConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/MysqlConfig.java new file mode 100644 index 0000000000..ede507e1be --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/MysqlConfig.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.jdbc; + +import lombok.Data; + +@Data +public class MysqlConfig { + + private int serverId; + + private boolean keepAlive = true; + + private long keepAliveInterval; + + private SnapshotLockingMode snapshotLockingMode = SnapshotLockingMode.MINIMAL; + + private boolean useGlobalLock = true; + + public enum SnapshotLockingMode { + + EXTENDED("extended"), + + MINIMAL("minimal"), + + NONE("none"); + + private final String value; + + SnapshotLockingMode(String value) { + this.value = value; + } + + public boolean usesLocking() { + return !value.equals(NONE.value); + } + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/SinkConnectorConfig.java new file mode 100644 index 0000000000..afbd51d143 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/SinkConnectorConfig.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.jdbc; + +import lombok.Data; + +/** + * Configuration parameters for a sink connector. + */ +@Data +public class SinkConnectorConfig { + + /** + * The name of the sink connector. + */ + private String connectorName; + + /** + * JDBC configuration for connecting to a database. + */ + private JdbcConfig jdbcConfig; + + public String getDatabaseType() { + return "mysql"; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/SourceConnectorConfig.java new file mode 100644 index 0000000000..a10d8e09d0 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/jdbc/SourceConnectorConfig.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.jdbc; + +import java.util.List; + +import lombok.Data; + +/** + * Represents the configuration for a database connector. + */ +@Data +public class SourceConnectorConfig { + + private static final int DEFAULT_SNAPSHOT_FETCH_SIZE = 100; + + /** + * Max task number,The maximum cannot exceed the number of tables scanned. If it exceeds, it will be set to the number of tables. + */ + private int maxTask; + + private int batchMaxRows; + + private boolean skipSnapshot = false; + + // A list of database names to include in the connector. + private List databaseIncludeList; + + // A list of database names to exclude from the connector. + private List databaseExcludeList; + + // A list of table names to include in the connector. + private List tableIncludeList; + + // A list of table names to exclude from the connector. + private List tableExcludeList; + + // database type e.g. mysql + private String databaseType; + + private int snapshotMaxThreads; + + // The snapshot mode also require handling the database schema (database and table schema) + private boolean snapshotSchema = true; + + // The snapshot mode require handling table data + private boolean snapshotData = true; + + private int snapshotFetchSize = DEFAULT_SNAPSHOT_FETCH_SIZE; + + private JdbcConfig jdbcConfig; + + private boolean skipViews = false; + + private boolean skipComments = false; + + // The configuration for the MySQL database. + private MysqlConfig mysqlConfig; + + private String name = "mysql-connector"; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/MongodbSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/MongodbSinkConfig.java new file mode 100644 index 0000000000..7d019ba1ff --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/MongodbSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.mongodb; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class MongodbSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/MongodbSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/MongodbSourceConfig.java new file mode 100644 index 0000000000..00dca10b29 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/MongodbSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.mongodb; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class MongodbSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/SinkConnectorConfig.java new file mode 100644 index 0000000000..58ae5ffc42 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/SinkConnectorConfig.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.mongodb; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String connectorType; + + private String url; + + private String database; + + private String collection; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/SourceConnectorConfig.java new file mode 100644 index 0000000000..8ace602f80 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/rdb/mongodb/SourceConnectorConfig.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.rdb.mongodb; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String connectorType; + + private String url; + + private String database; + + private String collection; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/RedisSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/RedisSinkConfig.java new file mode 100644 index 0000000000..27070343d4 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/RedisSinkConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.redis; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RedisSinkConfig extends SinkConfig { + + public SinkConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/RedisSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/RedisSourceConfig.java new file mode 100644 index 0000000000..5b04e6a820 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/RedisSourceConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.redis; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RedisSourceConfig extends SourceConfig { + + public SourceConnectorConfig connectorConfig; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/SinkConnectorConfig.java new file mode 100644 index 0000000000..ebf53adc3b --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/SinkConnectorConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.redis; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String server; + + private String topic; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/SourceConnectorConfig.java new file mode 100644 index 0000000000..b363924ecb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/redis/SourceConnectorConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.redis; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String server; + + private String topic; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/s3/S3SourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/s3/S3SourceConfig.java new file mode 100644 index 0000000000..7691b6e235 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/s3/S3SourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.s3; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class S3SourceConfig extends SourceConfig { + + private SourceConnectorConfig sourceConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/s3/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/s3/SourceConnectorConfig.java new file mode 100644 index 0000000000..fdc4531255 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/s3/SourceConnectorConfig.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.s3; + +import java.util.Map; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + + private String region; + + private String bucket; + + private String accessKey; + + private String secretKey; + + private String fileName; + + /** + * The schema for the data to be read from S3. + */ + private Map schema; + + /** + * The maximum number of records that should be returned in each batch poll. + */ + private Integer batchSize = 20; + + /** + * The maximum ms to wait for request futures to complete. + */ + private long timeout = 3000; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/slack/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/slack/SinkConnectorConfig.java new file mode 100644 index 0000000000..4267beddff --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/slack/SinkConnectorConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.slack; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String appToken; + + private String channelId; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/slack/SlackSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/slack/SlackSinkConfig.java new file mode 100644 index 0000000000..969306ae6e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/slack/SlackSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.slack; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class SlackSinkConfig extends SinkConfig { + + private SinkConnectorConfig sinkConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SinkConnectorConfig.java new file mode 100644 index 0000000000..0ded9886dc --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SinkConnectorConfig.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.spring; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SourceConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SourceConnectorConfig.java new file mode 100644 index 0000000000..c31f8c9885 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SourceConnectorConfig.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.spring; + +import lombok.Data; + +@Data +public class SourceConnectorConfig { + + private String connectorName; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SpringSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SpringSinkConfig.java new file mode 100644 index 0000000000..14f1f4bbe5 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SpringSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.spring; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class SpringSinkConfig extends SinkConfig { + + private SinkConnectorConfig sinkConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SpringSourceConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SpringSourceConfig.java new file mode 100644 index 0000000000..e99dfc594c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/spring/SpringSourceConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.spring; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class SpringSourceConfig extends SourceConfig { + + private SourceConnectorConfig sourceConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wechat/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wechat/SinkConnectorConfig.java new file mode 100644 index 0000000000..95ca5e64c2 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wechat/SinkConnectorConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.wechat; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String appId; + + private String appSecret; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wechat/WeChatSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wechat/WeChatSinkConfig.java new file mode 100644 index 0000000000..e968202c4c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wechat/WeChatSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.wechat; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class WeChatSinkConfig extends SinkConfig { + + private SinkConnectorConfig sinkConnectorConfig; +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wecom/SinkConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wecom/SinkConnectorConfig.java new file mode 100644 index 0000000000..b32b5b7d36 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wecom/SinkConnectorConfig.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.wecom; + +import lombok.Data; + +@Data +public class SinkConnectorConfig { + + private String connectorName; + + private String robotWebhookKey; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wecom/WeComSinkConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wecom/WeComSinkConfig.java new file mode 100644 index 0000000000..5177baa448 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/connector/wecom/WeComSinkConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.connector.wecom; + +import org.apache.eventmesh.common.config.connector.SinkConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class WeComSinkConfig extends SinkConfig { + + private SinkConnectorConfig sinkConnectorConfig; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/Convert.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/Convert.java new file mode 100644 index 0000000000..84fbdc380e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/Convert.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert; + +import org.apache.eventmesh.common.config.ConfigInfo; + +import java.util.Properties; + +/** + * Used to convert Config properties + */ +public class Convert { + + public Object doConvert(ConfigInfo configInfo, Properties properties) { + Class clazz = configInfo.getClazz(); + ConvertInfo convertInfo = new ConvertInfo(); + convertInfo.setConfigInfo(configInfo); + convertInfo.setProperties(properties); + convertInfo.setClazz(clazz); + + ConvertValue clazzConverter = ConverterMap.getClazzConverter(clazz); + return clazzConverter.convert(convertInfo); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConvertInfo.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConvertInfo.java new file mode 100644 index 0000000000..4f9c3c7b7e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConvertInfo.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert; + +import org.apache.eventmesh.common.config.ConfigInfo; + +import java.lang.reflect.Field; +import java.util.Properties; + +import lombok.Data; + +/** + * Records the information about the field to be converted + */ +@Data +public class ConvertInfo { + + char hump; + String key; + Field field; + Object value; + Class clazz; + Properties properties; + ConfigInfo configInfo; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConvertValue.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConvertValue.java new file mode 100644 index 0000000000..8b1372199e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConvertValue.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert; + +import org.apache.eventmesh.common.config.ConfigField; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; + +/** + * convert convertInfo to obj + * + * @param obj type + */ +public interface ConvertValue { + + T convert(ConvertInfo convertInfo); + + /** + * @return Whether can to process null values + */ + default boolean canHandleNullValue() { + return false; + } + + /** + * @return The value converter needs + */ + default Object processFieldValue(ConvertInfo convertInfo, String key, ConfigField configField) { + Properties properties = convertInfo.getProperties(); + String value = properties.getProperty(key); + + if (Objects.isNull(value)) { + return null; + } + + value = value.trim(); + + boolean findEnv = configField.findEnv(); + String fieldName = configField.field(); + + if (StringUtils.isBlank(value) && !StringUtils.isBlank(fieldName) && findEnv) { + value = Optional.ofNullable(System.getProperty(fieldName)).orElse(System.getenv(fieldName)); + } + + if (StringUtils.isBlank(value) && configField.notEmpty()) { + throw new RuntimeException(key + " can't be empty!"); + } + + return value; + } + + class DefaultConverter implements ConvertValue { + + @Override + public Object convert(ConvertInfo convertInfo) { + return null; + } + } +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConverterMap.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConverterMap.java new file mode 100644 index 0000000000..48d8c83ee8 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/ConverterMap.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert; + +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.common.config.convert.converter.BaseDataTypeConverter; +import org.apache.eventmesh.common.config.convert.converter.DateConverter; +import org.apache.eventmesh.common.config.convert.converter.EnumConverter; +import org.apache.eventmesh.common.config.convert.converter.IPAddressConverter; +import org.apache.eventmesh.common.config.convert.converter.ListConverter; +import org.apache.eventmesh.common.config.convert.converter.LocalDateConverter; +import org.apache.eventmesh.common.config.convert.converter.LocalDateTimeConverter; +import org.apache.eventmesh.common.config.convert.converter.MapConverter; +import org.apache.eventmesh.common.config.convert.converter.ObjectConverter; +import org.apache.eventmesh.common.config.convert.converter.PropertiesConverter; +import org.apache.eventmesh.common.config.convert.converter.StringConverter; +import org.apache.eventmesh.common.config.convert.converter.URIConverter; + +import java.lang.reflect.Field; +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.TreeMap; +import java.util.Vector; + +import lombok.extern.slf4j.Slf4j; + +import inet.ipaddr.IPAddress; + +/** + * Use to map the field clazz and the converter for the field clazz + */ +@Slf4j +public class ConverterMap { + + private static final ObjectConverter objectConverter = new ObjectConverter(); + + private static final Map, ConvertValue> classToConverter = new HashMap<>(); + + static { + register(new URIConverter(), URI.class); + register(new EnumConverter(), Enum.class); + register(new DateConverter(), Date.class); + register(new StringConverter(), String.class); + register(new LocalDateConverter(), LocalDate.class); + register(new IPAddressConverter(), IPAddress.class); + register(new PropertiesConverter(), Properties.class); + register(new LocalDateTimeConverter(), LocalDateTime.class); + register(new ListConverter(), List.class, ArrayList.class, LinkedList.class, Vector.class); + register(new MapConverter(), Map.class, HashMap.class, TreeMap.class, LinkedHashMap.class); + register(new BaseDataTypeConverter.CharacterConverter(), Character.class, char.class); + register(new BaseDataTypeConverter.ByteConverter(), Byte.class, byte.class); + register(new BaseDataTypeConverter.ShortConverter(), Short.class, short.class); + register(new BaseDataTypeConverter.IntegerConverter(), Integer.class, int.class); + register(new BaseDataTypeConverter.LongConverter(), Long.class, long.class); + register(new BaseDataTypeConverter.FloatConverter(), Float.class, float.class); + register(new BaseDataTypeConverter.DoubleConverter(), Double.class, double.class); + register(new BaseDataTypeConverter.BooleanConverter(), Boolean.class, boolean.class); + } + + public static void register(ConvertValue convertValue, Class... clazzs) { + for (Class clazz : clazzs) { + classToConverter.put(clazz, convertValue); + } + } + + /** + * Get the converter for the field + * + * @param field The field to be parsed + * @return the converter for the field + */ + public static ConvertValue getFieldConverter(Field field) { + Class clazz = field.getType(); + ConfigField configField = field.getAnnotation(ConfigField.class); + + Class converter1 = configField.converter(); + if (!converter1.equals(ConvertValue.DefaultConverter.class)) { + if (!classToConverter.containsKey(converter1)) { + try { + ConvertValue convertValue = (ConvertValue) converter1.newInstance(); + register(convertValue, converter1); + } catch (Exception e) { + log.error("The converter failed to register.", e); + } + } + + return classToConverter.get(converter1); + } + + return getClazzConverter(clazz); + } + + /** + * Get the converter for the clazz + * + * @param clazz The clazz to be parsed + * @return the converter for the clazz + */ + public static ConvertValue getClazzConverter(Class clazz) { + ConvertValue converter = classToConverter.get(clazz); + if (Objects.isNull(converter)) { + if (clazz.isEnum()) { + converter = classToConverter.get(Enum.class); + } else { + converter = objectConverter; + } + } + + return converter; + } + + public static Map, ConvertValue> getClassToConverter() { + return classToConverter; + } + + public static ObjectConverter getObjectConverter() { + return objectConverter; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/BaseDataTypeConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/BaseDataTypeConverter.java new file mode 100644 index 0000000000..fac41fea13 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/BaseDataTypeConverter.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import java.util.Objects; + +/** + * Config field conversion class for base data types + */ +public class BaseDataTypeConverter { + + public static class CharacterConverter implements ConvertValue { + + @Override + public Character convert(ConvertInfo convertInfo) { + String value = (String) convertInfo.getValue(); + + return value.charAt(0); + } + } + + public static class BooleanConverter implements ConvertValue { + + @Override + public Boolean convert(ConvertInfo convertInfo) { + String value = (String) convertInfo.getValue(); + if (value.length() == 1) { + return Objects.equals(convertInfo.getValue(), "1") ? Boolean.TRUE : Boolean.FALSE; + } + + return Boolean.valueOf((String) convertInfo.getValue()); + } + } + + public static class ByteConverter implements ConvertValue { + + @Override + public Byte convert(ConvertInfo convertInfo) { + return Byte.valueOf((String) convertInfo.getValue()); + } + } + + public static class ShortConverter implements ConvertValue { + + @Override + public Short convert(ConvertInfo convertInfo) { + return Short.valueOf((String) convertInfo.getValue()); + } + } + + public static class IntegerConverter implements ConvertValue { + + @Override + public Integer convert(ConvertInfo convertInfo) { + return Integer.valueOf((String) convertInfo.getValue()); + } + } + + public static class LongConverter implements ConvertValue { + + @Override + public Long convert(ConvertInfo convertInfo) { + return Long.valueOf((String) convertInfo.getValue()); + } + } + + public static class FloatConverter implements ConvertValue { + + @Override + public Float convert(ConvertInfo convertInfo) { + return Float.valueOf((String) convertInfo.getValue()); + } + } + + public static class DoubleConverter implements ConvertValue { + + @Override + public Double convert(ConvertInfo convertInfo) { + return Double.valueOf((String) convertInfo.getValue()); + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/DateConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/DateConverter.java new file mode 100644 index 0000000000..4a864eb6b2 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/DateConverter.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Config field conversion class for Date + */ +public class DateConverter implements ConvertValue { + + @Override + public Date convert(ConvertInfo convertInfo) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + try { + return sdf.parse((String) convertInfo.getValue()); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/EnumConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/EnumConverter.java new file mode 100644 index 0000000000..513adf101e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/EnumConverter.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +/** + * Config field conversion class for Enum + */ +public class EnumConverter implements ConvertValue> { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Enum convert(ConvertInfo convertInfo) { + Class enumType = (Class) convertInfo.getField().getType(); + String name = (String) convertInfo.getValue(); + + return Enum.valueOf(enumType, name); + } +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/IPAddressConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/IPAddressConverter.java new file mode 100644 index 0000000000..ee3ebae8c5 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/IPAddressConverter.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import inet.ipaddr.AddressStringException; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; + +/** + * Config field conversion class for IPAddress + */ +public class IPAddressConverter implements ConvertValue { + + @Override + public IPAddress convert(ConvertInfo convertInfo) { + try { + return new IPAddressString((String) convertInfo.getValue()).toAddress(); + } catch (AddressStringException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/ListConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/ListConverter.java new file mode 100644 index 0000000000..3d0e92e9c9 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/ListConverter.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; +import org.apache.eventmesh.common.config.convert.ConverterMap; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.google.common.base.Splitter; + +/** + * Config field conversion class for List + */ +public class ListConverter implements ConvertValue> { + + public String separator = ","; + + @Override + public boolean canHandleNullValue() { + return true; + } + + public String getSeparator() { + return separator; + } + + @Override + public List convert(ConvertInfo convertInfo) { + return convert(convertInfo, this.getSeparator()); + } + + @SuppressWarnings("unchecked") + public List convert(ConvertInfo convertInfo, String separator) { + try { + if (convertInfo.getValue() == null) { + return new ArrayList<>(); + } + List list; + if (Objects.equals(convertInfo.getField().getType(), List.class)) { + list = new ArrayList<>(); + } else { + list = (List) convertInfo.getField().getType().newInstance(); + } + + Type parameterizedType = ((ParameterizedType) convertInfo.getField().getGenericType()).getActualTypeArguments()[0]; + + ConvertValue clazzConverter = ConverterMap.getClazzConverter((Class) parameterizedType); + + List values = Splitter.on(separator).omitEmptyStrings().trimResults().splitToList((String) convertInfo.getValue()); + for (String value : values) { + convertInfo.setValue(value); + list.add(clazzConverter.convert(convertInfo)); + } + + return list; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static class ListConverterSemi extends ListConverter { + + public String separator = ";"; + + public String getSeparator() { + return separator; + } + + @Override + public List convert(ConvertInfo convertInfo) { + return super.convert(convertInfo, this.getSeparator()); + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/LocalDateConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/LocalDateConverter.java new file mode 100644 index 0000000000..b8c19ee0ea --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/LocalDateConverter.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Config field conversion class for LocalDate + */ +public class LocalDateConverter implements ConvertValue { + + @Override + public LocalDate convert(ConvertInfo convertInfo) { + String value = (String) convertInfo.getValue(); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + return LocalDate.parse(value, timeFormatter); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/LocalDateTimeConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/LocalDateTimeConverter.java new file mode 100644 index 0000000000..e2423397e6 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/LocalDateTimeConverter.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Config field conversion class for LocalDateTime + */ +public class LocalDateTimeConverter implements ConvertValue { + + @Override + public LocalDateTime convert(ConvertInfo convertInfo) { + String value = (String) convertInfo.getValue(); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + return LocalDateTime.parse(value, timeFormatter); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/MapConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/MapConverter.java new file mode 100644 index 0000000000..0902a758f7 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/MapConverter.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; +import org.apache.eventmesh.common.config.convert.ConverterMap; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Config field conversion class for Map + */ +public class MapConverter implements ConvertValue> { + + @Override + public boolean canHandleNullValue() { + return true; + } + + @SuppressWarnings("unchecked") + @Override + public Map convert(ConvertInfo convertInfo) { + try { + String key = convertInfo.getKey() + convertInfo.getHump(); + Map map; + if (Objects.equals(Map.class, convertInfo.getField().getType())) { + map = new HashMap<>(); + } else { + map = (Map) convertInfo.getField().getType().newInstance(); + } + Type parameterizedType = ((ParameterizedType) convertInfo.getField().getGenericType()).getActualTypeArguments()[1]; + ConvertValue clazzConverter = ConverterMap.getClazzConverter((Class) parameterizedType); + + for (Map.Entry entry : convertInfo.getProperties().entrySet()) { + String propertiesKey = entry.getKey().toString(); + if (propertiesKey.startsWith(key)) { + String value = entry.getValue().toString(); + convertInfo.setValue(value); + map.put(propertiesKey.replace(key, ""), clazzConverter.convert(convertInfo)); + } + } + return map; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/ObjectConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/ObjectConverter.java new file mode 100644 index 0000000000..4f9cdd473b --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/ObjectConverter.java @@ -0,0 +1,218 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.common.config.ConfigInfo; +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; +import org.apache.eventmesh.common.config.convert.ConverterMap; + +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Objects; + +import org.assertj.core.util.Strings; + +/** + * Config field conversion class for Configuration class + */ +public class ObjectConverter implements ConvertValue { + + private String prefix; + + private ConvertInfo convertInfo; + + private Object object; + + private char hump; + + private Class clazz; + + private String reloadMethodName; + + private void init(ConfigInfo configInfo) { + if (configInfo != null) { + String prefix = configInfo.getPrefix(); + if (Objects.nonNull(prefix)) { + this.prefix = prefix.endsWith(".") ? prefix : prefix + "."; + } + this.hump = Objects.equals(configInfo.getHump(), ConfigInfo.HUMP_ROD) ? '_' : '.'; + this.convertInfo.setHump(this.hump); + this.reloadMethodName = configInfo.getReloadMethodName(); + } + this.clazz = convertInfo.getClazz(); + } + + @Override + public Object convert(ConvertInfo convertInfo) { + try { + this.convertInfo = convertInfo; + this.object = convertInfo.getClazz().newInstance(); + this.init(convertInfo.getConfigInfo()); + this.setValue(); + + Class superclass = convertInfo.getClazz(); + for (;;) { + superclass = superclass.getSuperclass(); + if (Objects.equals(superclass, Object.class) || Objects.isNull(superclass)) { + break; + } + + this.clazz = superclass; + this.prefix = null; + Config[] configArray = clazz.getAnnotationsByType(Config.class); + if (configArray.length != 0 && !Strings.isNullOrEmpty(configArray[0].prefix())) { + String prefix = configArray[0].prefix(); + this.prefix = prefix.endsWith(".") ? prefix : prefix + "."; + this.hump = Objects.equals(configArray[0].hump(), ConfigInfo.HUMP_ROD) ? '_' : '.'; + this.convertInfo.setHump(this.hump); + this.reloadMethodName = configArray[0].reloadMethodName(); + } + + this.setValue(); + } + + return object; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void setValue() throws Exception { + boolean needReload = Boolean.FALSE; + + for (Field field : this.clazz.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + + boolean isAccessible = field.isAccessible(); + try { + field.setAccessible(true); + + ConvertInfo convertInfo = this.convertInfo; + ConfigField configField = field.getAnnotation(ConfigField.class); + if (Objects.isNull(configField)) { + continue; + } + + String key = this.buildKey(configField); + needReload = this.checkNeedReload(needReload, configField); + + ConvertValue convertValue = ConverterMap.getFieldConverter(field); + Object fieldValue = convertValue.processFieldValue(convertInfo, key, configField); + + if (!checkFieldValueBefore(configField, key, convertValue, fieldValue)) { + continue; + } + convertInfo.setValue(fieldValue); + convertInfo.setField(field); + convertInfo.setKey(key); + Object convertedValue = convertValue.convert(convertInfo); + + if (!checkFieldValueAfter(configField, key, convertedValue)) { + continue; + } + field.set(object, convertedValue); + } finally { + field.setAccessible(isAccessible); + } + } + + reloadConfigIfNeed(needReload); + } + + private void reloadConfigIfNeed(boolean needReload) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + if (needReload) { + Method method = this.clazz.getDeclaredMethod(this.reloadMethodName == null ? "reload" : this.reloadMethodName); + + boolean isAccessible = method.isAccessible(); + try { + method.setAccessible(true); + method.invoke(this.object); + } finally { + method.setAccessible(isAccessible); + } + } + } + + private boolean checkFieldValueAfter(ConfigField configField, String key, Object convertedValue) { + if (Objects.isNull(convertedValue)) { + if (configField.notNull()) { + throw new RuntimeException(key + " can not be null!"); + } + + return false; + } + + if (configField.beNumber()) { + if (!StringUtils.isNumeric(String.valueOf(convertedValue))) { + throw new RuntimeException(key + " must be number!"); + } + } + + return true; + } + + private boolean checkFieldValueBefore(ConfigField configField, String key, ConvertValue convertValue, Object fieldValue) { + if (Objects.isNull(fieldValue) && !convertValue.canHandleNullValue()) { + if (configField.notNull()) { + throw new RuntimeException(key + " can not be null!"); + } + + return false; + } + + return true; + } + + private boolean checkNeedReload(boolean needReload, ConfigField configField) { + if (!needReload && configField != null && configField.reload()) { + needReload = Boolean.TRUE; + } + + if (needReload) { + try { + this.clazz.getDeclaredMethod(this.reloadMethodName == null ? "reload" : this.reloadMethodName); + } catch (NoSuchMethodException e) { + throw new RuntimeException("The field needs to be reloaded, but the reload method cannot be found.", e); + } + } + + return needReload; + } + + private String buildKey(ConfigField configField) { + String key; + StringBuilder keyPrefix = new StringBuilder(Objects.isNull(prefix) ? "" : prefix); + + if (configField == null || configField.field().isEmpty() && keyPrefix.length() > 0) { + key = keyPrefix.deleteCharAt(keyPrefix.length() - 1).toString(); + } else { + key = keyPrefix.append(configField.field()).toString(); + } + + return key; + } +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/PropertiesConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/PropertiesConverter.java new file mode 100644 index 0000000000..7c58fccdc3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/PropertiesConverter.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; +import org.apache.eventmesh.common.utils.PropertiesUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Properties; + +/** + * Config field conversion class for Properties, by prefix + */ +public class PropertiesConverter implements ConvertValue { + + @Override + public Properties convert(ConvertInfo convertInfo) { + try { + return (Properties) convertInfo.getValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Object processFieldValue(ConvertInfo convertInfo, String prefix, ConfigField configField) { + Properties properties = convertInfo.getProperties(); + + if (StringUtils.isBlank(prefix)) { + return null; + } + + return PropertiesUtils.getPropertiesByPrefix(properties, prefix); + } +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/StringConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/StringConverter.java new file mode 100644 index 0000000000..5397dccce9 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/StringConverter.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import org.apache.commons.lang3.StringUtils; + +/** + * Config field conversion class for String + */ +public class StringConverter implements ConvertValue { + + @Override + public String convert(ConvertInfo convertInfo) { + String value = (String) convertInfo.getValue(); + + return StringUtils.trim(value); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/URIConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/URIConverter.java new file mode 100644 index 0000000000..bbf951c681 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/config/convert/converter/URIConverter.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.convert.ConvertInfo; +import org.apache.eventmesh.common.config.convert.ConvertValue; + +import java.net.URI; + +/** + * Config field conversion class for URI + */ +public class URIConverter implements ConvertValue { + + @Override + public URI convert(ConvertInfo convertInfo) { + return URI.create((String) convertInfo.getValue()); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ComponentType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ComponentType.java new file mode 100644 index 0000000000..a48e3fe013 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ComponentType.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.enums; + +public enum ComponentType { + CONNECTOR("connector"), + FUNCTION("function"), + MESH("mesh"); + + public String name; + + ComponentType(String name) { + this.name = name; + } + + public String componentTypeName() { + return this.name; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ConnectionType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ConnectionType.java new file mode 100644 index 0000000000..ce7e062a54 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ConnectionType.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.enums; + +public enum ConnectionType { + PERSISTENT, + SHORT_LIVED +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ConnectorStage.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ConnectorStage.java new file mode 100644 index 0000000000..90265fba4a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ConnectorStage.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.enums; + +public enum ConnectorStage { + SOURCE, + SINK +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/EventMeshDataContentType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/EventMeshDataContentType.java new file mode 100644 index 0000000000..05341c96b8 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/EventMeshDataContentType.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.enums; + +import lombok.Getter; + +public enum EventMeshDataContentType { + + JSON("application/json"); + + @Getter + private String code; + + EventMeshDataContentType(String code) { + this.code = code; + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/EventMeshProtocolType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/EventMeshProtocolType.java new file mode 100644 index 0000000000..6108f4ce50 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/EventMeshProtocolType.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.enums; + +public enum EventMeshProtocolType { + + CLOUD_EVENTS("cloudevents"), + EVENT_MESH_MESSAGE("eventmeshmessage"), + OPEN_MESSAGE("openmessage"); + + private String name; + + EventMeshProtocolType(String name) { + this.name = name; + } + + public String protocolTypeName() { + return this.name; + } + + public static EventMeshProtocolType eventMeshProtocolType(String name) { + for (EventMeshProtocolType protocolType : EventMeshProtocolType.values()) { + if (protocolType.protocolTypeName().equals(name)) { + return protocolType; + } + } + return null; + } + +} diff --git a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/HttpMethod.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/HttpMethod.java similarity index 95% rename from eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/HttpMethod.java rename to eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/HttpMethod.java index 2fb4ddef3e..75a81b4976 100644 --- a/eventmesh-admin/eventmesh-admin-rocketmq/src/main/java/org/apache/eventmesh/admin/rocketmq/HttpMethod.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/HttpMethod.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.admin.rocketmq; +package org.apache.eventmesh.common.enums; public enum HttpMethod { diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ProtocolType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ProtocolType.java new file mode 100644 index 0000000000..d7ac9aabbb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/enums/ProtocolType.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.enums; + +public enum ProtocolType { + TCP, + HTTP, + GRPC +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/EventMeshException.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/EventMeshException.java index 9dc45c29f9..39728b3f90 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/EventMeshException.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/EventMeshException.java @@ -17,7 +17,9 @@ package org.apache.eventmesh.common.exception; -public class EventMeshException extends Exception { +public class EventMeshException extends RuntimeException { + + private static final long serialVersionUID = 5648256502005456586L; public EventMeshException(String message) { super(message); diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/JsonException.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/JsonException.java index 50f4bfa48c..2c2c055aba 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/JsonException.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/exception/JsonException.java @@ -22,6 +22,8 @@ */ public class JsonException extends RuntimeException { + private static final long serialVersionUID = -7236194555178359309L; + public JsonException(String message) { super(message); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/FileChangeListener.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/FileChangeListener.java index a11efa9e9c..015e500e77 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/FileChangeListener.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/FileChangeListener.java @@ -18,13 +18,14 @@ package org.apache.eventmesh.common.file; /** - * Users can register {@link FileChangeListener} with WatchFileManager via the - * {@link WatchFileManager#registerFileChangeListener(java.lang.String, org.apache.eventmesh.common.file.FileChangeListener)} method. - * The {@link FileChangeListener#onChanged(org.apache.eventmesh.common.file.FileChangeContext)} method fires when a file changes, - * and the {@link FileChangeListener#support(org.apache.eventmesh.common.file.FileChangeContext)} method let the user customize - * which files are supported + * Users can register {@link FileChangeListener} with WatchFileManager via the {@link WatchFileManager#registerFileChangeListener(java.lang.String, + * org.apache.eventmesh.common.file.FileChangeListener)} method. + * The {@link FileChangeListener#onChanged(org.apache.eventmesh.common.file.FileChangeContext)} + * method fires when a file changes, and the {@link FileChangeListener#support(org.apache.eventmesh.common.file.FileChangeContext)} method let the + * user customize which files are supported */ public interface FileChangeListener { + /** * triggered when a file change occurs * diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileManager.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileManager.java index 157109f0d1..77dd5cf981 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileManager.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileManager.java @@ -21,26 +21,23 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class WatchFileManager { - private static final Logger LOGGER = LoggerFactory.getLogger(WatchFileManager.class); - private static final AtomicBoolean CLOSED = new AtomicBoolean(false); private static final Map WATCH_FILE_TASK_MAP = new HashMap<>(); static { Runtime.getRuntime().addShutdownHook(new Thread(() -> { - LOGGER.warn("[WatchFileManager] WatchFileManager closed"); + log.warn("[WatchFileManager] WatchFileManager closed"); shutdown(); })); } - public static void registerFileChangeListener(String directoryPath, - FileChangeListener listener) { + public static void registerFileChangeListener(String directoryPath, FileChangeListener listener) { WatchFileTask task = WATCH_FILE_TASK_MAP.get(directoryPath); if (task == null) { task = new WatchFileTask(directoryPath); @@ -62,16 +59,19 @@ private static void shutdown() { if (!CLOSED.compareAndSet(false, true)) { return; } - LOGGER.warn("[WatchFileManager] start close"); + + log.info("[WatchFileManager] start close"); + for (Map.Entry entry : WATCH_FILE_TASK_MAP.entrySet()) { - LOGGER.warn("[WatchFileManager] start to shutdown : " + entry.getKey()); + log.info("[WatchFileManager] start to shutdown : {}", entry.getKey()); + try { entry.getValue().shutdown(); - } catch (Throwable ex) { - LOGGER.error("[WatchFileManager] shutdown has error : ", ex); + } catch (Exception ex) { + log.error("[WatchFileManager] shutdown has error : ", ex); } } WATCH_FILE_TASK_MAP.clear(); - LOGGER.warn("[WatchFileManager] already closed"); + log.warn("[WatchFileManager] already closed"); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileTask.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileTask.java index 577d75cc68..3de204e3db 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileTask.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/file/WatchFileTask.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.common.file; +import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -28,22 +29,20 @@ import java.util.ArrayList; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class WatchFileTask extends Thread { - private static final Logger LOGGER = LoggerFactory.getLogger(WatchFileTask.class); - private static final FileSystem FILE_SYSTEM = FileSystems.getDefault(); - private final WatchService watchService; + private final transient WatchService watchService; - private final List fileChangeListeners = new ArrayList<>(); + private final transient List fileChangeListeners = new ArrayList<>(); - private volatile boolean watch = true; + private transient volatile boolean watch = true; - private final String directoryPath; + private final transient String directoryPath; public WatchFileTask(String directoryPath) { this.directoryPath = directoryPath; @@ -56,11 +55,20 @@ public WatchFileTask(String directoryPath) { } try { - WatchService service = FILE_SYSTEM.newWatchService(); - path.register(service, StandardWatchEventKinds.OVERFLOW, StandardWatchEventKinds.ENTRY_MODIFY, - StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE); - this.watchService = service; - } catch (Throwable ex) { + this.watchService = FILE_SYSTEM.newWatchService(); + } catch (IOException ex) { + throw new RuntimeException("WatchService initialization fail", ex); + } + + try { + path.register(this.watchService, StandardWatchEventKinds.OVERFLOW, StandardWatchEventKinds.ENTRY_MODIFY, + StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE); + } catch (IOException ex) { + try { + this.watchService.close(); + } catch (IOException e) { + ex.addSuppressed(e); + } throw new UnsupportedOperationException("WatchService registry fail", ex); } } @@ -73,6 +81,11 @@ public void addFileChangeListener(FileChangeListener fileChangeListener) { public void shutdown() { watch = false; + try { + this.watchService.close(); + } catch (IOException e) { + throw new RuntimeException("Unable to close WatchService", e); + } } @Override @@ -90,7 +103,7 @@ public void run() { for (WatchEvent event : events) { WatchEvent.Kind kind = event.kind(); if (kind.equals(StandardWatchEventKinds.OVERFLOW)) { - LOGGER.warn("[WatchFileTask] file overflow: " + event.context()); + log.warn("[WatchFileTask] file overflow: {}", event.context()); continue; } precessWatchEvent(event); @@ -98,12 +111,10 @@ public void run() { } catch (InterruptedException ex) { boolean interrupted = Thread.interrupted(); if (interrupted) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("[WatchFileTask] file watch is interrupted"); - } + log.debug("[WatchFileTask] file watch is interrupted"); } - } catch (Throwable ex) { - LOGGER.error("[WatchFileTask] an exception occurred during file listening : ", ex); + } catch (Exception ex) { + log.error("[WatchFileTask] an exception occurred during file listening : ", ex); } } } @@ -119,8 +130,8 @@ private void precessWatchEvent(WatchEvent event) { fileChangeListener.onChanged(context); } } - } catch (Throwable ex) { - LOGGER.error("[WatchFileTask] file change event callback error : ", ex); + } catch (Exception ex) { + log.error("[WatchFileTask] file change event callback error : ", ex); } } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/LoadBalanceType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/LoadBalanceType.java index 6096abdf6b..61df341383 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/LoadBalanceType.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/LoadBalanceType.java @@ -1,31 +1,30 @@ /* - * 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 + * 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. + * 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. */ package org.apache.eventmesh.common.loadbalance; public enum LoadBalanceType { + RANDOM(0, "random load balance strategy"), WEIGHT_ROUND_ROBIN(1, "weight round robin load balance strategy"), WEIGHT_RANDOM(2, "weight random load balance strategy"); - private int code; - private String desc; + private final int code; + private final String desc; LoadBalanceType(int code, String desc) { this.code = code; @@ -36,16 +35,8 @@ public int getCode() { return code; } - public void setCode(int code) { - this.code = code; - } - public String getDesc() { return desc; } - public void setDesc(String desc) { - this.desc = desc; - } - } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelector.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelector.java index f04a7683c2..5c4dbacee8 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelector.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelector.java @@ -18,24 +18,21 @@ package org.apache.eventmesh.common.loadbalance; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.RandomUtils; import java.util.List; +import java.util.concurrent.ThreadLocalRandom; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** - * This selector use random strategy. - * Each selection will randomly give one from the given list + * This selector use random strategy. Each selection will randomly give one from the given list * * @param Target type */ +@Slf4j public class RandomLoadBalanceSelector implements LoadBalanceSelector { - private final Logger logger = LoggerFactory.getLogger(RandomLoadBalanceSelector.class); - - private final List clusterGroup; + private final transient List clusterGroup; public RandomLoadBalanceSelector(List clusterGroup) { this.clusterGroup = clusterGroup; @@ -44,10 +41,10 @@ public RandomLoadBalanceSelector(List clusterGroup) { @Override public T select() { if (CollectionUtils.isEmpty(clusterGroup)) { - logger.warn("No servers available"); + log.warn("No servers available"); return null; } - return clusterGroup.get(RandomUtils.nextInt(0, clusterGroup.size())); + return clusterGroup.get(ThreadLocalRandom.current().nextInt(clusterGroup.size())); } @Override diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/Weight.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/Weight.java index cba255b43d..89befd6d30 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/Weight.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/Weight.java @@ -23,13 +23,13 @@ public class Weight { private T target; - private final int weight; + private final int value; private final AtomicInteger currentWeight; - public Weight(T target, int weight) { + public Weight(T target, int value) { this.target = target; - this.weight = weight; + this.value = value; this.currentWeight = new AtomicInteger(0); } @@ -38,10 +38,9 @@ public void decreaseTotal(int total) { } public void increaseCurrentWeight() { - currentWeight.addAndGet(weight); + currentWeight.addAndGet(value); } - public T getTarget() { return target; } @@ -50,11 +49,10 @@ public void setTarget(T target) { this.target = target; } - public int getWeight() { - return weight; + public int getValue() { + return value; } - public AtomicInteger getCurrentWeight() { return currentWeight; } @@ -62,9 +60,9 @@ public AtomicInteger getCurrentWeight() { @Override public String toString() { return "Wight{" - + "target=" + target - + ", weight=" + weight - + ", currentWeight=" + currentWeight - + '}'; + + "target=" + target + + ", value=" + value + + ", currentWeight=" + currentWeight + + '}'; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelector.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelector.java index 5b7904e69f..edada94ce2 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelector.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelector.java @@ -20,34 +20,33 @@ import org.apache.eventmesh.common.exception.EventMeshException; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.RandomUtils; import java.util.List; +import java.util.concurrent.ThreadLocalRandom; /** - * This selector use the weighted random strategy to select from list. - * If all the weights are same, it will randomly select one from list. - * If the weights are different, it will select one by using RandomUtils.nextInt(0, w0 + w1 ... + wn) + * This selector use the weighted random strategy to select from list. If all the weights are same, it will randomly select one from list. If the + * weights are different, it will select one by using RandomUtils.nextInt(0, w0 + w1 ... + wn) * * @param Target type */ public class WeightRandomLoadBalanceSelector implements LoadBalanceSelector { - private final List> clusterGroup; + private final transient List> clusterGroup; - private final int totalWeight; + private final transient int totalWeight; - private boolean sameWeightGroup = true; + private transient boolean sameWeightGroup = true; public WeightRandomLoadBalanceSelector(List> clusterGroup) throws EventMeshException { if (CollectionUtils.isEmpty(clusterGroup)) { throw new EventMeshException("clusterGroup can not be empty"); } int totalWeight = 0; - int firstWeight = clusterGroup.get(0).getWeight(); + int firstWeight = clusterGroup.get(0).getValue(); for (Weight weight : clusterGroup) { - totalWeight += weight.getWeight(); - if (sameWeightGroup && firstWeight != weight.getWeight()) { + totalWeight += weight.getValue(); + if (sameWeightGroup && firstWeight != weight.getValue()) { sameWeightGroup = false; } } @@ -58,16 +57,17 @@ public WeightRandomLoadBalanceSelector(List> clusterGroup) throws Even @Override public T select() { if (!sameWeightGroup) { - int targetWeight = RandomUtils.nextInt(0, totalWeight); + int targetWeight = ThreadLocalRandom.current().nextInt(totalWeight); for (Weight weight : clusterGroup) { - targetWeight -= weight.getWeight(); + targetWeight -= weight.getValue(); if (targetWeight < 0) { return weight.getTarget(); } } } + int length = clusterGroup.size(); - return clusterGroup.get(RandomUtils.nextInt(0, length)).getTarget(); + return clusterGroup.get(ThreadLocalRandom.current().nextInt(length)).getTarget(); } @Override diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelector.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelector.java index 29dcc729e9..7557b3dc2d 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelector.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelector.java @@ -21,38 +21,34 @@ import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** - * This selector use the weighted round robin strategy to select from list. - * If the weight is greater, the probability of being selected is larger. + * This selector use the weighted round robin strategy to select from list. If the weight is greater, the probability of being selected is larger. * * @param Target type */ +@Slf4j public class WeightRoundRobinLoadBalanceSelector implements LoadBalanceSelector { - private final Logger logger = LoggerFactory.getLogger(WeightRoundRobinLoadBalanceSelector.class); + private final transient List> clusterGroup; - private final List> clusterGroup; - - private final int totalWeight; + private final transient int totalWeight; public WeightRoundRobinLoadBalanceSelector(List> clusterGroup) { int totalWeight = 0; for (Weight weight : clusterGroup) { - totalWeight += weight.getWeight(); + totalWeight += weight.getValue(); } this.clusterGroup = clusterGroup; this.totalWeight = totalWeight; } - @Override @SuppressWarnings("ConstantConditions") public T select() { if (CollectionUtils.isEmpty(clusterGroup)) { - logger.warn("No servers available"); + log.warn("No servers available"); return null; } Weight targetWeight = null; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/HeartbeatItem.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/HeartbeatItem.java new file mode 100644 index 0000000000..1b66c28f23 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/HeartbeatItem.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HeartbeatItem { + + private String topic; + + private String url; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/ProtocolTransportObject.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/ProtocolTransportObject.java index ca7c36626a..6527dfa865 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/ProtocolTransportObject.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/ProtocolTransportObject.java @@ -28,4 +28,5 @@ * */ public interface ProtocolTransportObject extends Serializable { + } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionItem.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionItem.java index 5fb0e5f132..6f64617e27 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionItem.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionItem.java @@ -24,6 +24,8 @@ public class SubscriptionItem implements Serializable { + private static final long serialVersionUID = 171486618880705657L; + private String topic; @JsonDeserialize(converter = SubscriptionModeConverter.class) @@ -68,10 +70,10 @@ public void setMode(SubscriptionMode mode) { @Override public String toString() { return "SubscriptionItem{" - + "topic=" + topic - + ", mode=" + mode - + ", type=" + type - + '}'; + + "topic=" + topic + + ", mode=" + mode + + ", type=" + type + + '}'; } @Override @@ -91,5 +93,3 @@ public int hashCode() { return Objects.hashCode(topic, mode, type); } } - - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionMode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionMode.java index ad4b751a46..d05c7ce20e 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionMode.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionMode.java @@ -26,9 +26,14 @@ public enum SubscriptionMode { /** * clustering */ - CLUSTERING("CLUSTERING"); + CLUSTERING("CLUSTERING"), - private String mode; + /** + * UNRECOGNIZED + */ + UNRECOGNIZED("UNRECOGNIZED"); + + private final String mode; SubscriptionMode(String mode) { this.mode = mode; @@ -38,8 +43,4 @@ public String getMode() { return mode; } - public void setMode(String mode) { - this.mode = mode; - } - } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionModeConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionModeConverter.java index 2b1980f363..bdb3c41acf 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionModeConverter.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionModeConverter.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.util.Converter; public class SubscriptionModeConverter implements Converter { + @Override public SubscriptionMode convert(String value) { return SubscriptionMode.valueOf(value); diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionType.java index 7efe3089b8..c6d19eaf9e 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionType.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionType.java @@ -18,6 +18,7 @@ package org.apache.eventmesh.common.protocol; public enum SubscriptionType { + /** * SYNC */ @@ -25,9 +26,14 @@ public enum SubscriptionType { /** * ASYNC */ - ASYNC("ASYNC"); + ASYNC("ASYNC"), + + /** + * UNRECOGNIZED + */ + UNRECOGNIZED("UNRECOGNIZED"); - private String type; + private final String type; SubscriptionType(String type) { this.type = type; @@ -37,7 +43,4 @@ public String getType() { return type; } - public void setType(String type) { - this.type = type; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionTypeConverter.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionTypeConverter.java index 50d28914fe..5a514cf0e7 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionTypeConverter.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/SubscriptionTypeConverter.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.util.Converter; public class SubscriptionTypeConverter implements Converter { + @Override public SubscriptionType convert(String value) { return SubscriptionType.valueOf(value); diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/CatalogGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/CatalogGrpc.java new file mode 100644 index 0000000000..a176da4685 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/CatalogGrpc.java @@ -0,0 +1,385 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.catalog.protos; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + * + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.49.1-SNAPSHOT)", + comments = "Source: catalog.proto") +@io.grpc.stub.annotations.GrpcGenerated +@SuppressWarnings({"all"}) +public final class CatalogGrpc { + + private CatalogGrpc() { + } + + public static final String SERVICE_NAME = "eventmesh.catalog.api.protocol.Catalog"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getRegistryMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "Registry", + requestType = RegistryRequest.class, + responseType = RegistryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getRegistryMethod() { + io.grpc.MethodDescriptor getRegistryMethod; + if ((getRegistryMethod = CatalogGrpc.getRegistryMethod) == null) { + synchronized (CatalogGrpc.class) { + if ((getRegistryMethod = CatalogGrpc.getRegistryMethod) == null) { + CatalogGrpc.getRegistryMethod = getRegistryMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "Registry")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + RegistryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + RegistryResponse.getDefaultInstance())) + .setSchemaDescriptor(new CatalogMethodDescriptorSupplier("Registry")) + .build(); + } + } + } + return getRegistryMethod; + } + + private static volatile io.grpc.MethodDescriptor getQueryOperationsMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "QueryOperations", + requestType = QueryOperationsRequest.class, + responseType = QueryOperationsResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getQueryOperationsMethod() { + io.grpc.MethodDescriptor getQueryOperationsMethod; + if ((getQueryOperationsMethod = CatalogGrpc.getQueryOperationsMethod) == null) { + synchronized (CatalogGrpc.class) { + if ((getQueryOperationsMethod = CatalogGrpc.getQueryOperationsMethod) == null) { + CatalogGrpc.getQueryOperationsMethod = getQueryOperationsMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "QueryOperations")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + QueryOperationsRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + QueryOperationsResponse.getDefaultInstance())) + .setSchemaDescriptor(new CatalogMethodDescriptorSupplier("QueryOperations")) + .build(); + } + } + } + return getQueryOperationsMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static CatalogStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public CatalogStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CatalogStub(channel, callOptions); + } + }; + return CatalogStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static CatalogBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public CatalogBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CatalogBlockingStub(channel, callOptions); + } + }; + return CatalogBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static CatalogFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public CatalogFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CatalogFutureStub(channel, callOptions); + } + }; + return CatalogFutureStub.newStub(factory, channel); + } + + /** + * + */ + public static abstract class CatalogImplBase implements io.grpc.BindableService { + + /** + * + */ + public void registry(RegistryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRegistryMethod(), responseObserver); + } + + /** + * + */ + public void queryOperations(QueryOperationsRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getQueryOperationsMethod(), responseObserver); + } + + @Override + public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getRegistryMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + RegistryRequest, + RegistryResponse>( + this, METHODID_REGISTRY))) + .addMethod( + getQueryOperationsMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + QueryOperationsRequest, + QueryOperationsResponse>( + this, METHODID_QUERY_OPERATIONS))) + .build(); + } + } + + /** + * + */ + public static final class CatalogStub extends io.grpc.stub.AbstractAsyncStub { + private CatalogStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected CatalogStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CatalogStub(channel, callOptions); + } + + /** + * + */ + public void registry(RegistryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getRegistryMethod(), getCallOptions()), request, responseObserver); + } + + /** + * + */ + public void queryOperations(QueryOperationsRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getQueryOperationsMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * + */ + public static final class CatalogBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private CatalogBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected CatalogBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CatalogBlockingStub(channel, callOptions); + } + + /** + * + */ + public RegistryResponse registry(RegistryRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getRegistryMethod(), getCallOptions(), request); + } + + /** + * + */ + public QueryOperationsResponse queryOperations(QueryOperationsRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getQueryOperationsMethod(), getCallOptions(), request); + } + } + + /** + * + */ + public static final class CatalogFutureStub extends io.grpc.stub.AbstractFutureStub { + private CatalogFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected CatalogFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CatalogFutureStub(channel, callOptions); + } + + /** + * + */ + public com.google.common.util.concurrent.ListenableFuture registry( + RegistryRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getRegistryMethod(), getCallOptions()), request); + } + + /** + * + */ + public com.google.common.util.concurrent.ListenableFuture queryOperations( + QueryOperationsRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getQueryOperationsMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_REGISTRY = 0; + private static final int METHODID_QUERY_OPERATIONS = 1; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final CatalogImplBase serviceImpl; + private final int methodId; + + MethodHandlers(CatalogImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_REGISTRY: + serviceImpl.registry((RegistryRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_QUERY_OPERATIONS: + serviceImpl.queryOperations((QueryOperationsRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + private static abstract class CatalogBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + CatalogBaseDescriptorSupplier() { + } + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventmeshCatalogGrpc.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("Catalog"); + } + } + + private static final class CatalogFileDescriptorSupplier + extends CatalogBaseDescriptorSupplier { + CatalogFileDescriptorSupplier() { + } + } + + private static final class CatalogMethodDescriptorSupplier + extends CatalogBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + CatalogMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (CatalogGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new CatalogFileDescriptorSupplier()) + .addMethod(getRegistryMethod()) + .addMethod(getQueryOperationsMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/EventmeshCatalogGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/EventmeshCatalogGrpc.java new file mode 100644 index 0000000000..38497afa3c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/EventmeshCatalogGrpc.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +@SuppressWarnings({"all"}) +public final class EventmeshCatalogGrpc { + private EventmeshCatalogGrpc() { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_catalog_api_protocol_RegistryRequest_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_catalog_api_protocol_RegistryRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_catalog_api_protocol_RegistryResponse_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_catalog_api_protocol_RegistryResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_catalog_api_protocol_Operation_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_catalog_api_protocol_Operation_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + + static { + String[] descriptorData = { + "\n\rcatalog.proto\022\036eventmesh.catalog.api.p" + + "rotocol\"8\n\017RegistryRequest\022\021\n\tfile_name\030" + + "\001 \001(\t\022\022\n\ndefinition\030\002 \001(\t\"\022\n\020RegistryRes" + + "ponse\"D\n\026QueryOperationsRequest\022\024\n\014servi" + + "ce_name\030\001 \001(\t\022\024\n\014operation_id\030\002 \001(\t\"?\n\tO" + + "peration\022\024\n\014channel_name\030\001 \001(\t\022\016\n\006schema" + + "\030\002 \001(\t\022\014\n\004type\030\003 \001(\t\"X\n\027QueryOperationsR" + + "esponse\022=\n\noperations\030\001 \003(\0132).eventmesh." + + "catalog.api.protocol.Operation2\201\002\n\007Catal" + + "og\022o\n\010Registry\022/.eventmesh.catalog.api.p" + + "rotocol.RegistryRequest\0320.eventmesh.cata" + + "log.api.protocol.RegistryResponse\"\000\022\204\001\n\017" + + "QueryOperations\0226.eventmesh.catalog.api." + + "protocol.QueryOperationsRequest\0327.eventm" + + "esh.catalog.api.protocol.QueryOperations" + + "Response\"\000B\223\001\n3org.apache.eventmesh.comm" + + "on.protocol.catalog.protosB\024EventmeshCat" + + "alogGrpcP\001ZDgithub.com/apache/incubator-" + + "eventmesh/eventmesh-catalog-go/api/proto" + + "b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_eventmesh_catalog_api_protocol_RegistryRequest_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_eventmesh_catalog_api_protocol_RegistryRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_catalog_api_protocol_RegistryRequest_descriptor, + new String[] {"FileName", "Definition",}); + internal_static_eventmesh_catalog_api_protocol_RegistryResponse_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_eventmesh_catalog_api_protocol_RegistryResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_catalog_api_protocol_RegistryResponse_descriptor, + new String[] {}); + internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_descriptor, + new String[] {"ServiceName", "OperationId",}); + internal_static_eventmesh_catalog_api_protocol_Operation_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_eventmesh_catalog_api_protocol_Operation_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_catalog_api_protocol_Operation_descriptor, + new String[] {"ChannelName", "Schema", "Type",}); + internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_descriptor, + new String[] {"Operations",}); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/Operation.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/Operation.java new file mode 100644 index 0000000000..07e2407f49 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/Operation.java @@ -0,0 +1,836 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +import java.util.Objects; + +import com.google.protobuf.ByteString; + +/** + * Protobuf type {@code eventmesh.catalog.api.protocol.Operation} + */ +@SuppressWarnings({"all"}) +public final class Operation extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:eventmesh.catalog.api.protocol.Operation) + OperationOrBuilder { + private static final long serialVersionUID = 7231240618302324570L; + + public static final int CHANNEL_NAME_FIELD_NUMBER = 1; + public static final int SCHEMA_FIELD_NUMBER = 2; + public static final int TYPE_FIELD_NUMBER = 3; + + private static final Operation DEFAULT_INSTANCE; + + private volatile String channelName; + private volatile String schema; + private volatile String type; + private byte memoizedIsInitialized = -1; + + // Use Operation.newBuilder() to construct. + + + static { + DEFAULT_INSTANCE = new Operation(); + } + + public static Operation getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private Operation(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private Operation() { + channelName = ""; + schema = ""; + type = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new Operation(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet getUnknownFields() { + return this.unknownFields; + } + + private Operation( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + + this(); + Objects.requireNonNull(input, "CodedInputStream can not be null"); + Objects.requireNonNull(extensionRegistry, "ExtensionRegistryLite can not be null"); + + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + channelName = input.readStringRequireUtf8(); + break; + } + case 18: { + schema = input.readStringRequireUtf8(); + break; + } + case 26: { + type = input.readStringRequireUtf8(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_Operation_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_Operation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + Operation.class, Builder.class); + } + + + /** + * string channel_name = 1; + * + * @return The channelName. + */ + @Override + public String getChannelName() { + return channelName; + } + + /** + * string channel_name = 1; + * + * @return The bytes for channelName. + */ + @Override + public com.google.protobuf.ByteString getChannelNameBytes() { + return ByteString.copyFromUtf8(channelName); + } + + + /** + * string schema = 2; + * + * @return The schema. + */ + @Override + public String getSchema() { + return schema; + } + + /** + * string schema = 2; + * + * @return The bytes for schema. + */ + @Override + public com.google.protobuf.ByteString getSchemaBytes() { + + return ByteString.copyFromUtf8(schema); + } + + /** + *
+     * publish/subscribe
+     * 
+ * + * string type = 3; + * + * @return The type. + */ + @Override + public String getType() { + + return type; + } + + /** + *
+     * publish/subscribe
+     * 
+ * + * string type = 3; + * + * @return The bytes for type. + */ + @Override + public com.google.protobuf.ByteString getTypeBytes() { + + return ByteString.copyFromUtf8(type); + } + + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getChannelNameBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, channelName); + } + if (!getSchemaBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, schema); + } + if (!getTypeBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, type); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!getChannelNameBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, channelName); + } + if (!getSchemaBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, schema); + } + if (!getTypeBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, type); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Operation)) { + return super.equals(obj); + } + Operation other = (Operation) obj; + + if (!getChannelName() + .equals(other.getChannelName())) { + return false; + } + if (!getSchema() + .equals(other.getSchema())) { + return false; + } + if (!getType() + .equals(other.getType())) { + return false; + } + if (!unknownFields.equals(other.unknownFields)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + CHANNEL_NAME_FIELD_NUMBER; + hash = (53 * hash) + getChannelName().hashCode(); + hash = (37 * hash) + SCHEMA_FIELD_NUMBER; + hash = (53 * hash) + getSchema().hashCode(); + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + getType().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static Operation parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Operation parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Operation parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Operation parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Operation parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Operation parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Operation parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static Operation parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static Operation parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static Operation parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static Operation parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static Operation parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(Operation prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this.equals(DEFAULT_INSTANCE) + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType(BuilderParent parent) { + return new Builder(parent); + } + + + /** + * Protobuf type {@code eventmesh.catalog.api.protocol.Operation} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder + implements OperationOrBuilder { + + private String type = ""; + private String channelName = ""; + private String schema = ""; + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_Operation_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_Operation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + Operation.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.catalog.protos.Operation.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + channelName = ""; + schema = ""; + type = ""; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_Operation_descriptor; + } + + @Override + public Operation getDefaultInstanceForType() { + return Operation.getDefaultInstance(); + } + + @Override + public Operation build() { + Operation result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public Operation buildPartial() { + Operation result = new Operation(this); + result.channelName = channelName; + result.schema = schema; + result.type = type; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof Operation) { + return mergeFrom((Operation) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(Operation other) { + if (other.equals(Operation.getDefaultInstance())) { + return this; + } + if (!other.getChannelName().isEmpty()) { + channelName = other.channelName; + onChanged(); + } + if (!other.getSchema().isEmpty()) { + schema = other.schema; + onChanged(); + } + if (!other.getType().isEmpty()) { + type = other.type; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Operation parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (Operation) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + + /** + * string channel_name = 1; + * + * @return The channelName. + */ + public String getChannelName() { + return channelName; + } + + /** + * string channel_name = 1; + * + * @return The bytes for channelName. + */ + public com.google.protobuf.ByteString getChannelNameBytes() { + + return ByteString.copyFromUtf8(channelName); + } + + /** + * string channel_name = 1; + * + * @param value The channelName to set. + * @return This builder for chaining. + */ + public Builder setChannelName(String value) { + Objects.requireNonNull(value, "channelname can not be null"); + + channelName = value; + onChanged(); + return this; + } + + /** + * string channel_name = 1; + * + * @return This builder for chaining. + */ + public Builder clearChannelName() { + channelName = getDefaultInstance().getChannelName(); + onChanged(); + return this; + } + + /** + * string channel_name = 1; + * + * @param value The bytes for channelName to set. + * @return This builder for chaining. + */ + public Builder setChannelNameBytes(com.google.protobuf.ByteString value) { + Objects.requireNonNull(value, "channelname can not be null"); + checkByteStringIsUtf8(value); + + channelName = value.toStringUtf8(); + onChanged(); + return this; + } + + /** + * string schema = 2; + * + * @return The schema. + */ + public String getSchema() { + return schema; + } + + /** + * string schema = 2; + * + * @return The bytes for schema. + */ + public com.google.protobuf.ByteString + getSchemaBytes() { + return ByteString.copyFromUtf8(schema); + } + + /** + * string schema = 2; + * + * @param value The schema to set. + * @return This builder for chaining. + */ + public Builder setSchema(String value) { + Objects.requireNonNull(value, "schema can not be null"); + + schema = value; + onChanged(); + return this; + } + + /** + * string schema = 2; + * + * @return This builder for chaining. + */ + public Builder clearSchema() { + schema = getDefaultInstance().getSchema(); + onChanged(); + return this; + } + + /** + * string schema = 2; + * + * @param value The bytes for schema to set. + * @return This builder for chaining. + */ + public Builder setSchemaBytes(com.google.protobuf.ByteString value) { + Objects.requireNonNull(value, "schema can not be null"); + checkByteStringIsUtf8(value); + + schema = value.toStringUtf8(); + onChanged(); + return this; + } + + + /** + *
+         * publish/subscribe
+         * 
+ * + * string type = 3; + * + * @return The type. + */ + public String getType() { + + return type; + } + + /** + *
+         * publish/subscribe
+         * 
+ * + * string type = 3; + * + * @return The bytes for type. + */ + public com.google.protobuf.ByteString getTypeBytes() { + return ByteString.copyFromUtf8(type); + } + + /** + *
+         * publish/subscribe
+         * 
+ * + * string type = 3; + * + * @param value The type to set. + * @return This builder for chaining. + */ + public Builder setType(String value) { + Objects.requireNonNull(value, "type can not be null"); + + type = value; + onChanged(); + return this; + } + + /** + *
+         * publish/subscribe
+         * 
+ * + * string type = 3; + * + * @return This builder for chaining. + */ + public Builder clearType() { + type = getDefaultInstance().getType(); + onChanged(); + return this; + } + + /** + *
+         * publish/subscribe
+         * 
+ * + * string type = 3; + * + * @param value The bytes for type to set. + * @return This builder for chaining. + */ + public Builder setTypeBytes(com.google.protobuf.ByteString value) { + Objects.requireNonNull(value, "type can not be null"); + checkByteStringIsUtf8(value); + + type = value.toStringUtf8(); + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.catalog.api.protocol.Operation) + } + + // @@protoc_insertion_point(class_scope:eventmesh.catalog.api.protocol.Operation) + + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public Operation parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Operation(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public Operation getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/OperationOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/OperationOrBuilder.java new file mode 100644 index 0000000000..2c610acb4f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/OperationOrBuilder.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +@SuppressWarnings({"all"}) +public interface OperationOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.catalog.api.protocol.Operation) + com.google.protobuf.MessageOrBuilder { + + /** + * string channel_name = 1; + * + * @return The channelName. + */ + String getChannelName(); + + /** + * string channel_name = 1; + * + * @return The bytes for channelName. + */ + com.google.protobuf.ByteString + getChannelNameBytes(); + + /** + * string schema = 2; + * + * @return The schema. + */ + String getSchema(); + + /** + * string schema = 2; + * + * @return The bytes for schema. + */ + com.google.protobuf.ByteString + getSchemaBytes(); + + /** + *
+     * publish/subscribe
+     * 
+ * + * string type = 3; + * + * @return The type. + */ + String getType(); + + /** + *
+     * publish/subscribe
+     * 
+ * + * string type = 3; + * + * @return The bytes for type. + */ + com.google.protobuf.ByteString + getTypeBytes(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsRequest.java new file mode 100644 index 0000000000..27401bb4b9 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsRequest.java @@ -0,0 +1,786 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +/** + * Protobuf type {@code eventmesh.catalog.api.protocol.QueryOperationsRequest} + */ +@SuppressWarnings({"all"}) +public final class QueryOperationsRequest extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:eventmesh.catalog.api.protocol.QueryOperationsRequest) + QueryOperationsRequestOrBuilder { + private static final long serialVersionUID = 0L; + + // Use QueryOperationsRequest.newBuilder() to construct. + private QueryOperationsRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private QueryOperationsRequest() { + serviceName_ = ""; + operationId_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new QueryOperationsRequest(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private QueryOperationsRequest( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + String s = input.readStringRequireUtf8(); + + serviceName_ = s; + break; + } + case 18: { + String s = input.readStringRequireUtf8(); + + operationId_ = s; + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + QueryOperationsRequest.class, Builder.class); + } + + public static final int SERVICE_NAME_FIELD_NUMBER = 1; + private volatile Object serviceName_; + + /** + * string service_name = 1; + * + * @return The serviceName. + */ + @Override + public String getServiceName() { + Object ref = serviceName_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + serviceName_ = s; + return s; + } + } + + /** + * string service_name = 1; + * + * @return The bytes for serviceName. + */ + @Override + public com.google.protobuf.ByteString + getServiceNameBytes() { + Object ref = serviceName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + serviceName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int OPERATION_ID_FIELD_NUMBER = 2; + private volatile Object operationId_; + + /** + * string operation_id = 2; + * + * @return The operationId. + */ + @Override + public String getOperationId() { + Object ref = operationId_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + operationId_ = s; + return s; + } + } + + /** + * string operation_id = 2; + * + * @return The bytes for operationId. + */ + @Override + public com.google.protobuf.ByteString + getOperationIdBytes() { + Object ref = operationId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + operationId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getServiceNameBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, serviceName_); + } + if (!getOperationIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, operationId_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!getServiceNameBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, serviceName_); + } + if (!getOperationIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, operationId_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof QueryOperationsRequest)) { + return super.equals(obj); + } + QueryOperationsRequest other = (QueryOperationsRequest) obj; + + if (!getServiceName() + .equals(other.getServiceName())) { + return false; + } + if (!getOperationId() + .equals(other.getOperationId())) { + return false; + } + if (!unknownFields.equals(other.unknownFields)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + SERVICE_NAME_FIELD_NUMBER; + hash = (53 * hash) + getServiceName().hashCode(); + hash = (37 * hash) + OPERATION_ID_FIELD_NUMBER; + hash = (53 * hash) + getOperationId().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static QueryOperationsRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static QueryOperationsRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static QueryOperationsRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static QueryOperationsRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static QueryOperationsRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static QueryOperationsRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static QueryOperationsRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static QueryOperationsRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static QueryOperationsRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static QueryOperationsRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static QueryOperationsRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static QueryOperationsRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(QueryOperationsRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this.equals(DEFAULT_INSTANCE) + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + return new Builder(parent); + } + + /** + * Protobuf type {@code eventmesh.catalog.api.protocol.QueryOperationsRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:eventmesh.catalog.api.protocol.QueryOperationsRequest) + QueryOperationsRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + QueryOperationsRequest.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.catalog.protos.QueryOperationsRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + serviceName_ = ""; + + operationId_ = ""; + + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsRequest_descriptor; + } + + @Override + public QueryOperationsRequest getDefaultInstanceForType() { + return QueryOperationsRequest.getDefaultInstance(); + } + + @Override + public QueryOperationsRequest build() { + QueryOperationsRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public QueryOperationsRequest buildPartial() { + QueryOperationsRequest result = new QueryOperationsRequest(this); + result.serviceName_ = serviceName_; + result.operationId_ = operationId_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof QueryOperationsRequest) { + return mergeFrom((QueryOperationsRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(QueryOperationsRequest other) { + if (other.equals(QueryOperationsRequest.getDefaultInstance())) { + return this; + } + if (!other.getServiceName().isEmpty()) { + serviceName_ = other.serviceName_; + onChanged(); + } + if (!other.getOperationId().isEmpty()) { + operationId_ = other.operationId_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + QueryOperationsRequest parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (QueryOperationsRequest) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private Object serviceName_ = ""; + + /** + * string service_name = 1; + * + * @return The serviceName. + */ + public String getServiceName() { + Object ref = serviceName_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + serviceName_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + * string service_name = 1; + * + * @return The bytes for serviceName. + */ + public com.google.protobuf.ByteString + getServiceNameBytes() { + Object ref = serviceName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + serviceName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string service_name = 1; + * + * @param value The serviceName to set. + * @return This builder for chaining. + */ + public Builder setServiceName( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + serviceName_ = value; + onChanged(); + return this; + } + + /** + * string service_name = 1; + * + * @return This builder for chaining. + */ + public Builder clearServiceName() { + + serviceName_ = getDefaultInstance().getServiceName(); + onChanged(); + return this; + } + + /** + * string service_name = 1; + * + * @param value The bytes for serviceName to set. + * @return This builder for chaining. + */ + public Builder setServiceNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + serviceName_ = value; + onChanged(); + return this; + } + + private Object operationId_ = ""; + + /** + * string operation_id = 2; + * + * @return The operationId. + */ + public String getOperationId() { + Object ref = operationId_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + operationId_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + * string operation_id = 2; + * + * @return The bytes for operationId. + */ + public com.google.protobuf.ByteString + getOperationIdBytes() { + Object ref = operationId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + operationId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string operation_id = 2; + * + * @param value The operationId to set. + * @return This builder for chaining. + */ + public Builder setOperationId( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + operationId_ = value; + onChanged(); + return this; + } + + /** + * string operation_id = 2; + * + * @return This builder for chaining. + */ + public Builder clearOperationId() { + + operationId_ = getDefaultInstance().getOperationId(); + onChanged(); + return this; + } + + /** + * string operation_id = 2; + * + * @param value The bytes for operationId to set. + * @return This builder for chaining. + */ + public Builder setOperationIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + operationId_ = value; + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.catalog.api.protocol.QueryOperationsRequest) + } + + // @@protoc_insertion_point(class_scope:eventmesh.catalog.api.protocol.QueryOperationsRequest) + private static final QueryOperationsRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new QueryOperationsRequest(); + } + + public static QueryOperationsRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public QueryOperationsRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new QueryOperationsRequest(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public QueryOperationsRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsRequestOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsRequestOrBuilder.java new file mode 100644 index 0000000000..b9bd6728a7 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsRequestOrBuilder.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +@SuppressWarnings({"all"}) +public interface QueryOperationsRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.catalog.api.protocol.QueryOperationsRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * string service_name = 1; + * + * @return The serviceName. + */ + String getServiceName(); + + /** + * string service_name = 1; + * + * @return The bytes for serviceName. + */ + com.google.protobuf.ByteString + getServiceNameBytes(); + + /** + * string operation_id = 2; + * + * @return The operationId. + */ + String getOperationId(); + + /** + * string operation_id = 2; + * + * @return The bytes for operationId. + */ + com.google.protobuf.ByteString + getOperationIdBytes(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsResponse.java new file mode 100644 index 0000000000..da89c60580 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsResponse.java @@ -0,0 +1,857 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +/** + * Protobuf type {@code eventmesh.catalog.api.protocol.QueryOperationsResponse} + */ +@SuppressWarnings({"all"}) +public final class QueryOperationsResponse extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:eventmesh.catalog.api.protocol.QueryOperationsResponse) + QueryOperationsResponseOrBuilder { + private static final long serialVersionUID = 0L; + + // Use QueryOperationsResponse.newBuilder() to construct. + private QueryOperationsResponse(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private QueryOperationsResponse() { + operations_ = java.util.Collections.emptyList(); + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new QueryOperationsResponse(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private QueryOperationsResponse( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + if (!((mutable_bitField0_ & 0x00000001) != 0)) { + operations_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + operations_.add( + input.readMessage(Operation.parser(), extensionRegistry)); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) != 0)) { + operations_ = java.util.Collections.unmodifiableList(operations_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + QueryOperationsResponse.class, Builder.class); + } + + public static final int OPERATIONS_FIELD_NUMBER = 1; + private java.util.List operations_; + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + @Override + public java.util.List getOperationsList() { + return operations_; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + @Override + public java.util.List + getOperationsOrBuilderList() { + return operations_; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + @Override + public int getOperationsCount() { + return operations_.size(); + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + @Override + public Operation getOperations(int index) { + return operations_.get(index); + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + @Override + public OperationOrBuilder getOperationsOrBuilder( + int index) { + return operations_.get(index); + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (Operation operation : operations_) { + output.writeMessage(1, operation); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + for (Operation operation : operations_) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, operation); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof QueryOperationsResponse)) { + return super.equals(obj); + } + QueryOperationsResponse other = (QueryOperationsResponse) obj; + + if (!getOperationsList() + .equals(other.getOperationsList())) { + return false; + } + if (!unknownFields.equals(other.unknownFields)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getOperationsCount() > 0) { + hash = (37 * hash) + OPERATIONS_FIELD_NUMBER; + hash = (53 * hash) + getOperationsList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static QueryOperationsResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static QueryOperationsResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static QueryOperationsResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static QueryOperationsResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static QueryOperationsResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static QueryOperationsResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static QueryOperationsResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static QueryOperationsResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static QueryOperationsResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static QueryOperationsResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static QueryOperationsResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static QueryOperationsResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(QueryOperationsResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this.equals(DEFAULT_INSTANCE) + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + return new Builder(parent); + } + + /** + * Protobuf type {@code eventmesh.catalog.api.protocol.QueryOperationsResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:eventmesh.catalog.api.protocol.QueryOperationsResponse) + QueryOperationsResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + QueryOperationsResponse.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.catalog.protos.QueryOperationsResponse.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getOperationsFieldBuilder(); + } + } + + @Override + public Builder clear() { + super.clear(); + if (operationsBuilder_ == null) { + operations_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + operationsBuilder_.clear(); + } + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_QueryOperationsResponse_descriptor; + } + + @Override + public QueryOperationsResponse getDefaultInstanceForType() { + return QueryOperationsResponse.getDefaultInstance(); + } + + @Override + public QueryOperationsResponse build() { + QueryOperationsResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public QueryOperationsResponse buildPartial() { + QueryOperationsResponse result = new QueryOperationsResponse(this); + int from_bitField0_ = bitField0_; + if (operationsBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + operations_ = java.util.Collections.unmodifiableList(operations_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.operations_ = operations_; + } else { + result.operations_ = operationsBuilder_.build(); + } + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof QueryOperationsResponse) { + return mergeFrom((QueryOperationsResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(QueryOperationsResponse other) { + if (other.equals(QueryOperationsResponse.getDefaultInstance())) { + return this; + } + if (operationsBuilder_ == null) { + if (!other.operations_.isEmpty()) { + if (operations_.isEmpty()) { + operations_ = other.operations_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureOperationsIsMutable(); + operations_.addAll(other.operations_); + } + onChanged(); + } + } else { + if (!other.operations_.isEmpty()) { + if (operationsBuilder_.isEmpty()) { + operationsBuilder_.dispose(); + operationsBuilder_ = null; + operations_ = other.operations_; + bitField0_ = (bitField0_ & ~0x00000001); + operationsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getOperationsFieldBuilder() : null; + } else { + operationsBuilder_.addAllMessages(other.operations_); + } + } + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + QueryOperationsResponse parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (QueryOperationsResponse) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int bitField0_; + + private java.util.List operations_ = + java.util.Collections.emptyList(); + + private void ensureOperationsIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + operations_ = new java.util.ArrayList(operations_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + Operation, Operation.Builder, OperationOrBuilder> operationsBuilder_; + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public java.util.List getOperationsList() { + if (operationsBuilder_ == null) { + return java.util.Collections.unmodifiableList(operations_); + } else { + return operationsBuilder_.getMessageList(); + } + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public int getOperationsCount() { + if (operationsBuilder_ == null) { + return operations_.size(); + } else { + return operationsBuilder_.getCount(); + } + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Operation getOperations(int index) { + if (operationsBuilder_ == null) { + return operations_.get(index); + } else { + return operationsBuilder_.getMessage(index); + } + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder setOperations( + int index, Operation value) { + if (operationsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOperationsIsMutable(); + operations_.set(index, value); + onChanged(); + } else { + operationsBuilder_.setMessage(index, value); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder setOperations( + int index, Operation.Builder builderForValue) { + if (operationsBuilder_ == null) { + ensureOperationsIsMutable(); + operations_.set(index, builderForValue.build()); + onChanged(); + } else { + operationsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder addOperations(Operation value) { + if (operationsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOperationsIsMutable(); + operations_.add(value); + onChanged(); + } else { + operationsBuilder_.addMessage(value); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder addOperations( + int index, Operation value) { + if (operationsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOperationsIsMutable(); + operations_.add(index, value); + onChanged(); + } else { + operationsBuilder_.addMessage(index, value); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder addOperations( + Operation.Builder builderForValue) { + if (operationsBuilder_ == null) { + ensureOperationsIsMutable(); + operations_.add(builderForValue.build()); + onChanged(); + } else { + operationsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder addOperations( + int index, Operation.Builder builderForValue) { + if (operationsBuilder_ == null) { + ensureOperationsIsMutable(); + operations_.add(index, builderForValue.build()); + onChanged(); + } else { + operationsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder addAllOperations( + Iterable values) { + if (operationsBuilder_ == null) { + ensureOperationsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, operations_); + onChanged(); + } else { + operationsBuilder_.addAllMessages(values); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder clearOperations() { + if (operationsBuilder_ == null) { + operations_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + operationsBuilder_.clear(); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Builder removeOperations(int index) { + if (operationsBuilder_ == null) { + ensureOperationsIsMutable(); + operations_.remove(index); + onChanged(); + } else { + operationsBuilder_.remove(index); + } + return this; + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Operation.Builder getOperationsBuilder( + int index) { + return getOperationsFieldBuilder().getBuilder(index); + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public OperationOrBuilder getOperationsOrBuilder( + int index) { + if (operationsBuilder_ == null) { + return operations_.get(index); + } else { + return operationsBuilder_.getMessageOrBuilder(index); + } + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public java.util.List + getOperationsOrBuilderList() { + if (operationsBuilder_ != null) { + return operationsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(operations_); + } + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Operation.Builder addOperationsBuilder() { + return getOperationsFieldBuilder().addBuilder( + Operation.getDefaultInstance()); + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public Operation.Builder addOperationsBuilder( + int index) { + return getOperationsFieldBuilder().addBuilder( + index, Operation.getDefaultInstance()); + } + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + public java.util.List + getOperationsBuilderList() { + return getOperationsFieldBuilder().getBuilderList(); + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + Operation, Operation.Builder, OperationOrBuilder> + getOperationsFieldBuilder() { + if (operationsBuilder_ == null) { + operationsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + Operation, Operation.Builder, OperationOrBuilder>( + operations_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + operations_ = null; + } + return operationsBuilder_; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.catalog.api.protocol.QueryOperationsResponse) + } + + // @@protoc_insertion_point(class_scope:eventmesh.catalog.api.protocol.QueryOperationsResponse) + private static final QueryOperationsResponse DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new QueryOperationsResponse(); + } + + public static QueryOperationsResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public QueryOperationsResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new QueryOperationsResponse(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public QueryOperationsResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsResponseOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsResponseOrBuilder.java new file mode 100644 index 0000000000..818c970fa9 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/QueryOperationsResponseOrBuilder.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +@SuppressWarnings({"all"}) +public interface QueryOperationsResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.catalog.api.protocol.QueryOperationsResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + java.util.List + getOperationsList(); + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + Operation getOperations(int index); + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + int getOperationsCount(); + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + java.util.List + getOperationsOrBuilderList(); + + /** + * repeated .eventmesh.catalog.api.protocol.Operation operations = 1; + */ + OperationOrBuilder getOperationsOrBuilder( + int index); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryRequest.java new file mode 100644 index 0000000000..ae65571879 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryRequest.java @@ -0,0 +1,701 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +import java.util.Objects; + +import com.google.protobuf.ByteString; + +/** + * Protobuf type {@code eventmesh.catalog.api.protocol.RegistryRequest} + */ +@SuppressWarnings({"all"}) +public final class RegistryRequest extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:eventmesh.catalog.api.protocol.RegistryRequest) + RegistryRequestOrBuilder { + private static final long serialVersionUID = 3745623108415722309L; + + // Use RegistryRequest.newBuilder() to construct. + private RegistryRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private RegistryRequest() { + fileName_ = ""; + definition_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new RegistryRequest(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private RegistryRequest( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + Objects.requireNonNull(input, "CodedInputStream can not be null"); + Objects.requireNonNull(extensionRegistry, "ExtensionRegistryLite can not be null"); + + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + fileName_ = input.readStringRequireUtf8(); + break; + } + case 18: { + definition_ = input.readStringRequireUtf8(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + RegistryRequest.class, Builder.class); + } + + public static final int FILE_NAME_FIELD_NUMBER = 1; + private volatile String fileName_; + + /** + * string file_name = 1; + * + * @return The fileName. + */ + @Override + public String getFileName() { + return fileName_; + } + + /** + * string file_name = 1; + * + * @return The bytes for fileName. + */ + @Override + public com.google.protobuf.ByteString getFileNameBytes() { + return ByteString.copyFromUtf8(fileName_); + } + + public static final int DEFINITION_FIELD_NUMBER = 2; + private volatile String definition_; + + /** + * string definition = 2; + * + * @return The definition. + */ + @Override + public String getDefinition() { + return definition_; + } + + /** + * string definition = 2; + * + * @return The bytes for definition. + */ + @Override + public com.google.protobuf.ByteString + getDefinitionBytes() { + return ByteString.copyFromUtf8(definition_); + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + if (memoizedIsInitialized == 1) { + return true; + } + if (memoizedIsInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getFileNameBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, fileName_); + } + if (!getDefinitionBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, definition_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!getFileNameBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, fileName_); + } + if (!getDefinitionBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, definition_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof RegistryRequest)) { + return super.equals(obj); + } + RegistryRequest other = (RegistryRequest) obj; + + if (!getFileName() + .equals(other.getFileName()) + || !getDefinition() + .equals(other.getDefinition()) + || !unknownFields.equals(other.unknownFields)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + FILE_NAME_FIELD_NUMBER; + hash = (53 * hash) + getFileName().hashCode(); + hash = (37 * hash) + DEFINITION_FIELD_NUMBER; + hash = (53 * hash) + getDefinition().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static RegistryRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static RegistryRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static RegistryRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static RegistryRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static RegistryRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static RegistryRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static RegistryRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static RegistryRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static RegistryRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static RegistryRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static RegistryRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static RegistryRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(RegistryRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this.equals(DEFAULT_INSTANCE) + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code eventmesh.catalog.api.protocol.RegistryRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:eventmesh.catalog.api.protocol.RegistryRequest) + RegistryRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + RegistryRequest.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.catalog.protos.RegistryRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + fileName_ = ""; + + definition_ = ""; + + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryRequest_descriptor; + } + + @Override + public RegistryRequest getDefaultInstanceForType() { + return RegistryRequest.getDefaultInstance(); + } + + @Override + public RegistryRequest build() { + RegistryRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public RegistryRequest buildPartial() { + RegistryRequest result = new RegistryRequest(this); + result.fileName_ = fileName_; + result.definition_ = definition_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof RegistryRequest) { + return mergeFrom((RegistryRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(RegistryRequest other) { + if (other.equals(RegistryRequest.getDefaultInstance())) { + return this; + } + if (!other.getFileName().isEmpty()) { + fileName_ = other.fileName_; + onChanged(); + } + if (!other.getDefinition().isEmpty()) { + definition_ = other.definition_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + RegistryRequest parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (RegistryRequest) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private String fileName_ = ""; + + /** + * string file_name = 1; + * + * @return The fileName. + */ + public String getFileName() { + return fileName_; + } + + /** + * string file_name = 1; + * + * @return The bytes for fileName. + */ + public com.google.protobuf.ByteString + getFileNameBytes() { + return ByteString.copyFromUtf8(fileName_); + } + + /** + * string file_name = 1; + * + * @param value The fileName to set. + * @return This builder for chaining. + */ + public Builder setFileName( + String value) { + Objects.requireNonNull(value, "FileName can not be null"); + + fileName_ = value; + onChanged(); + return this; + } + + /** + * string file_name = 1; + * + * @return This builder for chaining. + */ + public Builder clearFileName() { + + fileName_ = getDefaultInstance().getFileName(); + onChanged(); + return this; + } + + /** + * string file_name = 1; + * + * @param value The bytes for fileName to set. + * @return This builder for chaining. + */ + public Builder setFileNameBytes( + com.google.protobuf.ByteString value) { + Objects.requireNonNull(value, "FileNameBytes can not be null"); + checkByteStringIsUtf8(value); + + fileName_ = value.toStringUtf8(); + onChanged(); + return this; + } + + private String definition_ = ""; + + /** + * string definition = 2; + * + * @return The definition. + */ + public String getDefinition() { + return definition_; + } + + /** + * string definition = 2; + * + * @return The bytes for definition. + */ + public com.google.protobuf.ByteString + getDefinitionBytes() { + return ByteString.copyFromUtf8(definition_); + } + + /** + * string definition = 2; + * + * @param value The definition to set. + * @return This builder for chaining. + */ + public Builder setDefinition( + String value) { + Objects.requireNonNull(value, "Definition can not be null"); + + definition_ = value; + onChanged(); + return this; + } + + /** + * string definition = 2; + * + * @return This builder for chaining. + */ + public Builder clearDefinition() { + + definition_ = getDefaultInstance().getDefinition(); + onChanged(); + return this; + } + + /** + * string definition = 2; + * + * @param value The bytes for definition to set. + * @return This builder for chaining. + */ + public Builder setDefinitionBytes( + com.google.protobuf.ByteString value) { + Objects.requireNonNull(value, "DefinitionBytes can not be null"); + checkByteStringIsUtf8(value); + + definition_ = value.toStringUtf8(); + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.catalog.api.protocol.RegistryRequest) + } + + // @@protoc_insertion_point(class_scope:eventmesh.catalog.api.protocol.RegistryRequest) + private static final RegistryRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new RegistryRequest(); + } + + public static RegistryRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public RegistryRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new RegistryRequest(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public RegistryRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryRequestOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryRequestOrBuilder.java new file mode 100644 index 0000000000..82cbf9d857 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryRequestOrBuilder.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +@SuppressWarnings({"all"}) +public interface RegistryRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.catalog.api.protocol.RegistryRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * string file_name = 1; + * + * @return The fileName. + */ + String getFileName(); + + /** + * string file_name = 1; + * + * @return The bytes for fileName. + */ + com.google.protobuf.ByteString + getFileNameBytes(); + + /** + * string definition = 2; + * + * @return The definition. + */ + String getDefinition(); + + /** + * string definition = 2; + * + * @return The bytes for definition. + */ + com.google.protobuf.ByteString + getDefinitionBytes(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryResponse.java new file mode 100644 index 0000000000..60bc018587 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryResponse.java @@ -0,0 +1,478 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +import java.util.Objects; + +/** + * Protobuf type {@code eventmesh.catalog.api.protocol.RegistryResponse} + */ +@SuppressWarnings({"all"}) +public final class RegistryResponse extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:eventmesh.catalog.api.protocol.RegistryResponse) + RegistryResponseOrBuilder { + private static final long serialVersionUID = 5690543722366991453L; + + // Use RegistryResponse.newBuilder() to construct. + private RegistryResponse(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private RegistryResponse() { + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new RegistryResponse(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private RegistryResponse( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + Objects.requireNonNull(input, "CodedInputStream can not be null"); + Objects.requireNonNull(extensionRegistry, "ExtensionRegistryLite can not be null"); + + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryResponse_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + RegistryResponse.class, Builder.class); + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + if (memoizedIsInitialized == 1) { + return true; + } + if (memoizedIsInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return memoizedSize; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof RegistryResponse)) { + return super.equals(obj); + } + RegistryResponse other = (RegistryResponse) obj; + + if (!unknownFields.equals(other.unknownFields)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static RegistryResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static RegistryResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static RegistryResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static RegistryResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static RegistryResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static RegistryResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static RegistryResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static RegistryResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static RegistryResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static RegistryResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static RegistryResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static RegistryResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(RegistryResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this.equals(DEFAULT_INSTANCE) + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType(BuilderParent parent) { + return new Builder(parent); + } + + /** + * Protobuf type {@code eventmesh.catalog.api.protocol.RegistryResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:eventmesh.catalog.api.protocol.RegistryResponse) + RegistryResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryResponse_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + RegistryResponse.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.catalog.protos.RegistryResponse.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventmeshCatalogGrpc.internal_static_eventmesh_catalog_api_protocol_RegistryResponse_descriptor; + } + + @Override + public RegistryResponse getDefaultInstanceForType() { + return RegistryResponse.getDefaultInstance(); + } + + @Override + public RegistryResponse build() { + RegistryResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public RegistryResponse buildPartial() { + RegistryResponse result = new RegistryResponse(this); + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof RegistryResponse) { + return mergeFrom((RegistryResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(RegistryResponse other) { + if (other.equals(RegistryResponse.getDefaultInstance())) { + return this; + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + RegistryResponse parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (RegistryResponse) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.catalog.api.protocol.RegistryResponse) + } + + // @@protoc_insertion_point(class_scope:eventmesh.catalog.api.protocol.RegistryResponse) + private static final RegistryResponse DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new RegistryResponse(); + } + + public static RegistryResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public RegistryResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new RegistryResponse(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public RegistryResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryResponseOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryResponseOrBuilder.java new file mode 100644 index 0000000000..a0d8f0520c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/catalog/protos/RegistryResponseOrBuilder.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: catalog.proto + +package org.apache.eventmesh.common.protocol.catalog.protos; + +@SuppressWarnings({"all"}) +public interface RegistryResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.catalog.api.protocol.RegistryResponse) + com.google.protobuf.MessageOrBuilder { +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/AdminServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/AdminServiceGrpc.java new file mode 100644 index 0000000000..df5f3ef338 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/AdminServiceGrpc.java @@ -0,0 +1,373 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.adminserver; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + * AdminServiceGrpc + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.40.0)", + comments = "Source: event_mesh_admin_service.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class AdminServiceGrpc { + + private AdminServiceGrpc() { + } + + public static final String SERVICE_NAME = "AdminService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getInvokeBiStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "invokeBiStream", + requestType = Payload.class, + responseType = Payload.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getInvokeBiStreamMethod() { + io.grpc.MethodDescriptor getInvokeBiStreamMethod; + if ((getInvokeBiStreamMethod = AdminServiceGrpc.getInvokeBiStreamMethod) == null) { + synchronized (AdminServiceGrpc.class) { + if ((getInvokeBiStreamMethod = AdminServiceGrpc.getInvokeBiStreamMethod) == null) { + AdminServiceGrpc.getInvokeBiStreamMethod = getInvokeBiStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "invokeBiStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + Payload.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + Payload.getDefaultInstance())) + .setSchemaDescriptor(new AdminServiceMethodDescriptorSupplier("invokeBiStream")) + .build(); + } + } + } + return getInvokeBiStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getInvokeMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "invoke", + requestType = Payload.class, + responseType = Payload.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getInvokeMethod() { + io.grpc.MethodDescriptor getInvokeMethod; + if ((getInvokeMethod = AdminServiceGrpc.getInvokeMethod) == null) { + synchronized (AdminServiceGrpc.class) { + if ((getInvokeMethod = AdminServiceGrpc.getInvokeMethod) == null) { + AdminServiceGrpc.getInvokeMethod = getInvokeMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "invoke")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + Payload.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + Payload.getDefaultInstance())) + .setSchemaDescriptor(new AdminServiceMethodDescriptorSupplier("invoke")) + .build(); + } + } + } + return getInvokeMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static AdminServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public AdminServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AdminServiceStub(channel, callOptions); + } + }; + return AdminServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static AdminServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public AdminServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AdminServiceBlockingStub(channel, callOptions); + } + }; + return AdminServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static AdminServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public AdminServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AdminServiceFutureStub(channel, callOptions); + } + }; + return AdminServiceFutureStub.newStub(factory, channel); + } + + /** + * + */ + public static abstract class AdminServiceImplBase implements io.grpc.BindableService { + + /** + * + */ + public io.grpc.stub.StreamObserver invokeBiStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getInvokeBiStreamMethod(), responseObserver); + } + + /** + * + */ + public void invoke(Payload request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getInvokeMethod(), responseObserver); + } + + @Override + public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getInvokeBiStreamMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + Payload, + Payload>( + this, METHODID_INVOKE_BI_STREAM))) + .addMethod( + getInvokeMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + Payload, + Payload>( + this, METHODID_INVOKE))) + .build(); + } + } + + /** + * + */ + public static final class AdminServiceStub extends io.grpc.stub.AbstractAsyncStub { + + private AdminServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected AdminServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AdminServiceStub(channel, callOptions); + } + + /** + * + */ + public io.grpc.stub.StreamObserver invokeBiStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getInvokeBiStreamMethod(), getCallOptions()), responseObserver); + } + + /** + * + */ + public void invoke(Payload request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getInvokeMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * + */ + public static final class AdminServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + + private AdminServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected AdminServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AdminServiceBlockingStub(channel, callOptions); + } + + /** + * + */ + public Payload invoke(Payload request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getInvokeMethod(), getCallOptions(), request); + } + } + + /** + * + */ + public static final class AdminServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + + private AdminServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected AdminServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AdminServiceFutureStub(channel, callOptions); + } + + /** + * + */ + public com.google.common.util.concurrent.ListenableFuture invoke( + Payload request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getInvokeMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_INVOKE = 0; + private static final int METHODID_INVOKE_BI_STREAM = 1; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + + private final AdminServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(AdminServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_INVOKE: + serviceImpl.invoke((Payload) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_INVOKE_BI_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.invokeBiStream( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class AdminServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + + AdminServiceBaseDescriptorSupplier() { + } + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventMeshAdminService.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("AdminService"); + } + } + + private static final class AdminServiceFileDescriptorSupplier + extends AdminServiceBaseDescriptorSupplier { + + AdminServiceFileDescriptorSupplier() { + } + } + + private static final class AdminServiceMethodDescriptorSupplier + extends AdminServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + + private final String methodName; + + AdminServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (AdminServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new AdminServiceFileDescriptorSupplier()) + .addMethod(getInvokeBiStreamMethod()) + .addMethod(getInvokeMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/EventMeshAdminService.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/EventMeshAdminService.java new file mode 100644 index 0000000000..d67ed4159a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/EventMeshAdminService.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.adminserver;// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: event_mesh_admin_service.proto + +public final class EventMeshAdminService { + + private EventMeshAdminService() { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + + static final com.google.protobuf.Descriptors.Descriptor + internal_static_Metadata_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_Metadata_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_Metadata_HeadersEntry_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_Metadata_HeadersEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_Payload_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_Payload_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + + static { + String[] descriptorData = { + "\n\036event_mesh_admin_service.proto\032\031google" + + "/protobuf/any.proto\"q\n\010Metadata\022\014\n\004type\030" + + "\003 \001(\t\022\'\n\007headers\030\007 \003(\0132\026.Metadata.Header" + + "sEntry\032.\n\014HeadersEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005v" + + "alue\030\002 \001(\t:\0028\001\"4\n\007Payload\022\033\n\010metadata\030\002 " + + "\001(\0132\t.Metadata\022\014\n\004body\030\003 \001(\0142Z\n\014AdminSer" + + "vice\022*\n\016invokeBiStream\022\010.Payload\032\010.Paylo" + + "ad\"\000(\0010\001\022\036\n\006invoke\022\010.Payload\032\010.Payload\"\000" + + "B\002P\001b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.protobuf.AnyProto.getDescriptor(), + }); + internal_static_Metadata_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_Metadata_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_Metadata_descriptor, + new String[] {"Type", "Headers",}); + internal_static_Metadata_HeadersEntry_descriptor = + internal_static_Metadata_descriptor.getNestedTypes().get(0); + internal_static_Metadata_HeadersEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_Metadata_HeadersEntry_descriptor, + new String[] {"Key", "Value",}); + internal_static_Payload_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_Payload_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_Payload_descriptor, + new String[] {"Metadata", "Body",}); + com.google.protobuf.AnyProto.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/Metadata.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/Metadata.java new file mode 100644 index 0000000000..f25754f288 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/Metadata.java @@ -0,0 +1,962 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.adminserver;// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: event_mesh_admin_service.proto + +/** + * Protobuf type {@code Metadata} + */ +public final class Metadata extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:Metadata) + MetadataOrBuilder { + + private static final long serialVersionUID = 0L; + + // Use Metadata.newBuilder() to construct. + private Metadata(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private Metadata() { + type_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new Metadata(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private Metadata( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 26: { + String s = input.readStringRequireUtf8(); + + type_ = s; + break; + } + case 58: { + if (!((mutable_bitField0_ & 0x00000001) != 0)) { + headers_ = com.google.protobuf.MapField.newMapField( + HeadersDefaultEntryHolder.defaultEntry); + mutable_bitField0_ |= 0x00000001; + } + com.google.protobuf.MapEntry + headers__ = input.readMessage( + HeadersDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + headers_.getMutableMap().put( + headers__.getKey(), headers__.getValue()); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshAdminService.internal_static_Metadata_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @Override + protected com.google.protobuf.MapField internalGetMapField( + int number) { + switch (number) { + case 7: + return internalGetHeaders(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + + @Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshAdminService.internal_static_Metadata_fieldAccessorTable + .ensureFieldAccessorsInitialized( + Metadata.class, Builder.class); + } + + public static final int TYPE_FIELD_NUMBER = 3; + private volatile Object type_; + + /** + * string type = 3; + * + * @return The type. + */ + @Override + public String getType() { + Object ref = type_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + type_ = s; + return s; + } + } + + /** + * string type = 3; + * + * @return The bytes for type. + */ + @Override + public com.google.protobuf.ByteString + getTypeBytes() { + Object ref = type_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HEADERS_FIELD_NUMBER = 7; + + private static final class HeadersDefaultEntryHolder { + + static final com.google.protobuf.MapEntry< + String, String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + EventMeshAdminService.internal_static_Metadata_HeadersEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + + private com.google.protobuf.MapField< + String, String> headers_; + + private com.google.protobuf.MapField + internalGetHeaders() { + if (headers_ == null) { + return com.google.protobuf.MapField.emptyMapField( + HeadersDefaultEntryHolder.defaultEntry); + } + return headers_; + } + + public int getHeadersCount() { + return internalGetHeaders().getMap().size(); + } + + /** + * map<string, string> headers = 7; + */ + + @Override + public boolean containsHeaders( + String key) { + if (key == null) { + throw new NullPointerException(); + } + return internalGetHeaders().getMap().containsKey(key); + } + + /** + * Use {@link #getHeadersMap()} instead. + */ + @Override + @Deprecated + public java.util.Map getHeaders() { + return getHeadersMap(); + } + + /** + * map<string, string> headers = 7; + */ + @Override + + public java.util.Map getHeadersMap() { + return internalGetHeaders().getMap(); + } + + /** + * map<string, string> headers = 7; + */ + @Override + + public String getHeadersOrDefault( + String key, + String defaultValue) { + if (key == null) { + throw new NullPointerException(); + } + java.util.Map map = + internalGetHeaders().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + + /** + * map<string, string> headers = 7; + */ + @Override + + public String getHeadersOrThrow( + String key) { + if (key == null) { + throw new NullPointerException(); + } + java.util.Map map = + internalGetHeaders().getMap(); + if (!map.containsKey(key)) { + throw new IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getTypeBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, type_); + } + com.google.protobuf.GeneratedMessageV3 + .serializeStringMapTo( + output, + internalGetHeaders(), + HeadersDefaultEntryHolder.defaultEntry, + 7); + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!getTypeBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, type_); + } + for (java.util.Map.Entry entry + : internalGetHeaders().getMap().entrySet()) { + com.google.protobuf.MapEntry + headers__ = HeadersDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, headers__); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Metadata)) { + return super.equals(obj); + } + Metadata other = (Metadata) obj; + + if (!getType() + .equals(other.getType())) { + return false; + } + if (!internalGetHeaders().equals( + other.internalGetHeaders())) { + return false; + } + if (!unknownFields.equals(other.unknownFields)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + getType().hashCode(); + if (!internalGetHeaders().getMap().isEmpty()) { + hash = (37 * hash) + HEADERS_FIELD_NUMBER; + hash = (53 * hash) + internalGetHeaders().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static Metadata parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Metadata parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Metadata parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Metadata parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Metadata parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Metadata parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Metadata parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static Metadata parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static Metadata parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static Metadata parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static Metadata parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static Metadata parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(Metadata prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code Metadata} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:Metadata) + MetadataOrBuilder { + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshAdminService.internal_static_Metadata_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapField internalGetMapField( + int number) { + switch (number) { + case 7: + return internalGetHeaders(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapField internalGetMutableMapField( + int number) { + switch (number) { + case 7: + return internalGetMutableHeaders(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + + @Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshAdminService.internal_static_Metadata_fieldAccessorTable + .ensureFieldAccessorsInitialized( + Metadata.class, Builder.class); + } + + // Construct using Metadata.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + type_ = ""; + + internalGetMutableHeaders().clear(); + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventMeshAdminService.internal_static_Metadata_descriptor; + } + + @Override + public Metadata getDefaultInstanceForType() { + return Metadata.getDefaultInstance(); + } + + @Override + public Metadata build() { + Metadata result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public Metadata buildPartial() { + Metadata result = new Metadata(this); + int from_bitField0_ = bitField0_; + result.type_ = type_; + result.headers_ = internalGetHeaders(); + result.headers_.makeImmutable(); + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof Metadata) { + return mergeFrom((Metadata) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(Metadata other) { + if (other == Metadata.getDefaultInstance()) { + return this; + } + if (!other.getType().isEmpty()) { + type_ = other.type_; + onChanged(); + } + internalGetMutableHeaders().mergeFrom( + other.internalGetHeaders()); + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Metadata parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (Metadata) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int bitField0_; + + private Object type_ = ""; + + /** + * string type = 3; + * + * @return The type. + */ + public String getType() { + Object ref = type_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + type_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + * string type = 3; + * + * @return The bytes for type. + */ + public com.google.protobuf.ByteString + getTypeBytes() { + Object ref = type_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string type = 3; + * + * @param value The type to set. + * @return This builder for chaining. + */ + public Builder setType( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + type_ = value; + onChanged(); + return this; + } + + /** + * string type = 3; + * + * @return This builder for chaining. + */ + public Builder clearType() { + + type_ = getDefaultInstance().getType(); + onChanged(); + return this; + } + + /** + * string type = 3; + * + * @param value The bytes for type to set. + * @return This builder for chaining. + */ + public Builder setTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + type_ = value; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + String, String> headers_; + + private com.google.protobuf.MapField + internalGetHeaders() { + if (headers_ == null) { + return com.google.protobuf.MapField.emptyMapField( + HeadersDefaultEntryHolder.defaultEntry); + } + return headers_; + } + + private com.google.protobuf.MapField + internalGetMutableHeaders() { + onChanged(); + ; + if (headers_ == null) { + headers_ = com.google.protobuf.MapField.newMapField( + HeadersDefaultEntryHolder.defaultEntry); + } + if (!headers_.isMutable()) { + headers_ = headers_.copy(); + } + return headers_; + } + + public int getHeadersCount() { + return internalGetHeaders().getMap().size(); + } + + /** + * map<string, string> headers = 7; + */ + + @Override + public boolean containsHeaders( + String key) { + if (key == null) { + throw new NullPointerException(); + } + return internalGetHeaders().getMap().containsKey(key); + } + + /** + * Use {@link #getHeadersMap()} instead. + */ + @Override + @Deprecated + public java.util.Map getHeaders() { + return getHeadersMap(); + } + + /** + * map<string, string> headers = 7; + */ + @Override + + public java.util.Map getHeadersMap() { + return internalGetHeaders().getMap(); + } + + /** + * map<string, string> headers = 7; + */ + @Override + + public String getHeadersOrDefault( + String key, + String defaultValue) { + if (key == null) { + throw new NullPointerException(); + } + java.util.Map map = + internalGetHeaders().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + + /** + * map<string, string> headers = 7; + */ + @Override + + public String getHeadersOrThrow( + String key) { + if (key == null) { + throw new NullPointerException(); + } + java.util.Map map = + internalGetHeaders().getMap(); + if (!map.containsKey(key)) { + throw new IllegalArgumentException(); + } + return map.get(key); + } + + public Builder clearHeaders() { + internalGetMutableHeaders().getMutableMap() + .clear(); + return this; + } + + /** + * map<string, string> headers = 7; + */ + + public Builder removeHeaders( + String key) { + if (key == null) { + throw new NullPointerException(); + } + internalGetMutableHeaders().getMutableMap() + .remove(key); + return this; + } + + /** + * Use alternate mutation accessors instead. + */ + @Deprecated + public java.util.Map + getMutableHeaders() { + return internalGetMutableHeaders().getMutableMap(); + } + + /** + * map<string, string> headers = 7; + */ + public Builder putHeaders( + String key, + String value) { + if (key == null) { + throw new NullPointerException(); + } + if (value == null) { + throw new NullPointerException(); + } + internalGetMutableHeaders().getMutableMap() + .put(key, value); + return this; + } + + /** + * map<string, string> headers = 7; + */ + + public Builder putAllHeaders( + java.util.Map values) { + internalGetMutableHeaders().getMutableMap() + .putAll(values); + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:Metadata) + } + + // @@protoc_insertion_point(class_scope:Metadata) + private static final Metadata DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new Metadata(); + } + + public static Metadata getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public Metadata parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Metadata(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public Metadata getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/MetadataOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/MetadataOrBuilder.java new file mode 100644 index 0000000000..7afef491f8 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/MetadataOrBuilder.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.adminserver;// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: event_mesh_admin_service.proto + +public interface MetadataOrBuilder extends + // @@protoc_insertion_point(interface_extends:Metadata) + com.google.protobuf.MessageOrBuilder { + + /** + * string type = 3; + * + * @return The type. + */ + String getType(); + + /** + * string type = 3; + * + * @return The bytes for type. + */ + com.google.protobuf.ByteString + getTypeBytes(); + + /** + * map<string, string> headers = 7; + */ + int getHeadersCount(); + + /** + * map<string, string> headers = 7; + */ + boolean containsHeaders( + String key); + + /** + * Use {@link #getHeadersMap()} instead. + */ + @Deprecated + java.util.Map + getHeaders(); + + /** + * map<string, string> headers = 7; + */ + java.util.Map + getHeadersMap(); + + /** + * map<string, string> headers = 7; + */ + + String getHeadersOrDefault( + String key, + String defaultValue); + + /** + * map<string, string> headers = 7; + */ + + String getHeadersOrThrow( + String key); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/Payload.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/Payload.java new file mode 100644 index 0000000000..a0067099a0 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/Payload.java @@ -0,0 +1,893 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.adminserver;// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: event_mesh_admin_service.proto + +/** + * Protobuf type {@code Payload} + */ +public final class Payload extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:Payload) + PayloadOrBuilder { + + private static final long serialVersionUID = 0L; + + // Use Payload.newBuilder() to construct. + private Payload(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private Payload() { + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new Payload(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private Payload( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 18: { + Metadata.Builder subBuilder = null; + if (metadata_ != null) { + subBuilder = metadata_.toBuilder(); + } + metadata_ = input.readMessage(Metadata.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(metadata_); + metadata_ = subBuilder.buildPartial(); + } + + break; + } + case 26: { + com.google.protobuf.Any.Builder subBuilder = null; + if (body_ != null) { + subBuilder = body_.toBuilder(); + } + body_ = input.readMessage(com.google.protobuf.Any.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(body_); + body_ = subBuilder.buildPartial(); + } + + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshAdminService.internal_static_Payload_descriptor; + } + + @Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshAdminService.internal_static_Payload_fieldAccessorTable + .ensureFieldAccessorsInitialized( + Payload.class, Builder.class); + } + + public static final int METADATA_FIELD_NUMBER = 2; + private Metadata metadata_; + + /** + * .Metadata metadata = 2; + * + * @return Whether the metadata field is set. + */ + @Override + public boolean hasMetadata() { + return metadata_ != null; + } + + /** + * .Metadata metadata = 2; + * + * @return The metadata. + */ + @Override + public Metadata getMetadata() { + return metadata_ == null ? Metadata.getDefaultInstance() : metadata_; + } + + /** + * .Metadata metadata = 2; + */ + @Override + public MetadataOrBuilder getMetadataOrBuilder() { + return getMetadata(); + } + + public static final int BODY_FIELD_NUMBER = 3; + private com.google.protobuf.Any body_; + + /** + * .google.protobuf.Any body = 3; + * + * @return Whether the body field is set. + */ + @Override + public boolean hasBody() { + return body_ != null; + } + + /** + * .google.protobuf.Any body = 3; + * + * @return The body. + */ + @Override + public com.google.protobuf.Any getBody() { + return body_ == null ? com.google.protobuf.Any.getDefaultInstance() : body_; + } + + /** + * .google.protobuf.Any body = 3; + */ + @Override + public com.google.protobuf.AnyOrBuilder getBodyOrBuilder() { + return getBody(); + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (metadata_ != null) { + output.writeMessage(2, getMetadata()); + } + if (body_ != null) { + output.writeMessage(3, getBody()); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (metadata_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, getMetadata()); + } + if (body_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getBody()); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Payload)) { + return super.equals(obj); + } + Payload other = (Payload) obj; + + if (hasMetadata() != other.hasMetadata()) { + return false; + } + if (hasMetadata()) { + if (!getMetadata() + .equals(other.getMetadata())) { + return false; + } + } + if (hasBody() != other.hasBody()) { + return false; + } + if (hasBody()) { + if (!getBody() + .equals(other.getBody())) { + return false; + } + } + if (!unknownFields.equals(other.unknownFields)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasMetadata()) { + hash = (37 * hash) + METADATA_FIELD_NUMBER; + hash = (53 * hash) + getMetadata().hashCode(); + } + if (hasBody()) { + hash = (37 * hash) + BODY_FIELD_NUMBER; + hash = (53 * hash) + getBody().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static Payload parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Payload parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Payload parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Payload parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Payload parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static Payload parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static Payload parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static Payload parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static Payload parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static Payload parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static Payload parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static Payload parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(Payload prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code Payload} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:Payload) + PayloadOrBuilder { + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshAdminService.internal_static_Payload_descriptor; + } + + @Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshAdminService.internal_static_Payload_fieldAccessorTable + .ensureFieldAccessorsInitialized( + Payload.class, Builder.class); + } + + // Construct using Payload.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + if (metadataBuilder_ == null) { + metadata_ = null; + } else { + metadata_ = null; + metadataBuilder_ = null; + } + if (bodyBuilder_ == null) { + body_ = null; + } else { + body_ = null; + bodyBuilder_ = null; + } + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventMeshAdminService.internal_static_Payload_descriptor; + } + + @Override + public Payload getDefaultInstanceForType() { + return Payload.getDefaultInstance(); + } + + @Override + public Payload build() { + Payload result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public Payload buildPartial() { + Payload result = new Payload(this); + if (metadataBuilder_ == null) { + result.metadata_ = metadata_; + } else { + result.metadata_ = metadataBuilder_.build(); + } + if (bodyBuilder_ == null) { + result.body_ = body_; + } else { + result.body_ = bodyBuilder_.build(); + } + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof Payload) { + return mergeFrom((Payload) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(Payload other) { + if (other == Payload.getDefaultInstance()) { + return this; + } + if (other.hasMetadata()) { + mergeMetadata(other.getMetadata()); + } + if (other.hasBody()) { + mergeBody(other.getBody()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Payload parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (Payload) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private Metadata metadata_; + private com.google.protobuf.SingleFieldBuilderV3< + Metadata, Metadata.Builder, MetadataOrBuilder> metadataBuilder_; + + /** + * .Metadata metadata = 2; + * + * @return Whether the metadata field is set. + */ + public boolean hasMetadata() { + return metadataBuilder_ != null || metadata_ != null; + } + + /** + * .Metadata metadata = 2; + * + * @return The metadata. + */ + public Metadata getMetadata() { + if (metadataBuilder_ == null) { + return metadata_ == null ? Metadata.getDefaultInstance() : metadata_; + } else { + return metadataBuilder_.getMessage(); + } + } + + /** + * .Metadata metadata = 2; + */ + public Builder setMetadata(Metadata value) { + if (metadataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + metadata_ = value; + onChanged(); + } else { + metadataBuilder_.setMessage(value); + } + + return this; + } + + /** + * .Metadata metadata = 2; + */ + public Builder setMetadata( + Metadata.Builder builderForValue) { + if (metadataBuilder_ == null) { + metadata_ = builderForValue.build(); + onChanged(); + } else { + metadataBuilder_.setMessage(builderForValue.build()); + } + + return this; + } + + /** + * .Metadata metadata = 2; + */ + public Builder mergeMetadata(Metadata value) { + if (metadataBuilder_ == null) { + if (metadata_ != null) { + metadata_ = + Metadata.newBuilder(metadata_).mergeFrom(value).buildPartial(); + } else { + metadata_ = value; + } + onChanged(); + } else { + metadataBuilder_.mergeFrom(value); + } + + return this; + } + + /** + * .Metadata metadata = 2; + */ + public Builder clearMetadata() { + if (metadataBuilder_ == null) { + metadata_ = null; + onChanged(); + } else { + metadata_ = null; + metadataBuilder_ = null; + } + + return this; + } + + /** + * .Metadata metadata = 2; + */ + public Metadata.Builder getMetadataBuilder() { + + onChanged(); + return getMetadataFieldBuilder().getBuilder(); + } + + /** + * .Metadata metadata = 2; + */ + public MetadataOrBuilder getMetadataOrBuilder() { + if (metadataBuilder_ != null) { + return metadataBuilder_.getMessageOrBuilder(); + } else { + return metadata_ == null ? + Metadata.getDefaultInstance() : metadata_; + } + } + + /** + * .Metadata metadata = 2; + */ + private com.google.protobuf.SingleFieldBuilderV3< + Metadata, Metadata.Builder, MetadataOrBuilder> + getMetadataFieldBuilder() { + if (metadataBuilder_ == null) { + metadataBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + Metadata, Metadata.Builder, MetadataOrBuilder>( + getMetadata(), + getParentForChildren(), + isClean()); + metadata_ = null; + } + return metadataBuilder_; + } + + private com.google.protobuf.Any body_; + private com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> bodyBuilder_; + + /** + * .google.protobuf.Any body = 3; + * + * @return Whether the body field is set. + */ + public boolean hasBody() { + return bodyBuilder_ != null || body_ != null; + } + + /** + * .google.protobuf.Any body = 3; + * + * @return The body. + */ + public com.google.protobuf.Any getBody() { + if (bodyBuilder_ == null) { + return body_ == null ? com.google.protobuf.Any.getDefaultInstance() : body_; + } else { + return bodyBuilder_.getMessage(); + } + } + + /** + * .google.protobuf.Any body = 3; + */ + public Builder setBody(com.google.protobuf.Any value) { + if (bodyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + body_ = value; + onChanged(); + } else { + bodyBuilder_.setMessage(value); + } + + return this; + } + + /** + * .google.protobuf.Any body = 3; + */ + public Builder setBody( + com.google.protobuf.Any.Builder builderForValue) { + if (bodyBuilder_ == null) { + body_ = builderForValue.build(); + onChanged(); + } else { + bodyBuilder_.setMessage(builderForValue.build()); + } + + return this; + } + + /** + * .google.protobuf.Any body = 3; + */ + public Builder mergeBody(com.google.protobuf.Any value) { + if (bodyBuilder_ == null) { + if (body_ != null) { + body_ = + com.google.protobuf.Any.newBuilder(body_).mergeFrom(value).buildPartial(); + } else { + body_ = value; + } + onChanged(); + } else { + bodyBuilder_.mergeFrom(value); + } + + return this; + } + + /** + * .google.protobuf.Any body = 3; + */ + public Builder clearBody() { + if (bodyBuilder_ == null) { + body_ = null; + onChanged(); + } else { + body_ = null; + bodyBuilder_ = null; + } + + return this; + } + + /** + * .google.protobuf.Any body = 3; + */ + public com.google.protobuf.Any.Builder getBodyBuilder() { + + onChanged(); + return getBodyFieldBuilder().getBuilder(); + } + + /** + * .google.protobuf.Any body = 3; + */ + public com.google.protobuf.AnyOrBuilder getBodyOrBuilder() { + if (bodyBuilder_ != null) { + return bodyBuilder_.getMessageOrBuilder(); + } else { + return body_ == null ? + com.google.protobuf.Any.getDefaultInstance() : body_; + } + } + + /** + * .google.protobuf.Any body = 3; + */ + private com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> + getBodyFieldBuilder() { + if (bodyBuilder_ == null) { + bodyBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder>( + getBody(), + getParentForChildren(), + isClean()); + body_ = null; + } + return bodyBuilder_; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:Payload) + } + + // @@protoc_insertion_point(class_scope:Payload) + private static final Payload DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new Payload(); + } + + public static Payload getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public Payload parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Payload(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public Payload getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/PayloadOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/PayloadOrBuilder.java new file mode 100644 index 0000000000..a50a340e1b --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/adminserver/PayloadOrBuilder.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.adminserver;// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: event_mesh_admin_service.proto + +public interface PayloadOrBuilder extends + // @@protoc_insertion_point(interface_extends:Payload) + com.google.protobuf.MessageOrBuilder { + + /** + * .Metadata metadata = 2; + * + * @return Whether the metadata field is set. + */ + boolean hasMetadata(); + + /** + * .Metadata metadata = 2; + * + * @return The metadata. + */ + Metadata getMetadata(); + + /** + * .Metadata metadata = 2; + */ + MetadataOrBuilder getMetadataOrBuilder(); + + /** + * .google.protobuf.Any body = 3; + * + * @return Whether the body field is set. + */ + boolean hasBody(); + + /** + * .google.protobuf.Any body = 3; + * + * @return The body. + */ + com.google.protobuf.Any getBody(); + + /** + * .google.protobuf.Any body = 3; + */ + com.google.protobuf.AnyOrBuilder getBodyOrBuilder(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEvent.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEvent.java new file mode 100644 index 0000000000..f04108f397 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEvent.java @@ -0,0 +1,3567 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: eventmesh-cloudevents.proto + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +/** + * Protobuf type {@code org.apache.eventmesh.cloudevents.v1.CloudEvent} + */ +public final class CloudEvent extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:org.apache.eventmesh.cloudevents.v1.CloudEvent) + CloudEventOrBuilder { +private static final long serialVersionUID = 0L; + // Use CloudEvent.newBuilder() to construct. + private CloudEvent(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private CloudEvent() { + id_ = ""; + source_ = ""; + specVersion_ = ""; + type_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new CloudEvent(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private CloudEvent( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + String s = input.readStringRequireUtf8(); + + id_ = s; + break; + } + case 18: { + String s = input.readStringRequireUtf8(); + + source_ = s; + break; + } + case 26: { + String s = input.readStringRequireUtf8(); + + specVersion_ = s; + break; + } + case 34: { + String s = input.readStringRequireUtf8(); + + type_ = s; + break; + } + case 42: { + if (!((mutable_bitField0_ & 0x00000001) != 0)) { + attributes_ = com.google.protobuf.MapField.newMapField( + AttributesDefaultEntryHolder.defaultEntry); + mutable_bitField0_ |= 0x00000001; + } + com.google.protobuf.MapEntry + attributes__ = input.readMessage( + AttributesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + attributes_.getMutableMap().put( + attributes__.getKey(), attributes__.getValue()); + break; + } + case 50: { + data_ = input.readBytes(); + dataCase_ = 6; + break; + } + case 58: { + String s = input.readStringRequireUtf8(); + dataCase_ = 7; + data_ = s; + break; + } + case 66: { + com.google.protobuf.Any.Builder subBuilder = null; + if (dataCase_ == 8) { + subBuilder = ((com.google.protobuf.Any) data_).toBuilder(); + } + data_ = + input.readMessage(com.google.protobuf.Any.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((com.google.protobuf.Any) data_); + data_ = subBuilder.buildPartial(); + } + dataCase_ = 8; + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @Override + protected com.google.protobuf.MapField internalGetMapField( + int number) { + switch (number) { + case 5: + return internalGetAttributes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + CloudEvent.class, Builder.class); + } + + public interface CloudEventAttributeValueOrBuilder extends + // @@protoc_insertion_point(interface_extends:org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue) + com.google.protobuf.MessageOrBuilder { + + /** + * bool ce_boolean = 1; + * @return Whether the ceBoolean field is set. + */ + boolean hasCeBoolean(); + /** + * bool ce_boolean = 1; + * @return The ceBoolean. + */ + boolean getCeBoolean(); + + /** + * int32 ce_integer = 2; + * @return Whether the ceInteger field is set. + */ + boolean hasCeInteger(); + /** + * int32 ce_integer = 2; + * @return The ceInteger. + */ + int getCeInteger(); + + /** + * string ce_string = 3; + * @return Whether the ceString field is set. + */ + boolean hasCeString(); + /** + * string ce_string = 3; + * @return The ceString. + */ + String getCeString(); + /** + * string ce_string = 3; + * @return The bytes for ceString. + */ + com.google.protobuf.ByteString + getCeStringBytes(); + + /** + * bytes ce_bytes = 4; + * @return Whether the ceBytes field is set. + */ + boolean hasCeBytes(); + /** + * bytes ce_bytes = 4; + * @return The ceBytes. + */ + com.google.protobuf.ByteString getCeBytes(); + + /** + * string ce_uri = 5; + * @return Whether the ceUri field is set. + */ + boolean hasCeUri(); + /** + * string ce_uri = 5; + * @return The ceUri. + */ + String getCeUri(); + /** + * string ce_uri = 5; + * @return The bytes for ceUri. + */ + com.google.protobuf.ByteString + getCeUriBytes(); + + /** + * string ce_uri_ref = 6; + * @return Whether the ceUriRef field is set. + */ + boolean hasCeUriRef(); + /** + * string ce_uri_ref = 6; + * @return The ceUriRef. + */ + String getCeUriRef(); + /** + * string ce_uri_ref = 6; + * @return The bytes for ceUriRef. + */ + com.google.protobuf.ByteString + getCeUriRefBytes(); + + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + * @return Whether the ceTimestamp field is set. + */ + boolean hasCeTimestamp(); + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + * @return The ceTimestamp. + */ + com.google.protobuf.Timestamp getCeTimestamp(); + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + com.google.protobuf.TimestampOrBuilder getCeTimestampOrBuilder(); + + public CloudEventAttributeValue.AttrCase getAttrCase(); + } + /** + * Protobuf type {@code org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue} + */ + public static final class CloudEventAttributeValue extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue) + CloudEventAttributeValueOrBuilder { + private static final long serialVersionUID = 0L; + // Use CloudEventAttributeValue.newBuilder() to construct. + private CloudEventAttributeValue(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private CloudEventAttributeValue() { + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new CloudEventAttributeValue(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private CloudEventAttributeValue( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + attr_ = input.readBool(); + attrCase_ = 1; + break; + } + case 16: { + attr_ = input.readInt32(); + attrCase_ = 2; + break; + } + case 26: { + String s = input.readStringRequireUtf8(); + attrCase_ = 3; + attr_ = s; + break; + } + case 34: { + attr_ = input.readBytes(); + attrCase_ = 4; + break; + } + case 42: { + String s = input.readStringRequireUtf8(); + attrCase_ = 5; + attr_ = s; + break; + } + case 50: { + String s = input.readStringRequireUtf8(); + attrCase_ = 6; + attr_ = s; + break; + } + case 58: { + com.google.protobuf.Timestamp.Builder subBuilder = null; + if (attrCase_ == 7) { + subBuilder = ((com.google.protobuf.Timestamp) attr_).toBuilder(); + } + attr_ = + input.readMessage(com.google.protobuf.Timestamp.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((com.google.protobuf.Timestamp) attr_); + attr_ = subBuilder.buildPartial(); + } + attrCase_ = 7; + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_fieldAccessorTable + .ensureFieldAccessorsInitialized( + CloudEventAttributeValue.class, Builder.class); + } + + private int attrCase_ = 0; + private Object attr_; + public enum AttrCase + implements com.google.protobuf.Internal.EnumLite, + InternalOneOfEnum { + CE_BOOLEAN(1), + CE_INTEGER(2), + CE_STRING(3), + CE_BYTES(4), + CE_URI(5), + CE_URI_REF(6), + CE_TIMESTAMP(7), + ATTR_NOT_SET(0); + private final int value; + private AttrCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @Deprecated + public static AttrCase valueOf(int value) { + return forNumber(value); + } + + public static AttrCase forNumber(int value) { + switch (value) { + case 1: return CE_BOOLEAN; + case 2: return CE_INTEGER; + case 3: return CE_STRING; + case 4: return CE_BYTES; + case 5: return CE_URI; + case 6: return CE_URI_REF; + case 7: return CE_TIMESTAMP; + case 0: return ATTR_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public AttrCase + getAttrCase() { + return AttrCase.forNumber( + attrCase_); + } + + public static final int CE_BOOLEAN_FIELD_NUMBER = 1; + /** + * bool ce_boolean = 1; + * @return Whether the ceBoolean field is set. + */ + @Override + public boolean hasCeBoolean() { + return attrCase_ == 1; + } + /** + * bool ce_boolean = 1; + * @return The ceBoolean. + */ + @Override + public boolean getCeBoolean() { + if (attrCase_ == 1) { + return (Boolean) attr_; + } + return false; + } + + public static final int CE_INTEGER_FIELD_NUMBER = 2; + /** + * int32 ce_integer = 2; + * @return Whether the ceInteger field is set. + */ + @Override + public boolean hasCeInteger() { + return attrCase_ == 2; + } + /** + * int32 ce_integer = 2; + * @return The ceInteger. + */ + @Override + public int getCeInteger() { + if (attrCase_ == 2) { + return (Integer) attr_; + } + return 0; + } + + public static final int CE_STRING_FIELD_NUMBER = 3; + /** + * string ce_string = 3; + * @return Whether the ceString field is set. + */ + public boolean hasCeString() { + return attrCase_ == 3; + } + /** + * string ce_string = 3; + * @return The ceString. + */ + public String getCeString() { + Object ref = ""; + if (attrCase_ == 3) { + ref = attr_; + } + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (attrCase_ == 3) { + attr_ = s; + } + return s; + } + } + /** + * string ce_string = 3; + * @return The bytes for ceString. + */ + public com.google.protobuf.ByteString + getCeStringBytes() { + Object ref = ""; + if (attrCase_ == 3) { + ref = attr_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (attrCase_ == 3) { + attr_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CE_BYTES_FIELD_NUMBER = 4; + /** + * bytes ce_bytes = 4; + * @return Whether the ceBytes field is set. + */ + @Override + public boolean hasCeBytes() { + return attrCase_ == 4; + } + /** + * bytes ce_bytes = 4; + * @return The ceBytes. + */ + @Override + public com.google.protobuf.ByteString getCeBytes() { + if (attrCase_ == 4) { + return (com.google.protobuf.ByteString) attr_; + } + return com.google.protobuf.ByteString.EMPTY; + } + + public static final int CE_URI_FIELD_NUMBER = 5; + /** + * string ce_uri = 5; + * @return Whether the ceUri field is set. + */ + public boolean hasCeUri() { + return attrCase_ == 5; + } + /** + * string ce_uri = 5; + * @return The ceUri. + */ + public String getCeUri() { + Object ref = ""; + if (attrCase_ == 5) { + ref = attr_; + } + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (attrCase_ == 5) { + attr_ = s; + } + return s; + } + } + /** + * string ce_uri = 5; + * @return The bytes for ceUri. + */ + public com.google.protobuf.ByteString + getCeUriBytes() { + Object ref = ""; + if (attrCase_ == 5) { + ref = attr_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (attrCase_ == 5) { + attr_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CE_URI_REF_FIELD_NUMBER = 6; + /** + * string ce_uri_ref = 6; + * @return Whether the ceUriRef field is set. + */ + public boolean hasCeUriRef() { + return attrCase_ == 6; + } + /** + * string ce_uri_ref = 6; + * @return The ceUriRef. + */ + public String getCeUriRef() { + Object ref = ""; + if (attrCase_ == 6) { + ref = attr_; + } + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (attrCase_ == 6) { + attr_ = s; + } + return s; + } + } + /** + * string ce_uri_ref = 6; + * @return The bytes for ceUriRef. + */ + public com.google.protobuf.ByteString + getCeUriRefBytes() { + Object ref = ""; + if (attrCase_ == 6) { + ref = attr_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (attrCase_ == 6) { + attr_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CE_TIMESTAMP_FIELD_NUMBER = 7; + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + * @return Whether the ceTimestamp field is set. + */ + @Override + public boolean hasCeTimestamp() { + return attrCase_ == 7; + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + * @return The ceTimestamp. + */ + @Override + public com.google.protobuf.Timestamp getCeTimestamp() { + if (attrCase_ == 7) { + return (com.google.protobuf.Timestamp) attr_; + } + return com.google.protobuf.Timestamp.getDefaultInstance(); + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + @Override + public com.google.protobuf.TimestampOrBuilder getCeTimestampOrBuilder() { + if (attrCase_ == 7) { + return (com.google.protobuf.Timestamp) attr_; + } + return com.google.protobuf.Timestamp.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (attrCase_ == 1) { + output.writeBool( + 1, (boolean)((Boolean) attr_)); + } + if (attrCase_ == 2) { + output.writeInt32( + 2, (int)((Integer) attr_)); + } + if (attrCase_ == 3) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, attr_); + } + if (attrCase_ == 4) { + output.writeBytes( + 4, (com.google.protobuf.ByteString) attr_); + } + if (attrCase_ == 5) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, attr_); + } + if (attrCase_ == 6) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 6, attr_); + } + if (attrCase_ == 7) { + output.writeMessage(7, (com.google.protobuf.Timestamp) attr_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (attrCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize( + 1, (boolean)((Boolean) attr_)); + } + if (attrCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size( + 2, (int)((Integer) attr_)); + } + if (attrCase_ == 3) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, attr_); + } + if (attrCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize( + 4, (com.google.protobuf.ByteString) attr_); + } + if (attrCase_ == 5) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, attr_); + } + if (attrCase_ == 6) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, attr_); + } + if (attrCase_ == 7) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, (com.google.protobuf.Timestamp) attr_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof CloudEventAttributeValue)) { + return super.equals(obj); + } + CloudEventAttributeValue other = (CloudEventAttributeValue) obj; + + if (!getAttrCase().equals(other.getAttrCase())) return false; + switch (attrCase_) { + case 1: + if (getCeBoolean() + != other.getCeBoolean()) return false; + break; + case 2: + if (getCeInteger() + != other.getCeInteger()) return false; + break; + case 3: + if (!getCeString() + .equals(other.getCeString())) return false; + break; + case 4: + if (!getCeBytes() + .equals(other.getCeBytes())) return false; + break; + case 5: + if (!getCeUri() + .equals(other.getCeUri())) return false; + break; + case 6: + if (!getCeUriRef() + .equals(other.getCeUriRef())) return false; + break; + case 7: + if (!getCeTimestamp() + .equals(other.getCeTimestamp())) return false; + break; + case 0: + default: + } + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (attrCase_) { + case 1: + hash = (37 * hash) + CE_BOOLEAN_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getCeBoolean()); + break; + case 2: + hash = (37 * hash) + CE_INTEGER_FIELD_NUMBER; + hash = (53 * hash) + getCeInteger(); + break; + case 3: + hash = (37 * hash) + CE_STRING_FIELD_NUMBER; + hash = (53 * hash) + getCeString().hashCode(); + break; + case 4: + hash = (37 * hash) + CE_BYTES_FIELD_NUMBER; + hash = (53 * hash) + getCeBytes().hashCode(); + break; + case 5: + hash = (37 * hash) + CE_URI_FIELD_NUMBER; + hash = (53 * hash) + getCeUri().hashCode(); + break; + case 6: + hash = (37 * hash) + CE_URI_REF_FIELD_NUMBER; + hash = (53 * hash) + getCeUriRef().hashCode(); + break; + case 7: + hash = (37 * hash) + CE_TIMESTAMP_FIELD_NUMBER; + hash = (53 * hash) + getCeTimestamp().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static CloudEventAttributeValue parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEventAttributeValue parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEventAttributeValue parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEventAttributeValue parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEventAttributeValue parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEventAttributeValue parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEventAttributeValue parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static CloudEventAttributeValue parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static CloudEventAttributeValue parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static CloudEventAttributeValue parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static CloudEventAttributeValue parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static CloudEventAttributeValue parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(CloudEventAttributeValue prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue) + CloudEventAttributeValueOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_fieldAccessorTable + .ensureFieldAccessorsInitialized( + CloudEventAttributeValue.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @Override + public Builder clear() { + super.clear(); + attrCase_ = 0; + attr_ = null; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_descriptor; + } + + @Override + public CloudEventAttributeValue getDefaultInstanceForType() { + return CloudEventAttributeValue.getDefaultInstance(); + } + + @Override + public CloudEventAttributeValue build() { + CloudEventAttributeValue result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public CloudEventAttributeValue buildPartial() { + CloudEventAttributeValue result = new CloudEventAttributeValue(this); + if (attrCase_ == 1) { + result.attr_ = attr_; + } + if (attrCase_ == 2) { + result.attr_ = attr_; + } + if (attrCase_ == 3) { + result.attr_ = attr_; + } + if (attrCase_ == 4) { + result.attr_ = attr_; + } + if (attrCase_ == 5) { + result.attr_ = attr_; + } + if (attrCase_ == 6) { + result.attr_ = attr_; + } + if (attrCase_ == 7) { + if (ceTimestampBuilder_ == null) { + result.attr_ = attr_; + } else { + result.attr_ = ceTimestampBuilder_.build(); + } + } + result.attrCase_ = attrCase_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof CloudEventAttributeValue) { + return mergeFrom((CloudEventAttributeValue)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(CloudEventAttributeValue other) { + if (other == CloudEventAttributeValue.getDefaultInstance()) return this; + switch (other.getAttrCase()) { + case CE_BOOLEAN: { + setCeBoolean(other.getCeBoolean()); + break; + } + case CE_INTEGER: { + setCeInteger(other.getCeInteger()); + break; + } + case CE_STRING: { + attrCase_ = 3; + attr_ = other.attr_; + onChanged(); + break; + } + case CE_BYTES: { + setCeBytes(other.getCeBytes()); + break; + } + case CE_URI: { + attrCase_ = 5; + attr_ = other.attr_; + onChanged(); + break; + } + case CE_URI_REF: { + attrCase_ = 6; + attr_ = other.attr_; + onChanged(); + break; + } + case CE_TIMESTAMP: { + mergeCeTimestamp(other.getCeTimestamp()); + break; + } + case ATTR_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + CloudEventAttributeValue parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (CloudEventAttributeValue) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int attrCase_ = 0; + private Object attr_; + public AttrCase + getAttrCase() { + return AttrCase.forNumber( + attrCase_); + } + + public Builder clearAttr() { + attrCase_ = 0; + attr_ = null; + onChanged(); + return this; + } + + + /** + * bool ce_boolean = 1; + * @return Whether the ceBoolean field is set. + */ + public boolean hasCeBoolean() { + return attrCase_ == 1; + } + /** + * bool ce_boolean = 1; + * @return The ceBoolean. + */ + public boolean getCeBoolean() { + if (attrCase_ == 1) { + return (Boolean) attr_; + } + return false; + } + /** + * bool ce_boolean = 1; + * @param value The ceBoolean to set. + * @return This builder for chaining. + */ + public Builder setCeBoolean(boolean value) { + attrCase_ = 1; + attr_ = value; + onChanged(); + return this; + } + /** + * bool ce_boolean = 1; + * @return This builder for chaining. + */ + public Builder clearCeBoolean() { + if (attrCase_ == 1) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + return this; + } + + /** + * int32 ce_integer = 2; + * @return Whether the ceInteger field is set. + */ + public boolean hasCeInteger() { + return attrCase_ == 2; + } + /** + * int32 ce_integer = 2; + * @return The ceInteger. + */ + public int getCeInteger() { + if (attrCase_ == 2) { + return (Integer) attr_; + } + return 0; + } + /** + * int32 ce_integer = 2; + * @param value The ceInteger to set. + * @return This builder for chaining. + */ + public Builder setCeInteger(int value) { + attrCase_ = 2; + attr_ = value; + onChanged(); + return this; + } + /** + * int32 ce_integer = 2; + * @return This builder for chaining. + */ + public Builder clearCeInteger() { + if (attrCase_ == 2) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + return this; + } + + /** + * string ce_string = 3; + * @return Whether the ceString field is set. + */ + @Override + public boolean hasCeString() { + return attrCase_ == 3; + } + /** + * string ce_string = 3; + * @return The ceString. + */ + @Override + public String getCeString() { + Object ref = ""; + if (attrCase_ == 3) { + ref = attr_; + } + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (attrCase_ == 3) { + attr_ = s; + } + return s; + } else { + return (String) ref; + } + } + /** + * string ce_string = 3; + * @return The bytes for ceString. + */ + @Override + public com.google.protobuf.ByteString + getCeStringBytes() { + Object ref = ""; + if (attrCase_ == 3) { + ref = attr_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (attrCase_ == 3) { + attr_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string ce_string = 3; + * @param value The ceString to set. + * @return This builder for chaining. + */ + public Builder setCeString( + String value) { + if (value == null) { + throw new NullPointerException(); + } + attrCase_ = 3; + attr_ = value; + onChanged(); + return this; + } + /** + * string ce_string = 3; + * @return This builder for chaining. + */ + public Builder clearCeString() { + if (attrCase_ == 3) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + return this; + } + /** + * string ce_string = 3; + * @param value The bytes for ceString to set. + * @return This builder for chaining. + */ + public Builder setCeStringBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + attrCase_ = 3; + attr_ = value; + onChanged(); + return this; + } + + /** + * bytes ce_bytes = 4; + * @return Whether the ceBytes field is set. + */ + public boolean hasCeBytes() { + return attrCase_ == 4; + } + /** + * bytes ce_bytes = 4; + * @return The ceBytes. + */ + public com.google.protobuf.ByteString getCeBytes() { + if (attrCase_ == 4) { + return (com.google.protobuf.ByteString) attr_; + } + return com.google.protobuf.ByteString.EMPTY; + } + /** + * bytes ce_bytes = 4; + * @param value The ceBytes to set. + * @return This builder for chaining. + */ + public Builder setCeBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + attrCase_ = 4; + attr_ = value; + onChanged(); + return this; + } + /** + * bytes ce_bytes = 4; + * @return This builder for chaining. + */ + public Builder clearCeBytes() { + if (attrCase_ == 4) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + return this; + } + + /** + * string ce_uri = 5; + * @return Whether the ceUri field is set. + */ + @Override + public boolean hasCeUri() { + return attrCase_ == 5; + } + /** + * string ce_uri = 5; + * @return The ceUri. + */ + @Override + public String getCeUri() { + Object ref = ""; + if (attrCase_ == 5) { + ref = attr_; + } + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (attrCase_ == 5) { + attr_ = s; + } + return s; + } else { + return (String) ref; + } + } + /** + * string ce_uri = 5; + * @return The bytes for ceUri. + */ + @Override + public com.google.protobuf.ByteString + getCeUriBytes() { + Object ref = ""; + if (attrCase_ == 5) { + ref = attr_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (attrCase_ == 5) { + attr_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string ce_uri = 5; + * @param value The ceUri to set. + * @return This builder for chaining. + */ + public Builder setCeUri( + String value) { + if (value == null) { + throw new NullPointerException(); + } + attrCase_ = 5; + attr_ = value; + onChanged(); + return this; + } + /** + * string ce_uri = 5; + * @return This builder for chaining. + */ + public Builder clearCeUri() { + if (attrCase_ == 5) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + return this; + } + /** + * string ce_uri = 5; + * @param value The bytes for ceUri to set. + * @return This builder for chaining. + */ + public Builder setCeUriBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + attrCase_ = 5; + attr_ = value; + onChanged(); + return this; + } + + /** + * string ce_uri_ref = 6; + * @return Whether the ceUriRef field is set. + */ + @Override + public boolean hasCeUriRef() { + return attrCase_ == 6; + } + /** + * string ce_uri_ref = 6; + * @return The ceUriRef. + */ + @Override + public String getCeUriRef() { + Object ref = ""; + if (attrCase_ == 6) { + ref = attr_; + } + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (attrCase_ == 6) { + attr_ = s; + } + return s; + } else { + return (String) ref; + } + } + /** + * string ce_uri_ref = 6; + * @return The bytes for ceUriRef. + */ + @Override + public com.google.protobuf.ByteString + getCeUriRefBytes() { + Object ref = ""; + if (attrCase_ == 6) { + ref = attr_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (attrCase_ == 6) { + attr_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string ce_uri_ref = 6; + * @param value The ceUriRef to set. + * @return This builder for chaining. + */ + public Builder setCeUriRef( + String value) { + if (value == null) { + throw new NullPointerException(); + } + attrCase_ = 6; + attr_ = value; + onChanged(); + return this; + } + /** + * string ce_uri_ref = 6; + * @return This builder for chaining. + */ + public Builder clearCeUriRef() { + if (attrCase_ == 6) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + return this; + } + /** + * string ce_uri_ref = 6; + * @param value The bytes for ceUriRef to set. + * @return This builder for chaining. + */ + public Builder setCeUriRefBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + attrCase_ = 6; + attr_ = value; + onChanged(); + return this; + } + + private com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> ceTimestampBuilder_; + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + * @return Whether the ceTimestamp field is set. + */ + @Override + public boolean hasCeTimestamp() { + return attrCase_ == 7; + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + * @return The ceTimestamp. + */ + @Override + public com.google.protobuf.Timestamp getCeTimestamp() { + if (ceTimestampBuilder_ == null) { + if (attrCase_ == 7) { + return (com.google.protobuf.Timestamp) attr_; + } + return com.google.protobuf.Timestamp.getDefaultInstance(); + } else { + if (attrCase_ == 7) { + return ceTimestampBuilder_.getMessage(); + } + return com.google.protobuf.Timestamp.getDefaultInstance(); + } + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + public Builder setCeTimestamp(com.google.protobuf.Timestamp value) { + if (ceTimestampBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + attr_ = value; + onChanged(); + } else { + ceTimestampBuilder_.setMessage(value); + } + attrCase_ = 7; + return this; + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + public Builder setCeTimestamp( + com.google.protobuf.Timestamp.Builder builderForValue) { + if (ceTimestampBuilder_ == null) { + attr_ = builderForValue.build(); + onChanged(); + } else { + ceTimestampBuilder_.setMessage(builderForValue.build()); + } + attrCase_ = 7; + return this; + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + public Builder mergeCeTimestamp(com.google.protobuf.Timestamp value) { + if (ceTimestampBuilder_ == null) { + if (attrCase_ == 7 && + attr_ != com.google.protobuf.Timestamp.getDefaultInstance()) { + attr_ = com.google.protobuf.Timestamp.newBuilder((com.google.protobuf.Timestamp) attr_) + .mergeFrom(value).buildPartial(); + } else { + attr_ = value; + } + onChanged(); + } else { + if (attrCase_ == 7) { + ceTimestampBuilder_.mergeFrom(value); + } else { + ceTimestampBuilder_.setMessage(value); + } + } + attrCase_ = 7; + return this; + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + public Builder clearCeTimestamp() { + if (ceTimestampBuilder_ == null) { + if (attrCase_ == 7) { + attrCase_ = 0; + attr_ = null; + onChanged(); + } + } else { + if (attrCase_ == 7) { + attrCase_ = 0; + attr_ = null; + } + ceTimestampBuilder_.clear(); + } + return this; + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + public com.google.protobuf.Timestamp.Builder getCeTimestampBuilder() { + return getCeTimestampFieldBuilder().getBuilder(); + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + @Override + public com.google.protobuf.TimestampOrBuilder getCeTimestampOrBuilder() { + if ((attrCase_ == 7) && (ceTimestampBuilder_ != null)) { + return ceTimestampBuilder_.getMessageOrBuilder(); + } else { + if (attrCase_ == 7) { + return (com.google.protobuf.Timestamp) attr_; + } + return com.google.protobuf.Timestamp.getDefaultInstance(); + } + } + /** + * .google.protobuf.Timestamp ce_timestamp = 7; + */ + private com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder> + getCeTimestampFieldBuilder() { + if (ceTimestampBuilder_ == null) { + if (!(attrCase_ == 7)) { + attr_ = com.google.protobuf.Timestamp.getDefaultInstance(); + } + ceTimestampBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Timestamp, com.google.protobuf.Timestamp.Builder, com.google.protobuf.TimestampOrBuilder>( + (com.google.protobuf.Timestamp) attr_, + getParentForChildren(), + isClean()); + attr_ = null; + } + attrCase_ = 7; + onChanged();; + return ceTimestampBuilder_; + } + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue) + } + + // @@protoc_insertion_point(class_scope:org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue) + private static final CloudEventAttributeValue DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new CloudEventAttributeValue(); + } + + public static CloudEventAttributeValue getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public CloudEventAttributeValue parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new CloudEventAttributeValue(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public CloudEventAttributeValue getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private int dataCase_ = 0; + private Object data_; + public enum DataCase + implements com.google.protobuf.Internal.EnumLite, + InternalOneOfEnum { + BINARY_DATA(6), + TEXT_DATA(7), + PROTO_DATA(8), + DATA_NOT_SET(0); + private final int value; + private DataCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @Deprecated + public static DataCase valueOf(int value) { + return forNumber(value); + } + + public static DataCase forNumber(int value) { + switch (value) { + case 6: return BINARY_DATA; + case 7: return TEXT_DATA; + case 8: return PROTO_DATA; + case 0: return DATA_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public DataCase + getDataCase() { + return DataCase.forNumber( + dataCase_); + } + + public static final int ID_FIELD_NUMBER = 1; + private volatile Object id_; + /** + *
+   * Required Attributes
+   * 
+ * + * string id = 1; + * @return The id. + */ + @Override + public String getId() { + Object ref = id_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + *
+   * Required Attributes
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + @Override + public com.google.protobuf.ByteString + getIdBytes() { + Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SOURCE_FIELD_NUMBER = 2; + private volatile Object source_; + /** + *
+   * URI-reference
+   * 
+ * + * string source = 2; + * @return The source. + */ + @Override + public String getSource() { + Object ref = source_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + source_ = s; + return s; + } + } + /** + *
+   * URI-reference
+   * 
+ * + * string source = 2; + * @return The bytes for source. + */ + @Override + public com.google.protobuf.ByteString + getSourceBytes() { + Object ref = source_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + source_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int SPEC_VERSION_FIELD_NUMBER = 3; + private volatile Object specVersion_; + /** + * string spec_version = 3; + * @return The specVersion. + */ + @Override + public String getSpecVersion() { + Object ref = specVersion_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + specVersion_ = s; + return s; + } + } + /** + * string spec_version = 3; + * @return The bytes for specVersion. + */ + @Override + public com.google.protobuf.ByteString + getSpecVersionBytes() { + Object ref = specVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + specVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TYPE_FIELD_NUMBER = 4; + private volatile Object type_; + /** + * string type = 4; + * @return The type. + */ + @Override + public String getType() { + Object ref = type_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + type_ = s; + return s; + } + } + /** + * string type = 4; + * @return The bytes for type. + */ + @Override + public com.google.protobuf.ByteString + getTypeBytes() { + Object ref = type_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ATTRIBUTES_FIELD_NUMBER = 5; + private static final class AttributesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + String, CloudEventAttributeValue> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_AttributesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.MESSAGE, + CloudEventAttributeValue.getDefaultInstance()); + } + private com.google.protobuf.MapField< + String, CloudEventAttributeValue> attributes_; + private com.google.protobuf.MapField + internalGetAttributes() { + if (attributes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + AttributesDefaultEntryHolder.defaultEntry); + } + return attributes_; + } + + public int getAttributesCount() { + return internalGetAttributes().getMap().size(); + } + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + + @Override + public boolean containsAttributes( + String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetAttributes().getMap().containsKey(key); + } + /** + * Use {@link #getAttributesMap()} instead. + */ + @Override + @Deprecated + public java.util.Map getAttributes() { + return getAttributesMap(); + } + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + @Override + + public java.util.Map getAttributesMap() { + return internalGetAttributes().getMap(); + } + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + @Override + + public CloudEventAttributeValue getAttributesOrDefault( + String key, + CloudEventAttributeValue defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetAttributes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + @Override + + public CloudEventAttributeValue getAttributesOrThrow( + String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetAttributes().getMap(); + if (!map.containsKey(key)) { + throw new IllegalArgumentException(); + } + return map.get(key); + } + + public static final int BINARY_DATA_FIELD_NUMBER = 6; + /** + * bytes binary_data = 6; + * @return Whether the binaryData field is set. + */ + @Override + public boolean hasBinaryData() { + return dataCase_ == 6; + } + /** + * bytes binary_data = 6; + * @return The binaryData. + */ + @Override + public com.google.protobuf.ByteString getBinaryData() { + if (dataCase_ == 6) { + return (com.google.protobuf.ByteString) data_; + } + return com.google.protobuf.ByteString.EMPTY; + } + + public static final int TEXT_DATA_FIELD_NUMBER = 7; + /** + * string text_data = 7; + * @return Whether the textData field is set. + */ + public boolean hasTextData() { + return dataCase_ == 7; + } + /** + * string text_data = 7; + * @return The textData. + */ + public String getTextData() { + Object ref = ""; + if (dataCase_ == 7) { + ref = data_; + } + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (dataCase_ == 7) { + data_ = s; + } + return s; + } + } + /** + * string text_data = 7; + * @return The bytes for textData. + */ + public com.google.protobuf.ByteString + getTextDataBytes() { + Object ref = ""; + if (dataCase_ == 7) { + ref = data_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (dataCase_ == 7) { + data_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PROTO_DATA_FIELD_NUMBER = 8; + /** + * .google.protobuf.Any proto_data = 8; + * @return Whether the protoData field is set. + */ + @Override + public boolean hasProtoData() { + return dataCase_ == 8; + } + /** + * .google.protobuf.Any proto_data = 8; + * @return The protoData. + */ + @Override + public com.google.protobuf.Any getProtoData() { + if (dataCase_ == 8) { + return (com.google.protobuf.Any) data_; + } + return com.google.protobuf.Any.getDefaultInstance(); + } + /** + * .google.protobuf.Any proto_data = 8; + */ + @Override + public com.google.protobuf.AnyOrBuilder getProtoDataOrBuilder() { + if (dataCase_ == 8) { + return (com.google.protobuf.Any) data_; + } + return com.google.protobuf.Any.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(source_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, source_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(specVersion_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, specVersion_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(type_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, type_); + } + com.google.protobuf.GeneratedMessageV3 + .serializeStringMapTo( + output, + internalGetAttributes(), + AttributesDefaultEntryHolder.defaultEntry, + 5); + if (dataCase_ == 6) { + output.writeBytes( + 6, (com.google.protobuf.ByteString) data_); + } + if (dataCase_ == 7) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 7, data_); + } + if (dataCase_ == 8) { + output.writeMessage(8, (com.google.protobuf.Any) data_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(source_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, source_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(specVersion_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, specVersion_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(type_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, type_); + } + for (java.util.Map.Entry entry + : internalGetAttributes().getMap().entrySet()) { + com.google.protobuf.MapEntry + attributes__ = AttributesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, attributes__); + } + if (dataCase_ == 6) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize( + 6, (com.google.protobuf.ByteString) data_); + } + if (dataCase_ == 7) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, data_); + } + if (dataCase_ == 8) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(8, (com.google.protobuf.Any) data_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof CloudEvent)) { + return super.equals(obj); + } + CloudEvent other = (CloudEvent) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getSource() + .equals(other.getSource())) return false; + if (!getSpecVersion() + .equals(other.getSpecVersion())) return false; + if (!getType() + .equals(other.getType())) return false; + if (!internalGetAttributes().equals( + other.internalGetAttributes())) return false; + if (!getDataCase().equals(other.getDataCase())) return false; + switch (dataCase_) { + case 6: + if (!getBinaryData() + .equals(other.getBinaryData())) return false; + break; + case 7: + if (!getTextData() + .equals(other.getTextData())) return false; + break; + case 8: + if (!getProtoData() + .equals(other.getProtoData())) return false; + break; + case 0: + default: + } + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + SOURCE_FIELD_NUMBER; + hash = (53 * hash) + getSource().hashCode(); + hash = (37 * hash) + SPEC_VERSION_FIELD_NUMBER; + hash = (53 * hash) + getSpecVersion().hashCode(); + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + getType().hashCode(); + if (!internalGetAttributes().getMap().isEmpty()) { + hash = (37 * hash) + ATTRIBUTES_FIELD_NUMBER; + hash = (53 * hash) + internalGetAttributes().hashCode(); + } + switch (dataCase_) { + case 6: + hash = (37 * hash) + BINARY_DATA_FIELD_NUMBER; + hash = (53 * hash) + getBinaryData().hashCode(); + break; + case 7: + hash = (37 * hash) + TEXT_DATA_FIELD_NUMBER; + hash = (53 * hash) + getTextData().hashCode(); + break; + case 8: + hash = (37 * hash) + PROTO_DATA_FIELD_NUMBER; + hash = (53 * hash) + getProtoData().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static CloudEvent parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEvent parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEvent parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEvent parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEvent parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEvent parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEvent parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static CloudEvent parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static CloudEvent parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static CloudEvent parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static CloudEvent parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static CloudEvent parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(CloudEvent prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code org.apache.eventmesh.cloudevents.v1.CloudEvent} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:org.apache.eventmesh.cloudevents.v1.CloudEvent) + CloudEventOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapField internalGetMapField( + int number) { + switch (number) { + case 5: + return internalGetAttributes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapField internalGetMutableMapField( + int number) { + switch (number) { + case 5: + return internalGetMutableAttributes(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_fieldAccessorTable + .ensureFieldAccessorsInitialized( + CloudEvent.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @Override + public Builder clear() { + super.clear(); + id_ = ""; + + source_ = ""; + + specVersion_ = ""; + + type_ = ""; + + internalGetMutableAttributes().clear(); + dataCase_ = 0; + data_ = null; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor; + } + + @Override + public CloudEvent getDefaultInstanceForType() { + return CloudEvent.getDefaultInstance(); + } + + @Override + public CloudEvent build() { + CloudEvent result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public CloudEvent buildPartial() { + CloudEvent result = new CloudEvent(this); + int from_bitField0_ = bitField0_; + result.id_ = id_; + result.source_ = source_; + result.specVersion_ = specVersion_; + result.type_ = type_; + result.attributes_ = internalGetAttributes(); + result.attributes_.makeImmutable(); + if (dataCase_ == 6) { + result.data_ = data_; + } + if (dataCase_ == 7) { + result.data_ = data_; + } + if (dataCase_ == 8) { + if (protoDataBuilder_ == null) { + result.data_ = data_; + } else { + result.data_ = protoDataBuilder_.build(); + } + } + result.dataCase_ = dataCase_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof CloudEvent) { + return mergeFrom((CloudEvent)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(CloudEvent other) { + if (other == CloudEvent.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + onChanged(); + } + if (!other.getSource().isEmpty()) { + source_ = other.source_; + onChanged(); + } + if (!other.getSpecVersion().isEmpty()) { + specVersion_ = other.specVersion_; + onChanged(); + } + if (!other.getType().isEmpty()) { + type_ = other.type_; + onChanged(); + } + internalGetMutableAttributes().mergeFrom( + other.internalGetAttributes()); + switch (other.getDataCase()) { + case BINARY_DATA: { + setBinaryData(other.getBinaryData()); + break; + } + case TEXT_DATA: { + dataCase_ = 7; + data_ = other.data_; + onChanged(); + break; + } + case PROTO_DATA: { + mergeProtoData(other.getProtoData()); + break; + } + case DATA_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + CloudEvent parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (CloudEvent) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int dataCase_ = 0; + private Object data_; + public DataCase + getDataCase() { + return DataCase.forNumber( + dataCase_); + } + + public Builder clearData() { + dataCase_ = 0; + data_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private Object id_ = ""; + /** + *
+     * Required Attributes
+     * 
+ * + * string id = 1; + * @return The id. + */ + public String getId() { + Object ref = id_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (String) ref; + } + } + /** + *
+     * Required Attributes
+     * 
+ * + * string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * Required Attributes
+     * 
+ * + * string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + id_ = value; + onChanged(); + return this; + } + /** + *
+     * Required Attributes
+     * 
+ * + * string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + + id_ = getDefaultInstance().getId(); + onChanged(); + return this; + } + /** + *
+     * Required Attributes
+     * 
+ * + * string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + id_ = value; + onChanged(); + return this; + } + + private Object source_ = ""; + /** + *
+     * URI-reference
+     * 
+ * + * string source = 2; + * @return The source. + */ + public String getSource() { + Object ref = source_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + source_ = s; + return s; + } else { + return (String) ref; + } + } + /** + *
+     * URI-reference
+     * 
+ * + * string source = 2; + * @return The bytes for source. + */ + public com.google.protobuf.ByteString + getSourceBytes() { + Object ref = source_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + source_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * URI-reference
+     * 
+ * + * string source = 2; + * @param value The source to set. + * @return This builder for chaining. + */ + public Builder setSource( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + source_ = value; + onChanged(); + return this; + } + /** + *
+     * URI-reference
+     * 
+ * + * string source = 2; + * @return This builder for chaining. + */ + public Builder clearSource() { + + source_ = getDefaultInstance().getSource(); + onChanged(); + return this; + } + /** + *
+     * URI-reference
+     * 
+ * + * string source = 2; + * @param value The bytes for source to set. + * @return This builder for chaining. + */ + public Builder setSourceBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + source_ = value; + onChanged(); + return this; + } + + private Object specVersion_ = ""; + /** + * string spec_version = 3; + * @return The specVersion. + */ + public String getSpecVersion() { + Object ref = specVersion_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + specVersion_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string spec_version = 3; + * @return The bytes for specVersion. + */ + public com.google.protobuf.ByteString + getSpecVersionBytes() { + Object ref = specVersion_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + specVersion_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string spec_version = 3; + * @param value The specVersion to set. + * @return This builder for chaining. + */ + public Builder setSpecVersion( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + specVersion_ = value; + onChanged(); + return this; + } + /** + * string spec_version = 3; + * @return This builder for chaining. + */ + public Builder clearSpecVersion() { + + specVersion_ = getDefaultInstance().getSpecVersion(); + onChanged(); + return this; + } + /** + * string spec_version = 3; + * @param value The bytes for specVersion to set. + * @return This builder for chaining. + */ + public Builder setSpecVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + specVersion_ = value; + onChanged(); + return this; + } + + private Object type_ = ""; + /** + * string type = 4; + * @return The type. + */ + public String getType() { + Object ref = type_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + type_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string type = 4; + * @return The bytes for type. + */ + public com.google.protobuf.ByteString + getTypeBytes() { + Object ref = type_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string type = 4; + * @param value The type to set. + * @return This builder for chaining. + */ + public Builder setType( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + type_ = value; + onChanged(); + return this; + } + /** + * string type = 4; + * @return This builder for chaining. + */ + public Builder clearType() { + + type_ = getDefaultInstance().getType(); + onChanged(); + return this; + } + /** + * string type = 4; + * @param value The bytes for type to set. + * @return This builder for chaining. + */ + public Builder setTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + type_ = value; + onChanged(); + return this; + } + + private com.google.protobuf.MapField< + String, CloudEventAttributeValue> attributes_; + private com.google.protobuf.MapField + internalGetAttributes() { + if (attributes_ == null) { + return com.google.protobuf.MapField.emptyMapField( + AttributesDefaultEntryHolder.defaultEntry); + } + return attributes_; + } + private com.google.protobuf.MapField + internalGetMutableAttributes() { + onChanged();; + if (attributes_ == null) { + attributes_ = com.google.protobuf.MapField.newMapField( + AttributesDefaultEntryHolder.defaultEntry); + } + if (!attributes_.isMutable()) { + attributes_ = attributes_.copy(); + } + return attributes_; + } + + public int getAttributesCount() { + return internalGetAttributes().getMap().size(); + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + + @Override + public boolean containsAttributes( + String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetAttributes().getMap().containsKey(key); + } + /** + * Use {@link #getAttributesMap()} instead. + */ + @Override + @Deprecated + public java.util.Map getAttributes() { + return getAttributesMap(); + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + @Override + + public java.util.Map getAttributesMap() { + return internalGetAttributes().getMap(); + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + @Override + + public CloudEventAttributeValue getAttributesOrDefault( + String key, + CloudEventAttributeValue defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetAttributes().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + @Override + + public CloudEventAttributeValue getAttributesOrThrow( + String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetAttributes().getMap(); + if (!map.containsKey(key)) { + throw new IllegalArgumentException(); + } + return map.get(key); + } + + public Builder clearAttributes() { + internalGetMutableAttributes().getMutableMap() + .clear(); + return this; + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + + public Builder removeAttributes( + String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableAttributes().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @Deprecated + public java.util.Map + getMutableAttributes() { + return internalGetMutableAttributes().getMutableMap(); + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + public Builder putAttributes( + String key, + CloudEventAttributeValue value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { + throw new NullPointerException("map value"); +} + + internalGetMutableAttributes().getMutableMap() + .put(key, value); + return this; + } + /** + *
+     * Optional & Extension Attributes
+     * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + + public Builder putAllAttributes( + java.util.Map values) { + internalGetMutableAttributes().getMutableMap() + .putAll(values); + return this; + } + + /** + * bytes binary_data = 6; + * @return Whether the binaryData field is set. + */ + public boolean hasBinaryData() { + return dataCase_ == 6; + } + /** + * bytes binary_data = 6; + * @return The binaryData. + */ + public com.google.protobuf.ByteString getBinaryData() { + if (dataCase_ == 6) { + return (com.google.protobuf.ByteString) data_; + } + return com.google.protobuf.ByteString.EMPTY; + } + /** + * bytes binary_data = 6; + * @param value The binaryData to set. + * @return This builder for chaining. + */ + public Builder setBinaryData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + dataCase_ = 6; + data_ = value; + onChanged(); + return this; + } + /** + * bytes binary_data = 6; + * @return This builder for chaining. + */ + public Builder clearBinaryData() { + if (dataCase_ == 6) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + return this; + } + + /** + * string text_data = 7; + * @return Whether the textData field is set. + */ + @Override + public boolean hasTextData() { + return dataCase_ == 7; + } + /** + * string text_data = 7; + * @return The textData. + */ + @Override + public String getTextData() { + Object ref = ""; + if (dataCase_ == 7) { + ref = data_; + } + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (dataCase_ == 7) { + data_ = s; + } + return s; + } else { + return (String) ref; + } + } + /** + * string text_data = 7; + * @return The bytes for textData. + */ + @Override + public com.google.protobuf.ByteString + getTextDataBytes() { + Object ref = ""; + if (dataCase_ == 7) { + ref = data_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + if (dataCase_ == 7) { + data_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string text_data = 7; + * @param value The textData to set. + * @return This builder for chaining. + */ + public Builder setTextData( + String value) { + if (value == null) { + throw new NullPointerException(); + } + dataCase_ = 7; + data_ = value; + onChanged(); + return this; + } + /** + * string text_data = 7; + * @return This builder for chaining. + */ + public Builder clearTextData() { + if (dataCase_ == 7) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + return this; + } + /** + * string text_data = 7; + * @param value The bytes for textData to set. + * @return This builder for chaining. + */ + public Builder setTextDataBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + dataCase_ = 7; + data_ = value; + onChanged(); + return this; + } + + private com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> protoDataBuilder_; + /** + * .google.protobuf.Any proto_data = 8; + * @return Whether the protoData field is set. + */ + @Override + public boolean hasProtoData() { + return dataCase_ == 8; + } + /** + * .google.protobuf.Any proto_data = 8; + * @return The protoData. + */ + @Override + public com.google.protobuf.Any getProtoData() { + if (protoDataBuilder_ == null) { + if (dataCase_ == 8) { + return (com.google.protobuf.Any) data_; + } + return com.google.protobuf.Any.getDefaultInstance(); + } else { + if (dataCase_ == 8) { + return protoDataBuilder_.getMessage(); + } + return com.google.protobuf.Any.getDefaultInstance(); + } + } + /** + * .google.protobuf.Any proto_data = 8; + */ + public Builder setProtoData(com.google.protobuf.Any value) { + if (protoDataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + onChanged(); + } else { + protoDataBuilder_.setMessage(value); + } + dataCase_ = 8; + return this; + } + /** + * .google.protobuf.Any proto_data = 8; + */ + public Builder setProtoData( + com.google.protobuf.Any.Builder builderForValue) { + if (protoDataBuilder_ == null) { + data_ = builderForValue.build(); + onChanged(); + } else { + protoDataBuilder_.setMessage(builderForValue.build()); + } + dataCase_ = 8; + return this; + } + /** + * .google.protobuf.Any proto_data = 8; + */ + public Builder mergeProtoData(com.google.protobuf.Any value) { + if (protoDataBuilder_ == null) { + if (dataCase_ == 8 && + data_ != com.google.protobuf.Any.getDefaultInstance()) { + data_ = com.google.protobuf.Any.newBuilder((com.google.protobuf.Any) data_) + .mergeFrom(value).buildPartial(); + } else { + data_ = value; + } + onChanged(); + } else { + if (dataCase_ == 8) { + protoDataBuilder_.mergeFrom(value); + } else { + protoDataBuilder_.setMessage(value); + } + } + dataCase_ = 8; + return this; + } + /** + * .google.protobuf.Any proto_data = 8; + */ + public Builder clearProtoData() { + if (protoDataBuilder_ == null) { + if (dataCase_ == 8) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + } else { + if (dataCase_ == 8) { + dataCase_ = 0; + data_ = null; + } + protoDataBuilder_.clear(); + } + return this; + } + /** + * .google.protobuf.Any proto_data = 8; + */ + public com.google.protobuf.Any.Builder getProtoDataBuilder() { + return getProtoDataFieldBuilder().getBuilder(); + } + /** + * .google.protobuf.Any proto_data = 8; + */ + @Override + public com.google.protobuf.AnyOrBuilder getProtoDataOrBuilder() { + if ((dataCase_ == 8) && (protoDataBuilder_ != null)) { + return protoDataBuilder_.getMessageOrBuilder(); + } else { + if (dataCase_ == 8) { + return (com.google.protobuf.Any) data_; + } + return com.google.protobuf.Any.getDefaultInstance(); + } + } + /** + * .google.protobuf.Any proto_data = 8; + */ + private com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> + getProtoDataFieldBuilder() { + if (protoDataBuilder_ == null) { + if (!(dataCase_ == 8)) { + data_ = com.google.protobuf.Any.getDefaultInstance(); + } + protoDataBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder>( + (com.google.protobuf.Any) data_, + getParentForChildren(), + isClean()); + data_ = null; + } + dataCase_ = 8; + onChanged();; + return protoDataBuilder_; + } + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:org.apache.eventmesh.cloudevents.v1.CloudEvent) + } + + // @@protoc_insertion_point(class_scope:org.apache.eventmesh.cloudevents.v1.CloudEvent) + private static final CloudEvent DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new CloudEvent(); + } + + public static CloudEvent getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public CloudEvent parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new CloudEvent(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public CloudEvent getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventBatch.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventBatch.java new file mode 100644 index 0000000000..5d541ec974 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventBatch.java @@ -0,0 +1,789 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: eventmesh-cloudevents.proto + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +/** + * Protobuf type {@code org.apache.eventmesh.cloudevents.v1.CloudEventBatch} + */ +public final class CloudEventBatch extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:org.apache.eventmesh.cloudevents.v1.CloudEventBatch) + CloudEventBatchOrBuilder { +private static final long serialVersionUID = 0L; + // Use CloudEventBatch.newBuilder() to construct. + private CloudEventBatch(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private CloudEventBatch() { + events_ = java.util.Collections.emptyList(); + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new CloudEventBatch(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private CloudEventBatch( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + if (!((mutable_bitField0_ & 0x00000001) != 0)) { + events_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + events_.add( + input.readMessage(CloudEvent.parser(), extensionRegistry)); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) != 0)) { + events_ = java.util.Collections.unmodifiableList(events_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_fieldAccessorTable + .ensureFieldAccessorsInitialized( + CloudEventBatch.class, Builder.class); + } + + public static final int EVENTS_FIELD_NUMBER = 1; + private java.util.List events_; + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + @Override + public java.util.List getEventsList() { + return events_; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + @Override + public java.util.List + getEventsOrBuilderList() { + return events_; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + @Override + public int getEventsCount() { + return events_.size(); + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + @Override + public CloudEvent getEvents(int index) { + return events_.get(index); + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + @Override + public CloudEventOrBuilder getEventsOrBuilder( + int index) { + return events_.get(index); + } + + private byte memoizedIsInitialized = -1; + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < events_.size(); i++) { + output.writeMessage(1, events_.get(i)); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < events_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, events_.get(i)); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof CloudEventBatch)) { + return super.equals(obj); + } + CloudEventBatch other = (CloudEventBatch) obj; + + if (!getEventsList() + .equals(other.getEventsList())) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getEventsCount() > 0) { + hash = (37 * hash) + EVENTS_FIELD_NUMBER; + hash = (53 * hash) + getEventsList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static CloudEventBatch parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEventBatch parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEventBatch parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEventBatch parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEventBatch parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static CloudEventBatch parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static CloudEventBatch parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static CloudEventBatch parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static CloudEventBatch parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static CloudEventBatch parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static CloudEventBatch parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static CloudEventBatch parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(CloudEventBatch prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code org.apache.eventmesh.cloudevents.v1.CloudEventBatch} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:org.apache.eventmesh.cloudevents.v1.CloudEventBatch) + CloudEventBatchOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_fieldAccessorTable + .ensureFieldAccessorsInitialized( + CloudEventBatch.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getEventsFieldBuilder(); + } + } + @Override + public Builder clear() { + super.clear(); + if (eventsBuilder_ == null) { + events_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + eventsBuilder_.clear(); + } + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventMeshCloudEvents.internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_descriptor; + } + + @Override + public CloudEventBatch getDefaultInstanceForType() { + return CloudEventBatch.getDefaultInstance(); + } + + @Override + public CloudEventBatch build() { + CloudEventBatch result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public CloudEventBatch buildPartial() { + CloudEventBatch result = new CloudEventBatch(this); + int from_bitField0_ = bitField0_; + if (eventsBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + events_ = java.util.Collections.unmodifiableList(events_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.events_ = events_; + } else { + result.events_ = eventsBuilder_.build(); + } + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof CloudEventBatch) { + return mergeFrom((CloudEventBatch)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(CloudEventBatch other) { + if (other == CloudEventBatch.getDefaultInstance()) return this; + if (eventsBuilder_ == null) { + if (!other.events_.isEmpty()) { + if (events_.isEmpty()) { + events_ = other.events_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureEventsIsMutable(); + events_.addAll(other.events_); + } + onChanged(); + } + } else { + if (!other.events_.isEmpty()) { + if (eventsBuilder_.isEmpty()) { + eventsBuilder_.dispose(); + eventsBuilder_ = null; + events_ = other.events_; + bitField0_ = (bitField0_ & ~0x00000001); + eventsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getEventsFieldBuilder() : null; + } else { + eventsBuilder_.addAllMessages(other.events_); + } + } + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + CloudEventBatch parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (CloudEventBatch) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.util.List events_ = + java.util.Collections.emptyList(); + private void ensureEventsIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + events_ = new java.util.ArrayList(events_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + CloudEvent, CloudEvent.Builder, CloudEventOrBuilder> eventsBuilder_; + + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public java.util.List getEventsList() { + if (eventsBuilder_ == null) { + return java.util.Collections.unmodifiableList(events_); + } else { + return eventsBuilder_.getMessageList(); + } + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public int getEventsCount() { + if (eventsBuilder_ == null) { + return events_.size(); + } else { + return eventsBuilder_.getCount(); + } + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public CloudEvent getEvents(int index) { + if (eventsBuilder_ == null) { + return events_.get(index); + } else { + return eventsBuilder_.getMessage(index); + } + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder setEvents( + int index, CloudEvent value) { + if (eventsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureEventsIsMutable(); + events_.set(index, value); + onChanged(); + } else { + eventsBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder setEvents( + int index, CloudEvent.Builder builderForValue) { + if (eventsBuilder_ == null) { + ensureEventsIsMutable(); + events_.set(index, builderForValue.build()); + onChanged(); + } else { + eventsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder addEvents(CloudEvent value) { + if (eventsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureEventsIsMutable(); + events_.add(value); + onChanged(); + } else { + eventsBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder addEvents( + int index, CloudEvent value) { + if (eventsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureEventsIsMutable(); + events_.add(index, value); + onChanged(); + } else { + eventsBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder addEvents( + CloudEvent.Builder builderForValue) { + if (eventsBuilder_ == null) { + ensureEventsIsMutable(); + events_.add(builderForValue.build()); + onChanged(); + } else { + eventsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder addEvents( + int index, CloudEvent.Builder builderForValue) { + if (eventsBuilder_ == null) { + ensureEventsIsMutable(); + events_.add(index, builderForValue.build()); + onChanged(); + } else { + eventsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder addAllEvents( + Iterable values) { + if (eventsBuilder_ == null) { + ensureEventsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, events_); + onChanged(); + } else { + eventsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder clearEvents() { + if (eventsBuilder_ == null) { + events_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + eventsBuilder_.clear(); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public Builder removeEvents(int index) { + if (eventsBuilder_ == null) { + ensureEventsIsMutable(); + events_.remove(index); + onChanged(); + } else { + eventsBuilder_.remove(index); + } + return this; + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public CloudEvent.Builder getEventsBuilder( + int index) { + return getEventsFieldBuilder().getBuilder(index); + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public CloudEventOrBuilder getEventsOrBuilder( + int index) { + if (eventsBuilder_ == null) { + return events_.get(index); } else { + return eventsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public java.util.List + getEventsOrBuilderList() { + if (eventsBuilder_ != null) { + return eventsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(events_); + } + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public CloudEvent.Builder addEventsBuilder() { + return getEventsFieldBuilder().addBuilder( + CloudEvent.getDefaultInstance()); + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public CloudEvent.Builder addEventsBuilder( + int index) { + return getEventsFieldBuilder().addBuilder( + index, CloudEvent.getDefaultInstance()); + } + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + public java.util.List + getEventsBuilderList() { + return getEventsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + CloudEvent, CloudEvent.Builder, CloudEventOrBuilder> + getEventsFieldBuilder() { + if (eventsBuilder_ == null) { + eventsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + CloudEvent, CloudEvent.Builder, CloudEventOrBuilder>( + events_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + events_ = null; + } + return eventsBuilder_; + } + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:org.apache.eventmesh.cloudevents.v1.CloudEventBatch) + } + + // @@protoc_insertion_point(class_scope:org.apache.eventmesh.cloudevents.v1.CloudEventBatch) + private static final CloudEventBatch DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new CloudEventBatch(); + } + + public static CloudEventBatch getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public CloudEventBatch parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new CloudEventBatch(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public CloudEventBatch getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventBatchOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventBatchOrBuilder.java new file mode 100644 index 0000000000..5f3256d6fa --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventBatchOrBuilder.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: eventmesh-cloudevents.proto + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +public interface CloudEventBatchOrBuilder extends + // @@protoc_insertion_point(interface_extends:org.apache.eventmesh.cloudevents.v1.CloudEventBatch) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + java.util.List + getEventsList(); + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + CloudEvent getEvents(int index); + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + int getEventsCount(); + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + java.util.List + getEventsOrBuilderList(); + /** + * repeated .org.apache.eventmesh.cloudevents.v1.CloudEvent events = 1; + */ + CloudEventOrBuilder getEventsOrBuilder( + int index); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventOrBuilder.java new file mode 100644 index 0000000000..a375b43a89 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/CloudEventOrBuilder.java @@ -0,0 +1,191 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: eventmesh-cloudevents.proto + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +public interface CloudEventOrBuilder extends + // @@protoc_insertion_point(interface_extends:org.apache.eventmesh.cloudevents.v1.CloudEvent) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * Required Attributes
+   * 
+ * + * string id = 1; + * @return The id. + */ + String getId(); + /** + *
+   * Required Attributes
+   * 
+ * + * string id = 1; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + *
+   * URI-reference
+   * 
+ * + * string source = 2; + * @return The source. + */ + String getSource(); + /** + *
+   * URI-reference
+   * 
+ * + * string source = 2; + * @return The bytes for source. + */ + com.google.protobuf.ByteString + getSourceBytes(); + + /** + * string spec_version = 3; + * @return The specVersion. + */ + String getSpecVersion(); + /** + * string spec_version = 3; + * @return The bytes for specVersion. + */ + com.google.protobuf.ByteString + getSpecVersionBytes(); + + /** + * string type = 4; + * @return The type. + */ + String getType(); + /** + * string type = 4; + * @return The bytes for type. + */ + com.google.protobuf.ByteString + getTypeBytes(); + + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + int getAttributesCount(); + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + boolean containsAttributes( + String key); + /** + * Use {@link #getAttributesMap()} instead. + */ + @Deprecated + java.util.Map + getAttributes(); + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + java.util.Map + getAttributesMap(); + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + + /* nullable */ +CloudEvent.CloudEventAttributeValue getAttributesOrDefault( + String key, + /* nullable */ +CloudEvent.CloudEventAttributeValue defaultValue); + /** + *
+   * Optional & Extension Attributes
+   * 
+ * + * map<string, .org.apache.eventmesh.cloudevents.v1.CloudEvent.CloudEventAttributeValue> attributes = 5; + */ + + CloudEvent.CloudEventAttributeValue getAttributesOrThrow( + String key); + + /** + * bytes binary_data = 6; + * @return Whether the binaryData field is set. + */ + boolean hasBinaryData(); + /** + * bytes binary_data = 6; + * @return The binaryData. + */ + com.google.protobuf.ByteString getBinaryData(); + + /** + * string text_data = 7; + * @return Whether the textData field is set. + */ + boolean hasTextData(); + /** + * string text_data = 7; + * @return The textData. + */ + String getTextData(); + /** + * string text_data = 7; + * @return The bytes for textData. + */ + com.google.protobuf.ByteString + getTextDataBytes(); + + /** + * .google.protobuf.Any proto_data = 8; + * @return Whether the protoData field is set. + */ + boolean hasProtoData(); + /** + * .google.protobuf.Any proto_data = 8; + * @return The protoData. + */ + com.google.protobuf.Any getProtoData(); + /** + * .google.protobuf.Any proto_data = 8; + */ + com.google.protobuf.AnyOrBuilder getProtoDataOrBuilder(); + + public CloudEvent.DataCase getDataCase(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/ConsumerServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/ConsumerServiceGrpc.java new file mode 100644 index 0000000000..d3f25f558e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/ConsumerServiceGrpc.java @@ -0,0 +1,443 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.43.2)", + comments = "Source: eventmesh-service.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class ConsumerServiceGrpc { + + private ConsumerServiceGrpc() {} + + public static final String SERVICE_NAME = "org.apache.eventmesh.cloudevents.v1.ConsumerService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getSubscribeMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "subscribe", + requestType = CloudEvent.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getSubscribeMethod() { + io.grpc.MethodDescriptor getSubscribeMethod; + if ((getSubscribeMethod = ConsumerServiceGrpc.getSubscribeMethod) == null) { + synchronized (ConsumerServiceGrpc.class) { + if ((getSubscribeMethod = ConsumerServiceGrpc.getSubscribeMethod) == null) { + ConsumerServiceGrpc.getSubscribeMethod = getSubscribeMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "subscribe")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new ConsumerServiceMethodDescriptorSupplier("subscribe")) + .build(); + } + } + } + return getSubscribeMethod; + } + + private static volatile io.grpc.MethodDescriptor getSubscribeStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "subscribeStream", + requestType = CloudEvent.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getSubscribeStreamMethod() { + io.grpc.MethodDescriptor getSubscribeStreamMethod; + if ((getSubscribeStreamMethod = ConsumerServiceGrpc.getSubscribeStreamMethod) == null) { + synchronized (ConsumerServiceGrpc.class) { + if ((getSubscribeStreamMethod = ConsumerServiceGrpc.getSubscribeStreamMethod) == null) { + ConsumerServiceGrpc.getSubscribeStreamMethod = getSubscribeStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "subscribeStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new ConsumerServiceMethodDescriptorSupplier("subscribeStream")) + .build(); + } + } + } + return getSubscribeStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getUnsubscribeMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "unsubscribe", + requestType = CloudEvent.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getUnsubscribeMethod() { + io.grpc.MethodDescriptor getUnsubscribeMethod; + if ((getUnsubscribeMethod = ConsumerServiceGrpc.getUnsubscribeMethod) == null) { + synchronized (ConsumerServiceGrpc.class) { + if ((getUnsubscribeMethod = ConsumerServiceGrpc.getUnsubscribeMethod) == null) { + ConsumerServiceGrpc.getUnsubscribeMethod = getUnsubscribeMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "unsubscribe")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new ConsumerServiceMethodDescriptorSupplier("unsubscribe")) + .build(); + } + } + } + return getUnsubscribeMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static ConsumerServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public ConsumerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ConsumerServiceStub(channel, callOptions); + } + }; + return ConsumerServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static ConsumerServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public ConsumerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ConsumerServiceBlockingStub(channel, callOptions); + } + }; + return ConsumerServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static ConsumerServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public ConsumerServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ConsumerServiceFutureStub(channel, callOptions); + } + }; + return ConsumerServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public static abstract class ConsumerServiceImplBase implements io.grpc.BindableService { + + /** + *
+     * The subscribed event will be delivered by invoking the webhook url in the Subscription
+     * 
+ */ + public void subscribe(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getSubscribeMethod(), responseObserver); + } + + /** + *
+     *  The subscribed event will be delivered through stream of Message
+     * 
+ */ + public io.grpc.stub.StreamObserver subscribeStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getSubscribeStreamMethod(), responseObserver); + } + + /** + */ + public void unsubscribe(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getUnsubscribeMethod(), responseObserver); + } + + @Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getSubscribeMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_SUBSCRIBE))) + .addMethod( + getSubscribeStreamMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_SUBSCRIBE_STREAM))) + .addMethod( + getUnsubscribeMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_UNSUBSCRIBE))) + .build(); + } + } + + /** + */ + public static final class ConsumerServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ConsumerServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected ConsumerServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ConsumerServiceStub(channel, callOptions); + } + + /** + *
+     * The subscribed event will be delivered by invoking the webhook url in the Subscription
+     * 
+ */ + public void subscribe(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getSubscribeMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     *  The subscribed event will be delivered through stream of Message
+     * 
+ */ + public io.grpc.stub.StreamObserver subscribeStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getSubscribeStreamMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void unsubscribe(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getUnsubscribeMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + */ + public static final class ConsumerServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ConsumerServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected ConsumerServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ConsumerServiceBlockingStub(channel, callOptions); + } + + /** + *
+     * The subscribed event will be delivered by invoking the webhook url in the Subscription
+     * 
+ */ + public CloudEvent subscribe(CloudEvent request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getSubscribeMethod(), getCallOptions(), request); + } + + /** + */ + public CloudEvent unsubscribe(CloudEvent request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getUnsubscribeMethod(), getCallOptions(), request); + } + } + + /** + */ + public static final class ConsumerServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ConsumerServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected ConsumerServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ConsumerServiceFutureStub(channel, callOptions); + } + + /** + *
+     * The subscribed event will be delivered by invoking the webhook url in the Subscription
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture subscribe( + CloudEvent request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getSubscribeMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture unsubscribe( + CloudEvent request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getUnsubscribeMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_SUBSCRIBE = 0; + private static final int METHODID_UNSUBSCRIBE = 1; + private static final int METHODID_SUBSCRIBE_STREAM = 2; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final ConsumerServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(ConsumerServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_SUBSCRIBE: + serviceImpl.subscribe((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_UNSUBSCRIBE: + serviceImpl.unsubscribe((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_SUBSCRIBE_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.subscribeStream( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class ConsumerServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + ConsumerServiceBaseDescriptorSupplier() {} + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventMeshGrpcService.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("ConsumerService"); + } + } + + private static final class ConsumerServiceFileDescriptorSupplier + extends ConsumerServiceBaseDescriptorSupplier { + ConsumerServiceFileDescriptorSupplier() {} + } + + private static final class ConsumerServiceMethodDescriptorSupplier + extends ConsumerServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + ConsumerServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (ConsumerServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new ConsumerServiceFileDescriptorSupplier()) + .addMethod(getSubscribeMethod()) + .addMethod(getSubscribeStreamMethod()) + .addMethod(getUnsubscribeMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/EventMeshCloudEvents.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/EventMeshCloudEvents.java new file mode 100644 index 0000000000..aebe0a06cb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/EventMeshCloudEvents.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: eventmesh-cloudevents.proto + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +public final class EventMeshCloudEvents { + private EventMeshCloudEvents() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_AttributesEntry_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_AttributesEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + String[] descriptorData = { + "\n\033eventmesh-cloudevents.proto\022#org.apach" + + "e.eventmesh.cloudevents.v1\032\031google/proto" + + "buf/any.proto\032\037google/protobuf/timestamp" + + ".proto\"\324\004\n\nCloudEvent\022\n\n\002id\030\001 \001(\t\022\016\n\006sou" + + "rce\030\002 \001(\t\022\024\n\014spec_version\030\003 \001(\t\022\014\n\004type\030" + + "\004 \001(\t\022S\n\nattributes\030\005 \003(\0132?.org.apache.e" + + "ventmesh.cloudevents.v1.CloudEvent.Attri" + + "butesEntry\022\025\n\013binary_data\030\006 \001(\014H\000\022\023\n\ttex" + + "t_data\030\007 \001(\tH\000\022*\n\nproto_data\030\010 \001(\0132\024.goo" + + "gle.protobuf.AnyH\000\032{\n\017AttributesEntry\022\013\n" + + "\003key\030\001 \001(\t\022W\n\005value\030\002 \001(\0132H.org.apache.e" + + "ventmesh.cloudevents.v1.CloudEvent.Cloud" + + "EventAttributeValue:\0028\001\032\323\001\n\030CloudEventAt" + + "tributeValue\022\024\n\nce_boolean\030\001 \001(\010H\000\022\024\n\nce" + + "_integer\030\002 \001(\005H\000\022\023\n\tce_string\030\003 \001(\tH\000\022\022\n" + + "\010ce_bytes\030\004 \001(\014H\000\022\020\n\006ce_uri\030\005 \001(\tH\000\022\024\n\nc" + + "e_uri_ref\030\006 \001(\tH\000\0222\n\014ce_timestamp\030\007 \001(\0132" + + "\032.google.protobuf.TimestampH\000B\006\n\004attrB\006\n" + + "\004data\"R\n\017CloudEventBatch\022?\n\006events\030\001 \003(\013" + + "2/.org.apache.eventmesh.cloudevents.v1.C" + + "loudEventBO\n5org.apache.eventmesh.common" + + ".protocol.grpc.cloudeventsB\024EventMeshClo" + + "udEventsP\001b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.protobuf.AnyProto.getDescriptor(), + com.google.protobuf.TimestampProto.getDescriptor(), + }); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor, + new String[] { "Id", "Source", "SpecVersion", "Type", "Attributes", "BinaryData", "TextData", "ProtoData", "Data", }); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_AttributesEntry_descriptor = + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor.getNestedTypes().get(0); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_AttributesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_AttributesEntry_descriptor, + new String[] { "Key", "Value", }); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_descriptor = + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_descriptor.getNestedTypes().get(1); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEvent_CloudEventAttributeValue_descriptor, + new String[] { "CeBoolean", "CeInteger", "CeString", "CeBytes", "CeUri", "CeUriRef", "CeTimestamp", "Attr", }); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_eventmesh_cloudevents_v1_CloudEventBatch_descriptor, + new String[] { "Events", }); + com.google.protobuf.AnyProto.getDescriptor(); + com.google.protobuf.TimestampProto.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/EventMeshGrpcService.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/EventMeshGrpcService.java new file mode 100644 index 0000000000..94dbdbbef3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/EventMeshGrpcService.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: eventmesh-service.proto + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +public final class EventMeshGrpcService { + private EventMeshGrpcService() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + String[] descriptorData = { + "\n\027eventmesh-service.proto\022#org.apache.ev" + + "entmesh.cloudevents.v1\032\033google/protobuf/" + + "empty.proto\032\033eventmesh-cloudevents.proto" + + "2\246\004\n\020PublisherService\022k\n\007publish\022/.org.a" + + "pache.eventmesh.cloudevents.v1.CloudEven" + + "t\032/.org.apache.eventmesh.cloudevents.v1." + + "CloudEvent\022p\n\014publishReply\022/.org.apache." + + "eventmesh.cloudevents.v1.CloudEvent\032/.or" + + "g.apache.eventmesh.cloudevents.v1.CloudE" + + "vent\022X\n\rpublishOneWay\022/.org.apache.event" + + "mesh.cloudevents.v1.CloudEvent\032\026.google." + + "protobuf.Empty\022u\n\014batchPublish\0224.org.apa" + + "che.eventmesh.cloudevents.v1.CloudEventB" + + "atch\032/.org.apache.eventmesh.cloudevents." + + "v1.CloudEvent\022b\n\022batchPublishOneWay\0224.or" + + "g.apache.eventmesh.cloudevents.v1.CloudE" + + "ventBatch\032\026.google.protobuf.Empty2\352\002\n\017Co" + + "nsumerService\022m\n\tsubscribe\022/.org.apache." + + "eventmesh.cloudevents.v1.CloudEvent\032/.or" + + "g.apache.eventmesh.cloudevents.v1.CloudE" + + "vent\022w\n\017subscribeStream\022/.org.apache.eve" + + "ntmesh.cloudevents.v1.CloudEvent\032/.org.a" + + "pache.eventmesh.cloudevents.v1.CloudEven" + + "t(\0010\001\022o\n\013unsubscribe\022/.org.apache.eventm" + + "esh.cloudevents.v1.CloudEvent\032/.org.apac" + + "he.eventmesh.cloudevents.v1.CloudEvent2\201" + + "\001\n\020HeartbeatService\022m\n\theartbeat\022/.org.a" + + "pache.eventmesh.cloudevents.v1.CloudEven" + + "t\032/.org.apache.eventmesh.cloudevents.v1." + + "CloudEventBO\n5org.apache.eventmesh.commo" + + "n.protocol.grpc.cloudeventsB\024EventMeshGr" + + "pcServiceP\001b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.protobuf.EmptyProto.getDescriptor(), + EventMeshCloudEvents.getDescriptor(), + }); + com.google.protobuf.EmptyProto.getDescriptor(); + EventMeshCloudEvents.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/HeartbeatServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/HeartbeatServiceGrpc.java new file mode 100644 index 0000000000..0b347e58c6 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/HeartbeatServiceGrpc.java @@ -0,0 +1,293 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.43.2)", + comments = "Source: eventmesh-service.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class HeartbeatServiceGrpc { + + private HeartbeatServiceGrpc() {} + + public static final String SERVICE_NAME = "org.apache.eventmesh.cloudevents.v1.HeartbeatService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getHeartbeatMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "heartbeat", + requestType = CloudEvent.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getHeartbeatMethod() { + io.grpc.MethodDescriptor getHeartbeatMethod; + if ((getHeartbeatMethod = HeartbeatServiceGrpc.getHeartbeatMethod) == null) { + synchronized (HeartbeatServiceGrpc.class) { + if ((getHeartbeatMethod = HeartbeatServiceGrpc.getHeartbeatMethod) == null) { + HeartbeatServiceGrpc.getHeartbeatMethod = getHeartbeatMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "heartbeat")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new HeartbeatServiceMethodDescriptorSupplier("heartbeat")) + .build(); + } + } + } + return getHeartbeatMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static HeartbeatServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public HeartbeatServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HeartbeatServiceStub(channel, callOptions); + } + }; + return HeartbeatServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static HeartbeatServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public HeartbeatServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HeartbeatServiceBlockingStub(channel, callOptions); + } + }; + return HeartbeatServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static HeartbeatServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public HeartbeatServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HeartbeatServiceFutureStub(channel, callOptions); + } + }; + return HeartbeatServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public static abstract class HeartbeatServiceImplBase implements io.grpc.BindableService { + + /** + */ + public void heartbeat(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getHeartbeatMethod(), responseObserver); + } + + @Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getHeartbeatMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_HEARTBEAT))) + .build(); + } + } + + /** + */ + public static final class HeartbeatServiceStub extends io.grpc.stub.AbstractAsyncStub { + private HeartbeatServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected HeartbeatServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HeartbeatServiceStub(channel, callOptions); + } + + /** + */ + public void heartbeat(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getHeartbeatMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + */ + public static final class HeartbeatServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private HeartbeatServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected HeartbeatServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HeartbeatServiceBlockingStub(channel, callOptions); + } + + /** + */ + public CloudEvent heartbeat(CloudEvent request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getHeartbeatMethod(), getCallOptions(), request); + } + } + + /** + */ + public static final class HeartbeatServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private HeartbeatServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected HeartbeatServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HeartbeatServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture heartbeat( + CloudEvent request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getHeartbeatMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_HEARTBEAT = 0; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final HeartbeatServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(HeartbeatServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_HEARTBEAT: + serviceImpl.heartbeat((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + private static abstract class HeartbeatServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + HeartbeatServiceBaseDescriptorSupplier() {} + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventMeshGrpcService.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("HeartbeatService"); + } + } + + private static final class HeartbeatServiceFileDescriptorSupplier + extends HeartbeatServiceBaseDescriptorSupplier { + HeartbeatServiceFileDescriptorSupplier() {} + } + + private static final class HeartbeatServiceMethodDescriptorSupplier + extends HeartbeatServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + HeartbeatServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (HeartbeatServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new HeartbeatServiceFileDescriptorSupplier()) + .addMethod(getHeartbeatMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/PublisherServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/PublisherServiceGrpc.java new file mode 100644 index 0000000000..2796402037 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/cloudevents/PublisherServiceGrpc.java @@ -0,0 +1,649 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.cloudevents; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.43.2)", + comments = "Source: eventmesh-service.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class PublisherServiceGrpc { + + private PublisherServiceGrpc() {} + + public static final String SERVICE_NAME = "org.apache.eventmesh.cloudevents.v1.PublisherService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getPublishMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "publish", + requestType = CloudEvent.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getPublishMethod() { + io.grpc.MethodDescriptor getPublishMethod; + if ((getPublishMethod = PublisherServiceGrpc.getPublishMethod) == null) { + synchronized (PublisherServiceGrpc.class) { + if ((getPublishMethod = PublisherServiceGrpc.getPublishMethod) == null) { + PublisherServiceGrpc.getPublishMethod = getPublishMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "publish")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("publish")) + .build(); + } + } + } + return getPublishMethod; + } + + private static volatile io.grpc.MethodDescriptor getRequestReplyMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "requestReply", + requestType = CloudEvent.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getRequestReplyMethod() { + io.grpc.MethodDescriptor getRequestReplyMethod; + if ((getRequestReplyMethod = PublisherServiceGrpc.getRequestReplyMethod) == null) { + synchronized (PublisherServiceGrpc.class) { + if ((getRequestReplyMethod = PublisherServiceGrpc.getRequestReplyMethod) == null) { + PublisherServiceGrpc.getRequestReplyMethod = getRequestReplyMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "requestReply")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("requestReply")) + .build(); + } + } + } + return getRequestReplyMethod; + } + + private static volatile io.grpc.MethodDescriptor getPublishOneWayMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "publishOneWay", + requestType = CloudEvent.class, + responseType = com.google.protobuf.Empty.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getPublishOneWayMethod() { + io.grpc.MethodDescriptor getPublishOneWayMethod; + if ((getPublishOneWayMethod = PublisherServiceGrpc.getPublishOneWayMethod) == null) { + synchronized (PublisherServiceGrpc.class) { + if ((getPublishOneWayMethod = PublisherServiceGrpc.getPublishOneWayMethod) == null) { + PublisherServiceGrpc.getPublishOneWayMethod = getPublishOneWayMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "publishOneWay")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.google.protobuf.Empty.getDefaultInstance())) + .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("publishOneWay")) + .build(); + } + } + } + return getPublishOneWayMethod; + } + + private static volatile io.grpc.MethodDescriptor getBatchPublishMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "batchPublish", + requestType = CloudEventBatch.class, + responseType = CloudEvent.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getBatchPublishMethod() { + io.grpc.MethodDescriptor getBatchPublishMethod; + if ((getBatchPublishMethod = PublisherServiceGrpc.getBatchPublishMethod) == null) { + synchronized (PublisherServiceGrpc.class) { + if ((getBatchPublishMethod = PublisherServiceGrpc.getBatchPublishMethod) == null) { + PublisherServiceGrpc.getBatchPublishMethod = getBatchPublishMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "batchPublish")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEventBatch.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("batchPublish")) + .build(); + } + } + } + return getBatchPublishMethod; + } + + private static volatile io.grpc.MethodDescriptor getBatchPublishOneWayMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "batchPublishOneWay", + requestType = CloudEventBatch.class, + responseType = com.google.protobuf.Empty.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getBatchPublishOneWayMethod() { + io.grpc.MethodDescriptor getBatchPublishOneWayMethod; + if ((getBatchPublishOneWayMethod = PublisherServiceGrpc.getBatchPublishOneWayMethod) == null) { + synchronized (PublisherServiceGrpc.class) { + if ((getBatchPublishOneWayMethod = PublisherServiceGrpc.getBatchPublishOneWayMethod) == null) { + PublisherServiceGrpc.getBatchPublishOneWayMethod = getBatchPublishOneWayMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "batchPublishOneWay")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEventBatch.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.google.protobuf.Empty.getDefaultInstance())) + .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("batchPublishOneWay")) + .build(); + } + } + } + return getBatchPublishOneWayMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static PublisherServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public PublisherServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PublisherServiceStub(channel, callOptions); + } + }; + return PublisherServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static PublisherServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public PublisherServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PublisherServiceBlockingStub(channel, callOptions); + } + }; + return PublisherServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static PublisherServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public PublisherServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PublisherServiceFutureStub(channel, callOptions); + } + }; + return PublisherServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public static abstract class PublisherServiceImplBase implements io.grpc.BindableService { + + /** + *
+     *publish event
+     * 
+ */ + public void publish(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getPublishMethod(), responseObserver); + } + + /** + *
+     *publish event with reply
+     * 
+ */ + public void requestReply(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRequestReplyMethod(), responseObserver); + } + + /** + *
+     *publish event one way
+     * 
+ */ + public void publishOneWay(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getPublishOneWayMethod(), responseObserver); + } + + /** + *
+     * publish batch event
+     * 
+ */ + public void batchPublish(CloudEventBatch request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getBatchPublishMethod(), responseObserver); + } + + /** + *
+     *publish batch event one way
+     * 
+ */ + public void batchPublishOneWay(CloudEventBatch request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getBatchPublishOneWayMethod(), responseObserver); + } + + @Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getPublishMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_PUBLISH))) + .addMethod( + getRequestReplyMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_REQUEST_REPLY))) + .addMethod( + getPublishOneWayMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEvent, + com.google.protobuf.Empty>( + this, METHODID_PUBLISH_ONE_WAY))) + .addMethod( + getBatchPublishMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEventBatch, + CloudEvent>( + this, METHODID_BATCH_PUBLISH))) + .addMethod( + getBatchPublishOneWayMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + CloudEventBatch, + com.google.protobuf.Empty>( + this, METHODID_BATCH_PUBLISH_ONE_WAY))) + .build(); + } + } + + /** + */ + public static final class PublisherServiceStub extends io.grpc.stub.AbstractAsyncStub { + private PublisherServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected PublisherServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PublisherServiceStub(channel, callOptions); + } + + /** + *
+     *publish event
+     * 
+ */ + public void publish(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getPublishMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     *publish event with reply
+     * 
+ */ + public void requestReply(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getRequestReplyMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     *publish event one way
+     * 
+ */ + public void publishOneWay(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getPublishOneWayMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * publish batch event
+     * 
+ */ + public void batchPublish(CloudEventBatch request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getBatchPublishMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     *publish batch event one way
+     * 
+ */ + public void batchPublishOneWay(CloudEventBatch request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getBatchPublishOneWayMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + */ + public static final class PublisherServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private PublisherServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected PublisherServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PublisherServiceBlockingStub(channel, callOptions); + } + + /** + *
+     *publish event
+     * 
+ */ + public CloudEvent publish(CloudEvent request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getPublishMethod(), getCallOptions(), request); + } + + /** + *
+     *publish event with reply
+     * 
+ */ + public CloudEvent requestReply(CloudEvent request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getRequestReplyMethod(), getCallOptions(), request); + } + + /** + *
+     *publish event one way
+     * 
+ */ + public com.google.protobuf.Empty publishOneWay(CloudEvent request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getPublishOneWayMethod(), getCallOptions(), request); + } + + /** + *
+     * publish batch event
+     * 
+ */ + public CloudEvent batchPublish(CloudEventBatch request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getBatchPublishMethod(), getCallOptions(), request); + } + + /** + *
+     *publish batch event one way
+     * 
+ */ + public com.google.protobuf.Empty batchPublishOneWay(CloudEventBatch request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getBatchPublishOneWayMethod(), getCallOptions(), request); + } + } + + /** + */ + public static final class PublisherServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private PublisherServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected PublisherServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PublisherServiceFutureStub(channel, callOptions); + } + + /** + *
+     *publish event
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture publish( + CloudEvent request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getPublishMethod(), getCallOptions()), request); + } + + /** + *
+     *publish event with reply
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture requestReply( + CloudEvent request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getRequestReplyMethod(), getCallOptions()), request); + } + + /** + *
+     *publish event one way
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture publishOneWay( + CloudEvent request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getPublishOneWayMethod(), getCallOptions()), request); + } + + /** + *
+     * publish batch event
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture batchPublish( + CloudEventBatch request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getBatchPublishMethod(), getCallOptions()), request); + } + + /** + *
+     *publish batch event one way
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture batchPublishOneWay( + CloudEventBatch request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getBatchPublishOneWayMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_PUBLISH = 0; + private static final int METHODID_REQUEST_REPLY = 1; + private static final int METHODID_PUBLISH_ONE_WAY = 2; + private static final int METHODID_BATCH_PUBLISH = 3; + private static final int METHODID_BATCH_PUBLISH_ONE_WAY = 4; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final PublisherServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(PublisherServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_PUBLISH: + serviceImpl.publish((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_REQUEST_REPLY: + serviceImpl.requestReply((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_PUBLISH_ONE_WAY: + serviceImpl.publishOneWay((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_BATCH_PUBLISH: + serviceImpl.batchPublish((CloudEventBatch) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_BATCH_PUBLISH_ONE_WAY: + serviceImpl.batchPublishOneWay((CloudEventBatch) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + private static abstract class PublisherServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + PublisherServiceBaseDescriptorSupplier() {} + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventMeshGrpcService.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("PublisherService"); + } + } + + private static final class PublisherServiceFileDescriptorSupplier + extends PublisherServiceBaseDescriptorSupplier { + PublisherServiceFileDescriptorSupplier() {} + } + + private static final class PublisherServiceMethodDescriptorSupplier + extends PublisherServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + PublisherServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (PublisherServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new PublisherServiceFileDescriptorSupplier()) + .addMethod(getPublishMethod()) + .addMethod(getRequestReplyMethod()) + .addMethod(getPublishOneWayMethod()) + .addMethod(getBatchPublishMethod()) + .addMethod(getBatchPublishOneWayMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/BatchEventMeshCloudEventWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/BatchEventMeshCloudEventWrapper.java new file mode 100644 index 0000000000..a35fbaef47 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/BatchEventMeshCloudEventWrapper.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; + +public class BatchEventMeshCloudEventWrapper implements ProtocolTransportObject { + + private static final long serialVersionUID = -3296467364340663768L; + private final CloudEventBatch cloudEventBatch; + + public BatchEventMeshCloudEventWrapper(CloudEventBatch cloudEventBatch) { + this.cloudEventBatch = cloudEventBatch; + } + + public CloudEventBatch getMessage() { + return cloudEventBatch; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/BatchMessageWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/BatchMessageWrapper.java deleted file mode 100644 index 4be71812b0..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/BatchMessageWrapper.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.protocol.grpc.common; - -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; - -public class BatchMessageWrapper implements ProtocolTransportObject { - - private final BatchMessage batchMessage; - - public BatchMessageWrapper(BatchMessage batchMessage) { - this.batchMessage = batchMessage; - } - - public BatchMessage getMessage() { - return batchMessage; - } -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ClientType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ClientType.java new file mode 100644 index 0000000000..a2851d26bc --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ClientType.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +public enum ClientType { + + PUB(1, "Client for publishing"), + + SUB(2, "Client for subscribing"); + + private final int type; + + private final String desc; + + ClientType(int type, String desc) { + this.type = type; + this.desc = desc; + } + + public static ClientType get(int type) { + for (ClientType clientType : ClientType.values()) { + if (clientType.type == type) { + return clientType; + } + } + return null; + } + + public static boolean contains(Integer clientType) { + boolean flag = false; + for (ClientType ct : ClientType.values()) { + if (ct.type == clientType.intValue()) { + flag = true; + break; + } + } + return flag; + } + + public int getType() { + return type; + } + + public String getDesc() { + return desc; + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventUtils.java new file mode 100644 index 0000000000..3ad97d7794 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventUtils.java @@ -0,0 +1,338 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; + +public abstract class EventMeshCloudEventUtils { + + private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Constants.DATE_FORMAT_DEFAULT); + + private EventMeshCloudEventUtils() { + + } + + private static String getValue(CloudEvent cloudEvent, String defaultValue, String protocolKey) { + try { + return cloudEvent.getAttributesOrThrow(protocolKey).getCeString(); + } catch (Exception e) { + return defaultValue; + } + } + + public static String getEnv(CloudEvent cloudEvent) { + return getEnv(cloudEvent, null); + } + + public static String getEnv(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.ENV); + } + + public static String getIdc(CloudEvent cloudEvent) { + return getIdc(cloudEvent, null); + } + + public static String getIdc(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.IDC); + } + + public static String getSys(CloudEvent cloudEvent) { + return getSys(cloudEvent, null); + } + + public static String getSys(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.SYS); + } + + public static String getPid(CloudEvent cloudEvent) { + return getPid(cloudEvent, null); + } + + public static String getPid(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PID); + } + + public static String getIp(CloudEvent cloudEvent) { + return getIp(cloudEvent, null); + } + + public static String getIp(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.IP); + } + + public static String getUserName(CloudEvent cloudEvent) { + return getUserName(cloudEvent, null); + } + + public static String getUserName(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.USERNAME); + } + + public static String getPassword(CloudEvent cloudEvent) { + return getPassword(cloudEvent, null); + } + + public static String getPassword(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PASSWD); + } + + public static String getLanguage(CloudEvent cloudEvent) { + return getLanguage(cloudEvent, null); + } + + public static String getLanguage(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.LANGUAGE); + } + + public static String getProtocolType(CloudEvent cloudEvent) { + return getProtocolType(cloudEvent, null); + } + + public static String getProtocolType(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PROTOCOL_TYPE); + } + + public static String getProtocolVersion(CloudEvent cloudEvent) { + return getProtocolVersion(cloudEvent, null); + } + + public static String getProtocolVersion(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PROTOCOL_VERSION); + } + + public static String getProtocolDesc(CloudEvent cloudEvent) { + return getProtocolDesc(cloudEvent, null); + } + + public static String getProtocolDesc(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PROTOCOL_DESC); + } + + public static String getSeqNum(CloudEvent cloudEvent) { + return getSeqNum(cloudEvent, null); + } + + public static String getSeqNum(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.SEQ_NUM); + } + + public static String getUniqueId(CloudEvent cloudEvent) { + return getUniqueId(cloudEvent, null); + } + + public static String getUniqueId(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.UNIQUE_ID); + } + + public static String getTtl(CloudEvent cloudEvent) { + return getTtl(cloudEvent, null); + } + + public static String getTtl(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.TTL); + } + + public static String getProducerGroup(CloudEvent cloudEvent) { + return getProducerGroup(cloudEvent, null); + } + + public static String getProducerGroup(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PRODUCERGROUP); + } + + public static String getTag(CloudEvent cloudEvent) { + return getTag(cloudEvent, null); + } + + public static String getTag(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.TAG); + } + + public static String getContentType(CloudEvent cloudEvent) { + return getContentType(cloudEvent, null); + } + + public static String getContentType(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.CONTENT_TYPE); + } + + public static String getSubject(CloudEvent cloudEvent) { + return getSubject(cloudEvent, null); + } + + public static String getSubject(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.SUBJECT); + } + + public static String getDataContentType(CloudEvent cloudEvent) { + return getDataContentType(cloudEvent, null); + } + + public static String getDataContentType(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.DATA_CONTENT_TYPE); + } + + public static String getResponseCode(CloudEvent cloudEvent) { + return getResponseCode(cloudEvent, null); + } + + public static String getResponseCode(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.GRPC_RESPONSE_CODE); + } + + public static String getResponseMessage(CloudEvent cloudEvent) { + return getResponseMessage(cloudEvent, null); + } + + public static String getResponseMessage(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.GRPC_RESPONSE_MESSAGE); + } + + public static String getResponseTime(CloudEvent cloudEvent) { + return getResponseTime(cloudEvent, null); + } + + public static String getResponseTime(CloudEvent cloudEvent, String defaultValue) { + try { + Timestamp timestamp = cloudEvent.getAttributesOrThrow(ProtocolKey.GRPC_RESPONSE_TIME).getCeTimestamp(); + return covertProtoTimestamp(timestamp).toString(); + } catch (Exception e) { + return defaultValue; + } + } + + public static String getCluster(CloudEvent cloudEvent) { + return getCluster(cloudEvent, null); + } + + public static String getCluster(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.PROPERTY_MESSAGE_CLUSTER); + } + + public static String getConsumerGroup(CloudEvent cloudEvent) { + return getConsumerGroup(cloudEvent, null); + } + + public static String getConsumerGroup(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.CONSUMERGROUP); + } + + public static ClientType getClientType(CloudEvent cloudEvent) { + return getClientType(cloudEvent, null); + } + + public static ClientType getClientType(CloudEvent cloudEvent, ClientType defaultValue) { + try { + int type = cloudEvent.getAttributesOrThrow(ProtocolKey.CLIENT_TYPE).getCeInteger(); + return ClientType.get(type); + } catch (Exception e) { + return defaultValue; + } + } + + public static String getURL(CloudEvent cloudEvent) { + return getURL(cloudEvent, null); + } + + public static String getURL(CloudEvent cloudEvent, String defaultValue) { + return getValue(cloudEvent, defaultValue, ProtocolKey.URL); + } + + public static String getDataContent(CloudEvent cloudEvent) { + return getDataContent(cloudEvent, null); + } + + public static String getDataContent(final CloudEvent cloudEvent, String defaultValue) { + String dataContentType = getDataContentType(cloudEvent); + if (ProtoSupport.isTextContent(dataContentType)) { + return Optional.of(cloudEvent.getTextData()).get(); + } + if (ProtoSupport.isProtoContent(dataContentType)) { + Any protoData = cloudEvent.getProtoData(); + return protoData == Any.getDefaultInstance() ? defaultValue + : new String(protoData.toByteArray(), Constants.DEFAULT_CHARSET); + } + ByteString binaryData = cloudEvent.getBinaryData(); + return ByteString.EMPTY == binaryData ? defaultValue : binaryData.toStringUtf8(); + + + } + + public static Map getAttributes(final CloudEvent cloudEvent) { + if (Objects.isNull(cloudEvent)) { + return new HashMap<>(0); + } + Map attributesMap = Optional.of(cloudEvent.getAttributesMap()).get(); + Map convertedAttributes = new HashMap<>(attributesMap.size()); + attributesMap.forEach((key, value) -> { + if (Objects.isNull(value)) { + return; + } + if (value.hasCeBoolean()) { + convertedAttributes.put(key, Boolean.toString(value.getCeBoolean())); + return; + } + if (value.hasCeInteger()) { + convertedAttributes.put(key, Integer.toString(value.getCeInteger())); + return; + } + if (value.hasCeString()) { + convertedAttributes.put(key, value.getCeString()); + return; + } + if (value.hasCeBytes()) { + convertedAttributes.put(key, value.getCeBytes().toString(Constants.DEFAULT_CHARSET)); + return; + } + if (value.hasCeUri()) { + convertedAttributes.put(key, value.getCeUri()); + return; + } + if (value.hasCeUriRef()) { + convertedAttributes.put(key, value.getCeUriRef()); + return; + } + if (value.hasCeTimestamp()) { + OffsetDateTime offsetDateTime = covertProtoTimestamp(value.getCeTimestamp()); + convertedAttributes.put(key, dateTimeFormatter.format(offsetDateTime.toLocalDateTime())); + } + }); + return convertedAttributes; + } + + private static OffsetDateTime covertProtoTimestamp(com.google.protobuf.Timestamp timestamp) { + Instant instant = Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); + return instant.atOffset(ZoneOffset.UTC); + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventWrapper.java new file mode 100644 index 0000000000..69b44128a1 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventWrapper.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; + +public class EventMeshCloudEventWrapper implements ProtocolTransportObject { + + private static final long serialVersionUID = 4562321593749195797L; + + private final CloudEvent cloudEvent; + + public EventMeshCloudEventWrapper(CloudEvent cloudEvent) { + this.cloudEvent = cloudEvent; + } + + public CloudEvent getMessage() { + return cloudEvent; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/GrpcType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/GrpcType.java similarity index 91% rename from eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/GrpcType.java rename to eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/GrpcType.java index 507942a5f5..81317310c6 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/GrpcType.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/GrpcType.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup; +package org.apache.eventmesh.common.protocol.grpc.common; public enum GrpcType { WEBHOOK, STREAM diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtoSupport.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtoSupport.java new file mode 100644 index 0000000000..e6fc5515db --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtoSupport.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +public class ProtoSupport { + + private ProtoSupport() { + + } + + public static boolean isTextContent(String contentType) { + + if (contentType == null) { + return false; + } + + return contentType.startsWith("text/") + || "application/json".equals(contentType) + || "application/xml".equals(contentType) + || contentType.endsWith("+json") + || contentType.endsWith("+xml") + ; + } + + public static boolean isProtoContent(String contentType) { + if (contentType == null) { + return false; + } + return "application/protobuf".equals(contentType); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtocolKey.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtocolKey.java index 0294ce1c54..ec47fda44b 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtocolKey.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/ProtocolKey.java @@ -19,6 +19,7 @@ public class ProtocolKey { + //EventMesh extensions public static final String ENV = "env"; public static final String IDC = "idc"; public static final String SYS = "sys"; @@ -27,16 +28,44 @@ public class ProtocolKey { public static final String USERNAME = "username"; public static final String PASSWD = "passwd"; public static final String LANGUAGE = "language"; - public static final String PROTOCOL_TYPE = "protocoltype"; public static final String PROTOCOL_VERSION = "protocolversion"; public static final String PROTOCOL_DESC = "protocoldesc"; - public static final String SEQ_NUM = "seqnum"; public static final String UNIQUE_ID = "uniqueid"; public static final String TTL = "ttl"; public static final String PRODUCERGROUP = "producergroup"; + public static final String CONSUMERGROUP = "consumergroup"; public static final String TAG = "tag"; - public static final String CONTENT_TYPE = "contenttype"; + public static final String PROPERTY_MESSAGE_CLUSTER = "cluster"; + public static final String URL = "url"; + + public static final String CLIENT_TYPE = "clienttype"; + + public static final String GRPC_RESPONSE_CODE = "statuscode"; + public static final String GRPC_RESPONSE_MESSAGE = "responsemessage"; + public static final String GRPC_RESPONSE_TIME = "time"; + + public static final String SUB_MESSAGE_TYPE = "submessagetype"; + public static final String SUB_REPLY_MESSAGE = "subscription_reply"; + + /** + * CloudEvents spec + * + * @see context-attributes + */ + + //Required attributes + public static final String ID = "id"; + public static final String SOURCE = "source"; + public static final String SPECVERSION = "specversion"; + public static final String TYPE = "type"; + + //Optional attributes + public static final String DATA_CONTENT_TYPE = "datacontenttype"; + public static final String DATA_SCHEMA = "dataschema"; + public static final String SUBJECT = "subject"; + public static final String TIME = "time"; + public static final String EVENT_DATA = "eventdata"; } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/Response.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/Response.java new file mode 100644 index 0000000000..965a454371 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/Response.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +@Builder +@ToString +public class Response { + + private String respCode; + + private String respMsg; + + private String respTime; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/SimpleMessageWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/SimpleMessageWrapper.java deleted file mode 100644 index 245f55bb38..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/SimpleMessageWrapper.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.protocol.grpc.common; - -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; - -public class SimpleMessageWrapper implements ProtocolTransportObject { - - private final SimpleMessage simpleMessage; - - public SimpleMessageWrapper(SimpleMessage simpleMessage) { - this.simpleMessage = simpleMessage; - } - - public SimpleMessage getMessage() { - return simpleMessage; - } -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/StatusCode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/StatusCode.java index 15831d8c41..65bbed9edd 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/StatusCode.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/common/StatusCode.java @@ -24,8 +24,8 @@ public enum StatusCode { EVENTMESH_REQUESTCODE_INVALID("2", "requestCode can't be null, or must be number, "), EVENTMESH_SEND_SYNC_MSG_ERR("3", "eventMesh send rr msg err, "), EVENTMESH_WAITING_RR_MSG_ERR("4", "eventMesh waiting rr msg err, "), - EVENTMESH_PROTOCOL_HEADER_ERR("6", "eventMesh protocol[header] err, "), - EVENTMESH_PROTOCOL_BODY_ERR("7", "eventMesh protocol[body] err, "), + EVENTMESH_PROTOCOL_HEADER_ERR("6", "eventMesh CloudEvent[header] err, "), + EVENTMESH_PROTOCOL_BODY_ERR("7", "eventMesh CloudEvent[body] err, "), EVENTMESH_STOP("8", "eventMesh will stop or had stopped, "), EVENTMESH_REJECT_BY_PROCESSOR_ERROR("9", "eventMesh reject by processor error, "), EVENTMESH_BATCH_PUBLISH_ERR("10", "eventMesh batch publish messages error, "), @@ -41,11 +41,12 @@ public enum StatusCode { EVENTMESH_HEARTBEAT_ERR("19", "eventMesh heartbeat err"), EVENTMESH_ACL_ERR("20", "eventMesh acl err"), EVENTMESH_SEND_MESSAGE_SPEED_OVER_LIMIT_ERR("21", "eventMesh send message speed over the limit err."), - EVENTMESH_REQUEST_REPLY_MSG_ERR("22", "eventMesh request reply msg err, "); + EVENTMESH_REQUEST_REPLY_MSG_ERR("22", "eventMesh request reply msg err, "), + CLIENT_RESUBSCRIBE("30", "client needs to resubscribe."); - private String retCode; + private final String retCode; - private String errMsg; + private final String errMsg; StatusCode(String retCode, String errMsg) { this.retCode = retCode; @@ -56,15 +57,8 @@ public String getRetCode() { return retCode; } - public void setRetCode(String retCode) { - this.retCode = retCode; - } - public String getErrMsg() { return errMsg; } - public void setErrMsg(String errMsg) { - this.errMsg = errMsg; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/proto/event_mesh_admin_service.proto b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/proto/event_mesh_admin_service.proto new file mode 100644 index 0000000000..fa7095840f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/proto/event_mesh_admin_service.proto @@ -0,0 +1,39 @@ +/* + * 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. + */ + +syntax="proto3"; + +import "google/protobuf/any.proto"; + +option java_multiple_files=true; + +message Metadata { + string type = 3; + map headers = 7; +} + + +message Payload { + Metadata metadata = 2; + bytes body = 3; +} + +service AdminService { + rpc invokeBiStream(stream Payload) returns (stream Payload){} + rpc invoke(Payload) returns (Payload){} +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/BatchMessage.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/BatchMessage.java deleted file mode 100644 index 9b638fc51e..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/BatchMessage.java +++ /dev/null @@ -1,2574 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -/** - * Protobuf type {@code eventmesh.common.protocol.grpc.BatchMessage} - */ -@SuppressWarnings({"all"}) -public final class BatchMessage extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.BatchMessage) - BatchMessageOrBuilder { -private static final long serialVersionUID = 0L; - // Use BatchMessage.newBuilder() to construct. - private BatchMessage(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private BatchMessage() { - producerGroup_ = ""; - topic_ = ""; - messageItem_ = java.util.Collections.emptyList(); - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private BatchMessage( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - RequestHeader.Builder subBuilder = null; - if (header_ != null) { - subBuilder = header_.toBuilder(); - } - header_ = input.readMessage(RequestHeader.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(header_); - header_ = subBuilder.buildPartial(); - } - - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - producerGroup_ = s; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - topic_ = s; - break; - } - case 34: { - if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { - messageItem_ = new java.util.ArrayList(); - mutable_bitField0_ |= 0x00000008; - } - messageItem_.add( - input.readMessage(MessageItem.parser(), extensionRegistry)); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { - messageItem_ = java.util.Collections.unmodifiableList(messageItem_); - } - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_fieldAccessorTable - .ensureFieldAccessorsInitialized( - BatchMessage.class, Builder.class); - } - - public interface MessageItemOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.BatchMessage.MessageItem) - com.google.protobuf.MessageOrBuilder { - - /** - * string content = 1; - */ - String getContent(); - /** - * string content = 1; - */ - com.google.protobuf.ByteString - getContentBytes(); - - /** - * string ttl = 2; - */ - String getTtl(); - /** - * string ttl = 2; - */ - com.google.protobuf.ByteString - getTtlBytes(); - - /** - * string uniqueId = 3; - */ - String getUniqueId(); - /** - * string uniqueId = 3; - */ - com.google.protobuf.ByteString - getUniqueIdBytes(); - - /** - * string seqNum = 4; - */ - String getSeqNum(); - /** - * string seqNum = 4; - */ - com.google.protobuf.ByteString - getSeqNumBytes(); - - /** - * string tag = 5; - */ - String getTag(); - /** - * string tag = 5; - */ - com.google.protobuf.ByteString - getTagBytes(); - - /** - * map<string, string> properties = 6; - */ - int getPropertiesCount(); - /** - * map<string, string> properties = 6; - */ - boolean containsProperties( - String key); - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - java.util.Map - getProperties(); - /** - * map<string, string> properties = 6; - */ - java.util.Map - getPropertiesMap(); - /** - * map<string, string> properties = 6; - */ - - String getPropertiesOrDefault( - String key, - String defaultValue); - /** - * map<string, string> properties = 6; - */ - - String getPropertiesOrThrow( - String key); - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.BatchMessage.MessageItem} - */ - public static final class MessageItem extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.BatchMessage.MessageItem) - MessageItemOrBuilder { - private static final long serialVersionUID = 0L; - // Use MessageItem.newBuilder() to construct. - private MessageItem(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private MessageItem() { - content_ = ""; - ttl_ = ""; - uniqueId_ = ""; - seqNum_ = ""; - tag_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private MessageItem( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - String s = input.readStringRequireUtf8(); - - content_ = s; - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - ttl_ = s; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - uniqueId_ = s; - break; - } - case 34: { - String s = input.readStringRequireUtf8(); - - seqNum_ = s; - break; - } - case 42: { - String s = input.readStringRequireUtf8(); - - tag_ = s; - break; - } - case 50: { - if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) { - properties_ = com.google.protobuf.MapField.newMapField( - PropertiesDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00000020; - } - com.google.protobuf.MapEntry - properties__ = input.readMessage( - PropertiesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - properties_.getMutableMap().put( - properties__.getKey(), properties__.getValue()); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 6: - return internalGetProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_fieldAccessorTable - .ensureFieldAccessorsInitialized( - MessageItem.class, Builder.class); - } - - private int bitField0_; - public static final int CONTENT_FIELD_NUMBER = 1; - private volatile Object content_; - /** - * string content = 1; - */ - public String getContent() { - Object ref = content_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - content_ = s; - return s; - } - } - /** - * string content = 1; - */ - public com.google.protobuf.ByteString - getContentBytes() { - Object ref = content_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - content_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TTL_FIELD_NUMBER = 2; - private volatile Object ttl_; - /** - * string ttl = 2; - */ - public String getTtl() { - Object ref = ttl_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ttl_ = s; - return s; - } - } - /** - * string ttl = 2; - */ - public com.google.protobuf.ByteString - getTtlBytes() { - Object ref = ttl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ttl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int UNIQUEID_FIELD_NUMBER = 3; - private volatile Object uniqueId_; - /** - * string uniqueId = 3; - */ - public String getUniqueId() { - Object ref = uniqueId_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - uniqueId_ = s; - return s; - } - } - /** - * string uniqueId = 3; - */ - public com.google.protobuf.ByteString - getUniqueIdBytes() { - Object ref = uniqueId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - uniqueId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SEQNUM_FIELD_NUMBER = 4; - private volatile Object seqNum_; - /** - * string seqNum = 4; - */ - public String getSeqNum() { - Object ref = seqNum_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - seqNum_ = s; - return s; - } - } - /** - * string seqNum = 4; - */ - public com.google.protobuf.ByteString - getSeqNumBytes() { - Object ref = seqNum_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - seqNum_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TAG_FIELD_NUMBER = 5; - private volatile Object tag_; - /** - * string tag = 5; - */ - public String getTag() { - Object ref = tag_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - tag_ = s; - return s; - } - } - /** - * string tag = 5; - */ - public com.google.protobuf.ByteString - getTagBytes() { - Object ref = tag_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - tag_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROPERTIES_FIELD_NUMBER = 6; - private static final class PropertiesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - String, String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_PropertiesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - private com.google.protobuf.MapField< - String, String> properties_; - private com.google.protobuf.MapField - internalGetProperties() { - if (properties_ == null) { - return com.google.protobuf.MapField.emptyMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - return properties_; - } - - public int getPropertiesCount() { - return internalGetProperties().getMap().size(); - } - /** - * map<string, string> properties = 6; - */ - - public boolean containsProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - return internalGetProperties().getMap().containsKey(key); - } - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - public java.util.Map getProperties() { - return getPropertiesMap(); - } - /** - * map<string, string> properties = 6; - */ - - public java.util.Map getPropertiesMap() { - return internalGetProperties().getMap(); - } - /** - * map<string, string> properties = 6; - */ - - public String getPropertiesOrDefault( - String key, - String defaultValue) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, string> properties = 6; - */ - - public String getPropertiesOrThrow( - String key) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getContentBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, content_); - } - if (!getTtlBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, ttl_); - } - if (!getUniqueIdBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, uniqueId_); - } - if (!getSeqNumBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, seqNum_); - } - if (!getTagBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 5, tag_); - } - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetProperties(), - PropertiesDefaultEntryHolder.defaultEntry, - 6); - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!getContentBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, content_); - } - if (!getTtlBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, ttl_); - } - if (!getUniqueIdBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, uniqueId_); - } - if (!getSeqNumBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, seqNum_); - } - if (!getTagBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, tag_); - } - for (java.util.Map.Entry entry - : internalGetProperties().getMap().entrySet()) { - com.google.protobuf.MapEntry - properties__ = PropertiesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(6, properties__); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof MessageItem)) { - return super.equals(obj); - } - MessageItem other = (MessageItem) obj; - - boolean result = true; - result = result && getContent() - .equals(other.getContent()); - result = result && getTtl() - .equals(other.getTtl()); - result = result && getUniqueId() - .equals(other.getUniqueId()); - result = result && getSeqNum() - .equals(other.getSeqNum()); - result = result && getTag() - .equals(other.getTag()); - result = result && internalGetProperties().equals( - other.internalGetProperties()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + CONTENT_FIELD_NUMBER; - hash = (53 * hash) + getContent().hashCode(); - hash = (37 * hash) + TTL_FIELD_NUMBER; - hash = (53 * hash) + getTtl().hashCode(); - hash = (37 * hash) + UNIQUEID_FIELD_NUMBER; - hash = (53 * hash) + getUniqueId().hashCode(); - hash = (37 * hash) + SEQNUM_FIELD_NUMBER; - hash = (53 * hash) + getSeqNum().hashCode(); - hash = (37 * hash) + TAG_FIELD_NUMBER; - hash = (53 * hash) + getTag().hashCode(); - if (!internalGetProperties().getMap().isEmpty()) { - hash = (37 * hash) + PROPERTIES_FIELD_NUMBER; - hash = (53 * hash) + internalGetProperties().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static MessageItem parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static MessageItem parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static MessageItem parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static MessageItem parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static MessageItem parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static MessageItem parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static MessageItem parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static MessageItem parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static MessageItem parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static MessageItem parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static MessageItem parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static MessageItem parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(MessageItem prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.BatchMessage.MessageItem} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.BatchMessage.MessageItem) - MessageItemOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 6: - return internalGetProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMutableMapField( - int number) { - switch (number) { - case 6: - return internalGetMutableProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_fieldAccessorTable - .ensureFieldAccessorsInitialized( - MessageItem.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage.MessageItem.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - content_ = ""; - - ttl_ = ""; - - uniqueId_ = ""; - - seqNum_ = ""; - - tag_ = ""; - - internalGetMutableProperties().clear(); - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor; - } - - public MessageItem getDefaultInstanceForType() { - return MessageItem.getDefaultInstance(); - } - - public MessageItem build() { - MessageItem result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public MessageItem buildPartial() { - MessageItem result = new MessageItem(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - result.content_ = content_; - result.ttl_ = ttl_; - result.uniqueId_ = uniqueId_; - result.seqNum_ = seqNum_; - result.tag_ = tag_; - result.properties_ = internalGetProperties(); - result.properties_.makeImmutable(); - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof MessageItem) { - return mergeFrom((MessageItem)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(MessageItem other) { - if (other == MessageItem.getDefaultInstance()) return this; - if (!other.getContent().isEmpty()) { - content_ = other.content_; - onChanged(); - } - if (!other.getTtl().isEmpty()) { - ttl_ = other.ttl_; - onChanged(); - } - if (!other.getUniqueId().isEmpty()) { - uniqueId_ = other.uniqueId_; - onChanged(); - } - if (!other.getSeqNum().isEmpty()) { - seqNum_ = other.seqNum_; - onChanged(); - } - if (!other.getTag().isEmpty()) { - tag_ = other.tag_; - onChanged(); - } - internalGetMutableProperties().mergeFrom( - other.internalGetProperties()); - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - MessageItem parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (MessageItem) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - private Object content_ = ""; - /** - * string content = 1; - */ - public String getContent() { - Object ref = content_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - content_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string content = 1; - */ - public com.google.protobuf.ByteString - getContentBytes() { - Object ref = content_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - content_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string content = 1; - */ - public Builder setContent( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - content_ = value; - onChanged(); - return this; - } - /** - * string content = 1; - */ - public Builder clearContent() { - - content_ = getDefaultInstance().getContent(); - onChanged(); - return this; - } - /** - * string content = 1; - */ - public Builder setContentBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - content_ = value; - onChanged(); - return this; - } - - private Object ttl_ = ""; - /** - * string ttl = 2; - */ - public String getTtl() { - Object ref = ttl_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ttl_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string ttl = 2; - */ - public com.google.protobuf.ByteString - getTtlBytes() { - Object ref = ttl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ttl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string ttl = 2; - */ - public Builder setTtl( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - ttl_ = value; - onChanged(); - return this; - } - /** - * string ttl = 2; - */ - public Builder clearTtl() { - - ttl_ = getDefaultInstance().getTtl(); - onChanged(); - return this; - } - /** - * string ttl = 2; - */ - public Builder setTtlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - ttl_ = value; - onChanged(); - return this; - } - - private Object uniqueId_ = ""; - /** - * string uniqueId = 3; - */ - public String getUniqueId() { - Object ref = uniqueId_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - uniqueId_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string uniqueId = 3; - */ - public com.google.protobuf.ByteString - getUniqueIdBytes() { - Object ref = uniqueId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - uniqueId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string uniqueId = 3; - */ - public Builder setUniqueId( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - uniqueId_ = value; - onChanged(); - return this; - } - /** - * string uniqueId = 3; - */ - public Builder clearUniqueId() { - - uniqueId_ = getDefaultInstance().getUniqueId(); - onChanged(); - return this; - } - /** - * string uniqueId = 3; - */ - public Builder setUniqueIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - uniqueId_ = value; - onChanged(); - return this; - } - - private Object seqNum_ = ""; - /** - * string seqNum = 4; - */ - public String getSeqNum() { - Object ref = seqNum_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - seqNum_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string seqNum = 4; - */ - public com.google.protobuf.ByteString - getSeqNumBytes() { - Object ref = seqNum_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - seqNum_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string seqNum = 4; - */ - public Builder setSeqNum( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - seqNum_ = value; - onChanged(); - return this; - } - /** - * string seqNum = 4; - */ - public Builder clearSeqNum() { - - seqNum_ = getDefaultInstance().getSeqNum(); - onChanged(); - return this; - } - /** - * string seqNum = 4; - */ - public Builder setSeqNumBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - seqNum_ = value; - onChanged(); - return this; - } - - private Object tag_ = ""; - /** - * string tag = 5; - */ - public String getTag() { - Object ref = tag_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - tag_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string tag = 5; - */ - public com.google.protobuf.ByteString - getTagBytes() { - Object ref = tag_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - tag_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string tag = 5; - */ - public Builder setTag( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - tag_ = value; - onChanged(); - return this; - } - /** - * string tag = 5; - */ - public Builder clearTag() { - - tag_ = getDefaultInstance().getTag(); - onChanged(); - return this; - } - /** - * string tag = 5; - */ - public Builder setTagBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - tag_ = value; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - String, String> properties_; - private com.google.protobuf.MapField - internalGetProperties() { - if (properties_ == null) { - return com.google.protobuf.MapField.emptyMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - return properties_; - } - private com.google.protobuf.MapField - internalGetMutableProperties() { - onChanged();; - if (properties_ == null) { - properties_ = com.google.protobuf.MapField.newMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - if (!properties_.isMutable()) { - properties_ = properties_.copy(); - } - return properties_; - } - - public int getPropertiesCount() { - return internalGetProperties().getMap().size(); - } - /** - * map<string, string> properties = 6; - */ - - public boolean containsProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - return internalGetProperties().getMap().containsKey(key); - } - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - public java.util.Map getProperties() { - return getPropertiesMap(); - } - /** - * map<string, string> properties = 6; - */ - - public java.util.Map getPropertiesMap() { - return internalGetProperties().getMap(); - } - /** - * map<string, string> properties = 6; - */ - - public String getPropertiesOrDefault( - String key, - String defaultValue) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, string> properties = 6; - */ - - public String getPropertiesOrThrow( - String key) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearProperties() { - internalGetMutableProperties().getMutableMap() - .clear(); - return this; - } - /** - * map<string, string> properties = 6; - */ - - public Builder removeProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - internalGetMutableProperties().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @Deprecated - public java.util.Map - getMutableProperties() { - return internalGetMutableProperties().getMutableMap(); - } - /** - * map<string, string> properties = 6; - */ - public Builder putProperties( - String key, - String value) { - if (key == null) { throw new NullPointerException(); } - if (value == null) { throw new NullPointerException(); } - internalGetMutableProperties().getMutableMap() - .put(key, value); - return this; - } - /** - * map<string, string> properties = 6; - */ - - public Builder putAllProperties( - java.util.Map values) { - internalGetMutableProperties().getMutableMap() - .putAll(values); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.BatchMessage.MessageItem) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.BatchMessage.MessageItem) - private static final MessageItem DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new MessageItem(); - } - - public static MessageItem getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public MessageItem parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new MessageItem(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public MessageItem getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - - } - - private int bitField0_; - public static final int HEADER_FIELD_NUMBER = 1; - private RequestHeader header_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - return getHeader(); - } - - public static final int PRODUCERGROUP_FIELD_NUMBER = 2; - private volatile Object producerGroup_; - /** - * string producerGroup = 2; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } - } - /** - * string producerGroup = 2; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TOPIC_FIELD_NUMBER = 3; - private volatile Object topic_; - /** - * string topic = 3; - */ - public String getTopic() { - Object ref = topic_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } - } - /** - * string topic = 3; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int MESSAGEITEM_FIELD_NUMBER = 4; - private java.util.List messageItem_; - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public java.util.List getMessageItemList() { - return messageItem_; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public java.util.List - getMessageItemOrBuilderList() { - return messageItem_; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public int getMessageItemCount() { - return messageItem_.size(); - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItem getMessageItem(int index) { - return messageItem_.get(index); - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItemOrBuilder getMessageItemOrBuilder( - int index) { - return messageItem_.get(index); - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (header_ != null) { - output.writeMessage(1, getHeader()); - } - if (!getProducerGroupBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, producerGroup_); - } - if (!getTopicBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, topic_); - } - for (int i = 0; i < messageItem_.size(); i++) { - output.writeMessage(4, messageItem_.get(i)); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (header_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, getHeader()); - } - if (!getProducerGroupBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, producerGroup_); - } - if (!getTopicBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, topic_); - } - for (int i = 0; i < messageItem_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, messageItem_.get(i)); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof BatchMessage)) { - return super.equals(obj); - } - BatchMessage other = (BatchMessage) obj; - - boolean result = true; - result = result && (hasHeader() == other.hasHeader()); - if (hasHeader()) { - result = result && getHeader() - .equals(other.getHeader()); - } - result = result && getProducerGroup() - .equals(other.getProducerGroup()); - result = result && getTopic() - .equals(other.getTopic()); - result = result && getMessageItemList() - .equals(other.getMessageItemList()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasHeader()) { - hash = (37 * hash) + HEADER_FIELD_NUMBER; - hash = (53 * hash) + getHeader().hashCode(); - } - hash = (37 * hash) + PRODUCERGROUP_FIELD_NUMBER; - hash = (53 * hash) + getProducerGroup().hashCode(); - hash = (37 * hash) + TOPIC_FIELD_NUMBER; - hash = (53 * hash) + getTopic().hashCode(); - if (getMessageItemCount() > 0) { - hash = (37 * hash) + MESSAGEITEM_FIELD_NUMBER; - hash = (53 * hash) + getMessageItemList().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static BatchMessage parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static BatchMessage parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static BatchMessage parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static BatchMessage parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static BatchMessage parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static BatchMessage parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static BatchMessage parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static BatchMessage parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static BatchMessage parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static BatchMessage parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static BatchMessage parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static BatchMessage parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(BatchMessage prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.BatchMessage} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.BatchMessage) - BatchMessageOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_fieldAccessorTable - .ensureFieldAccessorsInitialized( - BatchMessage.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - getMessageItemFieldBuilder(); - } - } - public Builder clear() { - super.clear(); - if (headerBuilder_ == null) { - header_ = null; - } else { - header_ = null; - headerBuilder_ = null; - } - producerGroup_ = ""; - - topic_ = ""; - - if (messageItemBuilder_ == null) { - messageItem_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - } else { - messageItemBuilder_.clear(); - } - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor; - } - - public BatchMessage getDefaultInstanceForType() { - return BatchMessage.getDefaultInstance(); - } - - public BatchMessage build() { - BatchMessage result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public BatchMessage buildPartial() { - BatchMessage result = new BatchMessage(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (headerBuilder_ == null) { - result.header_ = header_; - } else { - result.header_ = headerBuilder_.build(); - } - result.producerGroup_ = producerGroup_; - result.topic_ = topic_; - if (messageItemBuilder_ == null) { - if (((bitField0_ & 0x00000008) == 0x00000008)) { - messageItem_ = java.util.Collections.unmodifiableList(messageItem_); - bitField0_ = (bitField0_ & ~0x00000008); - } - result.messageItem_ = messageItem_; - } else { - result.messageItem_ = messageItemBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof BatchMessage) { - return mergeFrom((BatchMessage)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(BatchMessage other) { - if (other == BatchMessage.getDefaultInstance()) return this; - if (other.hasHeader()) { - mergeHeader(other.getHeader()); - } - if (!other.getProducerGroup().isEmpty()) { - producerGroup_ = other.producerGroup_; - onChanged(); - } - if (!other.getTopic().isEmpty()) { - topic_ = other.topic_; - onChanged(); - } - if (messageItemBuilder_ == null) { - if (!other.messageItem_.isEmpty()) { - if (messageItem_.isEmpty()) { - messageItem_ = other.messageItem_; - bitField0_ = (bitField0_ & ~0x00000008); - } else { - ensureMessageItemIsMutable(); - messageItem_.addAll(other.messageItem_); - } - onChanged(); - } - } else { - if (!other.messageItem_.isEmpty()) { - if (messageItemBuilder_.isEmpty()) { - messageItemBuilder_.dispose(); - messageItemBuilder_ = null; - messageItem_ = other.messageItem_; - bitField0_ = (bitField0_ & ~0x00000008); - messageItemBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? - getMessageItemFieldBuilder() : null; - } else { - messageItemBuilder_.addAllMessages(other.messageItem_); - } - } - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - BatchMessage parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (BatchMessage) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - private RequestHeader header_ = null; - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> headerBuilder_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return headerBuilder_ != null || header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - if (headerBuilder_ == null) { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } else { - return headerBuilder_.getMessage(); - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - header_ = value; - onChanged(); - } else { - headerBuilder_.setMessage(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader( - RequestHeader.Builder builderForValue) { - if (headerBuilder_ == null) { - header_ = builderForValue.build(); - onChanged(); - } else { - headerBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder mergeHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (header_ != null) { - header_ = - RequestHeader.newBuilder(header_).mergeFrom(value).buildPartial(); - } else { - header_ = value; - } - onChanged(); - } else { - headerBuilder_.mergeFrom(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder clearHeader() { - if (headerBuilder_ == null) { - header_ = null; - onChanged(); - } else { - header_ = null; - headerBuilder_ = null; - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader.Builder getHeaderBuilder() { - - onChanged(); - return getHeaderFieldBuilder().getBuilder(); - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - if (headerBuilder_ != null) { - return headerBuilder_.getMessageOrBuilder(); - } else { - return header_ == null ? - RequestHeader.getDefaultInstance() : header_; - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> - getHeaderFieldBuilder() { - if (headerBuilder_ == null) { - headerBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder>( - getHeader(), - getParentForChildren(), - isClean()); - header_ = null; - } - return headerBuilder_; - } - - private Object producerGroup_ = ""; - /** - * string producerGroup = 2; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string producerGroup = 2; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string producerGroup = 2; - */ - public Builder setProducerGroup( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - producerGroup_ = value; - onChanged(); - return this; - } - /** - * string producerGroup = 2; - */ - public Builder clearProducerGroup() { - - producerGroup_ = getDefaultInstance().getProducerGroup(); - onChanged(); - return this; - } - /** - * string producerGroup = 2; - */ - public Builder setProducerGroupBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - producerGroup_ = value; - onChanged(); - return this; - } - - private Object topic_ = ""; - /** - * string topic = 3; - */ - public String getTopic() { - Object ref = topic_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string topic = 3; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string topic = 3; - */ - public Builder setTopic( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - topic_ = value; - onChanged(); - return this; - } - /** - * string topic = 3; - */ - public Builder clearTopic() { - - topic_ = getDefaultInstance().getTopic(); - onChanged(); - return this; - } - /** - * string topic = 3; - */ - public Builder setTopicBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - topic_ = value; - onChanged(); - return this; - } - - private java.util.List messageItem_ = - java.util.Collections.emptyList(); - private void ensureMessageItemIsMutable() { - if (!((bitField0_ & 0x00000008) == 0x00000008)) { - messageItem_ = new java.util.ArrayList(messageItem_); - bitField0_ |= 0x00000008; - } - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - MessageItem, MessageItem.Builder, MessageItemOrBuilder> messageItemBuilder_; - - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public java.util.List getMessageItemList() { - if (messageItemBuilder_ == null) { - return java.util.Collections.unmodifiableList(messageItem_); - } else { - return messageItemBuilder_.getMessageList(); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public int getMessageItemCount() { - if (messageItemBuilder_ == null) { - return messageItem_.size(); - } else { - return messageItemBuilder_.getCount(); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItem getMessageItem(int index) { - if (messageItemBuilder_ == null) { - return messageItem_.get(index); - } else { - return messageItemBuilder_.getMessage(index); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder setMessageItem( - int index, MessageItem value) { - if (messageItemBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureMessageItemIsMutable(); - messageItem_.set(index, value); - onChanged(); - } else { - messageItemBuilder_.setMessage(index, value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder setMessageItem( - int index, MessageItem.Builder builderForValue) { - if (messageItemBuilder_ == null) { - ensureMessageItemIsMutable(); - messageItem_.set(index, builderForValue.build()); - onChanged(); - } else { - messageItemBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder addMessageItem(MessageItem value) { - if (messageItemBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureMessageItemIsMutable(); - messageItem_.add(value); - onChanged(); - } else { - messageItemBuilder_.addMessage(value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder addMessageItem( - int index, MessageItem value) { - if (messageItemBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureMessageItemIsMutable(); - messageItem_.add(index, value); - onChanged(); - } else { - messageItemBuilder_.addMessage(index, value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder addMessageItem( - MessageItem.Builder builderForValue) { - if (messageItemBuilder_ == null) { - ensureMessageItemIsMutable(); - messageItem_.add(builderForValue.build()); - onChanged(); - } else { - messageItemBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder addMessageItem( - int index, MessageItem.Builder builderForValue) { - if (messageItemBuilder_ == null) { - ensureMessageItemIsMutable(); - messageItem_.add(index, builderForValue.build()); - onChanged(); - } else { - messageItemBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder addAllMessageItem( - Iterable values) { - if (messageItemBuilder_ == null) { - ensureMessageItemIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, messageItem_); - onChanged(); - } else { - messageItemBuilder_.addAllMessages(values); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder clearMessageItem() { - if (messageItemBuilder_ == null) { - messageItem_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - } else { - messageItemBuilder_.clear(); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public Builder removeMessageItem(int index) { - if (messageItemBuilder_ == null) { - ensureMessageItemIsMutable(); - messageItem_.remove(index); - onChanged(); - } else { - messageItemBuilder_.remove(index); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItem.Builder getMessageItemBuilder( - int index) { - return getMessageItemFieldBuilder().getBuilder(index); - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItemOrBuilder getMessageItemOrBuilder( - int index) { - if (messageItemBuilder_ == null) { - return messageItem_.get(index); } else { - return messageItemBuilder_.getMessageOrBuilder(index); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public java.util.List - getMessageItemOrBuilderList() { - if (messageItemBuilder_ != null) { - return messageItemBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(messageItem_); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItem.Builder addMessageItemBuilder() { - return getMessageItemFieldBuilder().addBuilder( - MessageItem.getDefaultInstance()); - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public MessageItem.Builder addMessageItemBuilder( - int index) { - return getMessageItemFieldBuilder().addBuilder( - index, MessageItem.getDefaultInstance()); - } - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - public java.util.List - getMessageItemBuilderList() { - return getMessageItemFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilderV3< - MessageItem, MessageItem.Builder, MessageItemOrBuilder> - getMessageItemFieldBuilder() { - if (messageItemBuilder_ == null) { - messageItemBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< - MessageItem, MessageItem.Builder, MessageItemOrBuilder>( - messageItem_, - ((bitField0_ & 0x00000008) == 0x00000008), - getParentForChildren(), - isClean()); - messageItem_ = null; - } - return messageItemBuilder_; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.BatchMessage) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.BatchMessage) - private static final BatchMessage DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new BatchMessage(); - } - - public static BatchMessage getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public BatchMessage parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new BatchMessage(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public BatchMessage getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/BatchMessageOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/BatchMessageOrBuilder.java deleted file mode 100644 index 7f46dd24e9..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/BatchMessageOrBuilder.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public interface BatchMessageOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.BatchMessage) - com.google.protobuf.MessageOrBuilder { - - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - boolean hasHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeader getHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeaderOrBuilder getHeaderOrBuilder(); - - /** - * string producerGroup = 2; - */ - String getProducerGroup(); - /** - * string producerGroup = 2; - */ - com.google.protobuf.ByteString - getProducerGroupBytes(); - - /** - * string topic = 3; - */ - String getTopic(); - /** - * string topic = 3; - */ - com.google.protobuf.ByteString - getTopicBytes(); - - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - java.util.List - getMessageItemList(); - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - BatchMessage.MessageItem getMessageItem(int index); - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - int getMessageItemCount(); - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - java.util.List - getMessageItemOrBuilderList(); - /** - * repeated .eventmesh.common.protocol.grpc.BatchMessage.MessageItem messageItem = 4; - */ - BatchMessage.MessageItemOrBuilder getMessageItemOrBuilder( - int index); -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/ConsumerServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/ConsumerServiceGrpc.java deleted file mode 100644 index fbf4608c90..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/ConsumerServiceGrpc.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.protocol.grpc.protos; - -import static io.grpc.MethodDescriptor.generateFullMethodName; -import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; -import static io.grpc.stub.ClientCalls.asyncUnaryCall; -import static io.grpc.stub.ClientCalls.blockingUnaryCall; -import static io.grpc.stub.ClientCalls.futureUnaryCall; -import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall; -import static io.grpc.stub.ServerCalls.asyncUnaryCall; -import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; -import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; - -/** - */ -@SuppressWarnings({"all"}) -@javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.17.1)", - comments = "Source: eventmesh-client.proto") -public final class ConsumerServiceGrpc { - - private ConsumerServiceGrpc() {} - - public static final String SERVICE_NAME = "eventmesh.common.protocol.grpc.ConsumerService"; - - // Static method descriptors that strictly reflect the proto. - private static volatile io.grpc.MethodDescriptor getSubscribeMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "subscribe", - requestType = Subscription.class, - responseType = Response.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getSubscribeMethod() { - io.grpc.MethodDescriptor getSubscribeMethod; - if ((getSubscribeMethod = ConsumerServiceGrpc.getSubscribeMethod) == null) { - synchronized (ConsumerServiceGrpc.class) { - if ((getSubscribeMethod = ConsumerServiceGrpc.getSubscribeMethod) == null) { - ConsumerServiceGrpc.getSubscribeMethod = getSubscribeMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.ConsumerService", "subscribe")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Subscription.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Response.getDefaultInstance())) - .setSchemaDescriptor(new ConsumerServiceMethodDescriptorSupplier("subscribe")) - .build(); - } - } - } - return getSubscribeMethod; - } - - private static volatile io.grpc.MethodDescriptor getSubscribeStreamMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "subscribeStream", - requestType = Subscription.class, - responseType = SimpleMessage.class, - methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) - public static io.grpc.MethodDescriptor getSubscribeStreamMethod() { - io.grpc.MethodDescriptor getSubscribeStreamMethod; - if ((getSubscribeStreamMethod = ConsumerServiceGrpc.getSubscribeStreamMethod) == null) { - synchronized (ConsumerServiceGrpc.class) { - if ((getSubscribeStreamMethod = ConsumerServiceGrpc.getSubscribeStreamMethod) == null) { - ConsumerServiceGrpc.getSubscribeStreamMethod = getSubscribeStreamMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.ConsumerService", "subscribeStream")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Subscription.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - SimpleMessage.getDefaultInstance())) - .setSchemaDescriptor(new ConsumerServiceMethodDescriptorSupplier("subscribeStream")) - .build(); - } - } - } - return getSubscribeStreamMethod; - } - - private static volatile io.grpc.MethodDescriptor getUnsubscribeMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "unsubscribe", - requestType = Subscription.class, - responseType = Response.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getUnsubscribeMethod() { - io.grpc.MethodDescriptor getUnsubscribeMethod; - if ((getUnsubscribeMethod = ConsumerServiceGrpc.getUnsubscribeMethod) == null) { - synchronized (ConsumerServiceGrpc.class) { - if ((getUnsubscribeMethod = ConsumerServiceGrpc.getUnsubscribeMethod) == null) { - ConsumerServiceGrpc.getUnsubscribeMethod = getUnsubscribeMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.ConsumerService", "unsubscribe")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Subscription.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Response.getDefaultInstance())) - .setSchemaDescriptor(new ConsumerServiceMethodDescriptorSupplier("unsubscribe")) - .build(); - } - } - } - return getUnsubscribeMethod; - } - - /** - * Creates a new async stub that supports all call types for the service - */ - public static ConsumerServiceStub newStub(io.grpc.Channel channel) { - return new ConsumerServiceStub(channel); - } - - /** - * Creates a new blocking-style stub that supports unary and streaming output calls on the service - */ - public static ConsumerServiceBlockingStub newBlockingStub( - io.grpc.Channel channel) { - return new ConsumerServiceBlockingStub(channel); - } - - /** - * Creates a new ListenableFuture-style stub that supports unary calls on the service - */ - public static ConsumerServiceFutureStub newFutureStub( - io.grpc.Channel channel) { - return new ConsumerServiceFutureStub(channel); - } - - /** - */ - public static abstract class ConsumerServiceImplBase implements io.grpc.BindableService { - - /** - *
-     * The subscribed event will be delivered by invoking the webhook url in the Subscription
-     * 
- */ - public void subscribe(Subscription request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnimplementedUnaryCall(getSubscribeMethod(), responseObserver); - } - - /** - *
-     *  The subscribed event will be delivered through stream of Message
-     * 
- */ - public io.grpc.stub.StreamObserver subscribeStream( - io.grpc.stub.StreamObserver responseObserver) { - return asyncUnimplementedStreamingCall(getSubscribeStreamMethod(), responseObserver); - } - - /** - */ - public void unsubscribe(Subscription request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnimplementedUnaryCall(getUnsubscribeMethod(), responseObserver); - } - - @Override public final io.grpc.ServerServiceDefinition bindService() { - return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) - .addMethod( - getSubscribeMethod(), - asyncUnaryCall( - new MethodHandlers< - Subscription, - Response>( - this, METHODID_SUBSCRIBE))) - .addMethod( - getSubscribeStreamMethod(), - asyncBidiStreamingCall( - new MethodHandlers< - Subscription, - SimpleMessage>( - this, METHODID_SUBSCRIBE_STREAM))) - .addMethod( - getUnsubscribeMethod(), - asyncUnaryCall( - new MethodHandlers< - Subscription, - Response>( - this, METHODID_UNSUBSCRIBE))) - .build(); - } - } - - /** - */ - public static final class ConsumerServiceStub extends io.grpc.stub.AbstractStub { - private ConsumerServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private ConsumerServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected ConsumerServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new ConsumerServiceStub(channel, callOptions); - } - - /** - *
-     * The subscribed event will be delivered by invoking the webhook url in the Subscription
-     * 
- */ - public void subscribe(Subscription request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnaryCall( - getChannel().newCall(getSubscribeMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     *  The subscribed event will be delivered through stream of Message
-     * 
- */ - public io.grpc.stub.StreamObserver subscribeStream( - io.grpc.stub.StreamObserver responseObserver) { - return asyncBidiStreamingCall( - getChannel().newCall(getSubscribeStreamMethod(), getCallOptions()), responseObserver); - } - - /** - */ - public void unsubscribe(Subscription request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnaryCall( - getChannel().newCall(getUnsubscribeMethod(), getCallOptions()), request, responseObserver); - } - } - - /** - */ - public static final class ConsumerServiceBlockingStub extends io.grpc.stub.AbstractStub { - private ConsumerServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private ConsumerServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected ConsumerServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new ConsumerServiceBlockingStub(channel, callOptions); - } - - /** - *
-     * The subscribed event will be delivered by invoking the webhook url in the Subscription
-     * 
- */ - public Response subscribe(Subscription request) { - return blockingUnaryCall( - getChannel(), getSubscribeMethod(), getCallOptions(), request); - } - - /** - */ - public Response unsubscribe(Subscription request) { - return blockingUnaryCall( - getChannel(), getUnsubscribeMethod(), getCallOptions(), request); - } - } - - /** - */ - public static final class ConsumerServiceFutureStub extends io.grpc.stub.AbstractStub { - private ConsumerServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private ConsumerServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected ConsumerServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new ConsumerServiceFutureStub(channel, callOptions); - } - - /** - *
-     * The subscribed event will be delivered by invoking the webhook url in the Subscription
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture subscribe( - Subscription request) { - return futureUnaryCall( - getChannel().newCall(getSubscribeMethod(), getCallOptions()), request); - } - - /** - */ - public com.google.common.util.concurrent.ListenableFuture unsubscribe( - Subscription request) { - return futureUnaryCall( - getChannel().newCall(getUnsubscribeMethod(), getCallOptions()), request); - } - } - - private static final int METHODID_SUBSCRIBE = 0; - private static final int METHODID_UNSUBSCRIBE = 1; - private static final int METHODID_SUBSCRIBE_STREAM = 2; - - private static final class MethodHandlers implements - io.grpc.stub.ServerCalls.UnaryMethod, - io.grpc.stub.ServerCalls.ServerStreamingMethod, - io.grpc.stub.ServerCalls.ClientStreamingMethod, - io.grpc.stub.ServerCalls.BidiStreamingMethod { - private final ConsumerServiceImplBase serviceImpl; - private final int methodId; - - MethodHandlers(ConsumerServiceImplBase serviceImpl, int methodId) { - this.serviceImpl = serviceImpl; - this.methodId = methodId; - } - - @Override - @SuppressWarnings("unchecked") - public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - case METHODID_SUBSCRIBE: - serviceImpl.subscribe((Subscription) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_UNSUBSCRIBE: - serviceImpl.unsubscribe((Subscription) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - default: - throw new AssertionError(); - } - } - - @Override - @SuppressWarnings("unchecked") - public io.grpc.stub.StreamObserver invoke( - io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - case METHODID_SUBSCRIBE_STREAM: - return (io.grpc.stub.StreamObserver) serviceImpl.subscribeStream( - (io.grpc.stub.StreamObserver) responseObserver); - default: - throw new AssertionError(); - } - } - } - - private static abstract class ConsumerServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { - ConsumerServiceBaseDescriptorSupplier() {} - - @Override - public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { - return EventmeshGrpc.getDescriptor(); - } - - @Override - public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { - return getFileDescriptor().findServiceByName("ConsumerService"); - } - } - - private static final class ConsumerServiceFileDescriptorSupplier - extends ConsumerServiceBaseDescriptorSupplier { - ConsumerServiceFileDescriptorSupplier() {} - } - - private static final class ConsumerServiceMethodDescriptorSupplier - extends ConsumerServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { - private final String methodName; - - ConsumerServiceMethodDescriptorSupplier(String methodName) { - this.methodName = methodName; - } - - @Override - public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { - return getServiceDescriptor().findMethodByName(methodName); - } - } - - private static volatile io.grpc.ServiceDescriptor serviceDescriptor; - - public static io.grpc.ServiceDescriptor getServiceDescriptor() { - io.grpc.ServiceDescriptor result = serviceDescriptor; - if (result == null) { - synchronized (ConsumerServiceGrpc.class) { - result = serviceDescriptor; - if (result == null) { - serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) - .setSchemaDescriptor(new ConsumerServiceFileDescriptorSupplier()) - .addMethod(getSubscribeMethod()) - .addMethod(getSubscribeStreamMethod()) - .addMethod(getUnsubscribeMethod()) - .build(); - } - } - } - return result; - } -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/EventmeshGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/EventmeshGrpc.java deleted file mode 100644 index 4a1f2de63f..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/EventmeshGrpc.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public final class EventmeshGrpc { - private EventmeshGrpc() {} - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistryLite registry) { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - registerAllExtensions( - (com.google.protobuf.ExtensionRegistryLite) registry); - } - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_RequestHeader_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_RequestHeader_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_PropertiesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_PropertiesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_BatchMessage_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_PropertiesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_PropertiesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Response_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Response_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Subscription_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_PropertiesEntry_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_PropertiesEntry_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Heartbeat_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_descriptor; - static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_fieldAccessorTable; - - public static com.google.protobuf.Descriptors.FileDescriptor - getDescriptor() { - return descriptor; - } - private static com.google.protobuf.Descriptors.FileDescriptor - descriptor; - static { - String[] descriptorData = { - "\n\026eventmesh-client.proto\022\036eventmesh.comm" + - "on.protocol.grpc\"\332\001\n\rRequestHeader\022\013\n\003en" + - "v\030\001 \001(\t\022\016\n\006region\030\002 \001(\t\022\013\n\003idc\030\003 \001(\t\022\n\n\002" + - "ip\030\004 \001(\t\022\013\n\003pid\030\005 \001(\t\022\013\n\003sys\030\006 \001(\t\022\020\n\010us" + - "ername\030\007 \001(\t\022\020\n\010password\030\010 \001(\t\022\020\n\010langua" + - "ge\030\t \001(\t\022\024\n\014protocolType\030\n \001(\t\022\027\n\017protoc" + - "olVersion\030\013 \001(\t\022\024\n\014protocolDesc\030\014 \001(\t\"\307\002" + - "\n\rSimpleMessage\022=\n\006header\030\001 \001(\0132-.eventm" + - "esh.common.protocol.grpc.RequestHeader\022\025" + - "\n\rproducerGroup\030\002 \001(\t\022\r\n\005topic\030\003 \001(\t\022\017\n\007" + - "content\030\004 \001(\t\022\013\n\003ttl\030\005 \001(\t\022\020\n\010uniqueId\030\006" + - " \001(\t\022\016\n\006seqNum\030\007 \001(\t\022\013\n\003tag\030\010 \001(\t\022Q\n\npro" + - "perties\030\t \003(\0132=.eventmesh.common.protoco" + - "l.grpc.SimpleMessage.PropertiesEntry\0321\n\017" + - "PropertiesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 " + - "\001(\t:\0028\001\"\260\003\n\014BatchMessage\022=\n\006header\030\001 \001(\013" + - "2-.eventmesh.common.protocol.grpc.Reques" + - "tHeader\022\025\n\rproducerGroup\030\002 \001(\t\022\r\n\005topic\030" + - "\003 \001(\t\022M\n\013messageItem\030\004 \003(\01328.eventmesh.c" + - "ommon.protocol.grpc.BatchMessage.Message" + - "Item\032\353\001\n\013MessageItem\022\017\n\007content\030\001 \001(\t\022\013\n" + - "\003ttl\030\002 \001(\t\022\020\n\010uniqueId\030\003 \001(\t\022\016\n\006seqNum\030\004" + - " \001(\t\022\013\n\003tag\030\005 \001(\t\022\\\n\nproperties\030\006 \003(\0132H." + - "eventmesh.common.protocol.grpc.BatchMess" + - "age.MessageItem.PropertiesEntry\0321\n\017Prope" + - "rtiesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\002" + - "8\001\"?\n\010Response\022\020\n\010respCode\030\001 \001(\t\022\017\n\007resp" + - "Msg\030\002 \001(\t\022\020\n\010respTime\030\003 \001(\t\"\325\006\n\014Subscrip" + - "tion\022=\n\006header\030\001 \001(\0132-.eventmesh.common." + - "protocol.grpc.RequestHeader\022\025\n\rconsumerG" + - "roup\030\002 \001(\t\022X\n\021subscriptionItems\030\003 \003(\0132=." + - "eventmesh.common.protocol.grpc.Subscript" + - "ion.SubscriptionItem\022\013\n\003url\030\004 \001(\t\022A\n\005rep" + - "ly\030\005 \001(\01322.eventmesh.common.protocol.grp" + - "c.Subscription.Reply\032\274\002\n\020SubscriptionIte" + - "m\022\r\n\005topic\030\001 \001(\t\022\\\n\004mode\030\002 \001(\0162N.eventme" + - "sh.common.protocol.grpc.Subscription.Sub" + - "scriptionItem.SubscriptionMode\022\\\n\004type\030\003" + - " \001(\0162N.eventmesh.common.protocol.grpc.Su" + - "bscription.SubscriptionItem.Subscription" + - "Type\"4\n\020SubscriptionMode\022\016\n\nCLUSTERING\020\000" + - "\022\020\n\014BROADCASTING\020\001\"\'\n\020SubscriptionType\022\t" + - "\n\005ASYNC\020\000\022\010\n\004SYNC\020\001\032\205\002\n\005Reply\022\025\n\rproduce" + - "rGroup\030\001 \001(\t\022\r\n\005topic\030\002 \001(\t\022\017\n\007content\030\003" + - " \001(\t\022\013\n\003ttl\030\004 \001(\t\022\020\n\010uniqueId\030\005 \001(\t\022\016\n\006s" + - "eqNum\030\006 \001(\t\022\013\n\003tag\030\007 \001(\t\022V\n\nproperties\030\010" + - " \003(\0132B.eventmesh.common.protocol.grpc.Su" + - "bscription.Reply.PropertiesEntry\0321\n\017Prop" + - "ertiesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:" + - "\0028\001\"\340\002\n\tHeartbeat\022=\n\006header\030\001 \001(\0132-.even" + - "tmesh.common.protocol.grpc.RequestHeader" + - "\022H\n\nclientType\030\002 \001(\01624.eventmesh.common." + - "protocol.grpc.Heartbeat.ClientType\022\025\n\rpr" + - "oducerGroup\030\003 \001(\t\022\025\n\rconsumerGroup\030\004 \001(\t" + - "\022O\n\016heartbeatItems\030\005 \003(\01327.eventmesh.com" + - "mon.protocol.grpc.Heartbeat.HeartbeatIte" + - "m\032+\n\rHeartbeatItem\022\r\n\005topic\030\001 \001(\t\022\013\n\003url" + - "\030\002 \001(\t\"\036\n\nClientType\022\007\n\003PUB\020\000\022\007\n\003SUB\020\0012\314" + - "\002\n\020PublisherService\022b\n\007publish\022-.eventme" + - "sh.common.protocol.grpc.SimpleMessage\032(." + - "eventmesh.common.protocol.grpc.Response\022" + - "l\n\014requestReply\022-.eventmesh.common.proto" + - "col.grpc.SimpleMessage\032-.eventmesh.commo" + - "n.protocol.grpc.SimpleMessage\022f\n\014batchPu" + - "blish\022,.eventmesh.common.protocol.grpc.B" + - "atchMessage\032(.eventmesh.common.protocol." + - "grpc.Response2\321\002\n\017ConsumerService\022c\n\tsub" + - "scribe\022,.eventmesh.common.protocol.grpc." + - "Subscription\032(.eventmesh.common.protocol" + - ".grpc.Response\022r\n\017subscribeStream\022,.even" + - "tmesh.common.protocol.grpc.Subscription\032" + - "-.eventmesh.common.protocol.grpc.SimpleM" + - "essage(\0010\001\022e\n\013unsubscribe\022,.eventmesh.co" + - "mmon.protocol.grpc.Subscription\032(.eventm" + - "esh.common.protocol.grpc.Response2t\n\020Hea" + - "rtbeatService\022`\n\theartbeat\022).eventmesh.c" + - "ommon.protocol.grpc.Heartbeat\032(.eventmes" + - "h.common.protocol.grpc.ResponseBC\n0org.a" + - "pache.eventmesh.common.protocol.grpc.pro" + - "tosB\rEventmeshGrpcP\001b\006proto3" - }; - com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = - new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { - public com.google.protobuf.ExtensionRegistry assignDescriptors( - com.google.protobuf.Descriptors.FileDescriptor root) { - descriptor = root; - return null; - } - }; - com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - }, assigner); - internal_static_eventmesh_common_protocol_grpc_RequestHeader_descriptor = - getDescriptor().getMessageTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_RequestHeader_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_RequestHeader_descriptor, - new String[] { "Env", "Region", "Idc", "Ip", "Pid", "Sys", "Username", "Password", "Language", "ProtocolType", "ProtocolVersion", "ProtocolDesc", }); - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor = - getDescriptor().getMessageTypes().get(1); - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor, - new String[] { "Header", "ProducerGroup", "Topic", "Content", "Ttl", "UniqueId", "SeqNum", "Tag", "Properties", }); - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_PropertiesEntry_descriptor = - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor.getNestedTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_PropertiesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_SimpleMessage_PropertiesEntry_descriptor, - new String[] { "Key", "Value", }); - internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor = - getDescriptor().getMessageTypes().get(2); - internal_static_eventmesh_common_protocol_grpc_BatchMessage_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor, - new String[] { "Header", "ProducerGroup", "Topic", "MessageItem", }); - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor = - internal_static_eventmesh_common_protocol_grpc_BatchMessage_descriptor.getNestedTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor, - new String[] { "Content", "Ttl", "UniqueId", "SeqNum", "Tag", "Properties", }); - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_PropertiesEntry_descriptor = - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_descriptor.getNestedTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_PropertiesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_BatchMessage_MessageItem_PropertiesEntry_descriptor, - new String[] { "Key", "Value", }); - internal_static_eventmesh_common_protocol_grpc_Response_descriptor = - getDescriptor().getMessageTypes().get(3); - internal_static_eventmesh_common_protocol_grpc_Response_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Response_descriptor, - new String[] { "RespCode", "RespMsg", "RespTime", }); - internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor = - getDescriptor().getMessageTypes().get(4); - internal_static_eventmesh_common_protocol_grpc_Subscription_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor, - new String[] { "Header", "ConsumerGroup", "SubscriptionItems", "Url", "Reply", }); - internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_descriptor = - internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor.getNestedTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_descriptor, - new String[] { "Topic", "Mode", "Type", }); - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor = - internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor.getNestedTypes().get(1); - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor, - new String[] { "ProducerGroup", "Topic", "Content", "Ttl", "UniqueId", "SeqNum", "Tag", "Properties", }); - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_PropertiesEntry_descriptor = - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor.getNestedTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_PropertiesEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_PropertiesEntry_descriptor, - new String[] { "Key", "Value", }); - internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor = - getDescriptor().getMessageTypes().get(5); - internal_static_eventmesh_common_protocol_grpc_Heartbeat_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor, - new String[] { "Header", "ClientType", "ProducerGroup", "ConsumerGroup", "HeartbeatItems", }); - internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_descriptor = - internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor.getNestedTypes().get(0); - internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_descriptor, - new String[] { "Topic", "Url", }); - } - - // @@protoc_insertion_point(outer_class_scope) -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Heartbeat.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Heartbeat.java deleted file mode 100644 index bbab602dba..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Heartbeat.java +++ /dev/null @@ -1,2033 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -/** - * Protobuf type {@code eventmesh.common.protocol.grpc.Heartbeat} - */ -@SuppressWarnings({"all"}) -public final class Heartbeat extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.Heartbeat) - HeartbeatOrBuilder { -private static final long serialVersionUID = 0L; - // Use Heartbeat.newBuilder() to construct. - private Heartbeat(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private Heartbeat() { - clientType_ = 0; - producerGroup_ = ""; - consumerGroup_ = ""; - heartbeatItems_ = java.util.Collections.emptyList(); - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Heartbeat( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - RequestHeader.Builder subBuilder = null; - if (header_ != null) { - subBuilder = header_.toBuilder(); - } - header_ = input.readMessage(RequestHeader.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(header_); - header_ = subBuilder.buildPartial(); - } - - break; - } - case 16: { - int rawValue = input.readEnum(); - - clientType_ = rawValue; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - producerGroup_ = s; - break; - } - case 34: { - String s = input.readStringRequireUtf8(); - - consumerGroup_ = s; - break; - } - case 42: { - if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { - heartbeatItems_ = new java.util.ArrayList(); - mutable_bitField0_ |= 0x00000010; - } - heartbeatItems_.add( - input.readMessage(HeartbeatItem.parser(), extensionRegistry)); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { - heartbeatItems_ = java.util.Collections.unmodifiableList(heartbeatItems_); - } - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Heartbeat.class, Builder.class); - } - - /** - * Protobuf enum {@code eventmesh.common.protocol.grpc.Heartbeat.ClientType} - */ - public enum ClientType - implements com.google.protobuf.ProtocolMessageEnum { - /** - * PUB = 0; - */ - PUB(0), - /** - * SUB = 1; - */ - SUB(1), - UNRECOGNIZED(-1), - ; - - /** - * PUB = 0; - */ - public static final int PUB_VALUE = 0; - /** - * SUB = 1; - */ - public static final int SUB_VALUE = 1; - - - public final int getNumber() { - if (this == UNRECOGNIZED) { - throw new IllegalArgumentException( - "Can't get the number of an unknown enum value."); - } - return value; - } - - /** - * @deprecated Use {@link #forNumber(int)} instead. - */ - @Deprecated - public static ClientType valueOf(int value) { - return forNumber(value); - } - - public static ClientType forNumber(int value) { - switch (value) { - case 0: return PUB; - case 1: return SUB; - default: return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - private static final com.google.protobuf.Internal.EnumLiteMap< - ClientType> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public ClientType findValueByNumber(int number) { - return ClientType.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - return getDescriptor().getValues().get(ordinal()); - } - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - public static final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return Heartbeat.getDescriptor().getEnumTypes().get(0); - } - - private static final ClientType[] VALUES = values(); - - public static ClientType valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - if (desc.getIndex() == -1) { - return UNRECOGNIZED; - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private ClientType(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:eventmesh.common.protocol.grpc.Heartbeat.ClientType) - } - - public interface HeartbeatItemOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem) - com.google.protobuf.MessageOrBuilder { - - /** - * string topic = 1; - */ - String getTopic(); - /** - * string topic = 1; - */ - com.google.protobuf.ByteString - getTopicBytes(); - - /** - * string url = 2; - */ - String getUrl(); - /** - * string url = 2; - */ - com.google.protobuf.ByteString - getUrlBytes(); - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem} - */ - public static final class HeartbeatItem extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem) - HeartbeatItemOrBuilder { - private static final long serialVersionUID = 0L; - // Use HeartbeatItem.newBuilder() to construct. - private HeartbeatItem(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private HeartbeatItem() { - topic_ = ""; - url_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private HeartbeatItem( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - String s = input.readStringRequireUtf8(); - - topic_ = s; - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - url_ = s; - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_fieldAccessorTable - .ensureFieldAccessorsInitialized( - HeartbeatItem.class, Builder.class); - } - - public static final int TOPIC_FIELD_NUMBER = 1; - private volatile Object topic_; - /** - * string topic = 1; - */ - public String getTopic() { - Object ref = topic_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } - } - /** - * string topic = 1; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int URL_FIELD_NUMBER = 2; - private volatile Object url_; - /** - * string url = 2; - */ - public String getUrl() { - Object ref = url_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - url_ = s; - return s; - } - } - /** - * string url = 2; - */ - public com.google.protobuf.ByteString - getUrlBytes() { - Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getTopicBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, topic_); - } - if (!getUrlBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, url_); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!getTopicBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, topic_); - } - if (!getUrlBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, url_); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof HeartbeatItem)) { - return super.equals(obj); - } - HeartbeatItem other = (HeartbeatItem) obj; - - boolean result = true; - result = result && getTopic() - .equals(other.getTopic()); - result = result && getUrl() - .equals(other.getUrl()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TOPIC_FIELD_NUMBER; - hash = (53 * hash) + getTopic().hashCode(); - hash = (37 * hash) + URL_FIELD_NUMBER; - hash = (53 * hash) + getUrl().hashCode(); - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static HeartbeatItem parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static HeartbeatItem parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static HeartbeatItem parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static HeartbeatItem parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static HeartbeatItem parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static HeartbeatItem parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static HeartbeatItem parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static HeartbeatItem parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static HeartbeatItem parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static HeartbeatItem parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static HeartbeatItem parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static HeartbeatItem parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(HeartbeatItem prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem) - HeartbeatItemOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_fieldAccessorTable - .ensureFieldAccessorsInitialized( - HeartbeatItem.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat.HeartbeatItem.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - topic_ = ""; - - url_ = ""; - - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_HeartbeatItem_descriptor; - } - - public HeartbeatItem getDefaultInstanceForType() { - return HeartbeatItem.getDefaultInstance(); - } - - public HeartbeatItem build() { - HeartbeatItem result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public HeartbeatItem buildPartial() { - HeartbeatItem result = new HeartbeatItem(this); - result.topic_ = topic_; - result.url_ = url_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof HeartbeatItem) { - return mergeFrom((HeartbeatItem)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(HeartbeatItem other) { - if (other == HeartbeatItem.getDefaultInstance()) return this; - if (!other.getTopic().isEmpty()) { - topic_ = other.topic_; - onChanged(); - } - if (!other.getUrl().isEmpty()) { - url_ = other.url_; - onChanged(); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - HeartbeatItem parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (HeartbeatItem) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private Object topic_ = ""; - /** - * string topic = 1; - */ - public String getTopic() { - Object ref = topic_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string topic = 1; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string topic = 1; - */ - public Builder setTopic( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - topic_ = value; - onChanged(); - return this; - } - /** - * string topic = 1; - */ - public Builder clearTopic() { - - topic_ = getDefaultInstance().getTopic(); - onChanged(); - return this; - } - /** - * string topic = 1; - */ - public Builder setTopicBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - topic_ = value; - onChanged(); - return this; - } - - private Object url_ = ""; - /** - * string url = 2; - */ - public String getUrl() { - Object ref = url_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - url_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string url = 2; - */ - public com.google.protobuf.ByteString - getUrlBytes() { - Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string url = 2; - */ - public Builder setUrl( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - url_ = value; - onChanged(); - return this; - } - /** - * string url = 2; - */ - public Builder clearUrl() { - - url_ = getDefaultInstance().getUrl(); - onChanged(); - return this; - } - /** - * string url = 2; - */ - public Builder setUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - url_ = value; - onChanged(); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem) - private static final HeartbeatItem DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new HeartbeatItem(); - } - - public static HeartbeatItem getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public HeartbeatItem parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new HeartbeatItem(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public HeartbeatItem getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - - } - - private int bitField0_; - public static final int HEADER_FIELD_NUMBER = 1; - private RequestHeader header_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - return getHeader(); - } - - public static final int CLIENTTYPE_FIELD_NUMBER = 2; - private int clientType_; - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public int getClientTypeValue() { - return clientType_; - } - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public ClientType getClientType() { - ClientType result = ClientType.valueOf(clientType_); - return result == null ? ClientType.UNRECOGNIZED : result; - } - - public static final int PRODUCERGROUP_FIELD_NUMBER = 3; - private volatile Object producerGroup_; - /** - * string producerGroup = 3; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } - } - /** - * string producerGroup = 3; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONSUMERGROUP_FIELD_NUMBER = 4; - private volatile Object consumerGroup_; - /** - * string consumerGroup = 4; - */ - public String getConsumerGroup() { - Object ref = consumerGroup_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - consumerGroup_ = s; - return s; - } - } - /** - * string consumerGroup = 4; - */ - public com.google.protobuf.ByteString - getConsumerGroupBytes() { - Object ref = consumerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - consumerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int HEARTBEATITEMS_FIELD_NUMBER = 5; - private java.util.List heartbeatItems_; - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public java.util.List getHeartbeatItemsList() { - return heartbeatItems_; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public java.util.List - getHeartbeatItemsOrBuilderList() { - return heartbeatItems_; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public int getHeartbeatItemsCount() { - return heartbeatItems_.size(); - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItem getHeartbeatItems(int index) { - return heartbeatItems_.get(index); - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItemOrBuilder getHeartbeatItemsOrBuilder( - int index) { - return heartbeatItems_.get(index); - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (header_ != null) { - output.writeMessage(1, getHeader()); - } - if (clientType_ != ClientType.PUB.getNumber()) { - output.writeEnum(2, clientType_); - } - if (!getProducerGroupBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, producerGroup_); - } - if (!getConsumerGroupBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, consumerGroup_); - } - for (int i = 0; i < heartbeatItems_.size(); i++) { - output.writeMessage(5, heartbeatItems_.get(i)); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (header_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, getHeader()); - } - if (clientType_ != ClientType.PUB.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(2, clientType_); - } - if (!getProducerGroupBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, producerGroup_); - } - if (!getConsumerGroupBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, consumerGroup_); - } - for (int i = 0; i < heartbeatItems_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, heartbeatItems_.get(i)); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Heartbeat)) { - return super.equals(obj); - } - Heartbeat other = (Heartbeat) obj; - - boolean result = true; - result = result && (hasHeader() == other.hasHeader()); - if (hasHeader()) { - result = result && getHeader() - .equals(other.getHeader()); - } - result = result && clientType_ == other.clientType_; - result = result && getProducerGroup() - .equals(other.getProducerGroup()); - result = result && getConsumerGroup() - .equals(other.getConsumerGroup()); - result = result && getHeartbeatItemsList() - .equals(other.getHeartbeatItemsList()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasHeader()) { - hash = (37 * hash) + HEADER_FIELD_NUMBER; - hash = (53 * hash) + getHeader().hashCode(); - } - hash = (37 * hash) + CLIENTTYPE_FIELD_NUMBER; - hash = (53 * hash) + clientType_; - hash = (37 * hash) + PRODUCERGROUP_FIELD_NUMBER; - hash = (53 * hash) + getProducerGroup().hashCode(); - hash = (37 * hash) + CONSUMERGROUP_FIELD_NUMBER; - hash = (53 * hash) + getConsumerGroup().hashCode(); - if (getHeartbeatItemsCount() > 0) { - hash = (37 * hash) + HEARTBEATITEMS_FIELD_NUMBER; - hash = (53 * hash) + getHeartbeatItemsList().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static Heartbeat parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Heartbeat parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Heartbeat parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Heartbeat parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Heartbeat parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Heartbeat parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Heartbeat parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Heartbeat parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static Heartbeat parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static Heartbeat parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static Heartbeat parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Heartbeat parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(Heartbeat prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Heartbeat} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.Heartbeat) - HeartbeatOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Heartbeat.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - getHeartbeatItemsFieldBuilder(); - } - } - public Builder clear() { - super.clear(); - if (headerBuilder_ == null) { - header_ = null; - } else { - header_ = null; - headerBuilder_ = null; - } - clientType_ = 0; - - producerGroup_ = ""; - - consumerGroup_ = ""; - - if (heartbeatItemsBuilder_ == null) { - heartbeatItems_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000010); - } else { - heartbeatItemsBuilder_.clear(); - } - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Heartbeat_descriptor; - } - - public Heartbeat getDefaultInstanceForType() { - return Heartbeat.getDefaultInstance(); - } - - public Heartbeat build() { - Heartbeat result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public Heartbeat buildPartial() { - Heartbeat result = new Heartbeat(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (headerBuilder_ == null) { - result.header_ = header_; - } else { - result.header_ = headerBuilder_.build(); - } - result.clientType_ = clientType_; - result.producerGroup_ = producerGroup_; - result.consumerGroup_ = consumerGroup_; - if (heartbeatItemsBuilder_ == null) { - if (((bitField0_ & 0x00000010) == 0x00000010)) { - heartbeatItems_ = java.util.Collections.unmodifiableList(heartbeatItems_); - bitField0_ = (bitField0_ & ~0x00000010); - } - result.heartbeatItems_ = heartbeatItems_; - } else { - result.heartbeatItems_ = heartbeatItemsBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof Heartbeat) { - return mergeFrom((Heartbeat)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(Heartbeat other) { - if (other == Heartbeat.getDefaultInstance()) return this; - if (other.hasHeader()) { - mergeHeader(other.getHeader()); - } - if (other.clientType_ != 0) { - setClientTypeValue(other.getClientTypeValue()); - } - if (!other.getProducerGroup().isEmpty()) { - producerGroup_ = other.producerGroup_; - onChanged(); - } - if (!other.getConsumerGroup().isEmpty()) { - consumerGroup_ = other.consumerGroup_; - onChanged(); - } - if (heartbeatItemsBuilder_ == null) { - if (!other.heartbeatItems_.isEmpty()) { - if (heartbeatItems_.isEmpty()) { - heartbeatItems_ = other.heartbeatItems_; - bitField0_ = (bitField0_ & ~0x00000010); - } else { - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.addAll(other.heartbeatItems_); - } - onChanged(); - } - } else { - if (!other.heartbeatItems_.isEmpty()) { - if (heartbeatItemsBuilder_.isEmpty()) { - heartbeatItemsBuilder_.dispose(); - heartbeatItemsBuilder_ = null; - heartbeatItems_ = other.heartbeatItems_; - bitField0_ = (bitField0_ & ~0x00000010); - heartbeatItemsBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? - getHeartbeatItemsFieldBuilder() : null; - } else { - heartbeatItemsBuilder_.addAllMessages(other.heartbeatItems_); - } - } - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - Heartbeat parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (Heartbeat) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - private RequestHeader header_ = null; - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> headerBuilder_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return headerBuilder_ != null || header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - if (headerBuilder_ == null) { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } else { - return headerBuilder_.getMessage(); - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - header_ = value; - onChanged(); - } else { - headerBuilder_.setMessage(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader( - RequestHeader.Builder builderForValue) { - if (headerBuilder_ == null) { - header_ = builderForValue.build(); - onChanged(); - } else { - headerBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder mergeHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (header_ != null) { - header_ = - RequestHeader.newBuilder(header_).mergeFrom(value).buildPartial(); - } else { - header_ = value; - } - onChanged(); - } else { - headerBuilder_.mergeFrom(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder clearHeader() { - if (headerBuilder_ == null) { - header_ = null; - onChanged(); - } else { - header_ = null; - headerBuilder_ = null; - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader.Builder getHeaderBuilder() { - - onChanged(); - return getHeaderFieldBuilder().getBuilder(); - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - if (headerBuilder_ != null) { - return headerBuilder_.getMessageOrBuilder(); - } else { - return header_ == null ? - RequestHeader.getDefaultInstance() : header_; - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> - getHeaderFieldBuilder() { - if (headerBuilder_ == null) { - headerBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder>( - getHeader(), - getParentForChildren(), - isClean()); - header_ = null; - } - return headerBuilder_; - } - - private int clientType_ = 0; - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public int getClientTypeValue() { - return clientType_; - } - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public Builder setClientTypeValue(int value) { - clientType_ = value; - onChanged(); - return this; - } - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public ClientType getClientType() { - ClientType result = ClientType.valueOf(clientType_); - return result == null ? ClientType.UNRECOGNIZED : result; - } - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public Builder setClientType(ClientType value) { - if (value == null) { - throw new NullPointerException(); - } - - clientType_ = value.getNumber(); - onChanged(); - return this; - } - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - public Builder clearClientType() { - - clientType_ = 0; - onChanged(); - return this; - } - - private Object producerGroup_ = ""; - /** - * string producerGroup = 3; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string producerGroup = 3; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string producerGroup = 3; - */ - public Builder setProducerGroup( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - producerGroup_ = value; - onChanged(); - return this; - } - /** - * string producerGroup = 3; - */ - public Builder clearProducerGroup() { - - producerGroup_ = getDefaultInstance().getProducerGroup(); - onChanged(); - return this; - } - /** - * string producerGroup = 3; - */ - public Builder setProducerGroupBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - producerGroup_ = value; - onChanged(); - return this; - } - - private Object consumerGroup_ = ""; - /** - * string consumerGroup = 4; - */ - public String getConsumerGroup() { - Object ref = consumerGroup_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - consumerGroup_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string consumerGroup = 4; - */ - public com.google.protobuf.ByteString - getConsumerGroupBytes() { - Object ref = consumerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - consumerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string consumerGroup = 4; - */ - public Builder setConsumerGroup( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - consumerGroup_ = value; - onChanged(); - return this; - } - /** - * string consumerGroup = 4; - */ - public Builder clearConsumerGroup() { - - consumerGroup_ = getDefaultInstance().getConsumerGroup(); - onChanged(); - return this; - } - /** - * string consumerGroup = 4; - */ - public Builder setConsumerGroupBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - consumerGroup_ = value; - onChanged(); - return this; - } - - private java.util.List heartbeatItems_ = - java.util.Collections.emptyList(); - private void ensureHeartbeatItemsIsMutable() { - if (!((bitField0_ & 0x00000010) == 0x00000010)) { - heartbeatItems_ = new java.util.ArrayList(heartbeatItems_); - bitField0_ |= 0x00000010; - } - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - HeartbeatItem, HeartbeatItem.Builder, HeartbeatItemOrBuilder> heartbeatItemsBuilder_; - - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public java.util.List getHeartbeatItemsList() { - if (heartbeatItemsBuilder_ == null) { - return java.util.Collections.unmodifiableList(heartbeatItems_); - } else { - return heartbeatItemsBuilder_.getMessageList(); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public int getHeartbeatItemsCount() { - if (heartbeatItemsBuilder_ == null) { - return heartbeatItems_.size(); - } else { - return heartbeatItemsBuilder_.getCount(); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItem getHeartbeatItems(int index) { - if (heartbeatItemsBuilder_ == null) { - return heartbeatItems_.get(index); - } else { - return heartbeatItemsBuilder_.getMessage(index); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder setHeartbeatItems( - int index, HeartbeatItem value) { - if (heartbeatItemsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.set(index, value); - onChanged(); - } else { - heartbeatItemsBuilder_.setMessage(index, value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder setHeartbeatItems( - int index, HeartbeatItem.Builder builderForValue) { - if (heartbeatItemsBuilder_ == null) { - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.set(index, builderForValue.build()); - onChanged(); - } else { - heartbeatItemsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder addHeartbeatItems(HeartbeatItem value) { - if (heartbeatItemsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.add(value); - onChanged(); - } else { - heartbeatItemsBuilder_.addMessage(value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder addHeartbeatItems( - int index, HeartbeatItem value) { - if (heartbeatItemsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.add(index, value); - onChanged(); - } else { - heartbeatItemsBuilder_.addMessage(index, value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder addHeartbeatItems( - HeartbeatItem.Builder builderForValue) { - if (heartbeatItemsBuilder_ == null) { - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.add(builderForValue.build()); - onChanged(); - } else { - heartbeatItemsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder addHeartbeatItems( - int index, HeartbeatItem.Builder builderForValue) { - if (heartbeatItemsBuilder_ == null) { - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.add(index, builderForValue.build()); - onChanged(); - } else { - heartbeatItemsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder addAllHeartbeatItems( - Iterable values) { - if (heartbeatItemsBuilder_ == null) { - ensureHeartbeatItemsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, heartbeatItems_); - onChanged(); - } else { - heartbeatItemsBuilder_.addAllMessages(values); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder clearHeartbeatItems() { - if (heartbeatItemsBuilder_ == null) { - heartbeatItems_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000010); - onChanged(); - } else { - heartbeatItemsBuilder_.clear(); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public Builder removeHeartbeatItems(int index) { - if (heartbeatItemsBuilder_ == null) { - ensureHeartbeatItemsIsMutable(); - heartbeatItems_.remove(index); - onChanged(); - } else { - heartbeatItemsBuilder_.remove(index); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItem.Builder getHeartbeatItemsBuilder( - int index) { - return getHeartbeatItemsFieldBuilder().getBuilder(index); - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItemOrBuilder getHeartbeatItemsOrBuilder( - int index) { - if (heartbeatItemsBuilder_ == null) { - return heartbeatItems_.get(index); } else { - return heartbeatItemsBuilder_.getMessageOrBuilder(index); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public java.util.List - getHeartbeatItemsOrBuilderList() { - if (heartbeatItemsBuilder_ != null) { - return heartbeatItemsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(heartbeatItems_); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItem.Builder addHeartbeatItemsBuilder() { - return getHeartbeatItemsFieldBuilder().addBuilder( - HeartbeatItem.getDefaultInstance()); - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public HeartbeatItem.Builder addHeartbeatItemsBuilder( - int index) { - return getHeartbeatItemsFieldBuilder().addBuilder( - index, HeartbeatItem.getDefaultInstance()); - } - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - public java.util.List - getHeartbeatItemsBuilderList() { - return getHeartbeatItemsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilderV3< - HeartbeatItem, HeartbeatItem.Builder, HeartbeatItemOrBuilder> - getHeartbeatItemsFieldBuilder() { - if (heartbeatItemsBuilder_ == null) { - heartbeatItemsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< - HeartbeatItem, HeartbeatItem.Builder, HeartbeatItemOrBuilder>( - heartbeatItems_, - ((bitField0_ & 0x00000010) == 0x00000010), - getParentForChildren(), - isClean()); - heartbeatItems_ = null; - } - return heartbeatItemsBuilder_; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.Heartbeat) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.Heartbeat) - private static final Heartbeat DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new Heartbeat(); - } - - public static Heartbeat getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public Heartbeat parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Heartbeat(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public Heartbeat getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/HeartbeatOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/HeartbeatOrBuilder.java deleted file mode 100644 index c3cddbdb4b..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/HeartbeatOrBuilder.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public interface HeartbeatOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.Heartbeat) - com.google.protobuf.MessageOrBuilder { - - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - boolean hasHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeader getHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeaderOrBuilder getHeaderOrBuilder(); - - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - int getClientTypeValue(); - /** - * .eventmesh.common.protocol.grpc.Heartbeat.ClientType clientType = 2; - */ - Heartbeat.ClientType getClientType(); - - /** - * string producerGroup = 3; - */ - String getProducerGroup(); - /** - * string producerGroup = 3; - */ - com.google.protobuf.ByteString - getProducerGroupBytes(); - - /** - * string consumerGroup = 4; - */ - String getConsumerGroup(); - /** - * string consumerGroup = 4; - */ - com.google.protobuf.ByteString - getConsumerGroupBytes(); - - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - java.util.List - getHeartbeatItemsList(); - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - Heartbeat.HeartbeatItem getHeartbeatItems(int index); - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - int getHeartbeatItemsCount(); - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - java.util.List - getHeartbeatItemsOrBuilderList(); - /** - * repeated .eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem heartbeatItems = 5; - */ - Heartbeat.HeartbeatItemOrBuilder getHeartbeatItemsOrBuilder( - int index); -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/HeartbeatServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/HeartbeatServiceGrpc.java deleted file mode 100644 index 0860cc7e23..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/HeartbeatServiceGrpc.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.protocol.grpc.protos; - -import static io.grpc.MethodDescriptor.generateFullMethodName; -import static io.grpc.stub.ClientCalls.asyncUnaryCall; -import static io.grpc.stub.ClientCalls.blockingUnaryCall; -import static io.grpc.stub.ClientCalls.futureUnaryCall; -import static io.grpc.stub.ServerCalls.asyncUnaryCall; -import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; - -/** - */ -@SuppressWarnings({"all"}) -@javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.17.1)", - comments = "Source: eventmesh-client.proto") -public final class HeartbeatServiceGrpc { - - private HeartbeatServiceGrpc() {} - - public static final String SERVICE_NAME = "eventmesh.common.protocol.grpc.HeartbeatService"; - - // Static method descriptors that strictly reflect the proto. - private static volatile io.grpc.MethodDescriptor getHeartbeatMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "heartbeat", - requestType = Heartbeat.class, - responseType = Response.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getHeartbeatMethod() { - io.grpc.MethodDescriptor getHeartbeatMethod; - if ((getHeartbeatMethod = HeartbeatServiceGrpc.getHeartbeatMethod) == null) { - synchronized (HeartbeatServiceGrpc.class) { - if ((getHeartbeatMethod = HeartbeatServiceGrpc.getHeartbeatMethod) == null) { - HeartbeatServiceGrpc.getHeartbeatMethod = getHeartbeatMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.HeartbeatService", "heartbeat")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Heartbeat.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Response.getDefaultInstance())) - .setSchemaDescriptor(new HeartbeatServiceMethodDescriptorSupplier("heartbeat")) - .build(); - } - } - } - return getHeartbeatMethod; - } - - /** - * Creates a new async stub that supports all call types for the service - */ - public static HeartbeatServiceStub newStub(io.grpc.Channel channel) { - return new HeartbeatServiceStub(channel); - } - - /** - * Creates a new blocking-style stub that supports unary and streaming output calls on the service - */ - public static HeartbeatServiceBlockingStub newBlockingStub( - io.grpc.Channel channel) { - return new HeartbeatServiceBlockingStub(channel); - } - - /** - * Creates a new ListenableFuture-style stub that supports unary calls on the service - */ - public static HeartbeatServiceFutureStub newFutureStub( - io.grpc.Channel channel) { - return new HeartbeatServiceFutureStub(channel); - } - - /** - */ - public static abstract class HeartbeatServiceImplBase implements io.grpc.BindableService { - - /** - */ - public void heartbeat(Heartbeat request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnimplementedUnaryCall(getHeartbeatMethod(), responseObserver); - } - - @Override public final io.grpc.ServerServiceDefinition bindService() { - return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) - .addMethod( - getHeartbeatMethod(), - asyncUnaryCall( - new MethodHandlers< - Heartbeat, - Response>( - this, METHODID_HEARTBEAT))) - .build(); - } - } - - /** - */ - public static final class HeartbeatServiceStub extends io.grpc.stub.AbstractStub { - private HeartbeatServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private HeartbeatServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected HeartbeatServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new HeartbeatServiceStub(channel, callOptions); - } - - /** - */ - public void heartbeat(Heartbeat request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnaryCall( - getChannel().newCall(getHeartbeatMethod(), getCallOptions()), request, responseObserver); - } - } - - /** - */ - public static final class HeartbeatServiceBlockingStub extends io.grpc.stub.AbstractStub { - private HeartbeatServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private HeartbeatServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected HeartbeatServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new HeartbeatServiceBlockingStub(channel, callOptions); - } - - /** - */ - public Response heartbeat(Heartbeat request) { - return blockingUnaryCall( - getChannel(), getHeartbeatMethod(), getCallOptions(), request); - } - } - - /** - */ - public static final class HeartbeatServiceFutureStub extends io.grpc.stub.AbstractStub { - private HeartbeatServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private HeartbeatServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected HeartbeatServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new HeartbeatServiceFutureStub(channel, callOptions); - } - - /** - */ - public com.google.common.util.concurrent.ListenableFuture heartbeat( - Heartbeat request) { - return futureUnaryCall( - getChannel().newCall(getHeartbeatMethod(), getCallOptions()), request); - } - } - - private static final int METHODID_HEARTBEAT = 0; - - private static final class MethodHandlers implements - io.grpc.stub.ServerCalls.UnaryMethod, - io.grpc.stub.ServerCalls.ServerStreamingMethod, - io.grpc.stub.ServerCalls.ClientStreamingMethod, - io.grpc.stub.ServerCalls.BidiStreamingMethod { - private final HeartbeatServiceImplBase serviceImpl; - private final int methodId; - - MethodHandlers(HeartbeatServiceImplBase serviceImpl, int methodId) { - this.serviceImpl = serviceImpl; - this.methodId = methodId; - } - - @Override - @SuppressWarnings("unchecked") - public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - case METHODID_HEARTBEAT: - serviceImpl.heartbeat((Heartbeat) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - default: - throw new AssertionError(); - } - } - - @Override - @SuppressWarnings("unchecked") - public io.grpc.stub.StreamObserver invoke( - io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - default: - throw new AssertionError(); - } - } - } - - private static abstract class HeartbeatServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { - HeartbeatServiceBaseDescriptorSupplier() {} - - @Override - public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { - return EventmeshGrpc.getDescriptor(); - } - - @Override - public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { - return getFileDescriptor().findServiceByName("HeartbeatService"); - } - } - - private static final class HeartbeatServiceFileDescriptorSupplier - extends HeartbeatServiceBaseDescriptorSupplier { - HeartbeatServiceFileDescriptorSupplier() {} - } - - private static final class HeartbeatServiceMethodDescriptorSupplier - extends HeartbeatServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { - private final String methodName; - - HeartbeatServiceMethodDescriptorSupplier(String methodName) { - this.methodName = methodName; - } - - @Override - public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { - return getServiceDescriptor().findMethodByName(methodName); - } - } - - private static volatile io.grpc.ServiceDescriptor serviceDescriptor; - - public static io.grpc.ServiceDescriptor getServiceDescriptor() { - io.grpc.ServiceDescriptor result = serviceDescriptor; - if (result == null) { - synchronized (HeartbeatServiceGrpc.class) { - result = serviceDescriptor; - if (result == null) { - serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) - .setSchemaDescriptor(new HeartbeatServiceFileDescriptorSupplier()) - .addMethod(getHeartbeatMethod()) - .build(); - } - } - } - return result; - } -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/PublisherServiceGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/PublisherServiceGrpc.java deleted file mode 100644 index c223f47a38..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/PublisherServiceGrpc.java +++ /dev/null @@ -1,476 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.protocol.grpc.protos; - -import static io.grpc.MethodDescriptor.generateFullMethodName; -import static io.grpc.stub.ClientCalls.asyncUnaryCall; -import static io.grpc.stub.ClientCalls.blockingUnaryCall; -import static io.grpc.stub.ClientCalls.futureUnaryCall; -import static io.grpc.stub.ServerCalls.asyncUnaryCall; -import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; - -/** - */ -@SuppressWarnings({"all"}) -@javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.17.1)", - comments = "Source: eventmesh-client.proto") -public final class PublisherServiceGrpc { - - private PublisherServiceGrpc() {} - - public static final String SERVICE_NAME = "eventmesh.common.protocol.grpc.PublisherService"; - - // Static method descriptors that strictly reflect the proto. - private static volatile io.grpc.MethodDescriptor getPublishMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "publish", - requestType = SimpleMessage.class, - responseType = Response.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getPublishMethod() { - io.grpc.MethodDescriptor getPublishMethod; - if ((getPublishMethod = PublisherServiceGrpc.getPublishMethod) == null) { - synchronized (PublisherServiceGrpc.class) { - if ((getPublishMethod = PublisherServiceGrpc.getPublishMethod) == null) { - PublisherServiceGrpc.getPublishMethod = getPublishMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.PublisherService", "publish")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - SimpleMessage.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Response.getDefaultInstance())) - .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("publish")) - .build(); - } - } - } - return getPublishMethod; - } - - private static volatile io.grpc.MethodDescriptor getRequestReplyMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "requestReply", - requestType = SimpleMessage.class, - responseType = SimpleMessage.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getRequestReplyMethod() { - io.grpc.MethodDescriptor getRequestReplyMethod; - if ((getRequestReplyMethod = PublisherServiceGrpc.getRequestReplyMethod) == null) { - synchronized (PublisherServiceGrpc.class) { - if ((getRequestReplyMethod = PublisherServiceGrpc.getRequestReplyMethod) == null) { - PublisherServiceGrpc.getRequestReplyMethod = getRequestReplyMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.PublisherService", "requestReply")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - SimpleMessage.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - SimpleMessage.getDefaultInstance())) - .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("requestReply")) - .build(); - } - } - } - return getRequestReplyMethod; - } - - private static volatile io.grpc.MethodDescriptor getBatchPublishMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "batchPublish", - requestType = BatchMessage.class, - responseType = Response.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getBatchPublishMethod() { - io.grpc.MethodDescriptor getBatchPublishMethod; - if ((getBatchPublishMethod = PublisherServiceGrpc.getBatchPublishMethod) == null) { - synchronized (PublisherServiceGrpc.class) { - if ((getBatchPublishMethod = PublisherServiceGrpc.getBatchPublishMethod) == null) { - PublisherServiceGrpc.getBatchPublishMethod = getBatchPublishMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName( - "eventmesh.common.protocol.grpc.PublisherService", "batchPublish")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - BatchMessage.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - Response.getDefaultInstance())) - .setSchemaDescriptor(new PublisherServiceMethodDescriptorSupplier("batchPublish")) - .build(); - } - } - } - return getBatchPublishMethod; - } - - /** - * Creates a new async stub that supports all call types for the service - */ - public static PublisherServiceStub newStub(io.grpc.Channel channel) { - return new PublisherServiceStub(channel); - } - - /** - * Creates a new blocking-style stub that supports unary and streaming output calls on the service - */ - public static PublisherServiceBlockingStub newBlockingStub( - io.grpc.Channel channel) { - return new PublisherServiceBlockingStub(channel); - } - - /** - * Creates a new ListenableFuture-style stub that supports unary calls on the service - */ - public static PublisherServiceFutureStub newFutureStub( - io.grpc.Channel channel) { - return new PublisherServiceFutureStub(channel); - } - - /** - */ - public static abstract class PublisherServiceImplBase implements io.grpc.BindableService { - - /** - *
-     * Async event publish
-     * 
- */ - public void publish(SimpleMessage request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnimplementedUnaryCall(getPublishMethod(), responseObserver); - } - - /** - *
-     * Sync event publish
-     * 
- */ - public void requestReply(SimpleMessage request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnimplementedUnaryCall(getRequestReplyMethod(), responseObserver); - } - - /** - *
-     * Async batch event publish
-     * 
- */ - public void batchPublish(BatchMessage request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnimplementedUnaryCall(getBatchPublishMethod(), responseObserver); - } - - @Override public final io.grpc.ServerServiceDefinition bindService() { - return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) - .addMethod( - getPublishMethod(), - asyncUnaryCall( - new MethodHandlers< - SimpleMessage, - Response>( - this, METHODID_PUBLISH))) - .addMethod( - getRequestReplyMethod(), - asyncUnaryCall( - new MethodHandlers< - SimpleMessage, - SimpleMessage>( - this, METHODID_REQUEST_REPLY))) - .addMethod( - getBatchPublishMethod(), - asyncUnaryCall( - new MethodHandlers< - BatchMessage, - Response>( - this, METHODID_BATCH_PUBLISH))) - .build(); - } - } - - /** - */ - public static final class PublisherServiceStub extends io.grpc.stub.AbstractStub { - private PublisherServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private PublisherServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected PublisherServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new PublisherServiceStub(channel, callOptions); - } - - /** - *
-     * Async event publish
-     * 
- */ - public void publish(SimpleMessage request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnaryCall( - getChannel().newCall(getPublishMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Sync event publish
-     * 
- */ - public void requestReply(SimpleMessage request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnaryCall( - getChannel().newCall(getRequestReplyMethod(), getCallOptions()), request, responseObserver); - } - - /** - *
-     * Async batch event publish
-     * 
- */ - public void batchPublish(BatchMessage request, - io.grpc.stub.StreamObserver responseObserver) { - asyncUnaryCall( - getChannel().newCall(getBatchPublishMethod(), getCallOptions()), request, responseObserver); - } - } - - /** - */ - public static final class PublisherServiceBlockingStub extends io.grpc.stub.AbstractStub { - private PublisherServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private PublisherServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected PublisherServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new PublisherServiceBlockingStub(channel, callOptions); - } - - /** - *
-     * Async event publish
-     * 
- */ - public Response publish(SimpleMessage request) { - return blockingUnaryCall( - getChannel(), getPublishMethod(), getCallOptions(), request); - } - - /** - *
-     * Sync event publish
-     * 
- */ - public SimpleMessage requestReply(SimpleMessage request) { - return blockingUnaryCall( - getChannel(), getRequestReplyMethod(), getCallOptions(), request); - } - - /** - *
-     * Async batch event publish
-     * 
- */ - public Response batchPublish(BatchMessage request) { - return blockingUnaryCall( - getChannel(), getBatchPublishMethod(), getCallOptions(), request); - } - } - - /** - */ - public static final class PublisherServiceFutureStub extends io.grpc.stub.AbstractStub { - private PublisherServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private PublisherServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @Override - protected PublisherServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { - return new PublisherServiceFutureStub(channel, callOptions); - } - - /** - *
-     * Async event publish
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture publish( - SimpleMessage request) { - return futureUnaryCall( - getChannel().newCall(getPublishMethod(), getCallOptions()), request); - } - - /** - *
-     * Sync event publish
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture requestReply( - SimpleMessage request) { - return futureUnaryCall( - getChannel().newCall(getRequestReplyMethod(), getCallOptions()), request); - } - - /** - *
-     * Async batch event publish
-     * 
- */ - public com.google.common.util.concurrent.ListenableFuture batchPublish( - BatchMessage request) { - return futureUnaryCall( - getChannel().newCall(getBatchPublishMethod(), getCallOptions()), request); - } - } - - private static final int METHODID_PUBLISH = 0; - private static final int METHODID_REQUEST_REPLY = 1; - private static final int METHODID_BATCH_PUBLISH = 2; - - private static final class MethodHandlers implements - io.grpc.stub.ServerCalls.UnaryMethod, - io.grpc.stub.ServerCalls.ServerStreamingMethod, - io.grpc.stub.ServerCalls.ClientStreamingMethod, - io.grpc.stub.ServerCalls.BidiStreamingMethod { - private final PublisherServiceImplBase serviceImpl; - private final int methodId; - - MethodHandlers(PublisherServiceImplBase serviceImpl, int methodId) { - this.serviceImpl = serviceImpl; - this.methodId = methodId; - } - - @Override - @SuppressWarnings("unchecked") - public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - case METHODID_PUBLISH: - serviceImpl.publish((SimpleMessage) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_REQUEST_REPLY: - serviceImpl.requestReply((SimpleMessage) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - case METHODID_BATCH_PUBLISH: - serviceImpl.batchPublish((BatchMessage) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - default: - throw new AssertionError(); - } - } - - @Override - @SuppressWarnings("unchecked") - public io.grpc.stub.StreamObserver invoke( - io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - default: - throw new AssertionError(); - } - } - } - - private static abstract class PublisherServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { - PublisherServiceBaseDescriptorSupplier() {} - - @Override - public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { - return EventmeshGrpc.getDescriptor(); - } - - @Override - public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { - return getFileDescriptor().findServiceByName("PublisherService"); - } - } - - private static final class PublisherServiceFileDescriptorSupplier - extends PublisherServiceBaseDescriptorSupplier { - PublisherServiceFileDescriptorSupplier() {} - } - - private static final class PublisherServiceMethodDescriptorSupplier - extends PublisherServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { - private final String methodName; - - PublisherServiceMethodDescriptorSupplier(String methodName) { - this.methodName = methodName; - } - - @Override - public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { - return getServiceDescriptor().findMethodByName(methodName); - } - } - - private static volatile io.grpc.ServiceDescriptor serviceDescriptor; - - public static io.grpc.ServiceDescriptor getServiceDescriptor() { - io.grpc.ServiceDescriptor result = serviceDescriptor; - if (result == null) { - synchronized (PublisherServiceGrpc.class) { - result = serviceDescriptor; - if (result == null) { - serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) - .setSchemaDescriptor(new PublisherServiceFileDescriptorSupplier()) - .addMethod(getPublishMethod()) - .addMethod(getRequestReplyMethod()) - .addMethod(getBatchPublishMethod()) - .build(); - } - } - } - return result; - } -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/RequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/RequestHeader.java deleted file mode 100644 index 3bd71b33e4..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/RequestHeader.java +++ /dev/null @@ -1,1931 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -/** - * Protobuf type {@code eventmesh.common.protocol.grpc.RequestHeader} - */ -@SuppressWarnings({"all"}) -public final class RequestHeader extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.RequestHeader) - RequestHeaderOrBuilder { -private static final long serialVersionUID = 0L; - // Use RequestHeader.newBuilder() to construct. - private RequestHeader(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private RequestHeader() { - env_ = ""; - region_ = ""; - idc_ = ""; - ip_ = ""; - pid_ = ""; - sys_ = ""; - username_ = ""; - password_ = ""; - language_ = ""; - protocolType_ = ""; - protocolVersion_ = ""; - protocolDesc_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private RequestHeader( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - String s = input.readStringRequireUtf8(); - - env_ = s; - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - region_ = s; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - idc_ = s; - break; - } - case 34: { - String s = input.readStringRequireUtf8(); - - ip_ = s; - break; - } - case 42: { - String s = input.readStringRequireUtf8(); - - pid_ = s; - break; - } - case 50: { - String s = input.readStringRequireUtf8(); - - sys_ = s; - break; - } - case 58: { - String s = input.readStringRequireUtf8(); - - username_ = s; - break; - } - case 66: { - String s = input.readStringRequireUtf8(); - - password_ = s; - break; - } - case 74: { - String s = input.readStringRequireUtf8(); - - language_ = s; - break; - } - case 82: { - String s = input.readStringRequireUtf8(); - - protocolType_ = s; - break; - } - case 90: { - String s = input.readStringRequireUtf8(); - - protocolVersion_ = s; - break; - } - case 98: { - String s = input.readStringRequireUtf8(); - - protocolDesc_ = s; - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_RequestHeader_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_RequestHeader_fieldAccessorTable - .ensureFieldAccessorsInitialized( - RequestHeader.class, Builder.class); - } - - public static final int ENV_FIELD_NUMBER = 1; - private volatile Object env_; - /** - * string env = 1; - */ - public String getEnv() { - Object ref = env_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - env_ = s; - return s; - } - } - /** - * string env = 1; - */ - public com.google.protobuf.ByteString - getEnvBytes() { - Object ref = env_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - env_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REGION_FIELD_NUMBER = 2; - private volatile Object region_; - /** - * string region = 2; - */ - public String getRegion() { - Object ref = region_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - region_ = s; - return s; - } - } - /** - * string region = 2; - */ - public com.google.protobuf.ByteString - getRegionBytes() { - Object ref = region_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - region_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int IDC_FIELD_NUMBER = 3; - private volatile Object idc_; - /** - * string idc = 3; - */ - public String getIdc() { - Object ref = idc_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - idc_ = s; - return s; - } - } - /** - * string idc = 3; - */ - public com.google.protobuf.ByteString - getIdcBytes() { - Object ref = idc_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - idc_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int IP_FIELD_NUMBER = 4; - private volatile Object ip_; - /** - * string ip = 4; - */ - public String getIp() { - Object ref = ip_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ip_ = s; - return s; - } - } - /** - * string ip = 4; - */ - public com.google.protobuf.ByteString - getIpBytes() { - Object ref = ip_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ip_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PID_FIELD_NUMBER = 5; - private volatile Object pid_; - /** - * string pid = 5; - */ - public String getPid() { - Object ref = pid_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - pid_ = s; - return s; - } - } - /** - * string pid = 5; - */ - public com.google.protobuf.ByteString - getPidBytes() { - Object ref = pid_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - pid_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SYS_FIELD_NUMBER = 6; - private volatile Object sys_; - /** - * string sys = 6; - */ - public String getSys() { - Object ref = sys_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - sys_ = s; - return s; - } - } - /** - * string sys = 6; - */ - public com.google.protobuf.ByteString - getSysBytes() { - Object ref = sys_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - sys_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int USERNAME_FIELD_NUMBER = 7; - private volatile Object username_; - /** - * string username = 7; - */ - public String getUsername() { - Object ref = username_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - username_ = s; - return s; - } - } - /** - * string username = 7; - */ - public com.google.protobuf.ByteString - getUsernameBytes() { - Object ref = username_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - username_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PASSWORD_FIELD_NUMBER = 8; - private volatile Object password_; - /** - * string password = 8; - */ - public String getPassword() { - Object ref = password_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - password_ = s; - return s; - } - } - /** - * string password = 8; - */ - public com.google.protobuf.ByteString - getPasswordBytes() { - Object ref = password_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - password_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int LANGUAGE_FIELD_NUMBER = 9; - private volatile Object language_; - /** - * string language = 9; - */ - public String getLanguage() { - Object ref = language_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - language_ = s; - return s; - } - } - /** - * string language = 9; - */ - public com.google.protobuf.ByteString - getLanguageBytes() { - Object ref = language_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - language_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROTOCOLTYPE_FIELD_NUMBER = 10; - private volatile Object protocolType_; - /** - * string protocolType = 10; - */ - public String getProtocolType() { - Object ref = protocolType_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - protocolType_ = s; - return s; - } - } - /** - * string protocolType = 10; - */ - public com.google.protobuf.ByteString - getProtocolTypeBytes() { - Object ref = protocolType_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - protocolType_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROTOCOLVERSION_FIELD_NUMBER = 11; - private volatile Object protocolVersion_; - /** - * string protocolVersion = 11; - */ - public String getProtocolVersion() { - Object ref = protocolVersion_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - protocolVersion_ = s; - return s; - } - } - /** - * string protocolVersion = 11; - */ - public com.google.protobuf.ByteString - getProtocolVersionBytes() { - Object ref = protocolVersion_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - protocolVersion_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROTOCOLDESC_FIELD_NUMBER = 12; - private volatile Object protocolDesc_; - /** - * string protocolDesc = 12; - */ - public String getProtocolDesc() { - Object ref = protocolDesc_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - protocolDesc_ = s; - return s; - } - } - /** - * string protocolDesc = 12; - */ - public com.google.protobuf.ByteString - getProtocolDescBytes() { - Object ref = protocolDesc_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - protocolDesc_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getEnvBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, env_); - } - if (!getRegionBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, region_); - } - if (!getIdcBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, idc_); - } - if (!getIpBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, ip_); - } - if (!getPidBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 5, pid_); - } - if (!getSysBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 6, sys_); - } - if (!getUsernameBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 7, username_); - } - if (!getPasswordBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 8, password_); - } - if (!getLanguageBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 9, language_); - } - if (!getProtocolTypeBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 10, protocolType_); - } - if (!getProtocolVersionBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 11, protocolVersion_); - } - if (!getProtocolDescBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 12, protocolDesc_); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!getEnvBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, env_); - } - if (!getRegionBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, region_); - } - if (!getIdcBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, idc_); - } - if (!getIpBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, ip_); - } - if (!getPidBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, pid_); - } - if (!getSysBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, sys_); - } - if (!getUsernameBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, username_); - } - if (!getPasswordBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(8, password_); - } - if (!getLanguageBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(9, language_); - } - if (!getProtocolTypeBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(10, protocolType_); - } - if (!getProtocolVersionBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(11, protocolVersion_); - } - if (!getProtocolDescBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(12, protocolDesc_); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof RequestHeader)) { - return super.equals(obj); - } - RequestHeader other = (RequestHeader) obj; - - boolean result = true; - result = result && getEnv() - .equals(other.getEnv()); - result = result && getRegion() - .equals(other.getRegion()); - result = result && getIdc() - .equals(other.getIdc()); - result = result && getIp() - .equals(other.getIp()); - result = result && getPid() - .equals(other.getPid()); - result = result && getSys() - .equals(other.getSys()); - result = result && getUsername() - .equals(other.getUsername()); - result = result && getPassword() - .equals(other.getPassword()); - result = result && getLanguage() - .equals(other.getLanguage()); - result = result && getProtocolType() - .equals(other.getProtocolType()); - result = result && getProtocolVersion() - .equals(other.getProtocolVersion()); - result = result && getProtocolDesc() - .equals(other.getProtocolDesc()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + ENV_FIELD_NUMBER; - hash = (53 * hash) + getEnv().hashCode(); - hash = (37 * hash) + REGION_FIELD_NUMBER; - hash = (53 * hash) + getRegion().hashCode(); - hash = (37 * hash) + IDC_FIELD_NUMBER; - hash = (53 * hash) + getIdc().hashCode(); - hash = (37 * hash) + IP_FIELD_NUMBER; - hash = (53 * hash) + getIp().hashCode(); - hash = (37 * hash) + PID_FIELD_NUMBER; - hash = (53 * hash) + getPid().hashCode(); - hash = (37 * hash) + SYS_FIELD_NUMBER; - hash = (53 * hash) + getSys().hashCode(); - hash = (37 * hash) + USERNAME_FIELD_NUMBER; - hash = (53 * hash) + getUsername().hashCode(); - hash = (37 * hash) + PASSWORD_FIELD_NUMBER; - hash = (53 * hash) + getPassword().hashCode(); - hash = (37 * hash) + LANGUAGE_FIELD_NUMBER; - hash = (53 * hash) + getLanguage().hashCode(); - hash = (37 * hash) + PROTOCOLTYPE_FIELD_NUMBER; - hash = (53 * hash) + getProtocolType().hashCode(); - hash = (37 * hash) + PROTOCOLVERSION_FIELD_NUMBER; - hash = (53 * hash) + getProtocolVersion().hashCode(); - hash = (37 * hash) + PROTOCOLDESC_FIELD_NUMBER; - hash = (53 * hash) + getProtocolDesc().hashCode(); - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static RequestHeader parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static RequestHeader parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static RequestHeader parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static RequestHeader parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static RequestHeader parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static RequestHeader parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static RequestHeader parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static RequestHeader parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static RequestHeader parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static RequestHeader parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static RequestHeader parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static RequestHeader parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(RequestHeader prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.RequestHeader} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.RequestHeader) - RequestHeaderOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_RequestHeader_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_RequestHeader_fieldAccessorTable - .ensureFieldAccessorsInitialized( - RequestHeader.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - env_ = ""; - - region_ = ""; - - idc_ = ""; - - ip_ = ""; - - pid_ = ""; - - sys_ = ""; - - username_ = ""; - - password_ = ""; - - language_ = ""; - - protocolType_ = ""; - - protocolVersion_ = ""; - - protocolDesc_ = ""; - - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_RequestHeader_descriptor; - } - - public RequestHeader getDefaultInstanceForType() { - return RequestHeader.getDefaultInstance(); - } - - public RequestHeader build() { - RequestHeader result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public RequestHeader buildPartial() { - RequestHeader result = new RequestHeader(this); - result.env_ = env_; - result.region_ = region_; - result.idc_ = idc_; - result.ip_ = ip_; - result.pid_ = pid_; - result.sys_ = sys_; - result.username_ = username_; - result.password_ = password_; - result.language_ = language_; - result.protocolType_ = protocolType_; - result.protocolVersion_ = protocolVersion_; - result.protocolDesc_ = protocolDesc_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof RequestHeader) { - return mergeFrom((RequestHeader)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(RequestHeader other) { - if (other == RequestHeader.getDefaultInstance()) return this; - if (!other.getEnv().isEmpty()) { - env_ = other.env_; - onChanged(); - } - if (!other.getRegion().isEmpty()) { - region_ = other.region_; - onChanged(); - } - if (!other.getIdc().isEmpty()) { - idc_ = other.idc_; - onChanged(); - } - if (!other.getIp().isEmpty()) { - ip_ = other.ip_; - onChanged(); - } - if (!other.getPid().isEmpty()) { - pid_ = other.pid_; - onChanged(); - } - if (!other.getSys().isEmpty()) { - sys_ = other.sys_; - onChanged(); - } - if (!other.getUsername().isEmpty()) { - username_ = other.username_; - onChanged(); - } - if (!other.getPassword().isEmpty()) { - password_ = other.password_; - onChanged(); - } - if (!other.getLanguage().isEmpty()) { - language_ = other.language_; - onChanged(); - } - if (!other.getProtocolType().isEmpty()) { - protocolType_ = other.protocolType_; - onChanged(); - } - if (!other.getProtocolVersion().isEmpty()) { - protocolVersion_ = other.protocolVersion_; - onChanged(); - } - if (!other.getProtocolDesc().isEmpty()) { - protocolDesc_ = other.protocolDesc_; - onChanged(); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - RequestHeader parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (RequestHeader) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private Object env_ = ""; - /** - * string env = 1; - */ - public String getEnv() { - Object ref = env_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - env_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string env = 1; - */ - public com.google.protobuf.ByteString - getEnvBytes() { - Object ref = env_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - env_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string env = 1; - */ - public Builder setEnv( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - env_ = value; - onChanged(); - return this; - } - /** - * string env = 1; - */ - public Builder clearEnv() { - - env_ = getDefaultInstance().getEnv(); - onChanged(); - return this; - } - /** - * string env = 1; - */ - public Builder setEnvBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - env_ = value; - onChanged(); - return this; - } - - private Object region_ = ""; - /** - * string region = 2; - */ - public String getRegion() { - Object ref = region_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - region_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string region = 2; - */ - public com.google.protobuf.ByteString - getRegionBytes() { - Object ref = region_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - region_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string region = 2; - */ - public Builder setRegion( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - region_ = value; - onChanged(); - return this; - } - /** - * string region = 2; - */ - public Builder clearRegion() { - - region_ = getDefaultInstance().getRegion(); - onChanged(); - return this; - } - /** - * string region = 2; - */ - public Builder setRegionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - region_ = value; - onChanged(); - return this; - } - - private Object idc_ = ""; - /** - * string idc = 3; - */ - public String getIdc() { - Object ref = idc_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - idc_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string idc = 3; - */ - public com.google.protobuf.ByteString - getIdcBytes() { - Object ref = idc_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - idc_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string idc = 3; - */ - public Builder setIdc( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - idc_ = value; - onChanged(); - return this; - } - /** - * string idc = 3; - */ - public Builder clearIdc() { - - idc_ = getDefaultInstance().getIdc(); - onChanged(); - return this; - } - /** - * string idc = 3; - */ - public Builder setIdcBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - idc_ = value; - onChanged(); - return this; - } - - private Object ip_ = ""; - /** - * string ip = 4; - */ - public String getIp() { - Object ref = ip_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ip_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string ip = 4; - */ - public com.google.protobuf.ByteString - getIpBytes() { - Object ref = ip_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ip_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string ip = 4; - */ - public Builder setIp( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - ip_ = value; - onChanged(); - return this; - } - /** - * string ip = 4; - */ - public Builder clearIp() { - - ip_ = getDefaultInstance().getIp(); - onChanged(); - return this; - } - /** - * string ip = 4; - */ - public Builder setIpBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - ip_ = value; - onChanged(); - return this; - } - - private Object pid_ = ""; - /** - * string pid = 5; - */ - public String getPid() { - Object ref = pid_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - pid_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string pid = 5; - */ - public com.google.protobuf.ByteString - getPidBytes() { - Object ref = pid_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - pid_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string pid = 5; - */ - public Builder setPid( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - pid_ = value; - onChanged(); - return this; - } - /** - * string pid = 5; - */ - public Builder clearPid() { - - pid_ = getDefaultInstance().getPid(); - onChanged(); - return this; - } - /** - * string pid = 5; - */ - public Builder setPidBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - pid_ = value; - onChanged(); - return this; - } - - private Object sys_ = ""; - /** - * string sys = 6; - */ - public String getSys() { - Object ref = sys_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - sys_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string sys = 6; - */ - public com.google.protobuf.ByteString - getSysBytes() { - Object ref = sys_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - sys_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string sys = 6; - */ - public Builder setSys( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - sys_ = value; - onChanged(); - return this; - } - /** - * string sys = 6; - */ - public Builder clearSys() { - - sys_ = getDefaultInstance().getSys(); - onChanged(); - return this; - } - /** - * string sys = 6; - */ - public Builder setSysBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - sys_ = value; - onChanged(); - return this; - } - - private Object username_ = ""; - /** - * string username = 7; - */ - public String getUsername() { - Object ref = username_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - username_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string username = 7; - */ - public com.google.protobuf.ByteString - getUsernameBytes() { - Object ref = username_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - username_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string username = 7; - */ - public Builder setUsername( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - username_ = value; - onChanged(); - return this; - } - /** - * string username = 7; - */ - public Builder clearUsername() { - - username_ = getDefaultInstance().getUsername(); - onChanged(); - return this; - } - /** - * string username = 7; - */ - public Builder setUsernameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - username_ = value; - onChanged(); - return this; - } - - private Object password_ = ""; - /** - * string password = 8; - */ - public String getPassword() { - Object ref = password_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - password_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string password = 8; - */ - public com.google.protobuf.ByteString - getPasswordBytes() { - Object ref = password_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - password_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string password = 8; - */ - public Builder setPassword( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - password_ = value; - onChanged(); - return this; - } - /** - * string password = 8; - */ - public Builder clearPassword() { - - password_ = getDefaultInstance().getPassword(); - onChanged(); - return this; - } - /** - * string password = 8; - */ - public Builder setPasswordBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - password_ = value; - onChanged(); - return this; - } - - private Object language_ = ""; - /** - * string language = 9; - */ - public String getLanguage() { - Object ref = language_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - language_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string language = 9; - */ - public com.google.protobuf.ByteString - getLanguageBytes() { - Object ref = language_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - language_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string language = 9; - */ - public Builder setLanguage( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - language_ = value; - onChanged(); - return this; - } - /** - * string language = 9; - */ - public Builder clearLanguage() { - - language_ = getDefaultInstance().getLanguage(); - onChanged(); - return this; - } - /** - * string language = 9; - */ - public Builder setLanguageBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - language_ = value; - onChanged(); - return this; - } - - private Object protocolType_ = ""; - /** - * string protocolType = 10; - */ - public String getProtocolType() { - Object ref = protocolType_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - protocolType_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string protocolType = 10; - */ - public com.google.protobuf.ByteString - getProtocolTypeBytes() { - Object ref = protocolType_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - protocolType_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string protocolType = 10; - */ - public Builder setProtocolType( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - protocolType_ = value; - onChanged(); - return this; - } - /** - * string protocolType = 10; - */ - public Builder clearProtocolType() { - - protocolType_ = getDefaultInstance().getProtocolType(); - onChanged(); - return this; - } - /** - * string protocolType = 10; - */ - public Builder setProtocolTypeBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - protocolType_ = value; - onChanged(); - return this; - } - - private Object protocolVersion_ = ""; - /** - * string protocolVersion = 11; - */ - public String getProtocolVersion() { - Object ref = protocolVersion_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - protocolVersion_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string protocolVersion = 11; - */ - public com.google.protobuf.ByteString - getProtocolVersionBytes() { - Object ref = protocolVersion_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - protocolVersion_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string protocolVersion = 11; - */ - public Builder setProtocolVersion( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - protocolVersion_ = value; - onChanged(); - return this; - } - /** - * string protocolVersion = 11; - */ - public Builder clearProtocolVersion() { - - protocolVersion_ = getDefaultInstance().getProtocolVersion(); - onChanged(); - return this; - } - /** - * string protocolVersion = 11; - */ - public Builder setProtocolVersionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - protocolVersion_ = value; - onChanged(); - return this; - } - - private Object protocolDesc_ = ""; - /** - * string protocolDesc = 12; - */ - public String getProtocolDesc() { - Object ref = protocolDesc_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - protocolDesc_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string protocolDesc = 12; - */ - public com.google.protobuf.ByteString - getProtocolDescBytes() { - Object ref = protocolDesc_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - protocolDesc_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string protocolDesc = 12; - */ - public Builder setProtocolDesc( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - protocolDesc_ = value; - onChanged(); - return this; - } - /** - * string protocolDesc = 12; - */ - public Builder clearProtocolDesc() { - - protocolDesc_ = getDefaultInstance().getProtocolDesc(); - onChanged(); - return this; - } - /** - * string protocolDesc = 12; - */ - public Builder setProtocolDescBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - protocolDesc_ = value; - onChanged(); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.RequestHeader) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.RequestHeader) - private static final RequestHeader DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new RequestHeader(); - } - - public static RequestHeader getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public RequestHeader parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new RequestHeader(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public RequestHeader getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/RequestHeaderOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/RequestHeaderOrBuilder.java deleted file mode 100644 index ec8a176bba..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/RequestHeaderOrBuilder.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public interface RequestHeaderOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.RequestHeader) - com.google.protobuf.MessageOrBuilder { - - /** - * string env = 1; - */ - String getEnv(); - /** - * string env = 1; - */ - com.google.protobuf.ByteString - getEnvBytes(); - - /** - * string region = 2; - */ - String getRegion(); - /** - * string region = 2; - */ - com.google.protobuf.ByteString - getRegionBytes(); - - /** - * string idc = 3; - */ - String getIdc(); - /** - * string idc = 3; - */ - com.google.protobuf.ByteString - getIdcBytes(); - - /** - * string ip = 4; - */ - String getIp(); - /** - * string ip = 4; - */ - com.google.protobuf.ByteString - getIpBytes(); - - /** - * string pid = 5; - */ - String getPid(); - /** - * string pid = 5; - */ - com.google.protobuf.ByteString - getPidBytes(); - - /** - * string sys = 6; - */ - String getSys(); - /** - * string sys = 6; - */ - com.google.protobuf.ByteString - getSysBytes(); - - /** - * string username = 7; - */ - String getUsername(); - /** - * string username = 7; - */ - com.google.protobuf.ByteString - getUsernameBytes(); - - /** - * string password = 8; - */ - String getPassword(); - /** - * string password = 8; - */ - com.google.protobuf.ByteString - getPasswordBytes(); - - /** - * string language = 9; - */ - String getLanguage(); - /** - * string language = 9; - */ - com.google.protobuf.ByteString - getLanguageBytes(); - - /** - * string protocolType = 10; - */ - String getProtocolType(); - /** - * string protocolType = 10; - */ - com.google.protobuf.ByteString - getProtocolTypeBytes(); - - /** - * string protocolVersion = 11; - */ - String getProtocolVersion(); - /** - * string protocolVersion = 11; - */ - com.google.protobuf.ByteString - getProtocolVersionBytes(); - - /** - * string protocolDesc = 12; - */ - String getProtocolDesc(); - /** - * string protocolDesc = 12; - */ - com.google.protobuf.ByteString - getProtocolDescBytes(); -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Response.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Response.java deleted file mode 100644 index c8a1f79dec..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Response.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -/** - * Protobuf type {@code eventmesh.common.protocol.grpc.Response} - */ -@SuppressWarnings({"all"}) -public final class Response extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.Response) - ResponseOrBuilder { -private static final long serialVersionUID = 0L; - // Use Response.newBuilder() to construct. - private Response(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private Response() { - respCode_ = ""; - respMsg_ = ""; - respTime_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Response( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - String s = input.readStringRequireUtf8(); - - respCode_ = s; - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - respMsg_ = s; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - respTime_ = s; - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Response_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Response_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Response.class, Builder.class); - } - - public static final int RESPCODE_FIELD_NUMBER = 1; - private volatile Object respCode_; - /** - * string respCode = 1; - */ - public String getRespCode() { - Object ref = respCode_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - respCode_ = s; - return s; - } - } - /** - * string respCode = 1; - */ - public com.google.protobuf.ByteString - getRespCodeBytes() { - Object ref = respCode_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - respCode_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int RESPMSG_FIELD_NUMBER = 2; - private volatile Object respMsg_; - /** - * string respMsg = 2; - */ - public String getRespMsg() { - Object ref = respMsg_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - respMsg_ = s; - return s; - } - } - /** - * string respMsg = 2; - */ - public com.google.protobuf.ByteString - getRespMsgBytes() { - Object ref = respMsg_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - respMsg_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int RESPTIME_FIELD_NUMBER = 3; - private volatile Object respTime_; - /** - * string respTime = 3; - */ - public String getRespTime() { - Object ref = respTime_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - respTime_ = s; - return s; - } - } - /** - * string respTime = 3; - */ - public com.google.protobuf.ByteString - getRespTimeBytes() { - Object ref = respTime_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - respTime_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getRespCodeBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, respCode_); - } - if (!getRespMsgBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, respMsg_); - } - if (!getRespTimeBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, respTime_); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!getRespCodeBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, respCode_); - } - if (!getRespMsgBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, respMsg_); - } - if (!getRespTimeBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, respTime_); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Response)) { - return super.equals(obj); - } - Response other = (Response) obj; - - boolean result = true; - result = result && getRespCode() - .equals(other.getRespCode()); - result = result && getRespMsg() - .equals(other.getRespMsg()); - result = result && getRespTime() - .equals(other.getRespTime()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + RESPCODE_FIELD_NUMBER; - hash = (53 * hash) + getRespCode().hashCode(); - hash = (37 * hash) + RESPMSG_FIELD_NUMBER; - hash = (53 * hash) + getRespMsg().hashCode(); - hash = (37 * hash) + RESPTIME_FIELD_NUMBER; - hash = (53 * hash) + getRespTime().hashCode(); - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static Response parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Response parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Response parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Response parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Response parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Response parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Response parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Response parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static Response parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static Response parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static Response parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Response parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(Response prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Response} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.Response) - ResponseOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Response_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Response_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Response.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.Response.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - respCode_ = ""; - - respMsg_ = ""; - - respTime_ = ""; - - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Response_descriptor; - } - - public Response getDefaultInstanceForType() { - return Response.getDefaultInstance(); - } - - public Response build() { - Response result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public Response buildPartial() { - Response result = new Response(this); - result.respCode_ = respCode_; - result.respMsg_ = respMsg_; - result.respTime_ = respTime_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof Response) { - return mergeFrom((Response)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(Response other) { - if (other == Response.getDefaultInstance()) return this; - if (!other.getRespCode().isEmpty()) { - respCode_ = other.respCode_; - onChanged(); - } - if (!other.getRespMsg().isEmpty()) { - respMsg_ = other.respMsg_; - onChanged(); - } - if (!other.getRespTime().isEmpty()) { - respTime_ = other.respTime_; - onChanged(); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - Response parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (Response) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private Object respCode_ = ""; - /** - * string respCode = 1; - */ - public String getRespCode() { - Object ref = respCode_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - respCode_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string respCode = 1; - */ - public com.google.protobuf.ByteString - getRespCodeBytes() { - Object ref = respCode_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - respCode_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string respCode = 1; - */ - public Builder setRespCode( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - respCode_ = value; - onChanged(); - return this; - } - /** - * string respCode = 1; - */ - public Builder clearRespCode() { - - respCode_ = getDefaultInstance().getRespCode(); - onChanged(); - return this; - } - /** - * string respCode = 1; - */ - public Builder setRespCodeBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - respCode_ = value; - onChanged(); - return this; - } - - private Object respMsg_ = ""; - /** - * string respMsg = 2; - */ - public String getRespMsg() { - Object ref = respMsg_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - respMsg_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string respMsg = 2; - */ - public com.google.protobuf.ByteString - getRespMsgBytes() { - Object ref = respMsg_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - respMsg_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string respMsg = 2; - */ - public Builder setRespMsg( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - respMsg_ = value; - onChanged(); - return this; - } - /** - * string respMsg = 2; - */ - public Builder clearRespMsg() { - - respMsg_ = getDefaultInstance().getRespMsg(); - onChanged(); - return this; - } - /** - * string respMsg = 2; - */ - public Builder setRespMsgBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - respMsg_ = value; - onChanged(); - return this; - } - - private Object respTime_ = ""; - /** - * string respTime = 3; - */ - public String getRespTime() { - Object ref = respTime_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - respTime_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string respTime = 3; - */ - public com.google.protobuf.ByteString - getRespTimeBytes() { - Object ref = respTime_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - respTime_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string respTime = 3; - */ - public Builder setRespTime( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - respTime_ = value; - onChanged(); - return this; - } - /** - * string respTime = 3; - */ - public Builder clearRespTime() { - - respTime_ = getDefaultInstance().getRespTime(); - onChanged(); - return this; - } - /** - * string respTime = 3; - */ - public Builder setRespTimeBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - respTime_ = value; - onChanged(); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.Response) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.Response) - private static final Response DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new Response(); - } - - public static Response getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public Response parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Response(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public Response getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/ResponseOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/ResponseOrBuilder.java deleted file mode 100644 index 9ffcff9482..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/ResponseOrBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public interface ResponseOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.Response) - com.google.protobuf.MessageOrBuilder { - - /** - * string respCode = 1; - */ - String getRespCode(); - /** - * string respCode = 1; - */ - com.google.protobuf.ByteString - getRespCodeBytes(); - - /** - * string respMsg = 2; - */ - String getRespMsg(); - /** - * string respMsg = 2; - */ - com.google.protobuf.ByteString - getRespMsgBytes(); - - /** - * string respTime = 3; - */ - String getRespTime(); - /** - * string respTime = 3; - */ - com.google.protobuf.ByteString - getRespTimeBytes(); -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SimpleMessage.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SimpleMessage.java deleted file mode 100644 index 5ca4c70f12..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SimpleMessage.java +++ /dev/null @@ -1,1754 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -/** - * Protobuf type {@code eventmesh.common.protocol.grpc.SimpleMessage} - */ -@SuppressWarnings({"all"}) -public final class SimpleMessage extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.SimpleMessage) - SimpleMessageOrBuilder { -private static final long serialVersionUID = 0L; - // Use SimpleMessage.newBuilder() to construct. - private SimpleMessage(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private SimpleMessage() { - producerGroup_ = ""; - topic_ = ""; - content_ = ""; - ttl_ = ""; - uniqueId_ = ""; - seqNum_ = ""; - tag_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private SimpleMessage( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - RequestHeader.Builder subBuilder = null; - if (header_ != null) { - subBuilder = header_.toBuilder(); - } - header_ = input.readMessage(RequestHeader.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(header_); - header_ = subBuilder.buildPartial(); - } - - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - producerGroup_ = s; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - topic_ = s; - break; - } - case 34: { - String s = input.readStringRequireUtf8(); - - content_ = s; - break; - } - case 42: { - String s = input.readStringRequireUtf8(); - - ttl_ = s; - break; - } - case 50: { - String s = input.readStringRequireUtf8(); - - uniqueId_ = s; - break; - } - case 58: { - String s = input.readStringRequireUtf8(); - - seqNum_ = s; - break; - } - case 66: { - String s = input.readStringRequireUtf8(); - - tag_ = s; - break; - } - case 74: { - if (!((mutable_bitField0_ & 0x00000100) == 0x00000100)) { - properties_ = com.google.protobuf.MapField.newMapField( - PropertiesDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00000100; - } - com.google.protobuf.MapEntry - properties__ = input.readMessage( - PropertiesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - properties_.getMutableMap().put( - properties__.getKey(), properties__.getValue()); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 9: - return internalGetProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_SimpleMessage_fieldAccessorTable - .ensureFieldAccessorsInitialized( - SimpleMessage.class, Builder.class); - } - - private int bitField0_; - public static final int HEADER_FIELD_NUMBER = 1; - private RequestHeader header_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - return getHeader(); - } - - public static final int PRODUCERGROUP_FIELD_NUMBER = 2; - private volatile Object producerGroup_; - /** - * string producerGroup = 2; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } - } - /** - * string producerGroup = 2; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TOPIC_FIELD_NUMBER = 3; - private volatile Object topic_; - /** - * string topic = 3; - */ - public String getTopic() { - Object ref = topic_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } - } - /** - * string topic = 3; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTENT_FIELD_NUMBER = 4; - private volatile Object content_; - /** - * string content = 4; - */ - public String getContent() { - Object ref = content_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - content_ = s; - return s; - } - } - /** - * string content = 4; - */ - public com.google.protobuf.ByteString - getContentBytes() { - Object ref = content_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - content_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TTL_FIELD_NUMBER = 5; - private volatile Object ttl_; - /** - * string ttl = 5; - */ - public String getTtl() { - Object ref = ttl_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ttl_ = s; - return s; - } - } - /** - * string ttl = 5; - */ - public com.google.protobuf.ByteString - getTtlBytes() { - Object ref = ttl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ttl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int UNIQUEID_FIELD_NUMBER = 6; - private volatile Object uniqueId_; - /** - * string uniqueId = 6; - */ - public String getUniqueId() { - Object ref = uniqueId_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - uniqueId_ = s; - return s; - } - } - /** - * string uniqueId = 6; - */ - public com.google.protobuf.ByteString - getUniqueIdBytes() { - Object ref = uniqueId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - uniqueId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SEQNUM_FIELD_NUMBER = 7; - private volatile Object seqNum_; - /** - * string seqNum = 7; - */ - public String getSeqNum() { - Object ref = seqNum_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - seqNum_ = s; - return s; - } - } - /** - * string seqNum = 7; - */ - public com.google.protobuf.ByteString - getSeqNumBytes() { - Object ref = seqNum_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - seqNum_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TAG_FIELD_NUMBER = 8; - private volatile Object tag_; - /** - * string tag = 8; - */ - public String getTag() { - Object ref = tag_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - tag_ = s; - return s; - } - } - /** - * string tag = 8; - */ - public com.google.protobuf.ByteString - getTagBytes() { - Object ref = tag_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - tag_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROPERTIES_FIELD_NUMBER = 9; - private static final class PropertiesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - String, String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_SimpleMessage_PropertiesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - private com.google.protobuf.MapField< - String, String> properties_; - private com.google.protobuf.MapField - internalGetProperties() { - if (properties_ == null) { - return com.google.protobuf.MapField.emptyMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - return properties_; - } - - public int getPropertiesCount() { - return internalGetProperties().getMap().size(); - } - /** - * map<string, string> properties = 9; - */ - - public boolean containsProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - return internalGetProperties().getMap().containsKey(key); - } - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - public java.util.Map getProperties() { - return getPropertiesMap(); - } - /** - * map<string, string> properties = 9; - */ - - public java.util.Map getPropertiesMap() { - return internalGetProperties().getMap(); - } - /** - * map<string, string> properties = 9; - */ - - public String getPropertiesOrDefault( - String key, - String defaultValue) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, string> properties = 9; - */ - - public String getPropertiesOrThrow( - String key) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (header_ != null) { - output.writeMessage(1, getHeader()); - } - if (!getProducerGroupBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, producerGroup_); - } - if (!getTopicBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, topic_); - } - if (!getContentBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, content_); - } - if (!getTtlBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 5, ttl_); - } - if (!getUniqueIdBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 6, uniqueId_); - } - if (!getSeqNumBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 7, seqNum_); - } - if (!getTagBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 8, tag_); - } - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetProperties(), - PropertiesDefaultEntryHolder.defaultEntry, - 9); - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (header_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, getHeader()); - } - if (!getProducerGroupBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, producerGroup_); - } - if (!getTopicBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, topic_); - } - if (!getContentBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, content_); - } - if (!getTtlBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, ttl_); - } - if (!getUniqueIdBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, uniqueId_); - } - if (!getSeqNumBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, seqNum_); - } - if (!getTagBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(8, tag_); - } - for (java.util.Map.Entry entry - : internalGetProperties().getMap().entrySet()) { - com.google.protobuf.MapEntry - properties__ = PropertiesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(9, properties__); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof SimpleMessage)) { - return super.equals(obj); - } - SimpleMessage other = (SimpleMessage) obj; - - boolean result = true; - result = result && (hasHeader() == other.hasHeader()); - if (hasHeader()) { - result = result && getHeader() - .equals(other.getHeader()); - } - result = result && getProducerGroup() - .equals(other.getProducerGroup()); - result = result && getTopic() - .equals(other.getTopic()); - result = result && getContent() - .equals(other.getContent()); - result = result && getTtl() - .equals(other.getTtl()); - result = result && getUniqueId() - .equals(other.getUniqueId()); - result = result && getSeqNum() - .equals(other.getSeqNum()); - result = result && getTag() - .equals(other.getTag()); - result = result && internalGetProperties().equals( - other.internalGetProperties()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasHeader()) { - hash = (37 * hash) + HEADER_FIELD_NUMBER; - hash = (53 * hash) + getHeader().hashCode(); - } - hash = (37 * hash) + PRODUCERGROUP_FIELD_NUMBER; - hash = (53 * hash) + getProducerGroup().hashCode(); - hash = (37 * hash) + TOPIC_FIELD_NUMBER; - hash = (53 * hash) + getTopic().hashCode(); - hash = (37 * hash) + CONTENT_FIELD_NUMBER; - hash = (53 * hash) + getContent().hashCode(); - hash = (37 * hash) + TTL_FIELD_NUMBER; - hash = (53 * hash) + getTtl().hashCode(); - hash = (37 * hash) + UNIQUEID_FIELD_NUMBER; - hash = (53 * hash) + getUniqueId().hashCode(); - hash = (37 * hash) + SEQNUM_FIELD_NUMBER; - hash = (53 * hash) + getSeqNum().hashCode(); - hash = (37 * hash) + TAG_FIELD_NUMBER; - hash = (53 * hash) + getTag().hashCode(); - if (!internalGetProperties().getMap().isEmpty()) { - hash = (37 * hash) + PROPERTIES_FIELD_NUMBER; - hash = (53 * hash) + internalGetProperties().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static SimpleMessage parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static SimpleMessage parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static SimpleMessage parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static SimpleMessage parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static SimpleMessage parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static SimpleMessage parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static SimpleMessage parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static SimpleMessage parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static SimpleMessage parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static SimpleMessage parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static SimpleMessage parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static SimpleMessage parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(SimpleMessage prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.SimpleMessage} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.SimpleMessage) - SimpleMessageOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 9: - return internalGetProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMutableMapField( - int number) { - switch (number) { - case 9: - return internalGetMutableProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_SimpleMessage_fieldAccessorTable - .ensureFieldAccessorsInitialized( - SimpleMessage.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - if (headerBuilder_ == null) { - header_ = null; - } else { - header_ = null; - headerBuilder_ = null; - } - producerGroup_ = ""; - - topic_ = ""; - - content_ = ""; - - ttl_ = ""; - - uniqueId_ = ""; - - seqNum_ = ""; - - tag_ = ""; - - internalGetMutableProperties().clear(); - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_SimpleMessage_descriptor; - } - - public SimpleMessage getDefaultInstanceForType() { - return SimpleMessage.getDefaultInstance(); - } - - public SimpleMessage build() { - SimpleMessage result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public SimpleMessage buildPartial() { - SimpleMessage result = new SimpleMessage(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (headerBuilder_ == null) { - result.header_ = header_; - } else { - result.header_ = headerBuilder_.build(); - } - result.producerGroup_ = producerGroup_; - result.topic_ = topic_; - result.content_ = content_; - result.ttl_ = ttl_; - result.uniqueId_ = uniqueId_; - result.seqNum_ = seqNum_; - result.tag_ = tag_; - result.properties_ = internalGetProperties(); - result.properties_.makeImmutable(); - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof SimpleMessage) { - return mergeFrom((SimpleMessage)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(SimpleMessage other) { - if (other == SimpleMessage.getDefaultInstance()) return this; - if (other.hasHeader()) { - mergeHeader(other.getHeader()); - } - if (!other.getProducerGroup().isEmpty()) { - producerGroup_ = other.producerGroup_; - onChanged(); - } - if (!other.getTopic().isEmpty()) { - topic_ = other.topic_; - onChanged(); - } - if (!other.getContent().isEmpty()) { - content_ = other.content_; - onChanged(); - } - if (!other.getTtl().isEmpty()) { - ttl_ = other.ttl_; - onChanged(); - } - if (!other.getUniqueId().isEmpty()) { - uniqueId_ = other.uniqueId_; - onChanged(); - } - if (!other.getSeqNum().isEmpty()) { - seqNum_ = other.seqNum_; - onChanged(); - } - if (!other.getTag().isEmpty()) { - tag_ = other.tag_; - onChanged(); - } - internalGetMutableProperties().mergeFrom( - other.internalGetProperties()); - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - SimpleMessage parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (SimpleMessage) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - private RequestHeader header_ = null; - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> headerBuilder_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return headerBuilder_ != null || header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - if (headerBuilder_ == null) { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } else { - return headerBuilder_.getMessage(); - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - header_ = value; - onChanged(); - } else { - headerBuilder_.setMessage(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader( - RequestHeader.Builder builderForValue) { - if (headerBuilder_ == null) { - header_ = builderForValue.build(); - onChanged(); - } else { - headerBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder mergeHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (header_ != null) { - header_ = - RequestHeader.newBuilder(header_).mergeFrom(value).buildPartial(); - } else { - header_ = value; - } - onChanged(); - } else { - headerBuilder_.mergeFrom(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder clearHeader() { - if (headerBuilder_ == null) { - header_ = null; - onChanged(); - } else { - header_ = null; - headerBuilder_ = null; - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader.Builder getHeaderBuilder() { - - onChanged(); - return getHeaderFieldBuilder().getBuilder(); - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - if (headerBuilder_ != null) { - return headerBuilder_.getMessageOrBuilder(); - } else { - return header_ == null ? - RequestHeader.getDefaultInstance() : header_; - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> - getHeaderFieldBuilder() { - if (headerBuilder_ == null) { - headerBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder>( - getHeader(), - getParentForChildren(), - isClean()); - header_ = null; - } - return headerBuilder_; - } - - private Object producerGroup_ = ""; - /** - * string producerGroup = 2; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string producerGroup = 2; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string producerGroup = 2; - */ - public Builder setProducerGroup( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - producerGroup_ = value; - onChanged(); - return this; - } - /** - * string producerGroup = 2; - */ - public Builder clearProducerGroup() { - - producerGroup_ = getDefaultInstance().getProducerGroup(); - onChanged(); - return this; - } - /** - * string producerGroup = 2; - */ - public Builder setProducerGroupBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - producerGroup_ = value; - onChanged(); - return this; - } - - private Object topic_ = ""; - /** - * string topic = 3; - */ - public String getTopic() { - Object ref = topic_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string topic = 3; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string topic = 3; - */ - public Builder setTopic( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - topic_ = value; - onChanged(); - return this; - } - /** - * string topic = 3; - */ - public Builder clearTopic() { - - topic_ = getDefaultInstance().getTopic(); - onChanged(); - return this; - } - /** - * string topic = 3; - */ - public Builder setTopicBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - topic_ = value; - onChanged(); - return this; - } - - private Object content_ = ""; - /** - * string content = 4; - */ - public String getContent() { - Object ref = content_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - content_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string content = 4; - */ - public com.google.protobuf.ByteString - getContentBytes() { - Object ref = content_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - content_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string content = 4; - */ - public Builder setContent( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - content_ = value; - onChanged(); - return this; - } - /** - * string content = 4; - */ - public Builder clearContent() { - - content_ = getDefaultInstance().getContent(); - onChanged(); - return this; - } - /** - * string content = 4; - */ - public Builder setContentBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - content_ = value; - onChanged(); - return this; - } - - private Object ttl_ = ""; - /** - * string ttl = 5; - */ - public String getTtl() { - Object ref = ttl_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ttl_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string ttl = 5; - */ - public com.google.protobuf.ByteString - getTtlBytes() { - Object ref = ttl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ttl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string ttl = 5; - */ - public Builder setTtl( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - ttl_ = value; - onChanged(); - return this; - } - /** - * string ttl = 5; - */ - public Builder clearTtl() { - - ttl_ = getDefaultInstance().getTtl(); - onChanged(); - return this; - } - /** - * string ttl = 5; - */ - public Builder setTtlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - ttl_ = value; - onChanged(); - return this; - } - - private Object uniqueId_ = ""; - /** - * string uniqueId = 6; - */ - public String getUniqueId() { - Object ref = uniqueId_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - uniqueId_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string uniqueId = 6; - */ - public com.google.protobuf.ByteString - getUniqueIdBytes() { - Object ref = uniqueId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - uniqueId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string uniqueId = 6; - */ - public Builder setUniqueId( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - uniqueId_ = value; - onChanged(); - return this; - } - /** - * string uniqueId = 6; - */ - public Builder clearUniqueId() { - - uniqueId_ = getDefaultInstance().getUniqueId(); - onChanged(); - return this; - } - /** - * string uniqueId = 6; - */ - public Builder setUniqueIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - uniqueId_ = value; - onChanged(); - return this; - } - - private Object seqNum_ = ""; - /** - * string seqNum = 7; - */ - public String getSeqNum() { - Object ref = seqNum_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - seqNum_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string seqNum = 7; - */ - public com.google.protobuf.ByteString - getSeqNumBytes() { - Object ref = seqNum_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - seqNum_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string seqNum = 7; - */ - public Builder setSeqNum( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - seqNum_ = value; - onChanged(); - return this; - } - /** - * string seqNum = 7; - */ - public Builder clearSeqNum() { - - seqNum_ = getDefaultInstance().getSeqNum(); - onChanged(); - return this; - } - /** - * string seqNum = 7; - */ - public Builder setSeqNumBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - seqNum_ = value; - onChanged(); - return this; - } - - private Object tag_ = ""; - /** - * string tag = 8; - */ - public String getTag() { - Object ref = tag_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - tag_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string tag = 8; - */ - public com.google.protobuf.ByteString - getTagBytes() { - Object ref = tag_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - tag_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string tag = 8; - */ - public Builder setTag( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - tag_ = value; - onChanged(); - return this; - } - /** - * string tag = 8; - */ - public Builder clearTag() { - - tag_ = getDefaultInstance().getTag(); - onChanged(); - return this; - } - /** - * string tag = 8; - */ - public Builder setTagBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - tag_ = value; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - String, String> properties_; - private com.google.protobuf.MapField - internalGetProperties() { - if (properties_ == null) { - return com.google.protobuf.MapField.emptyMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - return properties_; - } - private com.google.protobuf.MapField - internalGetMutableProperties() { - onChanged();; - if (properties_ == null) { - properties_ = com.google.protobuf.MapField.newMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - if (!properties_.isMutable()) { - properties_ = properties_.copy(); - } - return properties_; - } - - public int getPropertiesCount() { - return internalGetProperties().getMap().size(); - } - /** - * map<string, string> properties = 9; - */ - - public boolean containsProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - return internalGetProperties().getMap().containsKey(key); - } - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - public java.util.Map getProperties() { - return getPropertiesMap(); - } - /** - * map<string, string> properties = 9; - */ - - public java.util.Map getPropertiesMap() { - return internalGetProperties().getMap(); - } - /** - * map<string, string> properties = 9; - */ - - public String getPropertiesOrDefault( - String key, - String defaultValue) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, string> properties = 9; - */ - - public String getPropertiesOrThrow( - String key) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearProperties() { - internalGetMutableProperties().getMutableMap() - .clear(); - return this; - } - /** - * map<string, string> properties = 9; - */ - - public Builder removeProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - internalGetMutableProperties().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @Deprecated - public java.util.Map - getMutableProperties() { - return internalGetMutableProperties().getMutableMap(); - } - /** - * map<string, string> properties = 9; - */ - public Builder putProperties( - String key, - String value) { - if (key == null) { throw new NullPointerException(); } - if (value == null) { throw new NullPointerException(); } - internalGetMutableProperties().getMutableMap() - .put(key, value); - return this; - } - /** - * map<string, string> properties = 9; - */ - - public Builder putAllProperties( - java.util.Map values) { - internalGetMutableProperties().getMutableMap() - .putAll(values); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.SimpleMessage) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.SimpleMessage) - private static final SimpleMessage DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new SimpleMessage(); - } - - public static SimpleMessage getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public SimpleMessage parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new SimpleMessage(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public SimpleMessage getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SimpleMessageOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SimpleMessageOrBuilder.java deleted file mode 100644 index dfda9c63ae..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SimpleMessageOrBuilder.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public interface SimpleMessageOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.SimpleMessage) - com.google.protobuf.MessageOrBuilder { - - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - boolean hasHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeader getHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeaderOrBuilder getHeaderOrBuilder(); - - /** - * string producerGroup = 2; - */ - String getProducerGroup(); - /** - * string producerGroup = 2; - */ - com.google.protobuf.ByteString - getProducerGroupBytes(); - - /** - * string topic = 3; - */ - String getTopic(); - /** - * string topic = 3; - */ - com.google.protobuf.ByteString - getTopicBytes(); - - /** - * string content = 4; - */ - String getContent(); - /** - * string content = 4; - */ - com.google.protobuf.ByteString - getContentBytes(); - - /** - * string ttl = 5; - */ - String getTtl(); - /** - * string ttl = 5; - */ - com.google.protobuf.ByteString - getTtlBytes(); - - /** - * string uniqueId = 6; - */ - String getUniqueId(); - /** - * string uniqueId = 6; - */ - com.google.protobuf.ByteString - getUniqueIdBytes(); - - /** - * string seqNum = 7; - */ - String getSeqNum(); - /** - * string seqNum = 7; - */ - com.google.protobuf.ByteString - getSeqNumBytes(); - - /** - * string tag = 8; - */ - String getTag(); - /** - * string tag = 8; - */ - com.google.protobuf.ByteString - getTagBytes(); - - /** - * map<string, string> properties = 9; - */ - int getPropertiesCount(); - /** - * map<string, string> properties = 9; - */ - boolean containsProperties( - String key); - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - java.util.Map - getProperties(); - /** - * map<string, string> properties = 9; - */ - java.util.Map - getPropertiesMap(); - /** - * map<string, string> properties = 9; - */ - - String getPropertiesOrDefault( - String key, - String defaultValue); - /** - * map<string, string> properties = 9; - */ - - String getPropertiesOrThrow( - String key); -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Subscription.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Subscription.java deleted file mode 100644 index 9fd70864c6..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/Subscription.java +++ /dev/null @@ -1,3934 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -/** - * Protobuf type {@code eventmesh.common.protocol.grpc.Subscription} - */ -@SuppressWarnings({"all"}) -public final class Subscription extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.Subscription) - SubscriptionOrBuilder { -private static final long serialVersionUID = 0L; - // Use Subscription.newBuilder() to construct. - private Subscription(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private Subscription() { - consumerGroup_ = ""; - subscriptionItems_ = java.util.Collections.emptyList(); - url_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Subscription( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - RequestHeader.Builder subBuilder = null; - if (header_ != null) { - subBuilder = header_.toBuilder(); - } - header_ = input.readMessage(RequestHeader.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(header_); - header_ = subBuilder.buildPartial(); - } - - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - consumerGroup_ = s; - break; - } - case 26: { - if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { - subscriptionItems_ = new java.util.ArrayList(); - mutable_bitField0_ |= 0x00000004; - } - subscriptionItems_.add( - input.readMessage(SubscriptionItem.parser(), extensionRegistry)); - break; - } - case 34: { - String s = input.readStringRequireUtf8(); - - url_ = s; - break; - } - case 42: { - Reply.Builder subBuilder = null; - if (reply_ != null) { - subBuilder = reply_.toBuilder(); - } - reply_ = input.readMessage(Reply.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(reply_); - reply_ = subBuilder.buildPartial(); - } - - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { - subscriptionItems_ = java.util.Collections.unmodifiableList(subscriptionItems_); - } - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Subscription.class, Builder.class); - } - - public interface SubscriptionItemOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem) - com.google.protobuf.MessageOrBuilder { - - /** - * string topic = 1; - */ - String getTopic(); - /** - * string topic = 1; - */ - com.google.protobuf.ByteString - getTopicBytes(); - - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - int getModeValue(); - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - SubscriptionItem.SubscriptionMode getMode(); - - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - int getTypeValue(); - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - SubscriptionItem.SubscriptionType getType(); - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Subscription.SubscriptionItem} - */ - public static final class SubscriptionItem extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem) - SubscriptionItemOrBuilder { - private static final long serialVersionUID = 0L; - // Use SubscriptionItem.newBuilder() to construct. - private SubscriptionItem(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private SubscriptionItem() { - topic_ = ""; - mode_ = 0; - type_ = 0; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private SubscriptionItem( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - String s = input.readStringRequireUtf8(); - - topic_ = s; - break; - } - case 16: { - int rawValue = input.readEnum(); - - mode_ = rawValue; - break; - } - case 24: { - int rawValue = input.readEnum(); - - type_ = rawValue; - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_fieldAccessorTable - .ensureFieldAccessorsInitialized( - SubscriptionItem.class, Builder.class); - } - - /** - * Protobuf enum {@code eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode} - */ - public enum SubscriptionMode - implements com.google.protobuf.ProtocolMessageEnum { - /** - * CLUSTERING = 0; - */ - CLUSTERING(0), - /** - * BROADCASTING = 1; - */ - BROADCASTING(1), - UNRECOGNIZED(-1), - ; - - /** - * CLUSTERING = 0; - */ - public static final int CLUSTERING_VALUE = 0; - /** - * BROADCASTING = 1; - */ - public static final int BROADCASTING_VALUE = 1; - - - public final int getNumber() { - if (this == UNRECOGNIZED) { - throw new IllegalArgumentException( - "Can't get the number of an unknown enum value."); - } - return value; - } - - /** - * @deprecated Use {@link #forNumber(int)} instead. - */ - @Deprecated - public static SubscriptionMode valueOf(int value) { - return forNumber(value); - } - - public static SubscriptionMode forNumber(int value) { - switch (value) { - case 0: return CLUSTERING; - case 1: return BROADCASTING; - default: return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - private static final com.google.protobuf.Internal.EnumLiteMap< - SubscriptionMode> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public SubscriptionMode findValueByNumber(int number) { - return SubscriptionMode.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - return getDescriptor().getValues().get(ordinal()); - } - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - public static final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return SubscriptionItem.getDescriptor().getEnumTypes().get(0); - } - - private static final SubscriptionMode[] VALUES = values(); - - public static SubscriptionMode valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - if (desc.getIndex() == -1) { - return UNRECOGNIZED; - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private SubscriptionMode(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode) - } - - /** - * Protobuf enum {@code eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType} - */ - public enum SubscriptionType - implements com.google.protobuf.ProtocolMessageEnum { - /** - * ASYNC = 0; - */ - ASYNC(0), - /** - * SYNC = 1; - */ - SYNC(1), - UNRECOGNIZED(-1), - ; - - /** - * ASYNC = 0; - */ - public static final int ASYNC_VALUE = 0; - /** - * SYNC = 1; - */ - public static final int SYNC_VALUE = 1; - - - public final int getNumber() { - if (this == UNRECOGNIZED) { - throw new IllegalArgumentException( - "Can't get the number of an unknown enum value."); - } - return value; - } - - /** - * @deprecated Use {@link #forNumber(int)} instead. - */ - @Deprecated - public static SubscriptionType valueOf(int value) { - return forNumber(value); - } - - public static SubscriptionType forNumber(int value) { - switch (value) { - case 0: return ASYNC; - case 1: return SYNC; - default: return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - private static final com.google.protobuf.Internal.EnumLiteMap< - SubscriptionType> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public SubscriptionType findValueByNumber(int number) { - return SubscriptionType.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - return getDescriptor().getValues().get(ordinal()); - } - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - public static final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return SubscriptionItem.getDescriptor().getEnumTypes().get(1); - } - - private static final SubscriptionType[] VALUES = values(); - - public static SubscriptionType valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - if (desc.getIndex() == -1) { - return UNRECOGNIZED; - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private SubscriptionType(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType) - } - - public static final int TOPIC_FIELD_NUMBER = 1; - private volatile Object topic_; - /** - * string topic = 1; - */ - public String getTopic() { - Object ref = topic_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } - } - /** - * string topic = 1; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int MODE_FIELD_NUMBER = 2; - private int mode_; - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public int getModeValue() { - return mode_; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public SubscriptionMode getMode() { - SubscriptionMode result = SubscriptionMode.valueOf(mode_); - return result == null ? SubscriptionMode.UNRECOGNIZED : result; - } - - public static final int TYPE_FIELD_NUMBER = 3; - private int type_; - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public int getTypeValue() { - return type_; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public SubscriptionType getType() { - SubscriptionType result = SubscriptionType.valueOf(type_); - return result == null ? SubscriptionType.UNRECOGNIZED : result; - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getTopicBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, topic_); - } - if (mode_ != SubscriptionMode.CLUSTERING.getNumber()) { - output.writeEnum(2, mode_); - } - if (type_ != SubscriptionType.ASYNC.getNumber()) { - output.writeEnum(3, type_); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!getTopicBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, topic_); - } - if (mode_ != SubscriptionMode.CLUSTERING.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(2, mode_); - } - if (type_ != SubscriptionType.ASYNC.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(3, type_); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof SubscriptionItem)) { - return super.equals(obj); - } - SubscriptionItem other = (SubscriptionItem) obj; - - boolean result = true; - result = result && getTopic() - .equals(other.getTopic()); - result = result && mode_ == other.mode_; - result = result && type_ == other.type_; - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + TOPIC_FIELD_NUMBER; - hash = (53 * hash) + getTopic().hashCode(); - hash = (37 * hash) + MODE_FIELD_NUMBER; - hash = (53 * hash) + mode_; - hash = (37 * hash) + TYPE_FIELD_NUMBER; - hash = (53 * hash) + type_; - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static SubscriptionItem parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static SubscriptionItem parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static SubscriptionItem parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static SubscriptionItem parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static SubscriptionItem parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static SubscriptionItem parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static SubscriptionItem parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static SubscriptionItem parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static SubscriptionItem parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static SubscriptionItem parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static SubscriptionItem parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static SubscriptionItem parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(SubscriptionItem prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Subscription.SubscriptionItem} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem) - SubscriptionItemOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_fieldAccessorTable - .ensureFieldAccessorsInitialized( - SubscriptionItem.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - topic_ = ""; - - mode_ = 0; - - type_ = 0; - - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_SubscriptionItem_descriptor; - } - - public SubscriptionItem getDefaultInstanceForType() { - return SubscriptionItem.getDefaultInstance(); - } - - public SubscriptionItem build() { - SubscriptionItem result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public SubscriptionItem buildPartial() { - SubscriptionItem result = new SubscriptionItem(this); - result.topic_ = topic_; - result.mode_ = mode_; - result.type_ = type_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof SubscriptionItem) { - return mergeFrom((SubscriptionItem)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(SubscriptionItem other) { - if (other == SubscriptionItem.getDefaultInstance()) return this; - if (!other.getTopic().isEmpty()) { - topic_ = other.topic_; - onChanged(); - } - if (other.mode_ != 0) { - setModeValue(other.getModeValue()); - } - if (other.type_ != 0) { - setTypeValue(other.getTypeValue()); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - SubscriptionItem parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (SubscriptionItem) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private Object topic_ = ""; - /** - * string topic = 1; - */ - public String getTopic() { - Object ref = topic_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string topic = 1; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string topic = 1; - */ - public Builder setTopic( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - topic_ = value; - onChanged(); - return this; - } - /** - * string topic = 1; - */ - public Builder clearTopic() { - - topic_ = getDefaultInstance().getTopic(); - onChanged(); - return this; - } - /** - * string topic = 1; - */ - public Builder setTopicBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - topic_ = value; - onChanged(); - return this; - } - - private int mode_ = 0; - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public int getModeValue() { - return mode_; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public Builder setModeValue(int value) { - mode_ = value; - onChanged(); - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public SubscriptionMode getMode() { - SubscriptionMode result = SubscriptionMode.valueOf(mode_); - return result == null ? SubscriptionMode.UNRECOGNIZED : result; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public Builder setMode(SubscriptionMode value) { - if (value == null) { - throw new NullPointerException(); - } - - mode_ = value.getNumber(); - onChanged(); - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode mode = 2; - */ - public Builder clearMode() { - - mode_ = 0; - onChanged(); - return this; - } - - private int type_ = 0; - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public int getTypeValue() { - return type_; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public Builder setTypeValue(int value) { - type_ = value; - onChanged(); - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public SubscriptionType getType() { - SubscriptionType result = SubscriptionType.valueOf(type_); - return result == null ? SubscriptionType.UNRECOGNIZED : result; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public Builder setType(SubscriptionType value) { - if (value == null) { - throw new NullPointerException(); - } - - type_ = value.getNumber(); - onChanged(); - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType type = 3; - */ - public Builder clearType() { - - type_ = 0; - onChanged(); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.Subscription.SubscriptionItem) - private static final SubscriptionItem DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new SubscriptionItem(); - } - - public static SubscriptionItem getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public SubscriptionItem parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new SubscriptionItem(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public SubscriptionItem getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - - } - - public interface ReplyOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.Subscription.Reply) - com.google.protobuf.MessageOrBuilder { - - /** - * string producerGroup = 1; - */ - String getProducerGroup(); - /** - * string producerGroup = 1; - */ - com.google.protobuf.ByteString - getProducerGroupBytes(); - - /** - * string topic = 2; - */ - String getTopic(); - /** - * string topic = 2; - */ - com.google.protobuf.ByteString - getTopicBytes(); - - /** - * string content = 3; - */ - String getContent(); - /** - * string content = 3; - */ - com.google.protobuf.ByteString - getContentBytes(); - - /** - * string ttl = 4; - */ - String getTtl(); - /** - * string ttl = 4; - */ - com.google.protobuf.ByteString - getTtlBytes(); - - /** - * string uniqueId = 5; - */ - String getUniqueId(); - /** - * string uniqueId = 5; - */ - com.google.protobuf.ByteString - getUniqueIdBytes(); - - /** - * string seqNum = 6; - */ - String getSeqNum(); - /** - * string seqNum = 6; - */ - com.google.protobuf.ByteString - getSeqNumBytes(); - - /** - * string tag = 7; - */ - String getTag(); - /** - * string tag = 7; - */ - com.google.protobuf.ByteString - getTagBytes(); - - /** - * map<string, string> properties = 8; - */ - int getPropertiesCount(); - /** - * map<string, string> properties = 8; - */ - boolean containsProperties( - String key); - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - java.util.Map - getProperties(); - /** - * map<string, string> properties = 8; - */ - java.util.Map - getPropertiesMap(); - /** - * map<string, string> properties = 8; - */ - - String getPropertiesOrDefault( - String key, - String defaultValue); - /** - * map<string, string> properties = 8; - */ - - String getPropertiesOrThrow( - String key); - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Subscription.Reply} - */ - public static final class Reply extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:eventmesh.common.protocol.grpc.Subscription.Reply) - ReplyOrBuilder { - private static final long serialVersionUID = 0L; - // Use Reply.newBuilder() to construct. - private Reply(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - private Reply() { - producerGroup_ = ""; - topic_ = ""; - content_ = ""; - ttl_ = ""; - uniqueId_ = ""; - seqNum_ = ""; - tag_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Reply( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - String s = input.readStringRequireUtf8(); - - producerGroup_ = s; - break; - } - case 18: { - String s = input.readStringRequireUtf8(); - - topic_ = s; - break; - } - case 26: { - String s = input.readStringRequireUtf8(); - - content_ = s; - break; - } - case 34: { - String s = input.readStringRequireUtf8(); - - ttl_ = s; - break; - } - case 42: { - String s = input.readStringRequireUtf8(); - - uniqueId_ = s; - break; - } - case 50: { - String s = input.readStringRequireUtf8(); - - seqNum_ = s; - break; - } - case 58: { - String s = input.readStringRequireUtf8(); - - tag_ = s; - break; - } - case 66: { - if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) { - properties_ = com.google.protobuf.MapField.newMapField( - PropertiesDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00000080; - } - com.google.protobuf.MapEntry - properties__ = input.readMessage( - PropertiesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - properties_.getMutableMap().put( - properties__.getKey(), properties__.getValue()); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 8: - return internalGetProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Reply.class, Builder.class); - } - - private int bitField0_; - public static final int PRODUCERGROUP_FIELD_NUMBER = 1; - private volatile Object producerGroup_; - /** - * string producerGroup = 1; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } - } - /** - * string producerGroup = 1; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TOPIC_FIELD_NUMBER = 2; - private volatile Object topic_; - /** - * string topic = 2; - */ - public String getTopic() { - Object ref = topic_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } - } - /** - * string topic = 2; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CONTENT_FIELD_NUMBER = 3; - private volatile Object content_; - /** - * string content = 3; - */ - public String getContent() { - Object ref = content_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - content_ = s; - return s; - } - } - /** - * string content = 3; - */ - public com.google.protobuf.ByteString - getContentBytes() { - Object ref = content_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - content_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TTL_FIELD_NUMBER = 4; - private volatile Object ttl_; - /** - * string ttl = 4; - */ - public String getTtl() { - Object ref = ttl_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ttl_ = s; - return s; - } - } - /** - * string ttl = 4; - */ - public com.google.protobuf.ByteString - getTtlBytes() { - Object ref = ttl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ttl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int UNIQUEID_FIELD_NUMBER = 5; - private volatile Object uniqueId_; - /** - * string uniqueId = 5; - */ - public String getUniqueId() { - Object ref = uniqueId_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - uniqueId_ = s; - return s; - } - } - /** - * string uniqueId = 5; - */ - public com.google.protobuf.ByteString - getUniqueIdBytes() { - Object ref = uniqueId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - uniqueId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SEQNUM_FIELD_NUMBER = 6; - private volatile Object seqNum_; - /** - * string seqNum = 6; - */ - public String getSeqNum() { - Object ref = seqNum_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - seqNum_ = s; - return s; - } - } - /** - * string seqNum = 6; - */ - public com.google.protobuf.ByteString - getSeqNumBytes() { - Object ref = seqNum_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - seqNum_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TAG_FIELD_NUMBER = 7; - private volatile Object tag_; - /** - * string tag = 7; - */ - public String getTag() { - Object ref = tag_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - tag_ = s; - return s; - } - } - /** - * string tag = 7; - */ - public com.google.protobuf.ByteString - getTagBytes() { - Object ref = tag_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - tag_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int PROPERTIES_FIELD_NUMBER = 8; - private static final class PropertiesDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - String, String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_PropertiesEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - private com.google.protobuf.MapField< - String, String> properties_; - private com.google.protobuf.MapField - internalGetProperties() { - if (properties_ == null) { - return com.google.protobuf.MapField.emptyMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - return properties_; - } - - public int getPropertiesCount() { - return internalGetProperties().getMap().size(); - } - /** - * map<string, string> properties = 8; - */ - - public boolean containsProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - return internalGetProperties().getMap().containsKey(key); - } - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - public java.util.Map getProperties() { - return getPropertiesMap(); - } - /** - * map<string, string> properties = 8; - */ - - public java.util.Map getPropertiesMap() { - return internalGetProperties().getMap(); - } - /** - * map<string, string> properties = 8; - */ - - public String getPropertiesOrDefault( - String key, - String defaultValue) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, string> properties = 8; - */ - - public String getPropertiesOrThrow( - String key) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getProducerGroupBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, producerGroup_); - } - if (!getTopicBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, topic_); - } - if (!getContentBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 3, content_); - } - if (!getTtlBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, ttl_); - } - if (!getUniqueIdBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 5, uniqueId_); - } - if (!getSeqNumBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 6, seqNum_); - } - if (!getTagBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 7, tag_); - } - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetProperties(), - PropertiesDefaultEntryHolder.defaultEntry, - 8); - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (!getProducerGroupBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, producerGroup_); - } - if (!getTopicBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, topic_); - } - if (!getContentBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, content_); - } - if (!getTtlBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, ttl_); - } - if (!getUniqueIdBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, uniqueId_); - } - if (!getSeqNumBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, seqNum_); - } - if (!getTagBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, tag_); - } - for (java.util.Map.Entry entry - : internalGetProperties().getMap().entrySet()) { - com.google.protobuf.MapEntry - properties__ = PropertiesDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(8, properties__); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Reply)) { - return super.equals(obj); - } - Reply other = (Reply) obj; - - boolean result = true; - result = result && getProducerGroup() - .equals(other.getProducerGroup()); - result = result && getTopic() - .equals(other.getTopic()); - result = result && getContent() - .equals(other.getContent()); - result = result && getTtl() - .equals(other.getTtl()); - result = result && getUniqueId() - .equals(other.getUniqueId()); - result = result && getSeqNum() - .equals(other.getSeqNum()); - result = result && getTag() - .equals(other.getTag()); - result = result && internalGetProperties().equals( - other.internalGetProperties()); - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + PRODUCERGROUP_FIELD_NUMBER; - hash = (53 * hash) + getProducerGroup().hashCode(); - hash = (37 * hash) + TOPIC_FIELD_NUMBER; - hash = (53 * hash) + getTopic().hashCode(); - hash = (37 * hash) + CONTENT_FIELD_NUMBER; - hash = (53 * hash) + getContent().hashCode(); - hash = (37 * hash) + TTL_FIELD_NUMBER; - hash = (53 * hash) + getTtl().hashCode(); - hash = (37 * hash) + UNIQUEID_FIELD_NUMBER; - hash = (53 * hash) + getUniqueId().hashCode(); - hash = (37 * hash) + SEQNUM_FIELD_NUMBER; - hash = (53 * hash) + getSeqNum().hashCode(); - hash = (37 * hash) + TAG_FIELD_NUMBER; - hash = (53 * hash) + getTag().hashCode(); - if (!internalGetProperties().getMap().isEmpty()) { - hash = (37 * hash) + PROPERTIES_FIELD_NUMBER; - hash = (53 * hash) + internalGetProperties().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static Reply parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Reply parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Reply parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Reply parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Reply parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Reply parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Reply parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Reply parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static Reply parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static Reply parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static Reply parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Reply parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(Reply prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Subscription.Reply} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.Subscription.Reply) - ReplyOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 8: - return internalGetProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMutableMapField( - int number) { - switch (number) { - case 8: - return internalGetMutableProperties(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Reply.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.Subscription.Reply.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - public Builder clear() { - super.clear(); - producerGroup_ = ""; - - topic_ = ""; - - content_ = ""; - - ttl_ = ""; - - uniqueId_ = ""; - - seqNum_ = ""; - - tag_ = ""; - - internalGetMutableProperties().clear(); - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_Reply_descriptor; - } - - public Reply getDefaultInstanceForType() { - return Reply.getDefaultInstance(); - } - - public Reply build() { - Reply result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public Reply buildPartial() { - Reply result = new Reply(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - result.producerGroup_ = producerGroup_; - result.topic_ = topic_; - result.content_ = content_; - result.ttl_ = ttl_; - result.uniqueId_ = uniqueId_; - result.seqNum_ = seqNum_; - result.tag_ = tag_; - result.properties_ = internalGetProperties(); - result.properties_.makeImmutable(); - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof Reply) { - return mergeFrom((Reply)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(Reply other) { - if (other == Reply.getDefaultInstance()) return this; - if (!other.getProducerGroup().isEmpty()) { - producerGroup_ = other.producerGroup_; - onChanged(); - } - if (!other.getTopic().isEmpty()) { - topic_ = other.topic_; - onChanged(); - } - if (!other.getContent().isEmpty()) { - content_ = other.content_; - onChanged(); - } - if (!other.getTtl().isEmpty()) { - ttl_ = other.ttl_; - onChanged(); - } - if (!other.getUniqueId().isEmpty()) { - uniqueId_ = other.uniqueId_; - onChanged(); - } - if (!other.getSeqNum().isEmpty()) { - seqNum_ = other.seqNum_; - onChanged(); - } - if (!other.getTag().isEmpty()) { - tag_ = other.tag_; - onChanged(); - } - internalGetMutableProperties().mergeFrom( - other.internalGetProperties()); - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - Reply parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (Reply) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - private Object producerGroup_ = ""; - /** - * string producerGroup = 1; - */ - public String getProducerGroup() { - Object ref = producerGroup_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - producerGroup_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string producerGroup = 1; - */ - public com.google.protobuf.ByteString - getProducerGroupBytes() { - Object ref = producerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - producerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string producerGroup = 1; - */ - public Builder setProducerGroup( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - producerGroup_ = value; - onChanged(); - return this; - } - /** - * string producerGroup = 1; - */ - public Builder clearProducerGroup() { - - producerGroup_ = getDefaultInstance().getProducerGroup(); - onChanged(); - return this; - } - /** - * string producerGroup = 1; - */ - public Builder setProducerGroupBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - producerGroup_ = value; - onChanged(); - return this; - } - - private Object topic_ = ""; - /** - * string topic = 2; - */ - public String getTopic() { - Object ref = topic_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - topic_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string topic = 2; - */ - public com.google.protobuf.ByteString - getTopicBytes() { - Object ref = topic_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - topic_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string topic = 2; - */ - public Builder setTopic( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - topic_ = value; - onChanged(); - return this; - } - /** - * string topic = 2; - */ - public Builder clearTopic() { - - topic_ = getDefaultInstance().getTopic(); - onChanged(); - return this; - } - /** - * string topic = 2; - */ - public Builder setTopicBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - topic_ = value; - onChanged(); - return this; - } - - private Object content_ = ""; - /** - * string content = 3; - */ - public String getContent() { - Object ref = content_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - content_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string content = 3; - */ - public com.google.protobuf.ByteString - getContentBytes() { - Object ref = content_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - content_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string content = 3; - */ - public Builder setContent( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - content_ = value; - onChanged(); - return this; - } - /** - * string content = 3; - */ - public Builder clearContent() { - - content_ = getDefaultInstance().getContent(); - onChanged(); - return this; - } - /** - * string content = 3; - */ - public Builder setContentBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - content_ = value; - onChanged(); - return this; - } - - private Object ttl_ = ""; - /** - * string ttl = 4; - */ - public String getTtl() { - Object ref = ttl_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - ttl_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string ttl = 4; - */ - public com.google.protobuf.ByteString - getTtlBytes() { - Object ref = ttl_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - ttl_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string ttl = 4; - */ - public Builder setTtl( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - ttl_ = value; - onChanged(); - return this; - } - /** - * string ttl = 4; - */ - public Builder clearTtl() { - - ttl_ = getDefaultInstance().getTtl(); - onChanged(); - return this; - } - /** - * string ttl = 4; - */ - public Builder setTtlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - ttl_ = value; - onChanged(); - return this; - } - - private Object uniqueId_ = ""; - /** - * string uniqueId = 5; - */ - public String getUniqueId() { - Object ref = uniqueId_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - uniqueId_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string uniqueId = 5; - */ - public com.google.protobuf.ByteString - getUniqueIdBytes() { - Object ref = uniqueId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - uniqueId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string uniqueId = 5; - */ - public Builder setUniqueId( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - uniqueId_ = value; - onChanged(); - return this; - } - /** - * string uniqueId = 5; - */ - public Builder clearUniqueId() { - - uniqueId_ = getDefaultInstance().getUniqueId(); - onChanged(); - return this; - } - /** - * string uniqueId = 5; - */ - public Builder setUniqueIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - uniqueId_ = value; - onChanged(); - return this; - } - - private Object seqNum_ = ""; - /** - * string seqNum = 6; - */ - public String getSeqNum() { - Object ref = seqNum_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - seqNum_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string seqNum = 6; - */ - public com.google.protobuf.ByteString - getSeqNumBytes() { - Object ref = seqNum_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - seqNum_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string seqNum = 6; - */ - public Builder setSeqNum( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - seqNum_ = value; - onChanged(); - return this; - } - /** - * string seqNum = 6; - */ - public Builder clearSeqNum() { - - seqNum_ = getDefaultInstance().getSeqNum(); - onChanged(); - return this; - } - /** - * string seqNum = 6; - */ - public Builder setSeqNumBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - seqNum_ = value; - onChanged(); - return this; - } - - private Object tag_ = ""; - /** - * string tag = 7; - */ - public String getTag() { - Object ref = tag_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - tag_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string tag = 7; - */ - public com.google.protobuf.ByteString - getTagBytes() { - Object ref = tag_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - tag_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string tag = 7; - */ - public Builder setTag( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - tag_ = value; - onChanged(); - return this; - } - /** - * string tag = 7; - */ - public Builder clearTag() { - - tag_ = getDefaultInstance().getTag(); - onChanged(); - return this; - } - /** - * string tag = 7; - */ - public Builder setTagBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - tag_ = value; - onChanged(); - return this; - } - - private com.google.protobuf.MapField< - String, String> properties_; - private com.google.protobuf.MapField - internalGetProperties() { - if (properties_ == null) { - return com.google.protobuf.MapField.emptyMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - return properties_; - } - private com.google.protobuf.MapField - internalGetMutableProperties() { - onChanged();; - if (properties_ == null) { - properties_ = com.google.protobuf.MapField.newMapField( - PropertiesDefaultEntryHolder.defaultEntry); - } - if (!properties_.isMutable()) { - properties_ = properties_.copy(); - } - return properties_; - } - - public int getPropertiesCount() { - return internalGetProperties().getMap().size(); - } - /** - * map<string, string> properties = 8; - */ - - public boolean containsProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - return internalGetProperties().getMap().containsKey(key); - } - /** - * Use {@link #getPropertiesMap()} instead. - */ - @Deprecated - public java.util.Map getProperties() { - return getPropertiesMap(); - } - /** - * map<string, string> properties = 8; - */ - - public java.util.Map getPropertiesMap() { - return internalGetProperties().getMap(); - } - /** - * map<string, string> properties = 8; - */ - - public String getPropertiesOrDefault( - String key, - String defaultValue) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - /** - * map<string, string> properties = 8; - */ - - public String getPropertiesOrThrow( - String key) { - if (key == null) { throw new NullPointerException(); } - java.util.Map map = - internalGetProperties().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearProperties() { - internalGetMutableProperties().getMutableMap() - .clear(); - return this; - } - /** - * map<string, string> properties = 8; - */ - - public Builder removeProperties( - String key) { - if (key == null) { throw new NullPointerException(); } - internalGetMutableProperties().getMutableMap() - .remove(key); - return this; - } - /** - * Use alternate mutation accessors instead. - */ - @Deprecated - public java.util.Map - getMutableProperties() { - return internalGetMutableProperties().getMutableMap(); - } - /** - * map<string, string> properties = 8; - */ - public Builder putProperties( - String key, - String value) { - if (key == null) { throw new NullPointerException(); } - if (value == null) { throw new NullPointerException(); } - internalGetMutableProperties().getMutableMap() - .put(key, value); - return this; - } - /** - * map<string, string> properties = 8; - */ - - public Builder putAllProperties( - java.util.Map values) { - internalGetMutableProperties().getMutableMap() - .putAll(values); - return this; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.Subscription.Reply) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.Subscription.Reply) - private static final Reply DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new Reply(); - } - - public static Reply getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public Reply parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Reply(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public Reply getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - - } - - private int bitField0_; - public static final int HEADER_FIELD_NUMBER = 1; - private RequestHeader header_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - return getHeader(); - } - - public static final int CONSUMERGROUP_FIELD_NUMBER = 2; - private volatile Object consumerGroup_; - /** - * string consumerGroup = 2; - */ - public String getConsumerGroup() { - Object ref = consumerGroup_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - consumerGroup_ = s; - return s; - } - } - /** - * string consumerGroup = 2; - */ - public com.google.protobuf.ByteString - getConsumerGroupBytes() { - Object ref = consumerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - consumerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int SUBSCRIPTIONITEMS_FIELD_NUMBER = 3; - private java.util.List subscriptionItems_; - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public java.util.List getSubscriptionItemsList() { - return subscriptionItems_; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public java.util.List - getSubscriptionItemsOrBuilderList() { - return subscriptionItems_; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public int getSubscriptionItemsCount() { - return subscriptionItems_.size(); - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItem getSubscriptionItems(int index) { - return subscriptionItems_.get(index); - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItemOrBuilder getSubscriptionItemsOrBuilder( - int index) { - return subscriptionItems_.get(index); - } - - public static final int URL_FIELD_NUMBER = 4; - private volatile Object url_; - /** - * string url = 4; - */ - public String getUrl() { - Object ref = url_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - url_ = s; - return s; - } - } - /** - * string url = 4; - */ - public com.google.protobuf.ByteString - getUrlBytes() { - Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int REPLY_FIELD_NUMBER = 5; - private Reply reply_; - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public boolean hasReply() { - return reply_ != null; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Reply getReply() { - return reply_ == null ? Reply.getDefaultInstance() : reply_; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public ReplyOrBuilder getReplyOrBuilder() { - return getReply(); - } - - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (header_ != null) { - output.writeMessage(1, getHeader()); - } - if (!getConsumerGroupBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, consumerGroup_); - } - for (int i = 0; i < subscriptionItems_.size(); i++) { - output.writeMessage(3, subscriptionItems_.get(i)); - } - if (!getUrlBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, url_); - } - if (reply_ != null) { - output.writeMessage(5, getReply()); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (header_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(1, getHeader()); - } - if (!getConsumerGroupBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, consumerGroup_); - } - for (int i = 0; i < subscriptionItems_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, subscriptionItems_.get(i)); - } - if (!getUrlBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, url_); - } - if (reply_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, getReply()); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Subscription)) { - return super.equals(obj); - } - Subscription other = (Subscription) obj; - - boolean result = true; - result = result && (hasHeader() == other.hasHeader()); - if (hasHeader()) { - result = result && getHeader() - .equals(other.getHeader()); - } - result = result && getConsumerGroup() - .equals(other.getConsumerGroup()); - result = result && getSubscriptionItemsList() - .equals(other.getSubscriptionItemsList()); - result = result && getUrl() - .equals(other.getUrl()); - result = result && (hasReply() == other.hasReply()); - if (hasReply()) { - result = result && getReply() - .equals(other.getReply()); - } - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - if (hasHeader()) { - hash = (37 * hash) + HEADER_FIELD_NUMBER; - hash = (53 * hash) + getHeader().hashCode(); - } - hash = (37 * hash) + CONSUMERGROUP_FIELD_NUMBER; - hash = (53 * hash) + getConsumerGroup().hashCode(); - if (getSubscriptionItemsCount() > 0) { - hash = (37 * hash) + SUBSCRIPTIONITEMS_FIELD_NUMBER; - hash = (53 * hash) + getSubscriptionItemsList().hashCode(); - } - hash = (37 * hash) + URL_FIELD_NUMBER; - hash = (53 * hash) + getUrl().hashCode(); - if (hasReply()) { - hash = (37 * hash) + REPLY_FIELD_NUMBER; - hash = (53 * hash) + getReply().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static Subscription parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Subscription parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Subscription parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Subscription parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Subscription parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static Subscription parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static Subscription parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Subscription parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - public static Subscription parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - public static Subscription parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static Subscription parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - public static Subscription parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(Subscription prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code eventmesh.common.protocol.grpc.Subscription} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:eventmesh.common.protocol.grpc.Subscription) - SubscriptionOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor; - } - - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Subscription.class, Builder.class); - } - - // Construct using org.apache.eventmesh.common.protocol.grpc.protos.Subscription.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - getSubscriptionItemsFieldBuilder(); - } - } - public Builder clear() { - super.clear(); - if (headerBuilder_ == null) { - header_ = null; - } else { - header_ = null; - headerBuilder_ = null; - } - consumerGroup_ = ""; - - if (subscriptionItemsBuilder_ == null) { - subscriptionItems_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000004); - } else { - subscriptionItemsBuilder_.clear(); - } - url_ = ""; - - if (replyBuilder_ == null) { - reply_ = null; - } else { - reply_ = null; - replyBuilder_ = null; - } - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return EventmeshGrpc.internal_static_eventmesh_common_protocol_grpc_Subscription_descriptor; - } - - public Subscription getDefaultInstanceForType() { - return Subscription.getDefaultInstance(); - } - - public Subscription build() { - Subscription result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public Subscription buildPartial() { - Subscription result = new Subscription(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (headerBuilder_ == null) { - result.header_ = header_; - } else { - result.header_ = headerBuilder_.build(); - } - result.consumerGroup_ = consumerGroup_; - if (subscriptionItemsBuilder_ == null) { - if (((bitField0_ & 0x00000004) == 0x00000004)) { - subscriptionItems_ = java.util.Collections.unmodifiableList(subscriptionItems_); - bitField0_ = (bitField0_ & ~0x00000004); - } - result.subscriptionItems_ = subscriptionItems_; - } else { - result.subscriptionItems_ = subscriptionItemsBuilder_.build(); - } - result.url_ = url_; - if (replyBuilder_ == null) { - result.reply_ = reply_; - } else { - result.reply_ = replyBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof Subscription) { - return mergeFrom((Subscription)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(Subscription other) { - if (other == Subscription.getDefaultInstance()) return this; - if (other.hasHeader()) { - mergeHeader(other.getHeader()); - } - if (!other.getConsumerGroup().isEmpty()) { - consumerGroup_ = other.consumerGroup_; - onChanged(); - } - if (subscriptionItemsBuilder_ == null) { - if (!other.subscriptionItems_.isEmpty()) { - if (subscriptionItems_.isEmpty()) { - subscriptionItems_ = other.subscriptionItems_; - bitField0_ = (bitField0_ & ~0x00000004); - } else { - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.addAll(other.subscriptionItems_); - } - onChanged(); - } - } else { - if (!other.subscriptionItems_.isEmpty()) { - if (subscriptionItemsBuilder_.isEmpty()) { - subscriptionItemsBuilder_.dispose(); - subscriptionItemsBuilder_ = null; - subscriptionItems_ = other.subscriptionItems_; - bitField0_ = (bitField0_ & ~0x00000004); - subscriptionItemsBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? - getSubscriptionItemsFieldBuilder() : null; - } else { - subscriptionItemsBuilder_.addAllMessages(other.subscriptionItems_); - } - } - } - if (!other.getUrl().isEmpty()) { - url_ = other.url_; - onChanged(); - } - if (other.hasReply()) { - mergeReply(other.getReply()); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - Subscription parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (Subscription) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - private RequestHeader header_ = null; - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> headerBuilder_; - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public boolean hasHeader() { - return headerBuilder_ != null || header_ != null; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader getHeader() { - if (headerBuilder_ == null) { - return header_ == null ? RequestHeader.getDefaultInstance() : header_; - } else { - return headerBuilder_.getMessage(); - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - header_ = value; - onChanged(); - } else { - headerBuilder_.setMessage(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder setHeader( - RequestHeader.Builder builderForValue) { - if (headerBuilder_ == null) { - header_ = builderForValue.build(); - onChanged(); - } else { - headerBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder mergeHeader(RequestHeader value) { - if (headerBuilder_ == null) { - if (header_ != null) { - header_ = - RequestHeader.newBuilder(header_).mergeFrom(value).buildPartial(); - } else { - header_ = value; - } - onChanged(); - } else { - headerBuilder_.mergeFrom(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public Builder clearHeader() { - if (headerBuilder_ == null) { - header_ = null; - onChanged(); - } else { - header_ = null; - headerBuilder_ = null; - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeader.Builder getHeaderBuilder() { - - onChanged(); - return getHeaderFieldBuilder().getBuilder(); - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - public RequestHeaderOrBuilder getHeaderOrBuilder() { - if (headerBuilder_ != null) { - return headerBuilder_.getMessageOrBuilder(); - } else { - return header_ == null ? - RequestHeader.getDefaultInstance() : header_; - } - } - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - private com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder> - getHeaderFieldBuilder() { - if (headerBuilder_ == null) { - headerBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< - RequestHeader, RequestHeader.Builder, RequestHeaderOrBuilder>( - getHeader(), - getParentForChildren(), - isClean()); - header_ = null; - } - return headerBuilder_; - } - - private Object consumerGroup_ = ""; - /** - * string consumerGroup = 2; - */ - public String getConsumerGroup() { - Object ref = consumerGroup_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - consumerGroup_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string consumerGroup = 2; - */ - public com.google.protobuf.ByteString - getConsumerGroupBytes() { - Object ref = consumerGroup_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - consumerGroup_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string consumerGroup = 2; - */ - public Builder setConsumerGroup( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - consumerGroup_ = value; - onChanged(); - return this; - } - /** - * string consumerGroup = 2; - */ - public Builder clearConsumerGroup() { - - consumerGroup_ = getDefaultInstance().getConsumerGroup(); - onChanged(); - return this; - } - /** - * string consumerGroup = 2; - */ - public Builder setConsumerGroupBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - consumerGroup_ = value; - onChanged(); - return this; - } - - private java.util.List subscriptionItems_ = - java.util.Collections.emptyList(); - private void ensureSubscriptionItemsIsMutable() { - if (!((bitField0_ & 0x00000004) == 0x00000004)) { - subscriptionItems_ = new java.util.ArrayList(subscriptionItems_); - bitField0_ |= 0x00000004; - } - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - SubscriptionItem, SubscriptionItem.Builder, SubscriptionItemOrBuilder> subscriptionItemsBuilder_; - - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public java.util.List getSubscriptionItemsList() { - if (subscriptionItemsBuilder_ == null) { - return java.util.Collections.unmodifiableList(subscriptionItems_); - } else { - return subscriptionItemsBuilder_.getMessageList(); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public int getSubscriptionItemsCount() { - if (subscriptionItemsBuilder_ == null) { - return subscriptionItems_.size(); - } else { - return subscriptionItemsBuilder_.getCount(); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItem getSubscriptionItems(int index) { - if (subscriptionItemsBuilder_ == null) { - return subscriptionItems_.get(index); - } else { - return subscriptionItemsBuilder_.getMessage(index); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder setSubscriptionItems( - int index, SubscriptionItem value) { - if (subscriptionItemsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.set(index, value); - onChanged(); - } else { - subscriptionItemsBuilder_.setMessage(index, value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder setSubscriptionItems( - int index, SubscriptionItem.Builder builderForValue) { - if (subscriptionItemsBuilder_ == null) { - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.set(index, builderForValue.build()); - onChanged(); - } else { - subscriptionItemsBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder addSubscriptionItems(SubscriptionItem value) { - if (subscriptionItemsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.add(value); - onChanged(); - } else { - subscriptionItemsBuilder_.addMessage(value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder addSubscriptionItems( - int index, SubscriptionItem value) { - if (subscriptionItemsBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.add(index, value); - onChanged(); - } else { - subscriptionItemsBuilder_.addMessage(index, value); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder addSubscriptionItems( - SubscriptionItem.Builder builderForValue) { - if (subscriptionItemsBuilder_ == null) { - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.add(builderForValue.build()); - onChanged(); - } else { - subscriptionItemsBuilder_.addMessage(builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder addSubscriptionItems( - int index, SubscriptionItem.Builder builderForValue) { - if (subscriptionItemsBuilder_ == null) { - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.add(index, builderForValue.build()); - onChanged(); - } else { - subscriptionItemsBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder addAllSubscriptionItems( - Iterable values) { - if (subscriptionItemsBuilder_ == null) { - ensureSubscriptionItemsIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, subscriptionItems_); - onChanged(); - } else { - subscriptionItemsBuilder_.addAllMessages(values); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder clearSubscriptionItems() { - if (subscriptionItemsBuilder_ == null) { - subscriptionItems_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - } else { - subscriptionItemsBuilder_.clear(); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public Builder removeSubscriptionItems(int index) { - if (subscriptionItemsBuilder_ == null) { - ensureSubscriptionItemsIsMutable(); - subscriptionItems_.remove(index); - onChanged(); - } else { - subscriptionItemsBuilder_.remove(index); - } - return this; - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItem.Builder getSubscriptionItemsBuilder( - int index) { - return getSubscriptionItemsFieldBuilder().getBuilder(index); - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItemOrBuilder getSubscriptionItemsOrBuilder( - int index) { - if (subscriptionItemsBuilder_ == null) { - return subscriptionItems_.get(index); } else { - return subscriptionItemsBuilder_.getMessageOrBuilder(index); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public java.util.List - getSubscriptionItemsOrBuilderList() { - if (subscriptionItemsBuilder_ != null) { - return subscriptionItemsBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(subscriptionItems_); - } - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItem.Builder addSubscriptionItemsBuilder() { - return getSubscriptionItemsFieldBuilder().addBuilder( - SubscriptionItem.getDefaultInstance()); - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public SubscriptionItem.Builder addSubscriptionItemsBuilder( - int index) { - return getSubscriptionItemsFieldBuilder().addBuilder( - index, SubscriptionItem.getDefaultInstance()); - } - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - public java.util.List - getSubscriptionItemsBuilderList() { - return getSubscriptionItemsFieldBuilder().getBuilderList(); - } - private com.google.protobuf.RepeatedFieldBuilderV3< - SubscriptionItem, SubscriptionItem.Builder, SubscriptionItemOrBuilder> - getSubscriptionItemsFieldBuilder() { - if (subscriptionItemsBuilder_ == null) { - subscriptionItemsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< - SubscriptionItem, SubscriptionItem.Builder, SubscriptionItemOrBuilder>( - subscriptionItems_, - ((bitField0_ & 0x00000004) == 0x00000004), - getParentForChildren(), - isClean()); - subscriptionItems_ = null; - } - return subscriptionItemsBuilder_; - } - - private Object url_ = ""; - /** - * string url = 4; - */ - public String getUrl() { - Object ref = url_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - url_ = s; - return s; - } else { - return (String) ref; - } - } - /** - * string url = 4; - */ - public com.google.protobuf.ByteString - getUrlBytes() { - Object ref = url_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - url_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string url = 4; - */ - public Builder setUrl( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - url_ = value; - onChanged(); - return this; - } - /** - * string url = 4; - */ - public Builder clearUrl() { - - url_ = getDefaultInstance().getUrl(); - onChanged(); - return this; - } - /** - * string url = 4; - */ - public Builder setUrlBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - url_ = value; - onChanged(); - return this; - } - - private Reply reply_ = null; - private com.google.protobuf.SingleFieldBuilderV3< - Reply, Reply.Builder, ReplyOrBuilder> replyBuilder_; - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public boolean hasReply() { - return replyBuilder_ != null || reply_ != null; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Reply getReply() { - if (replyBuilder_ == null) { - return reply_ == null ? Reply.getDefaultInstance() : reply_; - } else { - return replyBuilder_.getMessage(); - } - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Builder setReply(Reply value) { - if (replyBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - reply_ = value; - onChanged(); - } else { - replyBuilder_.setMessage(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Builder setReply( - Reply.Builder builderForValue) { - if (replyBuilder_ == null) { - reply_ = builderForValue.build(); - onChanged(); - } else { - replyBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Builder mergeReply(Reply value) { - if (replyBuilder_ == null) { - if (reply_ != null) { - reply_ = - Reply.newBuilder(reply_).mergeFrom(value).buildPartial(); - } else { - reply_ = value; - } - onChanged(); - } else { - replyBuilder_.mergeFrom(value); - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Builder clearReply() { - if (replyBuilder_ == null) { - reply_ = null; - onChanged(); - } else { - reply_ = null; - replyBuilder_ = null; - } - - return this; - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public Reply.Builder getReplyBuilder() { - - onChanged(); - return getReplyFieldBuilder().getBuilder(); - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - public ReplyOrBuilder getReplyOrBuilder() { - if (replyBuilder_ != null) { - return replyBuilder_.getMessageOrBuilder(); - } else { - return reply_ == null ? - Reply.getDefaultInstance() : reply_; - } - } - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - private com.google.protobuf.SingleFieldBuilderV3< - Reply, Reply.Builder, ReplyOrBuilder> - getReplyFieldBuilder() { - if (replyBuilder_ == null) { - replyBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< - Reply, Reply.Builder, ReplyOrBuilder>( - getReply(), - getParentForChildren(), - isClean()); - reply_ = null; - } - return replyBuilder_; - } - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:eventmesh.common.protocol.grpc.Subscription) - } - - // @@protoc_insertion_point(class_scope:eventmesh.common.protocol.grpc.Subscription) - private static final Subscription DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new Subscription(); - } - - public static Subscription getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public Subscription parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Subscription(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public Subscription getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SubscriptionOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SubscriptionOrBuilder.java deleted file mode 100644 index 4adff7d4fc..0000000000 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/grpc/protos/SubscriptionOrBuilder.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: eventmesh-client.proto - -package org.apache.eventmesh.common.protocol.grpc.protos; - -@SuppressWarnings({"all"}) -public interface SubscriptionOrBuilder extends - // @@protoc_insertion_point(interface_extends:eventmesh.common.protocol.grpc.Subscription) - com.google.protobuf.MessageOrBuilder { - - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - boolean hasHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeader getHeader(); - /** - * .eventmesh.common.protocol.grpc.RequestHeader header = 1; - */ - RequestHeaderOrBuilder getHeaderOrBuilder(); - - /** - * string consumerGroup = 2; - */ - String getConsumerGroup(); - /** - * string consumerGroup = 2; - */ - com.google.protobuf.ByteString - getConsumerGroupBytes(); - - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - java.util.List - getSubscriptionItemsList(); - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - Subscription.SubscriptionItem getSubscriptionItems(int index); - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - int getSubscriptionItemsCount(); - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - java.util.List - getSubscriptionItemsOrBuilderList(); - /** - * repeated .eventmesh.common.protocol.grpc.Subscription.SubscriptionItem subscriptionItems = 3; - */ - Subscription.SubscriptionItemOrBuilder getSubscriptionItemsOrBuilder( - int index); - - /** - * string url = 4; - */ - String getUrl(); - /** - * string url = 4; - */ - com.google.protobuf.ByteString - getUrlBytes(); - - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - boolean hasReply(); - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - Subscription.Reply getReply(); - /** - * .eventmesh.common.protocol.grpc.Subscription.Reply reply = 5; - */ - Subscription.ReplyOrBuilder getReplyOrBuilder(); -} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpCommand.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpCommand.java index 11ad66aa18..f7ebd0cab8 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpCommand.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpCommand.java @@ -22,12 +22,12 @@ import org.apache.eventmesh.common.protocol.http.body.BaseResponseBody; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.common.protocol.http.header.BaseResponseHeader; import org.apache.eventmesh.common.protocol.http.header.Header; import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.commons.lang3.StringUtils; - +import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; @@ -39,8 +39,14 @@ import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; +import lombok.Data; + +@Deprecated +@Data public class HttpCommand implements ProtocolTransportObject { + private static final long serialVersionUID = -8763824685105888009L; + private static final AtomicLong requestId = new AtomicLong(0); private long opaque; @@ -51,14 +57,14 @@ public class HttpCommand implements ProtocolTransportObject { public String httpVersion; - public Header header; + private transient Header header; - public Body body; + private transient Body body; - //Command request time + // Command request time public long reqTime; - //Command response time + // Command response time public long resTime; public CmdType cmdType = CmdType.REQ; @@ -76,8 +82,8 @@ public HttpCommand(String httpMethod, String httpVersion, String requestCode) { } public HttpCommand createHttpCommandResponse(Header header, Body body) { - if (StringUtils.isBlank(requestCode)) { - return null; + if (this.requestCode == null) { + this.requestCode = RequestCode.UNKNOWN.getRequestCode().toString(); } HttpCommand response = new HttpCommand(this.httpMethod, this.httpVersion, this.requestCode); response.setOpaque(this.opaque); @@ -90,8 +96,8 @@ public HttpCommand createHttpCommandResponse(Header header, Body body) { } public HttpCommand createHttpCommandResponse(EventMeshRetCode eventMeshRetCode) { - if (StringUtils.isBlank(requestCode)) { - return null; + if (this.requestCode == null) { + this.requestCode = RequestCode.UNKNOWN.getRequestCode().toString(); } HttpCommand response = new HttpCommand(this.httpMethod, this.httpVersion, this.requestCode); response.setOpaque(this.opaque); @@ -108,94 +114,22 @@ public HttpCommand createHttpCommandResponse(EventMeshRetCode eventMeshRetCode) return response; } - public long getReqTime() { - return reqTime; - } - - public void setReqTime(long reqTime) { - this.reqTime = reqTime; - } - - public long getResTime() { - return resTime; - } - - public void setResTime(long resTime) { - this.resTime = resTime; - } - - public long getOpaque() { - return opaque; - } - - public void setOpaque(long opaque) { - this.opaque = opaque; - } - - public CmdType getCmdType() { - return cmdType; - } - - public void setCmdType(CmdType cmdType) { - this.cmdType = cmdType; - } - - public String getHttpMethod() { - return httpMethod; - } - - public void setHttpMethod(String httpMethod) { - this.httpMethod = httpMethod; - } - - public String getHttpVersion() { - return httpVersion; - } - - public void setHttpVersion(String httpVersion) { - this.httpVersion = httpVersion; - } - - public String getRequestCode() { - return requestCode; - } - - public void setRequestCode(String requestCode) { - this.requestCode = requestCode; - } - - public Header getHeader() { - return header; - } - - public void setHeader(Header header) { - this.header = header; - } - - public Body getBody() { - return body; - } - - public void setBody(Body body) { - this.body = body; - } - @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("httpCommand={") - .append(cmdType).append(",") - .append(httpMethod).append("/").append(httpVersion).append(",") - .append("requestCode=").append(requestCode).append(",") - .append("opaque=").append(opaque).append(","); + .append(cmdType).append(",") + .append(httpMethod).append("/").append(httpVersion).append(",") + .append("requestCode=").append(requestCode).append(",") + .append("opaque=").append(opaque).append(","); if (cmdType == CmdType.RES) { sb.append("cost=").append(resTime - reqTime).append(","); } sb.append("header=").append(header).append(",") - .append("body=").append(body) - .append("}"); + .append("body=").append(body) + .append("}"); return sb.toString(); } @@ -203,17 +137,17 @@ public String toString() { public String abstractDesc() { StringBuilder sb = new StringBuilder(); sb.append("httpCommand={") - .append(cmdType).append(",") - .append(httpMethod).append("/").append(httpVersion).append(",") - .append("requestCode=").append(requestCode).append(",") - .append("opaque=").append(opaque).append(","); + .append(cmdType).append(",") + .append(httpMethod).append("/").append(httpVersion).append(",") + .append("requestCode=").append(requestCode).append(",") + .append("opaque=").append(opaque).append(","); if (cmdType == CmdType.RES) { sb.append("cost=").append(resTime - reqTime).append(","); } sb.append("header=").append(header).append(",") - .append("bodySize=").append(body.toString().length()).append("}"); + .append("bodySize=").append(body.toString().length()).append("}"); return sb.toString(); } @@ -221,9 +155,9 @@ public String abstractDesc() { public String simpleDesc() { StringBuilder sb = new StringBuilder(); sb.append("httpCommand={") - .append(cmdType).append(",") - .append(httpMethod).append("/").append(httpVersion).append(",") - .append("requestCode=").append(requestCode).append("}"); + .append(cmdType).append(",") + .append(httpMethod).append("/").append(httpVersion).append(",") + .append("requestCode=").append(requestCode).append("}"); return sb.toString(); } @@ -233,7 +167,21 @@ public DefaultFullHttpResponse httpResponse() throws Exception { return null; } DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, - Unpooled.wrappedBuffer(JsonUtils.serialize(this.getBody()).getBytes(Constants.DEFAULT_CHARSET))); + Unpooled.wrappedBuffer(Objects.requireNonNull(JsonUtils.toJSONString(this.getBody())).getBytes(Constants.DEFAULT_CHARSET))); + HttpHeaders headers = response.headers(); + headers.add(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=" + Constants.DEFAULT_CHARSET); + headers.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + headers.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + Optional.of(this.getHeader().toMap()).ifPresent(customerHeader -> customerHeader.forEach(headers::add)); + return response; + } + + public DefaultFullHttpResponse httpResponse(HttpResponseStatus httpResponseStatus) throws Exception { + if (cmdType == CmdType.REQ) { + return null; + } + DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, httpResponseStatus, + Unpooled.wrappedBuffer(Objects.requireNonNull(JsonUtils.toJSONString(this.getBody())).getBytes(Constants.DEFAULT_CHARSET))); HttpHeaders headers = response.headers(); headers.add(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=" + Constants.DEFAULT_CHARSET); headers.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); @@ -246,4 +194,4 @@ public enum CmdType { REQ, RES } -} \ No newline at end of file +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapper.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapper.java index 81a98b579d..a19539f477 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapper.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapper.java @@ -22,16 +22,15 @@ import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.RequestURI; -import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.commons.lang3.StringUtils; import java.net.URI; -import java.nio.charset.StandardCharsets; +import java.util.EnumSet; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -43,27 +42,29 @@ import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; - public class HttpEventWrapper implements ProtocolTransportObject { + public static final long serialVersionUID = -8547334421415366981L; - private Map headerMap = new HashMap<>(); + private transient Map headerMap = new HashMap<>(); - private Map sysHeaderMap = new HashMap<>(); + private transient Map sysHeaderMap = new HashMap<>(); private byte[] body; private String requestURI; - public String httpMethod; + private String httpMethod; + + private String httpVersion; - public String httpVersion; + // Command request time + private long reqTime; - //Command request time - public long reqTime; + // Command response time + private long resTime; - //Command response time - public long resTime; + private HttpResponseStatus httpResponseStatus = HttpResponseStatus.OK; public HttpEventWrapper() { this(null, null, null); @@ -83,7 +84,7 @@ public HttpEventWrapper createHttpResponse(Map responseHeaderMap HttpEventWrapper response = new HttpEventWrapper(this.httpMethod, this.httpVersion, this.requestURI); response.setReqTime(this.reqTime); response.setHeaderMap(responseHeaderMap); - response.setBody(JsonUtils.serialize(responseBodyMap).getBytes(StandardCharsets.UTF_8)); + response.setBody(Objects.requireNonNull(JsonUtils.toJSONString(responseBodyMap)).getBytes(Constants.DEFAULT_CHARSET)); response.setResTime(System.currentTimeMillis()); return response; } @@ -100,7 +101,7 @@ public HttpEventWrapper createHttpResponse(EventMeshRetCode eventMeshRetCode) { Map responseBodyMap = new HashMap<>(); responseBodyMap.put("retCode", eventMeshRetCode.getRetCode()); responseBodyMap.put("retMessage", eventMeshRetCode.getErrMsg()); - response.setBody(JsonUtils.serialize(responseBodyMap).getBytes(StandardCharsets.UTF_8)); + response.setBody(Objects.requireNonNull(JsonUtils.toJSONString(responseBodyMap)).getBytes(Constants.DEFAULT_CHARSET)); response.setResTime(System.currentTimeMillis()); return response; } @@ -162,16 +163,25 @@ public void setSysHeaderMap(Map sysHeaderMap) { } public byte[] getBody() { - return body; + int len = body.length; + byte[] b = new byte[len]; + System.arraycopy(body, 0, b, 0, len); + return b; } - public void setBody(byte[] body) { - this.body = body; + public void setBody(byte[] newBody) { + if (newBody == null || newBody.length == 0) { + return; + } + + int len = newBody.length; + this.body = new byte[len]; + System.arraycopy(newBody, 0, this.body, 0, len); } public DefaultFullHttpResponse httpResponse() throws Exception { - DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, - Unpooled.wrappedBuffer(this.body)); + DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, httpResponseStatus, + Unpooled.wrappedBuffer(this.body)); HttpHeaders headers = response.headers(); headers.add(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=" + Constants.DEFAULT_CHARSET); headers.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); @@ -182,19 +192,19 @@ public DefaultFullHttpResponse httpResponse() throws Exception { public void buildSysHeaderForClient() { // sys attributes - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.ENV, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.ENV, "env")); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.IDC, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.IDC, "idc")); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.IP, IPUtils.getLocalAddress())); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.PID, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.PID, ThreadUtils.getPID())); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.SYS, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.SYS, "1234")); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.USERNAME, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.USERNAME, "eventmesh")); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.PASSWD, headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.PASSWD, "pass")); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.PRODUCERGROUP, - headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.PRODUCERGROUP, "em-http-producer")); - sysHeaderMap.put(ProtocolKey.ClientInstanceKey.CONSUMERGROUP, - headerMap.getOrDefault(ProtocolKey.ClientInstanceKey.CONSUMERGROUP, "em-http-consumer")); sysHeaderMap.put(ProtocolKey.PROTOCOL_TYPE, "http"); sysHeaderMap.put(ProtocolKey.PROTOCOL_DESC, "http"); + EnumSet clientInstanceKeys = EnumSet.allOf(ProtocolKey.ClientInstanceKey.class); + for (ProtocolKey.ClientInstanceKey clientInstanceKey : clientInstanceKeys) { + switch (clientInstanceKey) { + case BIZSEQNO: + case UNIQUEID: + break; + default: + sysHeaderMap.put(clientInstanceKey.getKey(), + headerMap.getOrDefault(clientInstanceKey.getKey(), clientInstanceKey.getValue())); + } + } } public void buildSysHeaderForCE() { @@ -215,4 +225,8 @@ public void buildSysHeaderForCE() { sysHeaderMap.put(ProtocolKey.CloudEventsKey.SUBJECT, topic); } + public void setHttpResponseStatus(HttpResponseStatus httpResponseStatus) { + this.httpResponseStatus = httpResponseStatus; + } + } \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/WebhookProtocolTransportObject.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/WebhookProtocolTransportObject.java index f47d7851b3..9b490f978d 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/WebhookProtocolTransportObject.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/WebhookProtocolTransportObject.java @@ -22,12 +22,11 @@ import lombok.Builder; import lombok.Data; - @Data @Builder public class WebhookProtocolTransportObject implements ProtocolTransportObject { - private static final long serialVersionUID = -7247618154228090320L; + private static final long serialVersionUID = 7821703624838598761L; private String cloudEventId; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseRequestBody.java index a8d77c8e8f..423872bdf2 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseRequestBody.java @@ -28,7 +28,6 @@ public static BaseRequestBody buildBody(Map bodyParam) { @Override public Map toMap() { - Map map = new HashMap(); - return map; + return new HashMap(); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java index aefa711840..570e2af481 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBody.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.common.protocol.http.body; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import java.util.HashMap; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/Body.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/Body.java index 3dc8e6c272..2bb0775439 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/Body.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/Body.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.common.protocol.http.body; - import org.apache.eventmesh.common.protocol.http.body.client.HeartbeatRequestBody; import org.apache.eventmesh.common.protocol.http.body.client.RegRequestBody; import org.apache.eventmesh.common.protocol.http.body.client.SubscribeRequestBody; @@ -37,35 +36,38 @@ public abstract class Body { public abstract Map toMap(); public static Body buildBody(String requestCode, Map originalMap) throws Exception { - if (String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()).equals(requestCode)) { - return SendMessageBatchRequestBody.buildBody(originalMap); + RequestCode code = RequestCode.get(Integer.valueOf(requestCode)); + if (code == null) { + throw new Exception("Request code " + requestCode + "not support"); } - if (String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()).equals(requestCode)) { - return SendMessageBatchV2RequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()).equals(requestCode)) { - return SendMessageRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()).equals(requestCode)) { - return SendMessageRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()).equals(requestCode)) { - return PushMessageRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()).equals(requestCode)) { - return PushMessageRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.REGISTER.getRequestCode()).equals(requestCode)) { - return RegRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.UNREGISTER.getRequestCode()).equals(requestCode)) { - return UnRegRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.SUBSCRIBE.getRequestCode()).equals(requestCode)) { - return SubscribeRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.UNSUBSCRIBE.getRequestCode()).equals(requestCode)) { - return UnSubscribeRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.HEARTBEAT.getRequestCode()).equals(requestCode)) { - return HeartbeatRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.REPLY_MESSAGE.getRequestCode()).equals(requestCode)) { - return ReplyMessageRequestBody.buildBody(originalMap); - } else if (String.valueOf(RequestCode.ADMIN_SHUTDOWN.getRequestCode()).equals(requestCode)) { - return BaseRequestBody.buildBody(originalMap); - } else { - throw new Exception(); + switch (code) { + case MSG_BATCH_SEND: + return SendMessageBatchRequestBody.buildBody(originalMap); + case MSG_BATCH_SEND_V2: + return SendMessageBatchV2RequestBody.buildBody(originalMap); + case MSG_SEND_ASYNC: + case MSG_SEND_SYNC: + return SendMessageRequestBody.buildBody(originalMap); + case HTTP_PUSH_CLIENT_ASYNC: + case HTTP_PUSH_CLIENT_SYNC: + return PushMessageRequestBody.buildBody(originalMap); + case REGISTER: + return RegRequestBody.buildBody(originalMap); + case UNREGISTER: + return UnRegRequestBody.buildBody(originalMap); + case SUBSCRIBE: + return SubscribeRequestBody.buildBody(originalMap); + case UNSUBSCRIBE: + return UnSubscribeRequestBody.buildBody(originalMap); + case HEARTBEAT: + return HeartbeatRequestBody.buildBody(originalMap); + case REPLY_MESSAGE: + return ReplyMessageRequestBody.buildBody(originalMap); + case ADMIN_SHUTDOWN: + return BaseRequestBody.buildBody(originalMap); + default: + throw new Exception("Request code " + requestCode + "not support"); } + } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java index a26ed2d1dd..aef3177823 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatRequestBody.java @@ -28,6 +28,13 @@ import com.fasterxml.jackson.core.type.TypeReference; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString public class HeartbeatRequestBody extends Body { public static final String CLIENTTYPE = "clientType"; @@ -40,38 +47,13 @@ public class HeartbeatRequestBody extends Body { private List heartbeatEntities; - public String getClientType() { - return clientType; - } - - public void setClientType(String clientType) { - this.clientType = clientType; - } - - public List getHeartbeatEntities() { - return heartbeatEntities; - } - - public void setHeartbeatEntities(List heartbeatEntities) { - this.heartbeatEntities = heartbeatEntities; - } - - public String getConsumerGroup() { - return consumerGroup; - } - - public void setConsumerGroup(String consumerGroup) { - this.consumerGroup = consumerGroup; - } - public static HeartbeatRequestBody buildBody(Map bodyParam) { HeartbeatRequestBody body = new HeartbeatRequestBody(); body.setClientType(MapUtils.getString(bodyParam, CLIENTTYPE)); body.setConsumerGroup(MapUtils.getString(bodyParam, CONSUMERGROUP)); - body.setHeartbeatEntities(JsonUtils - .deserialize(MapUtils.getString(bodyParam, HEARTBEATENTITIES), - new TypeReference>() { - })); + body.setHeartbeatEntities(JsonUtils.parseTypeReferenceObject(MapUtils.getString(bodyParam, HEARTBEATENTITIES), + new TypeReference>() { + })); return body; } @@ -80,34 +62,20 @@ public Map toMap() { Map map = new HashMap<>(); map.put(CLIENTTYPE, clientType); map.put(CONSUMERGROUP, consumerGroup); - map.put(HEARTBEATENTITIES, JsonUtils.serialize(heartbeatEntities)); + map.put(HEARTBEATENTITIES, JsonUtils.toJSONString(heartbeatEntities)); return map; } + @Data public static class HeartbeatEntity { - public String topic; - public String serviceId; - public String url; - public String instanceId; - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("heartbeatEntity={") - .append("topic=").append(topic).append(",") - .append("serviceId=").append(serviceId).append(",") - .append("instanceId=").append(instanceId).append(",") - .append("url=").append(url).append("}"); - return sb.toString(); - } - } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("heartbeatRequestBody={") - .append("consumerGroup=").append(consumerGroup).append(",") - .append("clientType=").append(clientType).append("}"); - return sb.toString(); + private String topic; + private String serviceId; + private String url; + private String instanceId; + + } + + } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java index c9151dc658..5112b7cd4b 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/HeartbeatResponseBody.java @@ -28,13 +28,13 @@ public class HeartbeatResponseBody extends Body { - //return code + // return code private Integer retCode; - //response message + // response message private String retMsg; - //response time + // response time private long resTime = System.currentTimeMillis(); public Integer getRetCode() { @@ -61,7 +61,7 @@ public void setResTime(long resTime) { this.resTime = resTime; } - public static HeartbeatResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + public static HeartbeatResponseBody buildBody(Integer retCode, String retMsg) { HeartbeatResponseBody heartbeatResponseBody = new HeartbeatResponseBody(); heartbeatResponseBody.setRetMsg(retMsg); heartbeatResponseBody.setResTime(System.currentTimeMillis()); @@ -73,9 +73,9 @@ public static HeartbeatResponseBody buildBody(Integer retCode, String retMsg) th public String toString() { StringBuilder sb = new StringBuilder(); sb.append("heartbeatResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegRequestBody.java index affffdce09..83db73874f 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegRequestBody.java @@ -71,9 +71,9 @@ public static RegRequestBody buildBody(Map bodyParam) { RegRequestBody body = new RegRequestBody(); body.setClientType(MapUtils.getString(bodyParam, CLIENTTYPE)); body.setEndPoint(MapUtils.getString(bodyParam, ENDPOINT)); - body.setTopics(JsonUtils.deserialize(MapUtils.getString(bodyParam, TOPICS), - new TypeReference>() { - })); + body.setTopics(JsonUtils.parseTypeReferenceObject(MapUtils.getString(bodyParam, TOPICS), + new TypeReference>() { + })); return body; } @@ -82,16 +82,16 @@ public Map toMap() { Map map = new HashMap<>(); map.put(CLIENTTYPE, clientType); map.put(ENDPOINT, endPoint); - map.put(TOPICS, JsonUtils.serialize(topics)); + map.put(TOPICS, JsonUtils.toJSONString(topics)); return map; } @Override public String toString() { return "regRequestBody{" - + "clientType='" + clientType + '\'' - + ", endPoint='" + endPoint + '\'' - + ", topics=" + topics - + '}'; + + "clientType='" + clientType + '\'' + + ", endPoint='" + endPoint + '\'' + + ", topics=" + topics + + '}'; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegResponseBody.java index aeb3288538..63dd63a641 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/RegResponseBody.java @@ -27,6 +27,7 @@ import java.util.Map; public class RegResponseBody extends Body { + private Integer retCode; private String retMsg; private long resTime = System.currentTimeMillis(); @@ -55,7 +56,7 @@ public void setResTime(long resTime) { this.resTime = resTime; } - public static RegResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + public static RegResponseBody buildBody(Integer retCode, String retMsg) { RegResponseBody regResponseBody = new RegResponseBody(); regResponseBody.setRetMsg(retMsg); regResponseBody.setResTime(System.currentTimeMillis()); @@ -67,9 +68,9 @@ public static RegResponseBody buildBody(Integer retCode, String retMsg) throws E public String toString() { StringBuilder sb = new StringBuilder(); sb.append("regResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java index df413c1c33..627b511b21 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeRequestBody.java @@ -70,9 +70,9 @@ public void setUrl(String url) { public static SubscribeRequestBody buildBody(Map bodyParam) { SubscribeRequestBody body = new SubscribeRequestBody(); body.setUrl(MapUtils.getString(bodyParam, URL)); - body.setTopics(JsonUtils.deserialize(MapUtils.getString(bodyParam, TOPIC), - new TypeReference>() { - })); + body.setTopics(JsonUtils.parseTypeReferenceObject(MapUtils.getString(bodyParam, TOPIC), + new TypeReference>() { + })); body.setConsumerGroup(MapUtils.getString(bodyParam, CONSUMERGROUP)); return body; } @@ -81,7 +81,7 @@ public static SubscribeRequestBody buildBody(Map bodyParam) { public Map toMap() { Map map = new HashMap(); map.put(URL, url); - map.put(TOPIC, JsonUtils.serialize(topics)); + map.put(TOPIC, JsonUtils.toJSONString(topics)); map.put(CONSUMERGROUP, consumerGroup); return map; } @@ -89,9 +89,9 @@ public Map toMap() { @Override public String toString() { return "subscribeBody{" - + "consumerGroup='" + consumerGroup + '\'' - + ", url='" + url + '\'' - + ", topics=" + topics - + '}'; + + "consumerGroup='" + consumerGroup + '\'' + + ", url='" + url + '\'' + + ", topics=" + topics + + '}'; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java index 0b2f6cb3ab..480e0e8072 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/SubscribeResponseBody.java @@ -27,6 +27,7 @@ import java.util.Map; public class SubscribeResponseBody extends Body { + private Integer retCode; private String retMsg; private long resTime = System.currentTimeMillis(); @@ -55,7 +56,7 @@ public void setResTime(long resTime) { this.resTime = resTime; } - public static SubscribeResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + public static SubscribeResponseBody buildBody(Integer retCode, String retMsg) { SubscribeResponseBody regResponseBody = new SubscribeResponseBody(); regResponseBody.setRetMsg(retMsg); regResponseBody.setResTime(System.currentTimeMillis()); @@ -67,9 +68,9 @@ public static SubscribeResponseBody buildBody(Integer retCode, String retMsg) th public String toString() { StringBuilder sb = new StringBuilder(); sb.append("regResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java index 6fa82bda7c..2e478f7529 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegRequestBody.java @@ -57,9 +57,9 @@ public void setClientType(String clientType) { public static UnRegRequestBody buildBody(Map bodyParam) { UnRegRequestBody body = new UnRegRequestBody(); body.setClientType(MapUtils.getString(bodyParam, CLIENTTYPE)); - body.setTopics(JsonUtils.deserialize(MapUtils.getString(bodyParam, TOPICS), - new TypeReference>() { - })); + body.setTopics(JsonUtils.parseTypeReferenceObject(MapUtils.getString(bodyParam, TOPICS), + new TypeReference>() { + })); return body; } @@ -67,7 +67,7 @@ public static UnRegRequestBody buildBody(Map bodyParam) { public Map toMap() { Map map = new HashMap<>(); map.put(CLIENTTYPE, clientType); - map.put(TOPICS, JsonUtils.serialize(topics)); + map.put(TOPICS, JsonUtils.toJSONString(topics)); return map; } @@ -75,13 +75,14 @@ public Map toMap() { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("regRequestBody={") - .append("clientType=").append(clientType) - .append("topics=").append(topics) - .append("}"); + .append("clientType=").append(clientType) + .append("topics=").append(topics) + .append("}"); return sb.toString(); } public static class UnRegTopicEntity { + public String topic; public String serviceId; public String instanceId; @@ -90,9 +91,9 @@ public static class UnRegTopicEntity { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("unRegTopicEntity={") - .append("topic=").append(topic).append(",") - .append("serviceId=").append(serviceId).append(",") - .append("instanceId=").append(instanceId).append("}"); + .append("topic=").append(topic).append(",") + .append("serviceId=").append(serviceId).append(",") + .append("instanceId=").append(instanceId).append("}"); return sb.toString(); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java index 975cb35a54..d74db765f5 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnRegResponseBody.java @@ -27,6 +27,7 @@ import java.util.Map; public class UnRegResponseBody extends Body { + private Integer retCode; private String retMsg; private long resTime = System.currentTimeMillis(); @@ -55,7 +56,7 @@ public void setResTime(long resTime) { this.resTime = resTime; } - public static UnRegResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + public static UnRegResponseBody buildBody(Integer retCode, String retMsg) { UnRegResponseBody regResponseBody = new UnRegResponseBody(); regResponseBody.setRetMsg(retMsg); regResponseBody.setResTime(System.currentTimeMillis()); @@ -67,9 +68,9 @@ public static UnRegResponseBody buildBody(Integer retCode, String retMsg) throws public String toString() { StringBuilder sb = new StringBuilder(); sb.append("regResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java index ca9db6210e..86fda60aab 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeRequestBody.java @@ -70,8 +70,8 @@ public static UnSubscribeRequestBody buildBody(Map bodyParam) { UnSubscribeRequestBody body = new UnSubscribeRequestBody(); body.setUrl(MapUtils.getString(bodyParam, URL)); body.setTopics(JsonUtils - .deserialize(MapUtils.getString(bodyParam, TOPIC), new TypeReference>() { - })); + .parseTypeReferenceObject(MapUtils.getString(bodyParam, TOPIC), new TypeReference>() { + })); body.setConsumerGroup(MapUtils.getString(bodyParam, CONSUMERGROUP)); return body; } @@ -80,7 +80,7 @@ public static UnSubscribeRequestBody buildBody(Map bodyParam) { public Map toMap() { Map map = new HashMap<>(); map.put(URL, url); - map.put(TOPIC, JsonUtils.serialize(topics)); + map.put(TOPIC, JsonUtils.toJSONString(topics)); map.put(CONSUMERGROUP, consumerGroup); return map; } @@ -88,9 +88,9 @@ public Map toMap() { @Override public String toString() { return "unSubscribeRequestBody{" - + "consumerGroup='" + consumerGroup + '\'' - + ", url='" + url + '\'' - + ", topics=" + topics - + '}'; + + "consumerGroup='" + consumerGroup + '\'' + + ", url='" + url + '\'' + + ", topics=" + topics + + '}'; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java index d1eeb77db5..f2b7dae6f3 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/client/UnSubscribeResponseBody.java @@ -56,7 +56,7 @@ public void setResTime(long resTime) { this.resTime = resTime; } - public static UnSubscribeResponseBody buildBody(Integer retCode, String retMsg) throws Exception { + public static UnSubscribeResponseBody buildBody(Integer retCode, String retMsg) { UnSubscribeResponseBody regResponseBody = new UnSubscribeResponseBody(); regResponseBody.setRetMsg(retMsg); regResponseBody.setResTime(System.currentTimeMillis()); @@ -68,9 +68,9 @@ public static UnSubscribeResponseBody buildBody(Integer retCode, String retMsg) public String toString() { StringBuilder sb = new StringBuilder(); sb.append("regResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java index 4a8feeb818..0409494a01 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageRequestBody.java @@ -47,7 +47,7 @@ public class PushMessageRequestBody extends Body { private String uniqueId; - private HashMap extFields; + private Map extFields; public String getTopic() { return topic; @@ -89,11 +89,11 @@ public void setContent(String content) { this.content = content; } - public HashMap getExtFields() { + public Map getExtFields() { return extFields; } - public void setExtFields(HashMap extFields) { + public void setExtFields(Map extFields) { this.extFields = extFields; } @@ -108,8 +108,8 @@ public static PushMessageRequestBody buildBody(final Map bodyPar if (StringUtils.isNotBlank(extFields)) { pushMessageRequestBody.setExtFields( - JsonUtils.deserialize(extFields, new TypeReference>() { - })); + JsonUtils.parseTypeReferenceObject(extFields, new TypeReference>() { + })); } return pushMessageRequestBody; } @@ -122,7 +122,7 @@ public Map toMap() { map.put(CONTENT, content); map.put(BIZSEQNO, bizSeqNo); map.put(UNIQUEID, uniqueId); - map.put(EXTFIELDS, JsonUtils.serialize(extFields)); + map.put(EXTFIELDS, JsonUtils.toJSONString(extFields)); return map; } @@ -131,12 +131,12 @@ public Map toMap() { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("pushMessageRequestBody={") - .append("randomNo=").append(randomNo).append(",") - .append("topic=").append(topic).append(",") - .append("bizSeqNo=").append(bizSeqNo).append(",") - .append("uniqueId=").append(uniqueId).append(",") - .append("content=").append(content).append(",") - .append("extFields=").append(extFields).append("}"); + .append("randomNo=").append(randomNo).append(",") + .append("topic=").append(topic).append(",") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("content=").append(content).append(",") + .append("extFields=").append(extFields).append("}"); return sb.toString(); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java index 01000b0d0f..e42f8502c8 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/PushMessageResponseBody.java @@ -17,12 +17,9 @@ package org.apache.eventmesh.common.protocol.http.body.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.commons.lang3.time.DateFormatUtils; - import java.util.HashMap; import java.util.Map; @@ -70,9 +67,9 @@ public static PushMessageResponseBody buildBody(Integer retCode, String retMsg) public String toString() { StringBuilder sb = new StringBuilder(); sb.append("pushMessageResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(resTime).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java index 0814204e4c..0e2ac2f563 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageRequestBody.java @@ -45,7 +45,7 @@ public class ReplyMessageRequestBody extends Body { private String origTopic; - private HashMap extFields; + private Map extFields; private String producerGroup; @@ -81,11 +81,11 @@ public void setContent(String content) { this.content = content; } - public HashMap getExtFields() { + public Map getExtFields() { return extFields; } - public void setExtFields(HashMap extFields) { + public void setExtFields(Map extFields) { this.extFields = extFields; } @@ -106,8 +106,8 @@ public static ReplyMessageRequestBody buildBody(Map bodyParam) { String extFields = MapUtils.getString(bodyParam, EXTFIELDS); if (StringUtils.isNotBlank(extFields)) { body.setExtFields( - JsonUtils.deserialize(extFields, new TypeReference>() { - })); + JsonUtils.parseTypeReferenceObject(extFields, new TypeReference>() { + })); } body.setProducerGroup(MapUtils.getString(bodyParam, PRODUCERGROUP)); return body; @@ -117,12 +117,12 @@ public static ReplyMessageRequestBody buildBody(Map bodyParam) { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("replyMessageRequestBody={") - .append("bizSeqNo=").append(bizSeqNo).append(",") - .append("uniqueId=").append(uniqueId).append(",") - .append("origTopic=").append(origTopic).append(",") - .append("content=").append(content).append(",") - .append("producerGroup=").append(producerGroup).append(",") - .append("extFields=").append(extFields).append("}"); + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("origTopic=").append(origTopic).append(",") + .append("content=").append(content).append(",") + .append("producerGroup=").append(producerGroup).append(",") + .append("extFields=").append(extFields).append("}"); return sb.toString(); } @@ -133,7 +133,7 @@ public Map toMap() { map.put(ORIGTOPIC, origTopic); map.put(UNIQUEID, uniqueId); map.put(CONTENT, content); - map.put(EXTFIELDS, JsonUtils.serialize(extFields)); + map.put(EXTFIELDS, JsonUtils.toJSONString(extFields)); map.put(PRODUCERGROUP, producerGroup); return map; } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java index 342f151c0a..595d7b5b19 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/ReplyMessageResponseBody.java @@ -17,24 +17,21 @@ package org.apache.eventmesh.common.protocol.http.body.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.commons.lang3.time.DateFormatUtils; - import java.util.HashMap; import java.util.Map; public class ReplyMessageResponseBody extends Body { - //return code + // return code private Integer retCode; - //response message + // response message private String retMsg; - //response time + // response time private long resTime = System.currentTimeMillis(); public Integer getRetCode() { @@ -73,9 +70,9 @@ public static ReplyMessageResponseBody buildBody(Integer retCode, String retMsg) public String toString() { StringBuilder sb = new StringBuilder(); sb.append("replyMessageResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(resTime).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java index da77955333..4987e298e6 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchRequestBody.java @@ -83,14 +83,15 @@ public void setProducerGroup(String producerGroup) { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("sendMessageBatchRequestBody={") - .append("batchId=").append(batchId).append(",") - .append("size=").append(size).append(",") - .append("producerGroup=").append(producerGroup).append(",") - .append("contents=").append(JsonUtils.serialize(contents)).append("}"); + .append("batchId=").append(batchId).append(",") + .append("size=").append(size).append(",") + .append("producerGroup=").append(producerGroup).append(",") + .append("contents=").append(JsonUtils.toJSONString(contents)).append("}"); return sb.toString(); } public static class BatchMessageEntity { + public String bizSeqNo; public String topic; public String msg; @@ -101,29 +102,30 @@ public static class BatchMessageEntity { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("batchMessageEntity={") - .append("bizSeqNo=").append(bizSeqNo).append(",") - .append("topic=").append(topic).append(",") - .append("msg=").append(msg).append(",") - .append("ttl=").append(ttl).append(",") - .append("tag=").append(tag).append("}"); + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("topic=").append(topic).append(",") + .append("msg=").append(msg).append(",") + .append("ttl=").append(ttl).append(",") + .append("tag=").append(tag).append("}"); return sb.toString(); } } public static SendMessageBatchRequestBody buildBody(final Map bodyParam) { String batchId = MapUtils.getString(bodyParam, - BATCHID); + BATCHID); String size = StringUtils.isBlank(MapUtils.getString(bodyParam, - SIZE)) ? "1" : MapUtils.getString(bodyParam, - SIZE); + SIZE)) ? "1" + : MapUtils.getString(bodyParam, + SIZE); String contents = MapUtils.getString(bodyParam, - CONTENTS, null); + CONTENTS, null); SendMessageBatchRequestBody body = new SendMessageBatchRequestBody(); body.setBatchId(batchId); if (StringUtils.isNotBlank(contents)) { body.setContents( - JsonUtils.deserialize(contents, new TypeReference>() { - })); + JsonUtils.parseTypeReferenceObject(contents, new TypeReference>() { + })); } body.setSize(size); body.setProducerGroup(MapUtils.getString(bodyParam, PRODUCERGROUP)); diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java index f504473673..90b2316e34 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchResponseBody.java @@ -17,24 +17,21 @@ package org.apache.eventmesh.common.protocol.http.body.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.commons.lang3.time.DateFormatUtils; - import java.util.HashMap; import java.util.Map; public class SendMessageBatchResponseBody extends Body { - //return code + // return code private Integer retCode; - //response message + // response message private String retMsg; - //response time + // response time private long resTime = System.currentTimeMillis(); public Integer getRetCode() { @@ -73,9 +70,9 @@ public static SendMessageBatchResponseBody buildBody(Integer retCode, String ret public String toString() { StringBuilder sb = new StringBuilder(); sb.append("sendMessageBatchResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(resTime).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java index 5abd7bc0cf..7997d00971 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2RequestBody.java @@ -95,15 +95,15 @@ public void setProducerGroup(String producerGroup) { public static SendMessageBatchV2RequestBody buildBody(final Map bodyParam) { String bizSeqno = MapUtils.getString(bodyParam, - BIZSEQNO); + BIZSEQNO); String topic = MapUtils.getString(bodyParam, - TOPIC); + TOPIC); String tag = MapUtils.getString(bodyParam, - TAG); + TAG); String msg = MapUtils.getString(bodyParam, - MSG); + MSG); String ttl = MapUtils.getString(bodyParam, - TTL); + TTL); SendMessageBatchV2RequestBody body = new SendMessageBatchV2RequestBody(); body.setBizSeqNo(bizSeqno); body.setMsg(msg); @@ -130,12 +130,12 @@ public Map toMap() { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("SendMessageBatchV2RequestBody={") - .append("bizSeqNo=").append(bizSeqNo).append(",") - .append("topic=").append(topic).append(",") - .append("tag=").append(tag).append(",") - .append("ttl=").append(ttl).append(",") - .append("producerGroup=").append(producerGroup).append(",") - .append("msg=").append(msg).append("}"); + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("topic=").append(topic).append(",") + .append("tag=").append(tag).append(",") + .append("ttl=").append(ttl).append(",") + .append("producerGroup=").append(producerGroup).append(",") + .append("msg=").append(msg).append("}"); return sb.toString(); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java index 26cc08202c..cd4507e9ed 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageBatchV2ResponseBody.java @@ -17,24 +17,21 @@ package org.apache.eventmesh.common.protocol.http.body.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.commons.lang3.time.DateFormatUtils; - import java.util.HashMap; import java.util.Map; public class SendMessageBatchV2ResponseBody extends Body { - //return code + // return code private Integer retCode; - //response message + // response message private String retMsg; - //response time + // response time private long resTime = System.currentTimeMillis(); public Integer getRetCode() { @@ -73,9 +70,9 @@ public static SendMessageBatchV2ResponseBody buildBody(Integer retCode, String r public String toString() { StringBuilder sb = new StringBuilder(); sb.append("sendMessageBatchV2ResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(resTime).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java index e14d230a56..dfeebc58f5 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageRequestBody.java @@ -51,7 +51,7 @@ public class SendMessageRequestBody extends Body { private String tag; - private HashMap extFields; + private Map extFields; private String producerGroup; @@ -87,11 +87,11 @@ public void setContent(String content) { this.content = content; } - public HashMap getExtFields() { + public Map getExtFields() { return extFields; } - public void setExtFields(HashMap extFields) { + public void setExtFields(Map extFields) { this.extFields = extFields; } @@ -130,8 +130,8 @@ public static SendMessageRequestBody buildBody(Map bodyParam) { String extFields = MapUtils.getString(bodyParam, EXTFIELDS); if (StringUtils.isNotBlank(extFields)) { body.setExtFields( - JsonUtils.deserialize(extFields, new TypeReference>() { - })); + JsonUtils.parseTypeReferenceObject(extFields, new TypeReference>() { + })); } body.setProducerGroup(MapUtils.getString(bodyParam, PRODUCERGROUP)); return body; @@ -155,14 +155,14 @@ public Map toMap() { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("sendMessageRequestBody={") - .append("topic=").append(topic).append(",") - .append("bizSeqNo=").append(bizSeqNo).append(",") - .append("uniqueId=").append(uniqueId).append(",") - .append("content=").append(content).append(",") - .append("ttl=").append(ttl).append(",") - .append("tag=").append(tag).append(",") - .append("producerGroup=").append(producerGroup).append(",") - .append("extFields=").append(extFields).append("}"); + .append("topic=").append(topic).append(",") + .append("bizSeqNo=").append(bizSeqNo).append(",") + .append("uniqueId=").append(uniqueId).append(",") + .append("content=").append(content).append(",") + .append("ttl=").append(ttl).append(",") + .append("tag=").append(tag).append(",") + .append("producerGroup=").append(producerGroup).append(",") + .append("extFields=").append(extFields).append("}"); return sb.toString(); } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java index e4e9eaa120..1e53bbf9fe 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/body/message/SendMessageResponseBody.java @@ -17,12 +17,9 @@ package org.apache.eventmesh.common.protocol.http.body.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.commons.lang3.time.DateFormatUtils; - import java.util.HashMap; import java.util.Map; @@ -73,9 +70,9 @@ public static SendMessageResponseBody buildBody(Integer retCode, String retMsg) public String toString() { StringBuilder sb = new StringBuilder(); sb.append("sendMessageResponseBody={") - .append("retCode=").append(retCode).append(",") - .append("retMsg=").append(retMsg).append(",") - .append("resTime=").append(DateFormatUtils.format(resTime, Constants.DATE_FORMAT)).append("}"); + .append("retCode=").append(retCode).append(",") + .append("retMsg=").append(retMsg).append(",") + .append("resTime=").append(resTime).append("}"); return sb.toString(); } @@ -91,6 +88,7 @@ public Map toMap() { @Data @Builder public static class ReplyMessage { + public String topic; public String body; public Map properties; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientRetCode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientRetCode.java index ceaf05cef2..2ba2f55854 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientRetCode.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientRetCode.java @@ -20,8 +20,8 @@ public enum ClientRetCode { /** - * The "RETRY" means:when the client finds the delivered message and it does not listen, tell EventMesh to send - * next, try again several times to achieve grayscale, reserve + * The "RETRY" means:when the client finds the delivered message and it does not listen, tell EventMesh to send next, try again several times to + * achieve grayscale, reserve */ REMOTE_OK(0, "REMOTE Process OK"), @@ -57,23 +57,16 @@ public static ClientRetCode get(Integer clientRetCode) { return ret; } - private Integer retCode; + private final Integer retCode; - private String errMsg; + private final String errMsg; public Integer getRetCode() { return retCode; } - public void setRetCode(Integer retCode) { - this.retCode = retCode; - } - public String getErrMsg() { return errMsg; } - public void setErrMsg(String errMsg) { - this.errMsg = errMsg; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientType.java index c935da6cc4..6cee40077b 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientType.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ClientType.java @@ -23,9 +23,9 @@ public enum ClientType { SUB(2, "Client for subscribing"); - private Integer type; + private final Integer type; - private String desc; + private final String desc; ClientType(Integer type, String desc) { this.type = type; @@ -57,15 +57,8 @@ public Integer getType() { return type; } - public void setType(Integer type) { - this.type = type; - } - public String getDesc() { return desc; } - public void setDesc(String desc) { - this.desc = desc; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/EventMeshRetCode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/EventMeshRetCode.java index 831eaaca6a..5f21778628 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/EventMeshRetCode.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/EventMeshRetCode.java @@ -20,32 +20,35 @@ public enum EventMeshRetCode { SUCCESS(0, "success"), - OVERLOAD(1, "eventMesh overload, try later, "), - EVENTMESH_REQUESTCODE_INVALID(2, "requestCode can't be null, or must be number, "), - EVENTMESH_SEND_SYNC_MSG_ERR(3, "eventMesh send rr msg err, "), - EVENTMESH_WAITING_RR_MSG_ERR(4, "eventMesh waiting rr msg err, "), - EVENTMESH_PROTOCOL_HEADER_ERR(6, "eventMesh protocol[header] err, "), - EVENTMESH_PROTOCOL_BODY_ERR(7, "eventMesh protocol[body] err, "), - EVENTMESH_PROTOCOL_BODY_SIZE_ERR(8, "event size exceeds the limit, "), - EVENTMESH_STOP(9, "eventMesh will stop or had stopped, "), - EVENTMESH_REJECT_BY_PROCESSOR_ERROR(10, "eventMesh reject by processor error, "), - EVENTMESH_BATCH_PRODUCER_STOPED_ERR(11, "eventMesh batch msg producer stopped, "), - EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR(12, "eventMesh batch msg speed over the limit, "), + OVERLOAD(1, "eventMesh overload, try later"), + EVENTMESH_REQUESTCODE_INVALID(2, "requestCode can't be null, or must be number"), + EVENTMESH_SEND_SYNC_MSG_ERR(3, "eventMesh send rr msg error"), + EVENTMESH_WAITING_RR_MSG_ERR(4, "eventMesh waiting rr msg error"), + EVENTMESH_PROTOCOL_HEADER_ERR(6, "eventMesh protocol[header] error"), + EVENTMESH_PROTOCOL_BODY_ERR(7, "eventMesh protocol[body] error"), + EVENTMESH_PROTOCOL_BODY_SIZE_ERR(8, "event size exceeds the limit"), + EVENTMESH_STOP(9, "eventMesh will stop or had stopped"), + EVENTMESH_REJECT_BY_PROCESSOR_ERROR(10, "eventMesh reject by processor error"), + EVENTMESH_BATCH_PRODUCER_STOPED_ERR(11, "eventMesh batch msg producer stopped"), + EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR(12, "eventMesh batch msg speed over the limit"), EVENTMESH_PACKAGE_MSG_ERR(13, "eventMesh package msg err, "), - EVENTMESH_GROUP_PRODUCER_STOPED_ERR(14, "eventMesh group producer stopped, "), - EVENTMESH_SEND_ASYNC_MSG_ERR(15, "eventMesh send async msg err, "), + EVENTMESH_GROUP_PRODUCER_STOPED_ERR(14, "eventMesh group producer stopped"), + EVENTMESH_SEND_ASYNC_MSG_ERR(15, "eventMesh send async msg error"), EVENTMESH_REPLY_MSG_ERR(16, "eventMesh reply msg err, "), - EVENTMESH_SEND_BATCHLOG_MSG_ERR(17, "eventMesh send batchlog msg err, "), - EVENTMESH_RUNTIME_ERR(18, "eventMesh runtime err, "), - EVENTMESH_SUBSCRIBE_ERR(19, "eventMesh subscribe err"), - EVENTMESH_UNSUBSCRIBE_ERR(20, "eventMesh unsubscribe err"), - EVENTMESH_HEARTBEAT_ERR(21, "eventMesh heartbeat err"), - EVENTMESH_ACL_ERR(22, "eventMesh acl err"), - EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR(23, "eventMesh http msg send over the limit, "); + EVENTMESH_SEND_BATCHLOG_MSG_ERR(17, "eventMesh send batch log msg error"), + EVENTMESH_RUNTIME_ERR(18, "eventMesh runtime error"), + EVENTMESH_SUBSCRIBE_ERR(19, "eventMesh subscribe error"), + EVENTMESH_UNSUBSCRIBE_ERR(20, "eventMesh unsubscribe error"), + EVENTMESH_HEARTBEAT_ERR(21, "eventMesh heartbeat error"), + EVENTMESH_ACL_ERR(22, "eventMesh acl error"), + EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR(23, "eventMesh http msg send over the limit"), - private Integer retCode; + EVENTMESH_FILTER_MSG_ERR(24, "eventMesh filter async msg error"), + EVENTMESH_OPERATE_FAIL(100, "operate fail"); - private String errMsg; + private final Integer retCode; + + private final String errMsg; EventMeshRetCode(Integer retCode, String errMsg) { this.retCode = retCode; @@ -56,15 +59,8 @@ public Integer getRetCode() { return retCode; } - public void setRetCode(Integer retCode) { - this.retCode = retCode; - } - public String getErrMsg() { return errMsg; } - public void setErrMsg(String errMsg) { - this.errMsg = errMsg; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolKey.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolKey.java index 19a836ae3a..71ad6eef09 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolKey.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolKey.java @@ -17,6 +17,9 @@ package org.apache.eventmesh.common.protocol.http.common; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; + public class ProtocolKey { public static final String REQUEST_CODE = "code"; @@ -29,27 +32,48 @@ public class ProtocolKey { public static final String PROTOCOL_VERSION = "protocolversion"; public static final String PROTOCOL_DESC = "protocoldesc"; + public static final String TOPIC = "topic"; public static final String CONTENT_TYPE = "contenttype"; - public static class ClientInstanceKey { - ////////////////////////////////////Protocol layer requester description/////////// - public static final String ENV = "env"; - public static final String IDC = "idc"; - public static final String SYS = "sys"; - public static final String PID = "pid"; - public static final String IP = "ip"; - public static final String USERNAME = "username"; - public static final String PASSWD = "passwd"; - public static final String BIZSEQNO = "bizseqno"; - public static final String UNIQUEID = "uniqueid"; - public static final String PRODUCERGROUP = "producergroup"; - public static final String CONSUMERGROUP = "consumergroup"; - } + public enum ClientInstanceKey { + + //////////////////////////////////// Protocol layer requester description/////////// + ENV("env", "env"), + IDC("idc", "idc"), + SYS("sys", "1234"), + PID("pid", ThreadUtils.getPID()), + IP("ip", IPUtils.getLocalAddress()), + USERNAME("username", "eventmesh"), + PASSWD("passwd", "pass"), + BIZSEQNO("bizseqno", "bizseqno"), + UNIQUEID("uniqueid", "uniqueid"), + PRODUCERGROUP("producergroup", "em-http-producer"), + CONSUMERGROUP("consumergroup", "em-http-consumer"), + + TOKEN("token", "token"); + + private final String key; + + private final Object value; + public String getKey() { + return key; + } + + public Object getValue() { + return value; + } + + ClientInstanceKey(String key, Object value) { + this.key = key; + this.value = value; + } + } public static class EventMeshInstanceKey { - ///////////////////////////////////////////////Protocol layer EventMesh description + + /////////////////////////////////////////////// Protocol layer EventMesh description public static final String EVENTMESHCLUSTER = "eventmeshcluster"; public static final String EVENTMESHIP = "eventmeship"; public static final String EVENTMESHENV = "eventmeshenv"; @@ -57,14 +81,14 @@ public static class EventMeshInstanceKey { } public static class CloudEventsKey { + public static final String ID = "id"; public static final String SOURCE = "source"; public static final String SUBJECT = "subject"; public static final String TYPE = "type"; } - - //return of CLIENT <-> EventMesh + // return of CLIENT <-> EventMesh public static final String RETCODE = "retCode"; public static final String RETMSG = "retMsg"; public static final String RESTIME = "resTime"; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolVersion.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolVersion.java index acfd655246..23b3decb38 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolVersion.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/ProtocolVersion.java @@ -22,7 +22,7 @@ public enum ProtocolVersion { V1("1.0"), V2("2.0"); - private String version; + private final String version; ProtocolVersion(String version) { this.version = version; @@ -42,10 +42,6 @@ public String getVersion() { return version; } - public void setVersion(String version) { - this.version = version; - } - public static boolean contains(String version) { boolean flag = false; for (ProtocolVersion itr : ProtocolVersion.values()) { diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestCode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestCode.java index 32e1b7fbcc..7c89f38faf 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestCode.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestCode.java @@ -19,6 +19,8 @@ public enum RequestCode { + UNKNOWN(0, "UNKNOWN"), + MSG_BATCH_SEND(102, "SEND BATCH MSG"), MSG_BATCH_SEND_V2(107, "SEND BATCH MSG V2"), @@ -47,9 +49,9 @@ public enum RequestCode { ADMIN_SHUTDOWN(601, "ADMIN SHUTDOWN"); - private Integer requestCode; + private final Integer requestCode; - private String desc; + private final String desc; RequestCode(Integer requestCode, String desc) { this.requestCode = requestCode; @@ -82,15 +84,8 @@ public Integer getRequestCode() { return requestCode; } - public void setRequestCode(Integer requestCode) { - this.requestCode = requestCode; - } - public String getDesc() { return desc; } - public void setDesc(String desc) { - this.desc = desc; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestURI.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestURI.java index ff295c30a6..d15def4646 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestURI.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/common/RequestURI.java @@ -29,14 +29,19 @@ public enum RequestURI { SUBSCRIBE_REMOTE("/eventmesh/subscribe/remote", "SUBSCRIBE REMOTE"), - UNSUBSCRIBE_LOCAL("/eventmesh/unsubscribe/local", "SUBSCRIBE LOCAL"), + UNSUBSCRIBE_LOCAL("/eventmesh/unsubscribe/local", "UNSUBSCRIBE LOCAL"), - UNSUBSCRIBE_REMOTE("/eventmesh/unsubscribe/remote", "SUBSCRIBE REMOTE"); + UNSUBSCRIBE_REMOTE("/eventmesh/unsubscribe/remote", "UNSUBSCRIBE REMOTE"), + CREATE_TOPIC("/eventmesh/topic/create", "CREATE TOPIC"), - private String requestURI; + DELETE_TOPIC("/eventmesh/topic/delete", "DELETE TOPIC"), - private String desc; + SUBSCRIPTION_QUERY("/eventmesh/subscrition/query", "SUBSCRIPTION QUERY"); + + private final String requestURI; + + private final String desc; RequestURI(String requestURI, String desc) { this.requestURI = requestURI; @@ -69,15 +74,8 @@ public String getRequestURI() { return requestURI; } - public void setRequestURI(String requestURI) { - this.requestURI = requestURI; - } - public String getDesc() { return desc; } - public void setDesc(String desc) { - this.desc = desc; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeader.java index f34f915418..c72642589f 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeader.java @@ -25,6 +25,7 @@ import java.util.Map; public class BaseRequestHeader extends Header { + private String code; public String getCode() { @@ -51,8 +52,7 @@ public Map toMap() { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("baseRequestHeader={code=") - .append(code).append("}"); + sb.append("baseRequestHeader={code=").append(code).append("}"); return sb.toString(); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeader.java index 2a2e2c7665..f25e0a3c80 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeader.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.common.protocol.http.header; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import java.util.HashMap; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/Header.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/Header.java index 9a432202a1..453b4bd35d 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/Header.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/Header.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.common.protocol.http.header; - import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.common.protocol.http.header.client.HeartbeatRequestHeader; import org.apache.eventmesh.common.protocol.http.header.client.RegRequestHeader; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java index 85fceb6945..8dd8fbf055 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeader.java @@ -17,178 +17,64 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class HeartbeatRequestHeader extends Header { - //request code + // request code private String code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - private String producerGroup; + // private String producerGroup; - //USERNAME of the requester + // USERNAME of the requester private String username = "username"; - //PASSWD of the requester - private String passwd = "user@123"; - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } + // PASSWD of the requester + private String passwd = "default"; @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("heartbeatRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } public static HeartbeatRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); HeartbeatRequestHeader header = new HeartbeatRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; + return (HeartbeatRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java index c1c35c47d1..b4158a6968 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeader.java @@ -17,13 +17,19 @@ package org.apache.eventmesh.common.protocol.http.header.client; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class HeartbeatResponseHeader extends Header { private int code; @@ -36,49 +42,9 @@ public class HeartbeatResponseHeader extends Header { private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static HeartbeatResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, - String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, + String eventMeshIDC) { HeartbeatResponseHeader heartbeatResponseHeader = new HeartbeatResponseHeader(); heartbeatResponseHeader.setCode(requestCode); heartbeatResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -88,26 +54,11 @@ public static HeartbeatResponseHeader buildHeader(Integer requestCode, String ev return heartbeatResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("heartbeatResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeader.java index 3d88dbf312..a082ce8c95 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeader.java @@ -17,17 +17,20 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class RegRequestHeader extends Header { private String code; @@ -51,132 +54,15 @@ public class RegRequestHeader extends Header { private String passwd; public static RegRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); RegRequestHeader header = new RegRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; + return (RegRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("regRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeader.java index b928b79fd0..06f97099b3 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeader.java @@ -17,72 +17,38 @@ package org.apache.eventmesh.common.protocol.http.header.client; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class RegResponseHeader extends Header { - //response code, as same as the request code + // response code, as same as the request code private int code; - //The cluster name of the EventMesh that processes the request + // The cluster name of the EventMesh that processes the request private String eventMeshCluster; - //IP of the EventMesh that processes the request + // IP of the EventMesh that processes the request private String eventMeshIp; - //Environment number of the EventMesh that processes the request + // Environment number of the EventMesh that processes the request private String eventMeshEnv; - //IDC of the EventMesh that processes the request + // IDC of the EventMesh that processes the request private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static RegResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, String eventMeshIDC) { RegResponseHeader regResponseHeader = new RegResponseHeader(); regResponseHeader.setCode(requestCode); regResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -92,27 +58,12 @@ public static RegResponseHeader buildHeader(Integer requestCode, String eventMes return regResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("regResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java index adef902d93..82dc2ce167 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeader.java @@ -17,17 +17,20 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SubscribeRequestHeader extends Header { private String code; @@ -51,132 +54,16 @@ public class SubscribeRequestHeader extends Header { private String passwd; public static SubscribeRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); SubscribeRequestHeader header = new SubscribeRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; + return (SubscribeRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("subscribeRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java index d16fb4e6aa..f50d37743e 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeader.java @@ -19,10 +19,17 @@ import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SubscribeResponseHeader extends Header { private int code; @@ -35,49 +42,9 @@ public class SubscribeResponseHeader extends Header { private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static SubscribeResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, - String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, + String eventMeshIDC) { SubscribeResponseHeader subscribeResponseHeader = new SubscribeResponseHeader(); subscribeResponseHeader.setCode(requestCode); subscribeResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -87,27 +54,12 @@ public static SubscribeResponseHeader buildHeader(Integer requestCode, String ev return subscribeResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("subscribeResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java index 639d696476..841e79b1af 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeader.java @@ -17,177 +17,63 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class UnRegRequestHeader extends Header { - //request code + // request code private String code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - //USERNAME of the requester + // USERNAME of the requester private String username = "username"; - //PASSWD of the requester - private String passwd = "user@123"; + // PASSWD of the requester + private String passwd = "default"; public static UnRegRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); UnRegRequestHeader header = new UnRegRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; + return (UnRegRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("unRegRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java index 550e796be7..25bfc78e17 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeader.java @@ -17,13 +17,19 @@ package org.apache.eventmesh.common.protocol.http.header.client; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class UnRegResponseHeader extends Header { private int code; @@ -36,48 +42,8 @@ public class UnRegResponseHeader extends Header { private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static UnRegResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, String eventMeshIDC) { UnRegResponseHeader regResponseHeader = new UnRegResponseHeader(); regResponseHeader.setCode(requestCode); regResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -87,27 +53,12 @@ public static UnRegResponseHeader buildHeader(Integer requestCode, String eventM return regResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("nnRegResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java index 452e278846..b0390ec625 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeader.java @@ -17,17 +17,20 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class UnSubscribeRequestHeader extends Header { private String code; @@ -51,132 +54,16 @@ public class UnSubscribeRequestHeader extends Header { private String passwd; public static UnSubscribeRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); UnSubscribeRequestHeader header = new UnSubscribeRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; + return (UnSubscribeRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("subscribeRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java index bb90b4bf75..276cee6390 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeader.java @@ -19,10 +19,17 @@ import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class UnSubscribeResponseHeader extends Header { private int code; @@ -35,48 +42,8 @@ public class UnSubscribeResponseHeader extends Header { private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static UnSubscribeResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, String eventMeshIDC) { UnSubscribeResponseHeader unSubscribeResponseHeader = new UnSubscribeResponseHeader(); unSubscribeResponseHeader.setCode(requestCode); unSubscribeResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -86,26 +53,11 @@ public static UnSubscribeResponseHeader buildHeader(Integer requestCode, String return unSubscribeResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("unSubscribeResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java index 726c08a720..e22c3bf050 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeader.java @@ -17,26 +17,29 @@ package org.apache.eventmesh.common.protocol.http.header.message; - -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class PushMessageRequestHeader extends Header { - //request code + // request code private int code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; private String eventMeshCluster; @@ -47,99 +50,19 @@ public class PushMessageRequestHeader extends Header { private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - public static PushMessageRequestHeader buildHeader(final Map headerParam) { - PushMessageRequestHeader pushMessageRequestHeader = new PushMessageRequestHeader(); - pushMessageRequestHeader.setCode(MapUtils.getIntValue(headerParam, ProtocolKey.REQUEST_CODE)); - pushMessageRequestHeader.setLanguage(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA)); - pushMessageRequestHeader.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - pushMessageRequestHeader.setEventMeshCluster(MapUtils.getString(headerParam, ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER)); - pushMessageRequestHeader.setEventMeshIp(MapUtils.getString(headerParam, ProtocolKey.EventMeshInstanceKey.EVENTMESHIP)); - pushMessageRequestHeader.setEventMeshEnv(MapUtils.getString(headerParam, ProtocolKey.EventMeshInstanceKey.EVENTMESHENV)); - pushMessageRequestHeader.setEventMeshIdc(MapUtils.getString(headerParam, ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC)); - return pushMessageRequestHeader; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + PushMessageRequestHeader header = new PushMessageRequestHeader(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return (PushMessageRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam, eventMeshInstanceKey); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("pushMessageRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version.getVersion()).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java index c5b727111d..6ba742cd18 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeader.java @@ -17,129 +17,55 @@ package org.apache.eventmesh.common.protocol.http.header.message; - import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class PushMessageResponseHeader extends Header { - //response code + // response code private int code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - //USERNAME of the requester + // USERNAME of the requester private String username; - //PASSWD of the requester + // PASSWD of the requester private String passwd; - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - public static PushMessageResponseHeader buildHeader(int requestCode, String clientEnv, String clientIDC, - String clientSysId, String clientPid, String clientIP) { + String clientSysId, String clientPid, String clientIP) { PushMessageResponseHeader pushMessageResponseHeader = new PushMessageResponseHeader(); pushMessageResponseHeader.setCode(requestCode); pushMessageResponseHeader.setVersion(ProtocolVersion.V1); @@ -152,36 +78,10 @@ public static PushMessageResponseHeader buildHeader(int requestCode, String clie return pushMessageResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("pushMessageResponseHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java index ad4a8ec24e..94300c67a1 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeader.java @@ -17,213 +17,71 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class ReplyMessageRequestHeader extends Header { - //request code + // request code private String code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //protocol type, cloudevents or eventmeshMessage + // protocol type, cloudevents or eventmeshMessage private String protocolType; - //protocol version, cloudevents:1.0 or 0.3 + // protocol version, cloudevents:1.0 or 0.3 private String protocolVersion; - //protocol desc + // protocol desc private String protocolDesc; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - //USERNAME of the requester + // USERNAME of the requester private String username; - //PASSWD of the requester + // PASSWD of the requester private String passwd; - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getProtocolType() { - return protocolType; - } - - public void setProtocolType(String protocolType) { - this.protocolType = protocolType; - } - - public String getProtocolVersion() { - return protocolVersion; - } - - public void setProtocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - } - - public String getProtocolDesc() { - return protocolDesc; - } - - public void setProtocolDesc(String protocolDesc) { - this.protocolDesc = protocolDesc; - } - public static ReplyMessageRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); ReplyMessageRequestHeader header = new ReplyMessageRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - header.setProtocolType(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_TYPE)); - header.setProtocolVersion(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_VERSION)); - header.setProtocolDesc(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_DESC)); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; + return (ReplyMessageRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("replyMessageRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + ProtocolKey protocolKey = new ProtocolKey(); + return new HttpConvertsUtils().httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java index 20d6f107e9..05a20018a1 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeader.java @@ -17,73 +17,39 @@ package org.apache.eventmesh.common.protocol.http.header.message; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class ReplyMessageResponseHeader extends Header { - //response code, as same as the request code + // response code, as same as the request code private int code; - //The cluster name of the EventMesh that processes the request + // The cluster name of the EventMesh that processes the request private String eventMeshCluster; - //IP of the EventMesh that processes the request + // IP of the EventMesh that processes the request private String eventMeshIp; - //Environment number of the EventMesh that processes the request + // Environment number of the EventMesh that processes the request private String eventMeshEnv; - //IDC of the EventMesh that processes the request + // IDC of the EventMesh that processes the request private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static ReplyMessageResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, - String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, + String eventMeshIDC) { ReplyMessageResponseHeader replyMessageResponseHeader = new ReplyMessageResponseHeader(); replyMessageResponseHeader.setCode(requestCode); replyMessageResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -93,26 +59,11 @@ public static ReplyMessageResponseHeader buildHeader(Integer requestCode, String return replyMessageResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("replyMessageResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java index 9ee63f71b2..297cc70d66 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchRequestHeader.java @@ -17,214 +17,72 @@ package org.apache.eventmesh.common.protocol.http.header.message; - -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SendMessageBatchRequestHeader extends Header { - //request code + // request code private String code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //protocol type, cloudevents or eventmeshMessage + // protocol type, cloudevents or eventmeshMessage private String protocolType; - //protocol version, cloudevents:1.0 or 0.3 + // protocol version, cloudevents:1.0 or 0.3 private String protocolVersion; - //protocol desc + // protocol desc private String protocolDesc; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - //USERNAME of the requester + // USERNAME of the requester private String username; - //PASSWD of the requester + // PASSWD of the requester private String passwd; - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getProtocolType() { - return protocolType; - } - - public void setProtocolType(String protocolType) { - this.protocolType = protocolType; - } - - public String getProtocolVersion() { - return protocolVersion; - } - - public void setProtocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - } - - public String getProtocolDesc() { - return protocolDesc; - } - - public void setProtocolDesc(String protocolDesc) { - this.protocolDesc = protocolDesc; - } - public static SendMessageBatchRequestHeader buildHeader(final Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); SendMessageBatchRequestHeader header = new SendMessageBatchRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - header.setProtocolType(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_TYPE)); - header.setProtocolVersion(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_VERSION)); - header.setProtocolDesc(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_DESC)); - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; + return (SendMessageBatchRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageBatchRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java index 4ddfde68b8..7d9f8c6cd2 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchResponseHeader.java @@ -17,73 +17,39 @@ package org.apache.eventmesh.common.protocol.http.header.message; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SendMessageBatchResponseHeader extends Header { - //response code, as same as the request code + // response code, as same as the request code private int code; - //The cluster name of the EventMesh that processes the request + // The cluster name of the EventMesh that processes the request private String eventMeshCluster; - //IP of the EventMesh that processes the request + // IP of the EventMesh that processes the request private String eventMeshIp; - //Environment number of the EventMesh that processes the request + // Environment number of the EventMesh that processes the request private String eventMeshEnv; - //IDC of the EventMesh that processes the request + // IDC of the EventMesh that processes the request private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static SendMessageBatchResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, - String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, + String eventMeshIDC) { SendMessageBatchResponseHeader sendMessageBatchResponseHeader = new SendMessageBatchResponseHeader(); sendMessageBatchResponseHeader.setCode(requestCode); sendMessageBatchResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -93,26 +59,11 @@ public static SendMessageBatchResponseHeader buildHeader(Integer requestCode, St return sendMessageBatchResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageBatchResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java index 369d2c5460..25c42ac2d3 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2RequestHeader.java @@ -17,213 +17,71 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SendMessageBatchV2RequestHeader extends Header { - //request code + // request code private String code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //protocol type, cloudevents or eventmeshMessage + // protocol type, cloudevents or eventmeshMessage private String protocolType; - //protocol version, cloudevents:1.0 or 0.3 + // protocol version, cloudevents:1.0 or 0.3 private String protocolVersion; - //protocol desc + // protocol desc private String protocolDesc; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - //USERNAME of the requester + // USERNAME of the requester private String username; - //PASSWD of the requester + // PASSWD of the requester private String passwd; - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getProtocolType() { - return protocolType; - } - - public void setProtocolType(String protocolType) { - this.protocolType = protocolType; - } - - public String getProtocolVersion() { - return protocolVersion; - } - - public void setProtocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - } - - public String getProtocolDesc() { - return protocolDesc; - } - - public void setProtocolDesc(String protocolDesc) { - this.protocolDesc = protocolDesc; - } - public static SendMessageBatchV2RequestHeader buildHeader(final Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); SendMessageBatchV2RequestHeader header = new SendMessageBatchV2RequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - header.setProtocolType(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_TYPE)); - header.setProtocolVersion(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_VERSION)); - header.setProtocolDesc(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_DESC)); - - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; + return (SendMessageBatchV2RequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageBatchV2RequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java index a188c9713c..1afe670be0 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageBatchV2ResponseHeader.java @@ -19,99 +19,51 @@ import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; +import org.apache.eventmesh.common.utils.IPUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SendMessageBatchV2ResponseHeader extends Header { - //response code, as same as the request code + // response code, as same as the request code private int code; - //The cluster name of the EventMesh that processes the request + // The cluster name of the EventMesh that processes the request private String eventMeshCluster; - //IP of the EventMesh that processes the request + // IP of the EventMesh that processes the request private String eventMeshIp; - //Environment number of the EventMesh that processes the request + // Environment number of the EventMesh that processes the request private String eventMeshEnv; - //IDC of the EventMesh that processes the request + // IDC of the EventMesh that processes the request private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static SendMessageBatchV2ResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, - String eventMeshIDC) { + String eventMeshEnv, String eventMeshIDC) { SendMessageBatchV2ResponseHeader header = new SendMessageBatchV2ResponseHeader(); header.setCode(requestCode); header.setEventMeshCluster(eventMeshCluster); header.setEventMeshEnv(eventMeshEnv); header.setEventMeshIdc(eventMeshIDC); - header.setEventMeshIp(eventMeshIp); + header.setEventMeshIp(IPUtils.getLocalAddress()); return header; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageBatchV2ResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java index 19774280a4..c2aa5709a8 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageRequestHeader.java @@ -17,214 +17,72 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SendMessageRequestHeader extends Header { - //request code + // request code private String code; - //requester language description + // requester language description private String language; - //protocol version adopted by requester, default:1.0 + // protocol version adopted by requester, default:1.0 private ProtocolVersion version; - //protocol type, cloudevents or eventmeshMessage + // protocol type, cloudevents or eventmeshMessage private String protocolType; - //protocol version, cloudevents:1.0 or 0.3 + // protocol version, cloudevents:1.0 or 0.3 private String protocolVersion; - //protocol desc + // protocol desc private String protocolDesc; - //the environment number of the requester + // the environment number of the requester private String env; - //the IDC of the requester + // the IDC of the requester private String idc; - //subsystem of the requester + // subsystem of the requester private String sys; - //PID of the requester + // PID of the requester private String pid; - //IP of the requester + // IP of the requester private String ip; - //USERNAME of the requester + // USERNAME of the requester private String username; - //PASSWD of the requester + // PASSWD of the requester private String passwd; - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public ProtocolVersion getVersion() { - return version; - } - - public void setVersion(ProtocolVersion version) { - this.version = version; - } - - public String getEnv() { - return env; - } - - public void setEnv(String env) { - this.env = env; - } - - public String getIdc() { - return idc; - } - - public void setIdc(String idc) { - this.idc = idc; - } - - public String getSys() { - return sys; - } - - public void setSys(String sys) { - this.sys = sys; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getProtocolType() { - return protocolType; - } - - public void setProtocolType(String protocolType) { - this.protocolType = protocolType; - } - - public String getProtocolVersion() { - return protocolVersion; - } - - public void setProtocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - } - - public String getProtocolDesc() { - return protocolDesc; - } - - public void setProtocolDesc(String protocolDesc) { - this.protocolDesc = protocolDesc; - } - public static SendMessageRequestHeader buildHeader(Map headerParam) { + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); SendMessageRequestHeader header = new SendMessageRequestHeader(); - header.setCode(MapUtils.getString(headerParam, ProtocolKey.REQUEST_CODE)); - header.setVersion(ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION))); - header.setProtocolType(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_TYPE)); - header.setProtocolVersion(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_VERSION)); - header.setProtocolDesc(MapUtils.getString(headerParam, ProtocolKey.PROTOCOL_DESC)); - - String lan = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) - ? Constants.LANGUAGE_JAVA : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); - header.setLanguage(lan); - header.setEnv(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.ENV)); - header.setIdc(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IDC)); - header.setSys(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.SYS)); - header.setPid(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PID)); - header.setIp(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.IP)); - header.setUsername(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.USERNAME)); - header.setPasswd(MapUtils.getString(headerParam, ProtocolKey.ClientInstanceKey.PASSWD)); - return header; + return (SendMessageRequestHeader) httpConvertsUtils.httpHeaderConverts(header, headerParam); } @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.LANGUAGE, language); - map.put(ProtocolKey.VERSION, version); - map.put(ProtocolKey.ClientInstanceKey.ENV, env); - map.put(ProtocolKey.ClientInstanceKey.IDC, idc); - map.put(ProtocolKey.ClientInstanceKey.SYS, sys); - map.put(ProtocolKey.ClientInstanceKey.PID, pid); - map.put(ProtocolKey.ClientInstanceKey.IP, ip); - map.put(ProtocolKey.ClientInstanceKey.USERNAME, username); - map.put(ProtocolKey.ClientInstanceKey.PASSWD, passwd); - return map; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageRequestHeader={") - .append("code=").append(code).append(",") - .append("language=").append(language).append(",") - .append("version=").append(version).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("sys=").append(sys).append(",") - .append("pid=").append(pid).append(",") - .append("ip=").append(ip).append(",") - .append("username=").append(username).append(",") - .append("passwd=").append(passwd).append("}"); - return sb.toString(); + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java index a9db7ff587..70d391f614 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/http/header/message/SendMessageResponseHeader.java @@ -17,73 +17,39 @@ package org.apache.eventmesh.common.protocol.http.header.message; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; -import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString public class SendMessageResponseHeader extends Header { - //response code, as same as the request code + // response code, as same as the request code private int code; - //The cluster name of the EventMesh that processes the request + // The cluster name of the EventMesh that processes the request private String eventMeshCluster; - //IP of the EventMesh that processes the request + // IP of the EventMesh that processes the request private String eventMeshIp; - //Environment number of the EventMesh that processes the request + // Environment number of the EventMesh that processes the request private String eventMeshEnv; - //IDC of the EventMesh that processes the request + // IDC of the EventMesh that processes the request private String eventMeshIdc; - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getEventMeshCluster() { - return eventMeshCluster; - } - - public void setEventMeshCluster(String eventMeshCluster) { - this.eventMeshCluster = eventMeshCluster; - } - - public String getEventMeshIp() { - return eventMeshIp; - } - - public void setEventMeshIp(String eventMeshIp) { - this.eventMeshIp = eventMeshIp; - } - - public String getEventMeshEnv() { - return eventMeshEnv; - } - - public void setEventMeshEnv(String eventMeshEnv) { - this.eventMeshEnv = eventMeshEnv; - } - - public String getEventMeshIdc() { - return eventMeshIdc; - } - - public void setEventMeshIdc(String eventMeshIdc) { - this.eventMeshIdc = eventMeshIdc; - } - public static SendMessageResponseHeader buildHeader(Integer requestCode, String eventMeshCluster, - String eventMeshIp, String eventMeshEnv, - String eventMeshIDC) { + String eventMeshIp, String eventMeshEnv, + String eventMeshIDC) { SendMessageResponseHeader sendMessageResponseHeader = new SendMessageResponseHeader(); sendMessageResponseHeader.setCode(requestCode); sendMessageResponseHeader.setEventMeshCluster(eventMeshCluster); @@ -93,26 +59,11 @@ public static SendMessageResponseHeader buildHeader(Integer requestCode, String return sendMessageResponseHeader; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageResponseHeader={") - .append("code=").append(code).append(",") - .append("eventMeshEnv=").append(eventMeshEnv).append(",") - .append("eventMeshIdc=").append(eventMeshIdc).append(",") - .append("eventMeshCluster=").append(eventMeshCluster).append(",") - .append("eventMeshIp=").append(eventMeshIp).append("}"); - return sb.toString(); - } - @Override public Map toMap() { - Map map = new HashMap(); - map.put(ProtocolKey.REQUEST_CODE, code); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshCluster); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshIp); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshEnv); - map.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshIdc); - return map; + HttpConvertsUtils httpConvertsUtils = new HttpConvertsUtils(); + ProtocolKey protocolKey = new ProtocolKey(); + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey = new ProtocolKey.EventMeshInstanceKey(); + return httpConvertsUtils.httpMapConverts(this, protocolKey, eventMeshInstanceKey); } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Command.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Command.java index 6381f29413..7ab2744223 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Command.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Command.java @@ -19,70 +19,70 @@ public enum Command { - //heartbeat - HEARTBEAT_REQUEST(0), //client send heartbeat packet to server - HEARTBEAT_RESPONSE(1), //server response heartbeat packet of client - - //handshake - HELLO_REQUEST(2), //client send handshake request to server - HELLO_RESPONSE(3), //server response handshake request of client - - //disconnection - CLIENT_GOODBYE_REQUEST(4), //Notify server when client actively disconnects - CLIENT_GOODBYE_RESPONSE(5), //Server replies to client's active disconnection notification - SERVER_GOODBYE_REQUEST(6), //Notify client when server actively disconnects - SERVER_GOODBYE_RESPONSE(7), //Client replies to server's active disconnection notification - - //subscription management - SUBSCRIBE_REQUEST(8), //Subscription request sent by client to server - SUBSCRIBE_RESPONSE(9), //Server replies to client's subscription request - UNSUBSCRIBE_REQUEST(10), //Unsubscribe request from client to server - UNSUBSCRIBE_RESPONSE(11), //Server replies to client's unsubscribe request - - //monitor - LISTEN_REQUEST(12), //Request from client to server to start topic listening - LISTEN_RESPONSE(13), //The server replies to the client's listening request - - //RR - REQUEST_TO_SERVER(14), //The client sends the RR request to the server - REQUEST_TO_CLIENT(15), //The server pushes the RR request to the client - REQUEST_TO_CLIENT_ACK(16), //After receiving RR request, the client sends ACK to the server - RESPONSE_TO_SERVER(17), //The client sends the RR packet back to the server - RESPONSE_TO_CLIENT(18), //The server pushes the RR packet back to the client - RESPONSE_TO_CLIENT_ACK(19), //After receiving the return packet, the client sends ACK to the server - - //Asynchronous events - ASYNC_MESSAGE_TO_SERVER(20), //The client sends asynchronous events to the server - ASYNC_MESSAGE_TO_SERVER_ACK(21), //After receiving the asynchronous event, the server sends ack to the client - ASYNC_MESSAGE_TO_CLIENT(22), //The server pushes asynchronous events to the client - ASYNC_MESSAGE_TO_CLIENT_ACK(23), //After the client receives the asynchronous event, the ACK is sent to the server - - //radio broadcast - BROADCAST_MESSAGE_TO_SERVER(24), //The client sends the broadcast message to the server - BROADCAST_MESSAGE_TO_SERVER_ACK(25), //After receiving the broadcast message, the server sends ACK to the client - BROADCAST_MESSAGE_TO_CLIENT(26), //The server pushes the broadcast message to the client - BROADCAST_MESSAGE_TO_CLIENT_ACK(27), //After the client receives the broadcast message, the ACK is sent to the server - - //Log reporting - SYS_LOG_TO_LOGSERVER(28), //Business log reporting - - //RMB tracking log reporting - TRACE_LOG_TO_LOGSERVER(29), //RMB tracking log reporting - - //Redirecting instruction - REDIRECT_TO_CLIENT(30), //The server pushes the redirection instruction to the client - - //service register - REGISTER_REQUEST(31), //Client sends registration request to server - REGISTER_RESPONSE(32), //The server sends the registration result to the client - - //service unregister - UNREGISTER_REQUEST(33), //The client sends a de registration request to the server - UNREGISTER_RESPONSE(34), //The server will register the result to the client - - //The client asks which EventMesh to recommend - RECOMMEND_REQUEST(35), //Client sends recommendation request to server - RECOMMEND_RESPONSE(36); //The server will recommend the results to the client + // heartbeat + HEARTBEAT_REQUEST(0), // client send heartbeat packet to server + HEARTBEAT_RESPONSE(1), // server response heartbeat packet of client + + // handshake + HELLO_REQUEST(2), // client send handshake request to server + HELLO_RESPONSE(3), // server response handshake request of client + + // disconnection + CLIENT_GOODBYE_REQUEST(4), // Notify server when client actively disconnects + CLIENT_GOODBYE_RESPONSE(5), // Server replies to client's active disconnection notification + SERVER_GOODBYE_REQUEST(6), // Notify client when server actively disconnects + SERVER_GOODBYE_RESPONSE(7), // Client replies to server's active disconnection notification + + // subscription management + SUBSCRIBE_REQUEST(8), // Subscription request sent by client to server + SUBSCRIBE_RESPONSE(9), // Server replies to client's subscription request + UNSUBSCRIBE_REQUEST(10), // Unsubscribe request from client to server + UNSUBSCRIBE_RESPONSE(11), // Server replies to client's unsubscribe request + + // monitor + LISTEN_REQUEST(12), // Request from client to server to start topic listening + LISTEN_RESPONSE(13), // The server replies to the client's listening request + + // RR + REQUEST_TO_SERVER(14), // The client sends the RR request to the server + REQUEST_TO_CLIENT(15), // The server pushes the RR request to the client + REQUEST_TO_CLIENT_ACK(16), // After receiving RR request, the client sends ACK to the server + RESPONSE_TO_SERVER(17), // The client sends the RR packet back to the server + RESPONSE_TO_CLIENT(18), // The server pushes the RR packet back to the client + RESPONSE_TO_CLIENT_ACK(19), // After receiving the return packet, the client sends ACK to the server + + // Asynchronous events + ASYNC_MESSAGE_TO_SERVER(20), // The client sends asynchronous events to the server + ASYNC_MESSAGE_TO_SERVER_ACK(21), // After receiving the asynchronous event, the server sends ack to the client + ASYNC_MESSAGE_TO_CLIENT(22), // The server pushes asynchronous events to the client + ASYNC_MESSAGE_TO_CLIENT_ACK(23), // After the client receives the asynchronous event, the ACK is sent to the server + + // radio broadcast + BROADCAST_MESSAGE_TO_SERVER(24), // The client sends the broadcast message to the server + BROADCAST_MESSAGE_TO_SERVER_ACK(25), // After receiving the broadcast message, the server sends ACK to the client + BROADCAST_MESSAGE_TO_CLIENT(26), // The server pushes the broadcast message to the client + BROADCAST_MESSAGE_TO_CLIENT_ACK(27), // After the client receives the broadcast message, the ACK is sent to the server + + // Log reporting + SYS_LOG_TO_LOGSERVER(28), // Business log reporting + + // RMB tracking log reporting + TRACE_LOG_TO_LOGSERVER(29), // RMB tracking log reporting + + // Redirecting instruction + REDIRECT_TO_CLIENT(30), // The server pushes the redirection instruction to the client + + // service register + REGISTER_REQUEST(31), // Client sends registration request to server + REGISTER_RESPONSE(32), // The server sends the registration result to the client + + // service unregister + UNREGISTER_REQUEST(33), // The client sends a de registration request to the server + UNREGISTER_RESPONSE(34), // The server will register the result to the client + + // The client asks which EventMesh to recommend + RECOMMEND_REQUEST(35), // Client sends recommendation request to server + RECOMMEND_RESPONSE(36); // The server will recommend the results to the client private final byte value; @@ -90,7 +90,7 @@ public enum Command { this.value = (byte) value; } - public byte value() { + public byte getValue() { return this.value; } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/EventMeshMessage.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/EventMeshMessage.java index 945824074c..2a2c1a965a 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/EventMeshMessage.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/EventMeshMessage.java @@ -31,5 +31,6 @@ public class EventMeshMessage { private String topic; private Map properties = new ConcurrentHashMap<>(); + private Map headers = new ConcurrentHashMap<>(); private String body; } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Header.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Header.java index 9c9a2890bc..86699845c2 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Header.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Header.java @@ -48,9 +48,8 @@ public Header(int code, String desc, String seq, Map properties) this.properties = properties; } - public void putProperty(final String name, final Object value) { - if (null == this.properties) { + if (this.properties == null) { this.properties = new HashMap<>(); } @@ -58,7 +57,7 @@ public void putProperty(final String name, final Object value) { } public Object getProperty(final String name) { - if (null == this.properties) { + if (this.properties == null) { return null; } return this.properties.get(name); @@ -66,7 +65,7 @@ public Object getProperty(final String name) { public String getStringProperty(final String name) { Object property = getProperty(name); - if (null == property) { + if (property == null) { return null; } return property.toString(); diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/OPStatus.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/OPStatus.java index 4ecfd04dbc..b92803b3f5 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/OPStatus.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/OPStatus.java @@ -29,23 +29,16 @@ public enum OPStatus { this.desc = desc; } - private Integer code; + private final Integer code; - private String desc; + private final String desc; public Integer getCode() { return code; } - public void setCode(Integer code) { - this.code = code; - } - public String getDesc() { return desc; } - public void setDesc(String desc) { - this.desc = desc; - } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Package.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Package.java index 43c5d1a100..81294cc2a2 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Package.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Package.java @@ -17,24 +17,41 @@ package org.apache.eventmesh.common.protocol.tcp; - import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - - -@Data -@NoArgsConstructor -@AllArgsConstructor public class Package implements ProtocolTransportObject { - private Header header; + private static final long serialVersionUID = 3353018029137072737L; + private transient Header header; private Object body; + public Header getHeader() { + return header; + } + + public Object getBody() { + return body; + } + + public void setHeader(Header header) { + this.header = header; + } + + public void setBody(Object body) { + this.body = body; + } + + public Package() { + + } + public Package(Header header) { this.header = header; } + public Package(Header header, Object body) { + this.header = header; + this.body = body; + } + } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/RedirectInfo.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/RedirectInfo.java index 8b552bfd20..7b8d63f57c 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/RedirectInfo.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/RedirectInfo.java @@ -18,6 +18,7 @@ package org.apache.eventmesh.common.protocol.tcp; public class RedirectInfo { + private String ip; private int port; @@ -48,9 +49,9 @@ public void setPort(int port) { @Override public String toString() { return "RedirectInfo{" - + "ip='" + ip - + '\'' - + ", port=" + port - + '}'; + + "ip='" + ip + + '\'' + + ", port=" + port + + '}'; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Subscription.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Subscription.java index ad9f269417..f1a6dbcdd1 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Subscription.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/Subscription.java @@ -19,12 +19,12 @@ import org.apache.eventmesh.common.protocol.SubscriptionItem; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; public class Subscription { - private List topicList = new LinkedList<>(); + private List topicList = new ArrayList<>(); public Subscription() { } @@ -44,7 +44,7 @@ public void setTopicList(List topicList) { @Override public String toString() { return "Subscription{" - + "topicList=" + topicList - + '}'; + + "topicList=" + topicList + + '}'; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/UserAgent.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/UserAgent.java index 9e1d98b9b3..4d17a0735a 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/UserAgent.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/UserAgent.java @@ -35,6 +35,7 @@ public class UserAgent { private String version; private String username; private String password; + private String token; private String idc; private String group; private String purpose; @@ -45,7 +46,7 @@ public UserAgent() { } public UserAgent(String env, String subsystem, String path, int pid, String host, int port, String version, - String username, String password, String idc, String group, String purpose, int unack) { + String username, String password, String token, String idc, String group, String purpose, int unack) { this.env = env; this.subsystem = subsystem; this.path = path; @@ -55,6 +56,7 @@ public UserAgent(String env, String subsystem, String path, int pid, String host this.version = version; this.username = username; this.password = password; + this.token = token; this.idc = idc; this.group = group; this.purpose = purpose; @@ -64,9 +66,9 @@ public UserAgent(String env, String subsystem, String path, int pid, String host @Override public String toString() { return String.format( - "UserAgent{env='%s', subsystem='%s', group='%s', path='%s', pid=%d, host='%s'," + "UserAgent{env='%s', subsystem='%s', group='%s', path='%s', pid=%d, host='%s'," + " port=%d, version='%s', idc='%s', purpose='%s', unack='%d'}", - env, subsystem, group, path, pid, host, port, version, idc, purpose, unack); + env, subsystem, group, path, pid, host, port, version, idc, purpose, unack); } @Override @@ -101,7 +103,6 @@ public boolean equals(Object o) { return false; } - if (!Objects.equals(path, userAgent.path)) { return false; } @@ -126,6 +127,10 @@ public boolean equals(Object o) { return false; } + if (!Objects.equals(token, userAgent.token)) { + return false; + } + if (!Objects.equals(env, userAgent.env)) { return false; } @@ -145,6 +150,7 @@ public int hashCode() { result = 31 * result + (version != null ? version.hashCode() : 0); result = 31 * result + (username != null ? username.hashCode() : 0); result = 31 * result + (password != null ? password.hashCode() : 0); + result = 31 * result + (token != null ? token.hashCode() : 0); result = 31 * result + (idc != null ? idc.hashCode() : 0); result = 31 * result + (env != null ? env.hashCode() : 0); result = 31 * result + unack; diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/codec/Codec.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/codec/Codec.java index c13e681afc..a593a837e7 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/codec/Codec.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/tcp/codec/Codec.java @@ -25,25 +25,19 @@ import org.apache.eventmesh.common.protocol.tcp.Subscription; import org.apache.eventmesh.common.protocol.tcp.UserAgent; import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.LogUtil; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; -import java.nio.charset.Charset; import java.util.Arrays; -import java.util.List; -import java.util.TimeZone; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.MessageToByteEncoder; -import io.netty.handler.codec.ReplayingDecoder; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.base.Preconditions; import lombok.extern.slf4j.Slf4j; @@ -52,55 +46,49 @@ public class Codec { private static final int FRAME_MAX_LENGTH = 1024 * 1024 * 4; - private static final Charset DEFAULT_CHARSET = Charset.forName(Constants.DEFAULT_CHARSET); private static final byte[] CONSTANT_MAGIC_FLAG = serializeBytes("EventMesh"); private static final byte[] VERSION = serializeBytes("0000"); - // todo: move to constants - public static final String CLOUD_EVENTS_PROTOCOL_NAME = "cloudevents"; - public static final String EM_MESSAGE_PROTOCOL_NAME = "eventmeshmessage"; - public static final String OPEN_MESSAGE_PROTOCOL_NAME = "openmessage"; + private static final int PREFIX_LENGTH = CONSTANT_MAGIC_FLAG.length + VERSION.length; //13 - // todo: use json util - private static ObjectMapper OBJECT_MAPPER; - - static { - OBJECT_MAPPER = new ObjectMapper(); - OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); - OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - OBJECT_MAPPER.setTimeZone(TimeZone.getDefault()); - } + private static final int PACKAGE_BYTES_FIELD_LENGTH = 4; public static class Encoder extends MessageToByteEncoder { + @Override public void encode(ChannelHandlerContext ctx, Package pkg, ByteBuf out) throws Exception { Preconditions.checkNotNull(pkg, "TcpPackage cannot be null"); final Header header = pkg.getHeader(); Preconditions.checkNotNull(header, "TcpPackage header cannot be null", header); - if (log.isDebugEnabled()) { - log.debug("Encoder pkg={}", JsonUtils.serialize(pkg)); - } + LogUtil.debug(log, "Encode pkg={}", () -> JsonUtils.toJSONString(pkg)); - final byte[] headerData = serializeBytes(OBJECT_MAPPER.writeValueAsString(header)); + final byte[] headerData = JsonUtils.toJSONBytes(header); final byte[] bodyData; - if (StringUtils.equals(CLOUD_EVENTS_PROTOCOL_NAME, header.getStringProperty(Constants.PROTOCOL_TYPE))) { + if (StringUtils.equals(Constants.CLOUD_EVENTS_PROTOCOL_NAME, header.getStringProperty(Constants.PROTOCOL_TYPE))) { bodyData = (byte[]) pkg.getBody(); } else { - bodyData = serializeBytes(OBJECT_MAPPER.writeValueAsString(pkg.getBody())); + bodyData = JsonUtils.toJSONBytes(pkg.getBody()); } int headerLength = ArrayUtils.getLength(headerData); int bodyLength = ArrayUtils.getLength(bodyData); - int length = 4 + 4 + headerLength + bodyLength; + final int length = PREFIX_LENGTH + headerLength + bodyLength; if (length > FRAME_MAX_LENGTH) { throw new IllegalArgumentException("message size is exceed limit!"); } - + /** + * Header + Body, Format: + *
+             * ┌───────────────┬─────────────┬──────────────────┬──────────────────┬──────────────────┬─────────────────┐
+             * │   MAGIC_FLAG  │   VERSION   │ package length   │   Header length  │      Header      │      body       │
+             * │    (9bytes)   │  (4bytes)   │    (4bytes)      │      (4bytes)    │   (header bytes) │   (body bytes)  │
+             * └───────────────┴─────────────┴──────────────────┴──────────────────┴──────────────────┴─────────────────┘
+             * 
+ */ out.writeBytes(CONSTANT_MAGIC_FLAG); out.writeBytes(VERSION); out.writeInt(length); @@ -114,30 +102,62 @@ public void encode(ChannelHandlerContext ctx, Package pkg, ByteBuf out) throws E } } - public static class Decoder extends ReplayingDecoder { + public static class Decoder extends LengthFieldBasedFrameDecoder { + + public Decoder() { + /** + * lengthAdjustment value = -9 explain: + * Header + Body, Format: + *
+             * ┌───────────────┬─────────────┬──────────────────┬──────────────────┬──────────────────┬─────────────────┐
+             * │   MAGIC_FLAG  │   VERSION   │ package length   │   Header length  │      Header      │      body       │
+             * │    (9bytes)   │  (4bytes)   │    (4bytes)      │      (4bytes)    │   (header bytes) │   (body bytes)  │
+             * └───────────────┴─────────────┴──────────────────┴──────────────────┴──────────────────┴─────────────────┘
+             * 
+ * package length = MAGIC_FLAG + VERSION + Header length + Body length,Currently, + * adding MAGIC_FLAG + VERSION + package length field (4 bytes) actually adds 17 bytes. + * However, the value of the package length field is only reduced by the four bytes of + * the package length field itself and the four bytes of the header length field. + * Therefore, the compensation value to be added to the length field value is -9, + * which means subtracting the extra 9 bytes. + * Refer to the encoding in the {@link Encoder} + */ + super(FRAME_MAX_LENGTH, PREFIX_LENGTH, PACKAGE_BYTES_FIELD_LENGTH, -9, 0); + } + @Override - public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + + ByteBuf target = null; + try { - if (null == in) { - return; + target = (ByteBuf) super.decode(ctx, in); + if (target == null) { + return null; } - - byte[] flagBytes = parseFlag(in); - byte[] versionBytes = parseVersion(in); + byte[] flagBytes = parseFlag(target); + byte[] versionBytes = parseVersion(target); validateFlag(flagBytes, versionBytes, ctx); - final int length = in.readInt(); - final int headerLength = in.readInt(); - final int bodyLength = length - 8 - headerLength; - Header header = parseHeader(in, headerLength); - Object body = parseBody(in, header, bodyLength); + final int length = target.readInt(); + final int headerLength = target.readInt(); + final int bodyLength = length - PREFIX_LENGTH - headerLength; + Header header = parseHeader(target, headerLength); + Object body = parseBody(target, header, bodyLength); Package pkg = new Package(header, body); - out.add(pkg); - } catch (Exception e) { - log.error("decode error| receive: {}.", deserializeBytes(in.array())); - throw e; + return pkg; + + } catch (Exception ex) { + log.error("decode error", ex); + ctx.channel().close(); + } finally { + if (target != null) { + target.release(); + } } + + return null; } private byte[] parseFlag(ByteBuf in) { @@ -158,10 +178,8 @@ private Header parseHeader(ByteBuf in, int headerLength) throws JsonProcessingEx } final byte[] headerData = new byte[headerLength]; in.readBytes(headerData); - if (log.isDebugEnabled()) { - log.debug("Decode headerJson={}", deserializeBytes(headerData)); - } - return OBJECT_MAPPER.readValue(deserializeBytes(headerData), Header.class); + LogUtil.debug(log, "Decode headerJson={}", () -> deserializeBytes(headerData)); + return JsonUtils.parseObject(headerData, Header.class); } private Object parseBody(ByteBuf in, Header header, int bodyLength) throws JsonProcessingException { @@ -170,17 +188,14 @@ private Object parseBody(ByteBuf in, Header header, int bodyLength) throws JsonP } final byte[] bodyData = new byte[bodyLength]; in.readBytes(bodyData); - if (log.isDebugEnabled()) { - log.debug("Decode bodyJson={}", deserializeBytes(bodyData)); - } + LogUtil.debug(log, "Decode bodyJson={}", () -> deserializeBytes(bodyData)); return deserializeBody(deserializeBytes(bodyData), header); } private void validateFlag(byte[] flagBytes, byte[] versionBytes, ChannelHandlerContext ctx) { if (!Arrays.equals(flagBytes, CONSTANT_MAGIC_FLAG) || !Arrays.equals(versionBytes, VERSION)) { - String errorMsg = String.format( - "invalid magic flag or version|flag=%s|version=%s|remoteAddress=%s", - deserializeBytes(flagBytes), deserializeBytes(versionBytes), ctx.channel().remoteAddress()); + String errorMsg = String.format("invalid magic flag or version|flag=%s|version=%s|remoteAddress=%s", + deserializeBytes(flagBytes), deserializeBytes(versionBytes), ctx.channel().remoteAddress()); throw new IllegalArgumentException(errorMsg); } } @@ -191,10 +206,10 @@ private static Object deserializeBody(String bodyJsonString, Header header) thro switch (command) { case HELLO_REQUEST: case RECOMMEND_REQUEST: - return OBJECT_MAPPER.readValue(bodyJsonString, UserAgent.class); + return JsonUtils.parseObject(bodyJsonString, UserAgent.class); case SUBSCRIBE_REQUEST: case UNSUBSCRIBE_REQUEST: - return OBJECT_MAPPER.readValue(bodyJsonString, Subscription.class); + return JsonUtils.parseObject(bodyJsonString, Subscription.class); case REQUEST_TO_SERVER: case RESPONSE_TO_SERVER: case ASYNC_MESSAGE_TO_SERVER: @@ -207,11 +222,23 @@ private static Object deserializeBody(String bodyJsonString, Header header) thro case RESPONSE_TO_CLIENT_ACK: case ASYNC_MESSAGE_TO_CLIENT_ACK: case BROADCAST_MESSAGE_TO_CLIENT_ACK: + case HELLO_RESPONSE: + case RECOMMEND_RESPONSE: + case SUBSCRIBE_RESPONSE: + case LISTEN_RESPONSE: + case UNSUBSCRIBE_RESPONSE: + case HEARTBEAT_RESPONSE: + case ASYNC_MESSAGE_TO_SERVER_ACK: + case BROADCAST_MESSAGE_TO_SERVER_ACK: + case CLIENT_GOODBYE_REQUEST: + case CLIENT_GOODBYE_RESPONSE: + case SERVER_GOODBYE_REQUEST: + case SERVER_GOODBYE_RESPONSE: // The message string will be deserialized by protocol plugin, if the event is cloudevents, the body is // just a string. return bodyJsonString; case REDIRECT_TO_CLIENT: - return OBJECT_MAPPER.readValue(bodyJsonString, RedirectInfo.class); + return JsonUtils.parseObject(bodyJsonString, RedirectInfo.class); default: log.warn("Invalidate TCP command: {}", command); return null; @@ -225,7 +252,7 @@ private static Object deserializeBody(String bodyJsonString, Header header) thro * @return */ private static String deserializeBytes(byte[] bytes) { - return new String(bytes, DEFAULT_CHARSET); + return new String(bytes, Constants.DEFAULT_CHARSET); } /** @@ -236,10 +263,8 @@ private static String deserializeBytes(byte[] bytes) { */ private static byte[] serializeBytes(String str) { if (str == null) { - return null; + return new byte[0]; } - return str.getBytes(DEFAULT_CHARSET); + return str.getBytes(Constants.DEFAULT_CHARSET); } - - } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/EventmeshWorkflowGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/EventmeshWorkflowGrpc.java new file mode 100644 index 0000000000..4e99aa5a60 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/EventmeshWorkflowGrpc.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: workflow.proto + +package org.apache.eventmesh.common.protocol.workflow.protos; + +@SuppressWarnings({"all"}) +public final class EventmeshWorkflowGrpc { + private EventmeshWorkflowGrpc() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + String[] descriptorData = { + "\n\016workflow.proto\022\037eventmesh.workflow.api" + + ".protocol\"Z\n\016ExecuteRequest\022\n\n\002id\030\001 \001(\t\022" + + "\023\n\013instance_id\030\002 \001(\t\022\030\n\020task_instance_id" + + "\030\003 \001(\t\022\r\n\005input\030\004 \001(\t\"&\n\017ExecuteResponse" + + "\022\023\n\013instance_id\030\001 \001(\t2z\n\010Workflow\022n\n\007Exe" + + "cute\022/.eventmesh.workflow.api.protocol.E" + + "xecuteRequest\0320.eventmesh.workflow.api.p" + + "rotocol.ExecuteResponse\"\000B\226\001\n4org.apache" + + ".eventmesh.common.protocol.workflow.prot" + + "osB\025EventmeshWorkflowGrpcP\001ZEgithub.com/" + + "apache/eventmesh/eventmesh-wor" + + "kflow-go/api/protob\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_descriptor, + new String[] { "Id", "InstanceId", "TaskInstanceId", "Input", }); + internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_descriptor, + new String[] { "InstanceId", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteRequest.java new file mode 100644 index 0000000000..e6d6418830 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteRequest.java @@ -0,0 +1,988 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: workflow.proto + +package org.apache.eventmesh.common.protocol.workflow.protos; + +/** + * Protobuf type {@code eventmesh.workflow.api.protocol.ExecuteRequest} + */ +@SuppressWarnings({"all"}) +public final class ExecuteRequest extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:eventmesh.workflow.api.protocol.ExecuteRequest) + ExecuteRequestOrBuilder { +private static final long serialVersionUID = 0L; + // Use ExecuteRequest.newBuilder() to construct. + private ExecuteRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private ExecuteRequest() { + id_ = ""; + instanceId_ = ""; + taskInstanceId_ = ""; + input_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance( + UnusedPrivateParameter unused) { + return new ExecuteRequest(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private ExecuteRequest( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + String s = input.readStringRequireUtf8(); + + id_ = s; + break; + } + case 18: { + String s = input.readStringRequireUtf8(); + + instanceId_ = s; + break; + } + case 26: { + String s = input.readStringRequireUtf8(); + + taskInstanceId_ = s; + break; + } + case 34: { + String s = input.readStringRequireUtf8(); + + input_ = s; + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + ExecuteRequest.class, Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + private volatile Object id_; + /** + * string id = 1; + * @return The id. + */ + @Override + public String getId() { + Object ref = id_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + * string id = 1; + * @return The bytes for id. + */ + @Override + public com.google.protobuf.ByteString + getIdBytes() { + Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int INSTANCE_ID_FIELD_NUMBER = 2; + private volatile Object instanceId_; + /** + * string instance_id = 2; + * @return The instanceId. + */ + @Override + public String getInstanceId() { + Object ref = instanceId_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + instanceId_ = s; + return s; + } + } + /** + * string instance_id = 2; + * @return The bytes for instanceId. + */ + @Override + public com.google.protobuf.ByteString + getInstanceIdBytes() { + Object ref = instanceId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + instanceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TASK_INSTANCE_ID_FIELD_NUMBER = 3; + private volatile Object taskInstanceId_; + /** + * string task_instance_id = 3; + * @return The taskInstanceId. + */ + @Override + public String getTaskInstanceId() { + Object ref = taskInstanceId_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + taskInstanceId_ = s; + return s; + } + } + /** + * string task_instance_id = 3; + * @return The bytes for taskInstanceId. + */ + @Override + public com.google.protobuf.ByteString + getTaskInstanceIdBytes() { + Object ref = taskInstanceId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + taskInstanceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int INPUT_FIELD_NUMBER = 4; + private volatile Object input_; + /** + * string input = 4; + * @return The input. + */ + @Override + public String getInput() { + Object ref = input_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + input_ = s; + return s; + } + } + /** + * string input = 4; + * @return The bytes for input. + */ + @Override + public com.google.protobuf.ByteString + getInputBytes() { + Object ref = input_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + input_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, id_); + } + if (!getInstanceIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, instanceId_); + } + if (!getTaskInstanceIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, taskInstanceId_); + } + if (!getInputBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, input_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, id_); + } + if (!getInstanceIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, instanceId_); + } + if (!getTaskInstanceIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, taskInstanceId_); + } + if (!getInputBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, input_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ExecuteRequest)) { + return super.equals(obj); + } + ExecuteRequest other = (ExecuteRequest) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getInstanceId() + .equals(other.getInstanceId())) return false; + if (!getTaskInstanceId() + .equals(other.getTaskInstanceId())) return false; + if (!getInput() + .equals(other.getInput())) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + INSTANCE_ID_FIELD_NUMBER; + hash = (53 * hash) + getInstanceId().hashCode(); + hash = (37 * hash) + TASK_INSTANCE_ID_FIELD_NUMBER; + hash = (53 * hash) + getTaskInstanceId().hashCode(); + hash = (37 * hash) + INPUT_FIELD_NUMBER; + hash = (53 * hash) + getInput().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static ExecuteRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static ExecuteRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static ExecuteRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static ExecuteRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static ExecuteRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static ExecuteRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static ExecuteRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static ExecuteRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static ExecuteRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static ExecuteRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static ExecuteRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static ExecuteRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(ExecuteRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + return new Builder(parent); + } + /** + * Protobuf type {@code eventmesh.workflow.api.protocol.ExecuteRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:eventmesh.workflow.api.protocol.ExecuteRequest) + ExecuteRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_descriptor; + } + + @Override + protected FieldAccessorTable + internalGetFieldAccessorTable() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + ExecuteRequest.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.workflow.protos.ExecuteRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @Override + public Builder clear() { + super.clear(); + id_ = ""; + + instanceId_ = ""; + + taskInstanceId_ = ""; + + input_ = ""; + + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteRequest_descriptor; + } + + @Override + public ExecuteRequest getDefaultInstanceForType() { + return ExecuteRequest.getDefaultInstance(); + } + + @Override + public ExecuteRequest build() { + ExecuteRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public ExecuteRequest buildPartial() { + ExecuteRequest result = new ExecuteRequest(this); + result.id_ = id_; + result.instanceId_ = instanceId_; + result.taskInstanceId_ = taskInstanceId_; + result.input_ = input_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof ExecuteRequest) { + return mergeFrom((ExecuteRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(ExecuteRequest other) { + if (other == ExecuteRequest.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + onChanged(); + } + if (!other.getInstanceId().isEmpty()) { + instanceId_ = other.instanceId_; + onChanged(); + } + if (!other.getTaskInstanceId().isEmpty()) { + taskInstanceId_ = other.taskInstanceId_; + onChanged(); + } + if (!other.getInput().isEmpty()) { + input_ = other.input_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + ExecuteRequest parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (ExecuteRequest) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private Object id_ = ""; + /** + * string id = 1; + * @return The id. + */ + public String getId() { + Object ref = id_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + id_ = value; + onChanged(); + return this; + } + /** + * string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + + id_ = getDefaultInstance().getId(); + onChanged(); + return this; + } + /** + * string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + id_ = value; + onChanged(); + return this; + } + + private Object instanceId_ = ""; + /** + * string instance_id = 2; + * @return The instanceId. + */ + public String getInstanceId() { + Object ref = instanceId_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + instanceId_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string instance_id = 2; + * @return The bytes for instanceId. + */ + public com.google.protobuf.ByteString + getInstanceIdBytes() { + Object ref = instanceId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + instanceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string instance_id = 2; + * @param value The instanceId to set. + * @return This builder for chaining. + */ + public Builder setInstanceId( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + instanceId_ = value; + onChanged(); + return this; + } + /** + * string instance_id = 2; + * @return This builder for chaining. + */ + public Builder clearInstanceId() { + + instanceId_ = getDefaultInstance().getInstanceId(); + onChanged(); + return this; + } + /** + * string instance_id = 2; + * @param value The bytes for instanceId to set. + * @return This builder for chaining. + */ + public Builder setInstanceIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + instanceId_ = value; + onChanged(); + return this; + } + + private Object taskInstanceId_ = ""; + /** + * string task_instance_id = 3; + * @return The taskInstanceId. + */ + public String getTaskInstanceId() { + Object ref = taskInstanceId_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + taskInstanceId_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string task_instance_id = 3; + * @return The bytes for taskInstanceId. + */ + public com.google.protobuf.ByteString + getTaskInstanceIdBytes() { + Object ref = taskInstanceId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + taskInstanceId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string task_instance_id = 3; + * @param value The taskInstanceId to set. + * @return This builder for chaining. + */ + public Builder setTaskInstanceId( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + taskInstanceId_ = value; + onChanged(); + return this; + } + /** + * string task_instance_id = 3; + * @return This builder for chaining. + */ + public Builder clearTaskInstanceId() { + + taskInstanceId_ = getDefaultInstance().getTaskInstanceId(); + onChanged(); + return this; + } + /** + * string task_instance_id = 3; + * @param value The bytes for taskInstanceId to set. + * @return This builder for chaining. + */ + public Builder setTaskInstanceIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + taskInstanceId_ = value; + onChanged(); + return this; + } + + private Object input_ = ""; + /** + * string input = 4; + * @return The input. + */ + public String getInput() { + Object ref = input_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + input_ = s; + return s; + } else { + return (String) ref; + } + } + /** + * string input = 4; + * @return The bytes for input. + */ + public com.google.protobuf.ByteString + getInputBytes() { + Object ref = input_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (String) ref); + input_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string input = 4; + * @param value The input to set. + * @return This builder for chaining. + */ + public Builder setInput( + String value) { + if (value == null) { + throw new NullPointerException(); + } + + input_ = value; + onChanged(); + return this; + } + /** + * string input = 4; + * @return This builder for chaining. + */ + public Builder clearInput() { + + input_ = getDefaultInstance().getInput(); + onChanged(); + return this; + } + /** + * string input = 4; + * @param value The bytes for input to set. + * @return This builder for chaining. + */ + public Builder setInputBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + input_ = value; + onChanged(); + return this; + } + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.workflow.api.protocol.ExecuteRequest) + } + + // @@protoc_insertion_point(class_scope:eventmesh.workflow.api.protocol.ExecuteRequest) + private static final ExecuteRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new ExecuteRequest(); + } + + public static ExecuteRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @Override + public ExecuteRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ExecuteRequest(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public ExecuteRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteRequestOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteRequestOrBuilder.java new file mode 100644 index 0000000000..2a6c536268 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteRequestOrBuilder.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: workflow.proto + +package org.apache.eventmesh.common.protocol.workflow.protos; + +@SuppressWarnings({"all"}) +public interface ExecuteRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.workflow.api.protocol.ExecuteRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * string id = 1; + * @return The id. + */ + String getId(); + /** + * string id = 1; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + * string instance_id = 2; + * @return The instanceId. + */ + String getInstanceId(); + /** + * string instance_id = 2; + * @return The bytes for instanceId. + */ + com.google.protobuf.ByteString + getInstanceIdBytes(); + + /** + * string task_instance_id = 3; + * @return The taskInstanceId. + */ + String getTaskInstanceId(); + /** + * string task_instance_id = 3; + * @return The bytes for taskInstanceId. + */ + com.google.protobuf.ByteString + getTaskInstanceIdBytes(); + + /** + * string input = 4; + * @return The input. + */ + String getInput(); + /** + * string input = 4; + * @return The bytes for input. + */ + com.google.protobuf.ByteString + getInputBytes(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteResponse.java new file mode 100644 index 0000000000..c141b684d6 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteResponse.java @@ -0,0 +1,576 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: workflow.proto + +package org.apache.eventmesh.common.protocol.workflow.protos; + +import java.util.Objects; + +import com.google.protobuf.ByteString; + +/** + * Protobuf type {@code eventmesh.workflow.api.protocol.ExecuteResponse} + */ +@SuppressWarnings({"all"}) +public final class ExecuteResponse extends com.google.protobuf.GeneratedMessageV3 implements ExecuteResponseOrBuilder { + + private static final long serialVersionUID = -6807939196493979674L; + + public static final int INSTANCE_ID_FIELD_NUMBER = 1; + private volatile String instanceId; + + private byte memoizedIsInitialized = -1; + + // Use ExecuteResponse.newBuilder() to construct. + private ExecuteResponse(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private ExecuteResponse() { + instanceId = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new ExecuteResponse(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet getUnknownFields() { + return this.unknownFields; + } + + private ExecuteResponse( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + Objects.requireNonNull(extensionRegistry, "ExtensionRegistryLite can not be null"); + Objects.requireNonNull(input, "CodedInputStream can not be null"); + + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + instanceId = input.readStringRequireUtf8(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized(ExecuteResponse.class, Builder.class); + } + + + /** + * string instance_id = 1; + * + * @return The instanceId. + */ + @Override + public String getInstanceId() { + return instanceId; + } + + /** + * string instance_id = 1; + * + * @return The bytes for instanceId. + */ + @Override + public com.google.protobuf.ByteString getInstanceIdBytes() { + return ByteString.copyFromUtf8(instanceId); + } + + + @Override + public final boolean isInitialized() { + if (memoizedIsInitialized == 1) { + return true; + } + + if (memoizedIsInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!getInstanceIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, instanceId); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getInstanceIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, instanceId); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ExecuteResponse)) { + return super.equals(obj); + } + ExecuteResponse other = (ExecuteResponse) obj; + + if (!getInstanceId() + .equals(other.getInstanceId())) return false; + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + INSTANCE_ID_FIELD_NUMBER; + hash = (53 * hash) + getInstanceId().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static ExecuteResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static ExecuteResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static ExecuteResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static ExecuteResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static ExecuteResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static ExecuteResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static ExecuteResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static ExecuteResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static ExecuteResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static ExecuteResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static ExecuteResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static ExecuteResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(ExecuteResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType( + BuilderParent parent) { + return new Builder(parent); + } + + /** + * Protobuf type {@code eventmesh.workflow.api.protocol.ExecuteResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + ExecuteResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + ExecuteResponse.class, Builder.class); + } + + // Construct using org.apache.eventmesh.common.protocol.workflow.protos.ExecuteResponse.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) { + } + } + + @Override + public Builder clear() { + super.clear(); + instanceId = ""; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return EventmeshWorkflowGrpc.internal_static_eventmesh_workflow_api_protocol_ExecuteResponse_descriptor; + } + + @Override + public ExecuteResponse getDefaultInstanceForType() { + return ExecuteResponse.getDefaultInstance(); + } + + @Override + public ExecuteResponse build() { + ExecuteResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public ExecuteResponse buildPartial() { + ExecuteResponse result = new ExecuteResponse(this); + result.instanceId = instanceId; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + Objects.requireNonNull(other, "Message can not be null"); + + if (other instanceof ExecuteResponse) { + return mergeFrom((ExecuteResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(ExecuteResponse other) { + Objects.requireNonNull(other, "ExecuteResponse can not be null"); + + if (other == ExecuteResponse.getDefaultInstance()) return this; + if (!other.getInstanceId().isEmpty()) { + instanceId = other.instanceId; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Objects.requireNonNull(input, "CodedInputStream can not be null"); + Objects.requireNonNull(extensionRegistry, "ExtensionRegistryLite can not be null"); + + ExecuteResponse parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (ExecuteResponse) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + + return this; + } + + private String instanceId = ""; + + /** + * string instance_id = 1; + * + * @return The instanceId. + */ + public String getInstanceId() { + return instanceId; + } + + /** + * string instance_id = 1; + * + * @return The bytes for instanceId. + */ + public com.google.protobuf.ByteString getInstanceIdBytes() { + return ByteString.copyFromUtf8(instanceId); + } + + /** + * string instance_id = 1; + * + * @param value The instanceId to set. + * @return This builder for chaining. + */ + public Builder setInstanceId( + String value) { + Objects.requireNonNull(value, "InstanceId can not be null"); + instanceId = value; + onChanged(); + return this; + } + + /** + * string instance_id = 1; + * + * @return This builder for chaining. + */ + public Builder clearInstanceId() { + instanceId = getDefaultInstance().getInstanceId(); + onChanged(); + return this; + } + + /** + * string instance_id = 1; + * + * @param value The bytes for instanceId to set. + * @return This builder for chaining. + */ + public Builder setInstanceIdBytes( + com.google.protobuf.ByteString value) { + Objects.requireNonNull(value, "ByteString can not be null"); + checkByteStringIsUtf8(value); + instanceId = value.toStringUtf8(); + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:eventmesh.workflow.api.protocol.ExecuteResponse) + } + + // @@protoc_insertion_point(class_scope:eventmesh.workflow.api.protocol.ExecuteResponse) + private static final ExecuteResponse DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new ExecuteResponse(); + } + + public static ExecuteResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @Override + public ExecuteResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ExecuteResponse(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public ExecuteResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteResponseOrBuilder.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteResponseOrBuilder.java new file mode 100644 index 0000000000..160c32e648 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/ExecuteResponseOrBuilder.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: workflow.proto + +package org.apache.eventmesh.common.protocol.workflow.protos; + +@SuppressWarnings({"all"}) +public interface ExecuteResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:eventmesh.workflow.api.protocol.ExecuteResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * string instance_id = 1; + * @return The instanceId. + */ + String getInstanceId(); + /** + * string instance_id = 1; + * @return The bytes for instanceId. + */ + com.google.protobuf.ByteString + getInstanceIdBytes(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/WorkflowGrpc.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/WorkflowGrpc.java new file mode 100644 index 0000000000..c7bbffb074 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/protocol/workflow/protos/WorkflowGrpc.java @@ -0,0 +1,294 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.workflow.protos; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.49.1-SNAPSHOT)", + comments = "Source: workflow.proto") +@io.grpc.stub.annotations.GrpcGenerated +@SuppressWarnings({"all"}) +public final class WorkflowGrpc { + + private WorkflowGrpc() {} + + public static final String SERVICE_NAME = "eventmesh.workflow.api.protocol.Workflow"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getExecuteMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "Execute", + requestType = ExecuteRequest.class, + responseType = ExecuteResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getExecuteMethod() { + io.grpc.MethodDescriptor getExecuteMethod; + if ((getExecuteMethod = WorkflowGrpc.getExecuteMethod) == null) { + synchronized (WorkflowGrpc.class) { + if ((getExecuteMethod = WorkflowGrpc.getExecuteMethod) == null) { + WorkflowGrpc.getExecuteMethod = getExecuteMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "Execute")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + ExecuteRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + ExecuteResponse.getDefaultInstance())) + .setSchemaDescriptor(new WorkflowMethodDescriptorSupplier("Execute")) + .build(); + } + } + } + return getExecuteMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static WorkflowStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public WorkflowStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkflowStub(channel, callOptions); + } + }; + return WorkflowStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static WorkflowBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public WorkflowBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkflowBlockingStub(channel, callOptions); + } + }; + return WorkflowBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static WorkflowFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @Override + public WorkflowFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkflowFutureStub(channel, callOptions); + } + }; + return WorkflowFutureStub.newStub(factory, channel); + } + + /** + */ + public static abstract class WorkflowImplBase implements io.grpc.BindableService { + + /** + */ + public void execute(ExecuteRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getExecuteMethod(), responseObserver); + } + + @Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getExecuteMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + ExecuteRequest, + ExecuteResponse>( + this, METHODID_EXECUTE))) + .build(); + } + } + + /** + */ + public static final class WorkflowStub extends io.grpc.stub.AbstractAsyncStub { + private WorkflowStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected WorkflowStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkflowStub(channel, callOptions); + } + + /** + */ + public void execute(ExecuteRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getExecuteMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + */ + public static final class WorkflowBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private WorkflowBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected WorkflowBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkflowBlockingStub(channel, callOptions); + } + + /** + */ + public ExecuteResponse execute(ExecuteRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getExecuteMethod(), getCallOptions(), request); + } + } + + /** + */ + public static final class WorkflowFutureStub extends io.grpc.stub.AbstractFutureStub { + private WorkflowFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected WorkflowFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkflowFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture execute( + ExecuteRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getExecuteMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_EXECUTE = 0; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final WorkflowImplBase serviceImpl; + private final int methodId; + + MethodHandlers(WorkflowImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_EXECUTE: + serviceImpl.execute((ExecuteRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + private static abstract class WorkflowBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + WorkflowBaseDescriptorSupplier() {} + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventmeshWorkflowGrpc.getDescriptor(); + } + + @Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("Workflow"); + } + } + + private static final class WorkflowFileDescriptorSupplier + extends WorkflowBaseDescriptorSupplier { + WorkflowFileDescriptorSupplier() {} + } + + private static final class WorkflowMethodDescriptorSupplier + extends WorkflowBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + WorkflowMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (WorkflowGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new WorkflowFileDescriptorSupplier()) + .addMethod(getExecuteMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/JobState.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/JobState.java new file mode 100644 index 0000000000..150a67e302 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/JobState.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote; + +import java.util.HashMap; +import java.util.Map; + +import lombok.ToString; + +@ToString +public enum JobState { + INIT, RUNNING, COMPLETE, DELETE, FAIL, PAUSE; + private static final JobState[] STATES_NUM_INDEX = JobState.values(); + private static final Map STATES_NAME_INDEX = new HashMap<>(); + + static { + for (JobState jobState : STATES_NUM_INDEX) { + STATES_NAME_INDEX.put(jobState.name(), jobState); + } + } + + public static JobState fromIndex(Integer index) { + if (index == null || index < 0 || index >= STATES_NUM_INDEX.length) { + return null; + } + + return STATES_NUM_INDEX[index]; + } + + public static JobState fromIndex(String index) { + if (index == null || index.isEmpty()) { + return null; + } + + return STATES_NAME_INDEX.get(index); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/TaskState.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/TaskState.java new file mode 100644 index 0000000000..606339c443 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/TaskState.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote; + +import java.util.HashMap; +import java.util.Map; + +import lombok.ToString; + +@ToString +public enum TaskState { + INIT, STARTED, RUNNING, PAUSE, COMPLETE, DELETE, FAIL; + private static final TaskState[] STATES_NUM_INDEX = TaskState.values(); + private static final Map STATES_NAME_INDEX = new HashMap<>(); + static { + for (TaskState jobState : STATES_NUM_INDEX) { + STATES_NAME_INDEX.put(jobState.name(), jobState); + } + } + + public static TaskState fromIndex(Integer index) { + if (index == null || index < 0 || index >= STATES_NUM_INDEX.length) { + return null; + } + + return STATES_NUM_INDEX[index]; + } + + public static TaskState fromIndex(String index) { + if (index == null || index.isEmpty()) { + return null; + } + + return STATES_NAME_INDEX.get(index); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/TransportType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/TransportType.java new file mode 100644 index 0000000000..6b43598398 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/TransportType.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote; + +import org.apache.eventmesh.common.remote.datasource.DataSourceType; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Getter; + +@Getter +public enum TransportType { + MYSQL_MYSQL(DataSourceType.MYSQL, DataSourceType.MYSQL), + REDIS_REDIS(DataSourceType.REDIS, DataSourceType.REDIS), + ROCKETMQ_ROCKETMQ(DataSourceType.ROCKETMQ, DataSourceType.ROCKETMQ), + MYSQL_HTTP(DataSourceType.MYSQL, DataSourceType.HTTP), + ROCKETMQ_HTTP(DataSourceType.ROCKETMQ, DataSourceType.HTTP), + HTTP_MYSQL(DataSourceType.HTTP, DataSourceType.MYSQL), + HTTP_REDIS(DataSourceType.HTTP, DataSourceType.REDIS), + HTTP_ROCKETMQ(DataSourceType.HTTP, DataSourceType.ROCKETMQ), + REDIS_MQ(DataSourceType.REDIS, DataSourceType.ROCKETMQ), + HTTP_HTTP(DataSourceType.HTTP, DataSourceType.HTTP), + ; + private static final Map INDEX_TYPES = new HashMap<>(); + private static final TransportType[] TYPES = TransportType.values(); + private static final String SEPARATOR = "@"; + + static { + for (TransportType type : TYPES) { + INDEX_TYPES.put(type.name(), type); + } + } + + private final DataSourceType src; + + private final DataSourceType dst; + + TransportType(DataSourceType src, DataSourceType dst) { + this.src = src; + this.dst = dst; + } + + + public static TransportType getTransportType(String index) { + if (index == null || index.isEmpty()) { + return null; + } + return INDEX_TYPES.get(index); + } + + public static TransportType getTransportType(Integer index) { + if (index == null || index < 0 || index >= TYPES.length) { + return null; + } + return TYPES[index]; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSource.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSource.java new file mode 100644 index 0000000000..afda984805 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSource.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.datasource; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceConfig; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import lombok.Data; + +@Data +public class DataSource { + + private DataSourceType type; + + private String desc; + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) + @JsonSubTypes({ + @JsonSubTypes.Type(value = CanalSourceConfig.class, name = "CanalSourceConfig"), + @JsonSubTypes.Type(value = CanalSinkConfig.class, name = "CanalSinkConfig") + }) + private Config conf; + + private Class confClazz; + + private String region; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceClassify.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceClassify.java new file mode 100644 index 0000000000..8cb01c9204 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceClassify.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.datasource; + +public enum DataSourceClassify { + // relationship db + RDB, + MQ, + CACHE, + TUNNEL; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceConf.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceConf.java new file mode 100644 index 0000000000..9701a9fa11 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceConf.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.datasource; + + +public abstract class DataSourceConf { + public abstract Class getConfClass(); +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceDriverType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceDriverType.java new file mode 100644 index 0000000000..f1c0f54e5f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceDriverType.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.datasource; + +public enum DataSourceDriverType { + MYSQL, + MariaDB, + REDIS, + ROCKETMQ, + HTTP; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceType.java new file mode 100644 index 0000000000..1c14239c3b --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/datasource/DataSourceType.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.datasource; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString +public enum DataSourceType { + MYSQL("MySQL", DataSourceDriverType.MYSQL, DataSourceClassify.RDB), + MariaDB("MariaDB", DataSourceDriverType.MariaDB, DataSourceClassify.RDB), + REDIS("Redis", DataSourceDriverType.REDIS, DataSourceClassify.CACHE), + ROCKETMQ("RocketMQ", DataSourceDriverType.ROCKETMQ, DataSourceClassify.MQ), + HTTP("HTTP", DataSourceDriverType.HTTP, DataSourceClassify.TUNNEL); + private static final Map INDEX_TYPES = new HashMap<>(); + private static final DataSourceType[] TYPES = DataSourceType.values(); + static { + for (DataSourceType type : TYPES) { + INDEX_TYPES.put(type.name(), type); + } + } + + private final String name; + private final DataSourceDriverType driverType; + private final DataSourceClassify classify; + + DataSourceType(String name, DataSourceDriverType driverType, DataSourceClassify classify) { + this.name = name; + this.driverType = driverType; + this.classify = classify; + } + + public static DataSourceType getDataSourceType(String index) { + if (index == null || index.isEmpty()) { + return null; + } + return INDEX_TYPES.get(index); + } + + public static DataSourceType getDataSourceType(Integer index) { + if (index == null || index < 0 || index >= TYPES.length) { + return null; + } + return TYPES[index]; + } + + public static DataSourceType fromString(String type) { + for (DataSourceType dataSourceType : DataSourceType.values()) { + if (dataSourceType.name().equalsIgnoreCase(type)) { + return dataSourceType; + } + } + throw new IllegalArgumentException("No enum constant for type: " + type); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/ErrorCode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/ErrorCode.java new file mode 100644 index 0000000000..f24971acc7 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/ErrorCode.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.exception; + +public class ErrorCode { + + public static final int SUCCESS = 0; + public static final int BAD_REQUEST = 4001; + public static final int BAD_DB_DATA = 4002; + + public static final int INTERNAL_ERR = 5000; + public static final int STARTUP_CONFIG_MISS = 5001; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/PayloadFormatException.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/PayloadFormatException.java new file mode 100644 index 0000000000..affa6b8bbf --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/PayloadFormatException.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.exception; + +public class PayloadFormatException extends RemoteRuntimeException { + + public PayloadFormatException(int code, String desc) { + super(code, desc); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/RemoteRuntimeException.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/RemoteRuntimeException.java new file mode 100644 index 0000000000..708a558d37 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/exception/RemoteRuntimeException.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.exception; + +public class RemoteRuntimeException extends RuntimeException { + + protected final int code; + protected final String message; + + public RemoteRuntimeException(int code, String message) { + this.code = code; + this.message = message; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/JobConnectorConfig.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/JobConnectorConfig.java new file mode 100644 index 0000000000..14e8178cf3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/JobConnectorConfig.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.job; + +import java.util.Map; + +import lombok.Data; + +/** + * Description: + */ +@Data +public class JobConnectorConfig { + private Map sourceConnectorConfig; + + private String sourceConnectorDesc; + + private Map sinkConnectorConfig; + + private String sinkConnectorDesc; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/JobType.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/JobType.java new file mode 100644 index 0000000000..83d2f56964 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/JobType.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.job; + +import java.util.HashMap; +import java.util.Map; + +public enum JobType { + FULL, + INCREASE, + CHECK; + + private static final JobType[] STATES_NUM_INDEX = JobType.values(); + private static final Map STATES_NAME_INDEX = new HashMap<>(); + static { + for (JobType jobType : STATES_NUM_INDEX) { + STATES_NAME_INDEX.put(jobType.name(), jobType); + } + } + + public static JobType fromIndex(Integer index) { + if (index == null || index < 0 || index > STATES_NUM_INDEX.length) { + return null; + } + + return STATES_NUM_INDEX[index]; + } + + public static JobType fromIndex(String index) { + if (index == null || index.isEmpty()) { + return null; + } + + return STATES_NAME_INDEX.get(index); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/SyncConsistency.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/SyncConsistency.java new file mode 100644 index 0000000000..a5aec2aa38 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/SyncConsistency.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.job; + +public enum SyncConsistency { + /** + * based with media + */ + MEDIA("M"), + /** + * based with store + */ + STORE("S"), + /** + * Based on the current change value, eventual consistency + */ + BASE("B"); + + private String value; + + SyncConsistency(String value) { + this.value = value; + } + + public static SyncConsistency valuesOf(String value) { + SyncConsistency[] modes = values(); + for (SyncConsistency mode : modes) { + if (mode.value.equalsIgnoreCase(value)) { + return mode; + } + } + return null; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public boolean isMedia() { + return this.equals(SyncConsistency.MEDIA); + } + + public boolean isStore() { + return this.equals(SyncConsistency.STORE); + } + + public boolean isBase() { + return this.equals(SyncConsistency.BASE); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/SyncMode.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/SyncMode.java new file mode 100644 index 0000000000..0f2f9bdfcb --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/job/SyncMode.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.job; + +public enum SyncMode { + /** + * row + */ + ROW("R"), + /** + * field + */ + FIELD("F"); + + private String value; + + SyncMode(String value) { + this.value = value; + } + + public static SyncMode valuesOf(String value) { + SyncMode[] modes = values(); + for (SyncMode mode : modes) { + if (mode.value.equalsIgnoreCase(value)) { + return mode; + } + } + return null; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public boolean isRow() { + return this.equals(SyncMode.ROW); + } + + public boolean isField() { + return this.equals(SyncMode.FIELD); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordOffset.java new file mode 100644 index 0000000000..f78585ca15 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordOffset.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset; + +public abstract class RecordOffset { + + public abstract Class getRecordOffsetClass(); + + public RecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordPartition.java new file mode 100644 index 0000000000..00e4c30e48 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordPartition.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset; + +public abstract class RecordPartition { + + public abstract Class getRecordPartitionClass(); + + public RecordPartition() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordPosition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordPosition.java new file mode 100644 index 0000000000..5f45390b73 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/RecordPosition.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset; + +import org.apache.eventmesh.common.remote.offset.S3.S3RecordOffset; +import org.apache.eventmesh.common.remote.offset.S3.S3RecordPartition; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordOffset; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordPartition; +import org.apache.eventmesh.common.remote.offset.canal.CanalRecordOffset; +import org.apache.eventmesh.common.remote.offset.canal.CanalRecordPartition; +import org.apache.eventmesh.common.remote.offset.file.FileRecordOffset; +import org.apache.eventmesh.common.remote.offset.file.FileRecordPartition; +import org.apache.eventmesh.common.remote.offset.kafka.KafkaRecordOffset; +import org.apache.eventmesh.common.remote.offset.kafka.KafkaRecordPartition; +import org.apache.eventmesh.common.remote.offset.pulsar.PulsarRecordOffset; +import org.apache.eventmesh.common.remote.offset.pulsar.PulsarRecordPartition; +import org.apache.eventmesh.common.remote.offset.rocketmq.RocketMQRecordOffset; +import org.apache.eventmesh.common.remote.offset.rocketmq.RocketMQRecordPartition; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +public class RecordPosition { + + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) + @JsonSubTypes({ + @JsonSubTypes.Type(value = CanalRecordPartition.class, name = "CanalRecordPartition"), + @JsonSubTypes.Type(value = CanalFullRecordPartition.class, name = "CanalFullRecordPartition"), + @JsonSubTypes.Type(value = FileRecordPartition.class, name = "FileRecordPartition"), + @JsonSubTypes.Type(value = S3RecordPartition.class, name = "S3RecordPartition"), + @JsonSubTypes.Type(value = KafkaRecordPartition.class, name = "KafkaRecordPartition"), + @JsonSubTypes.Type(value = PulsarRecordPartition.class, name = "PulsarRecordPartition"), + @JsonSubTypes.Type(value = RocketMQRecordPartition.class, name = "RocketMQRecordPartition"), + }) + private RecordPartition recordPartition; + + private Class recordPartitionClazz; + + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) + @JsonSubTypes({ + @JsonSubTypes.Type(value = CanalRecordOffset.class, name = "CanalRecordOffset"), + @JsonSubTypes.Type(value = CanalFullRecordOffset.class, name = "CanalFullRecordOffset"), + @JsonSubTypes.Type(value = FileRecordOffset.class, name = "FileRecordOffset"), + @JsonSubTypes.Type(value = S3RecordOffset.class, name = "S3RecordOffset"), + @JsonSubTypes.Type(value = KafkaRecordOffset.class, name = "KafkaRecordOffset"), + @JsonSubTypes.Type(value = PulsarRecordOffset.class, name = "PulsarRecordOffset"), + @JsonSubTypes.Type(value = RocketMQRecordOffset.class, name = "RocketMQRecordOffset"), + }) + private RecordOffset recordOffset; + + private Class recordOffsetClazz; + + public RecordPosition() { + + } + + public RecordPosition( + RecordPartition recordPartition, RecordOffset recordOffset) { + this.recordPartition = recordPartition; + this.recordOffset = recordOffset; + this.recordPartitionClazz = recordPartition.getRecordPartitionClass(); + this.recordOffsetClazz = recordOffset.getRecordOffsetClass(); + } + + public RecordPartition getRecordPartition() { + return recordPartition; + } + + public void setRecordPartition(RecordPartition recordPartition) { + this.recordPartition = recordPartition; + if (recordPartition == null) { + this.recordPartitionClazz = null; + return; + } + this.recordPartitionClazz = recordPartition.getRecordPartitionClass(); + } + + public RecordOffset getRecordOffset() { + return recordOffset; + } + + public void setRecordOffset(RecordOffset recordOffset) { + this.recordOffset = recordOffset; + if (recordOffset == null) { + this.recordOffsetClazz = null; + return; + } + this.recordOffsetClazz = recordOffset.getRecordOffsetClass(); + } + + public Class getRecordPartitionClazz() { + return recordPartitionClazz; + } + + public Class getRecordOffsetClazz() { + return recordOffsetClazz; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RecordPosition)) { + return false; + } + RecordPosition position = (RecordPosition) o; + return recordPartition.equals(position.recordPartition) && recordOffset.equals(position.recordOffset); + } + + @Override + public int hashCode() { + return Objects.hash(recordPartition, recordOffset); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/S3/S3RecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/S3/S3RecordOffset.java new file mode 100644 index 0000000000..9f38e4b2c6 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/S3/S3RecordOffset.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.S3; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class S3RecordOffset extends RecordOffset { + + private Long offset; + + @Override + public Class getRecordOffsetClass() { + return S3RecordOffset.class; + } + + public S3RecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/S3/S3RecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/S3/S3RecordPartition.java new file mode 100644 index 0000000000..3e42a4d093 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/S3/S3RecordPartition.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.S3; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class S3RecordPartition extends RecordPartition { + + private String region; + + private String bucket; + + private String fileName; + + @Override + public Class getRecordPartitionClass() { + return S3RecordPartition.class; + } + + public S3RecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + S3RecordPartition that = (S3RecordPartition) o; + return Objects.equals(fileName, that.fileName); + } + + @Override + public int hashCode() { + return Objects.hash(fileName); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalFullRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalFullRecordOffset.java new file mode 100644 index 0000000000..a0a077b7f5 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalFullRecordOffset.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.canal; + +import org.apache.eventmesh.common.config.connector.rdb.canal.JobRdbFullPosition; +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class CanalFullRecordOffset extends RecordOffset { + private JobRdbFullPosition position; + + @Override + public Class getRecordOffsetClass() { + return CanalFullRecordOffset.class; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalFullRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalFullRecordPartition.java new file mode 100644 index 0000000000..73626fa78f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalFullRecordPartition.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.canal; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@Data +@ToString +@EqualsAndHashCode(callSuper = true) +public class CanalFullRecordPartition extends RecordPartition { + + @Override + public Class getRecordPartitionClass() { + return CanalFullRecordPartition.class; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalRecordOffset.java new file mode 100644 index 0000000000..d0f2053f4d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalRecordOffset.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.canal; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class CanalRecordOffset extends RecordOffset { + + private Long offset; + + // mysql instance gtid range + private String gtid; + + private String currentGtid; + + @Override + public Class getRecordOffsetClass() { + return CanalRecordOffset.class; + } + + public CanalRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalRecordPartition.java new file mode 100644 index 0000000000..ded82306e3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/canal/CanalRecordPartition.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.canal; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class CanalRecordPartition extends RecordPartition { + + private String serverUUID; + + private String journalName; + + private Long timeStamp; + + @Override + public Class getRecordPartitionClass() { + return CanalRecordPartition.class; + } + + public CanalRecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CanalRecordPartition that = (CanalRecordPartition) o; + return Objects.equals(journalName, that.journalName) && Objects.equals(timeStamp, that.timeStamp); + } + + @Override + public int hashCode() { + return Objects.hash(journalName, timeStamp); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/file/FileRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/file/FileRecordOffset.java new file mode 100644 index 0000000000..cda293cb8c --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/file/FileRecordOffset.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.file; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class FileRecordOffset extends RecordOffset { + + private Long offset; + + @Override + public Class getRecordOffsetClass() { + return FileRecordOffset.class; + } + + public FileRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/file/FileRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/file/FileRecordPartition.java new file mode 100644 index 0000000000..1a6dddad44 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/file/FileRecordPartition.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.file; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class FileRecordPartition extends RecordPartition { + + private String fileName; + + @Override + public Class getRecordPartitionClass() { + return FileRecordPartition.class; + } + + public FileRecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FileRecordPartition that = (FileRecordPartition) o; + return Objects.equals(fileName, that.fileName); + } + + @Override + public int hashCode() { + return Objects.hash(fileName); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/http/HttpRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/http/HttpRecordOffset.java new file mode 100644 index 0000000000..f5084c755f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/http/HttpRecordOffset.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.http; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import java.util.Map; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class HttpRecordOffset extends RecordOffset { + + private Map offsetMap; + + @Override + public Class getRecordOffsetClass() { + return HttpRecordOffset.class; + } + + public HttpRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/http/HttpRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/http/HttpRecordPartition.java new file mode 100644 index 0000000000..453b3b501e --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/http/HttpRecordPartition.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.http; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class HttpRecordPartition extends RecordPartition { + + @Override + public Class getRecordPartitionClass() { + return HttpRecordPartition.class; + } + + public HttpRecordPartition() { + super(); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/jdbc/JdbcRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/jdbc/JdbcRecordOffset.java new file mode 100644 index 0000000000..a97a90e658 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/jdbc/JdbcRecordOffset.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.jdbc; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class JdbcRecordOffset extends RecordOffset { + + private Long offset; + + @Override + public Class getRecordOffsetClass() { + return JdbcRecordOffset.class; + } + + public JdbcRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/jdbc/JdbcRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/jdbc/JdbcRecordPartition.java new file mode 100644 index 0000000000..1eb6937a87 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/jdbc/JdbcRecordPartition.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.jdbc; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class JdbcRecordPartition extends RecordPartition { + + private String fileName; + + @Override + public Class getRecordPartitionClass() { + return JdbcRecordPartition.class; + } + + public JdbcRecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JdbcRecordPartition that = (JdbcRecordPartition) o; + return Objects.equals(fileName, that.fileName); + } + + @Override + public int hashCode() { + return Objects.hash(fileName); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/kafka/KafkaRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/kafka/KafkaRecordOffset.java new file mode 100644 index 0000000000..134ef06fe4 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/kafka/KafkaRecordOffset.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.kafka; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class KafkaRecordOffset extends RecordOffset { + + private Long offset; + + @Override + public Class getRecordOffsetClass() { + return KafkaRecordOffset.class; + } + + public KafkaRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/kafka/KafkaRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/kafka/KafkaRecordPartition.java new file mode 100644 index 0000000000..77dec82267 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/kafka/KafkaRecordPartition.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.kafka; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class KafkaRecordPartition extends RecordPartition { + + private String topic; + + private Integer partition; + + @Override + public Class getRecordPartitionClass() { + return KafkaRecordPartition.class; + } + + public KafkaRecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + KafkaRecordPartition that = (KafkaRecordPartition) o; + return Objects.equals(topic, that.topic) && Objects.equals(partition, that.partition); + } + + @Override + public int hashCode() { + return Objects.hash(topic, partition); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/prometheus/PrometheusRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/prometheus/PrometheusRecordOffset.java new file mode 100644 index 0000000000..acb5b3ce02 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/prometheus/PrometheusRecordOffset.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.prometheus; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class PrometheusRecordOffset extends RecordOffset { + + private Long offset; + + @Override + public Class getRecordOffsetClass() { + return PrometheusRecordOffset.class; + } + + public PrometheusRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/prometheus/PrometheusRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/prometheus/PrometheusRecordPartition.java new file mode 100644 index 0000000000..74302504c2 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/prometheus/PrometheusRecordPartition.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.prometheus; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class PrometheusRecordPartition extends RecordPartition { + + @Override + public Class getRecordPartitionClass() { + return PrometheusRecordPartition.class; + } + + public PrometheusRecordPartition() { + super(); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/pulsar/PulsarRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/pulsar/PulsarRecordOffset.java new file mode 100644 index 0000000000..bbe3d43803 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/pulsar/PulsarRecordOffset.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.pulsar; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class PulsarRecordOffset extends RecordOffset { + + /** + * if pull message from mq + * key=queueOffset, + * value=queueOffset value + */ + private Long queueOffset; + + @Override + public Class getRecordOffsetClass() { + return PulsarRecordOffset.class; + } + + public PulsarRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/pulsar/PulsarRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/pulsar/PulsarRecordPartition.java new file mode 100644 index 0000000000..0c152b50b3 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/pulsar/PulsarRecordPartition.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.pulsar; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class PulsarRecordPartition extends RecordPartition { + + private String topic; + + private Long queueId; + + + @Override + public Class getRecordPartitionClass() { + return PulsarRecordPartition.class; + } + + public PulsarRecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PulsarRecordPartition that = (PulsarRecordPartition) o; + return Objects.equals(topic, that.topic) && Objects.equals(queueId, + that.queueId); + } + + @Override + public int hashCode() { + return Objects.hash(topic, queueId); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/rocketmq/RocketMQRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/rocketmq/RocketMQRecordOffset.java new file mode 100644 index 0000000000..56094c9e72 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/rocketmq/RocketMQRecordOffset.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.rocketmq; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class RocketMQRecordOffset extends RecordOffset { + + /** + * if pull message from mq + * key=queueOffset, + * value=queueOffset value + */ + private Long queueOffset; + + @Override + public Class getRecordOffsetClass() { + return RocketMQRecordOffset.class; + } + + public RocketMQRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/rocketmq/RocketMQRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/rocketmq/RocketMQRecordPartition.java new file mode 100644 index 0000000000..0963af6f59 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/rocketmq/RocketMQRecordPartition.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.rocketmq; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Objects; + +import lombok.Data; +import lombok.ToString; + + +@Data +@ToString +public class RocketMQRecordPartition extends RecordPartition { + + /** + * key=topic,value=topicName key=brokerName,value=brokerName key=queueId,value=queueId + */ + + private String broker; + + private String topic; + + private String queueId; + + + @Override + public Class getRecordPartitionClass() { + return RocketMQRecordPartition.class; + } + + public RocketMQRecordPartition() { + super(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RocketMQRecordPartition that = (RocketMQRecordPartition) o; + return Objects.equals(broker, that.broker) && Objects.equals(topic, that.topic) && Objects.equals(queueId, + that.queueId); + } + + @Override + public int hashCode() { + return Objects.hash(broker, topic, queueId); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/spring/SpringRecordOffset.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/spring/SpringRecordOffset.java new file mode 100644 index 0000000000..d0916c5175 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/spring/SpringRecordOffset.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.spring; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class SpringRecordOffset extends RecordOffset { + + private Long offset; + + @Override + public Class getRecordOffsetClass() { + return SpringRecordOffset.class; + } + + public SpringRecordOffset() { + + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/spring/SpringRecordPartition.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/spring/SpringRecordPartition.java new file mode 100644 index 0000000000..4b536da139 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/offset/spring/SpringRecordPartition.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.offset.spring; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@EqualsAndHashCode(callSuper = true) +@Data +@ToString +public class SpringRecordPartition extends RecordPartition { + + @Override + public Class getRecordPartitionClass() { + return SpringRecordPartition.class; + } + + public SpringRecordPartition() { + super(); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/IPayload.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/IPayload.java new file mode 100644 index 0000000000..aca27ffc21 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/IPayload.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.payload; + +/** + * IPayload + */ +public interface IPayload { + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/PayloadFactory.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/PayloadFactory.java new file mode 100644 index 0000000000..74e4880443 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/PayloadFactory.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.payload; + +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.concurrent.ConcurrentHashMap; + +public class PayloadFactory { + + private PayloadFactory() { + } + + private static class PayloadFactoryHolder { + + private static final PayloadFactory INSTANCE = new PayloadFactory(); + } + + public static PayloadFactory getInstance() { + return PayloadFactoryHolder.INSTANCE; + } + + private final Map> registryPayload = new ConcurrentHashMap<>(); + + private boolean initialized = false; + + public void init() { + scan(); + } + + private synchronized void scan() { + if (initialized) { + return; + } + ServiceLoader payloads = ServiceLoader.load(IPayload.class); + for (IPayload payload : payloads) { + register(payload.getClass().getSimpleName(), payload.getClass()); + } + initialized = true; + } + + public void register(String type, Class clazz) { + if (Modifier.isAbstract(clazz.getModifiers())) { + return; + } + if (registryPayload.containsKey(type)) { + throw new RuntimeException(String.format("Fail to register, type:%s ,clazz:%s ", type, clazz.getName())); + } + registryPayload.put(type, clazz); + } + + public Class getClassByType(String type) { + return registryPayload.get(type); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/PayloadUtil.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/PayloadUtil.java new file mode 100644 index 0000000000..6a21d5a825 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/payload/PayloadUtil.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.payload; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.exception.PayloadFormatException; +import org.apache.eventmesh.common.utils.JsonUtils; + +import com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream; +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +public class PayloadUtil { + + public static Payload from(IPayload payload) { + byte[] payloadBytes = JsonUtils.toJSONBytes(payload); + Metadata.Builder metadata = Metadata.newBuilder().setType(payload.getClass().getSimpleName()); + return Payload.newBuilder().setMetadata(metadata).setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(payloadBytes))).build(); + } + + public static IPayload parse(Payload payload) { + Class targetClass = PayloadFactory.getInstance().getClassByType(payload.getMetadata().getType()); + if (targetClass == null) { + throw new PayloadFormatException(ErrorCode.BAD_REQUEST, + "unknown payload type:" + payload.getMetadata().getType()); + } + return (IPayload) JsonUtils.parseObject(new ByteBufferBackedInputStream(payload.getBody().getValue().asReadOnlyByteBuffer()), targetClass); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/BaseRemoteRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/BaseRemoteRequest.java new file mode 100644 index 0000000000..b8c4c06207 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/BaseRemoteRequest.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.remote.payload.IPayload; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Getter; + +@Getter +public abstract class BaseRemoteRequest implements IPayload { + + private final Map header = new HashMap<>(); + + public void addHeader(String key, String value) { + if (key == null || value == null) { + return; + } + header.put(key, value); + } + + public void addHeaders(Map map) { + if (map == null || map.isEmpty()) { + return; + } + map.forEach((k, v) -> { + if (k == null || v == null) { + return; + } + this.header.put(k, v); + }); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/CreateOrUpdateDataSourceReq.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/CreateOrUpdateDataSourceReq.java new file mode 100644 index 0000000000..f78349703a --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/CreateOrUpdateDataSourceReq.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * create or update datasource with custom data source config + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class CreateOrUpdateDataSourceReq extends BaseRemoteRequest { + + private Integer id; + private DataSourceType type; + private String desc; + private Config config; + private String configClass; + private String region; + private String operator; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/CreateTaskRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/CreateTaskRequest.java new file mode 100644 index 0000000000..b09a3e10ed --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/CreateTaskRequest.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.remote.TransportType; +import org.apache.eventmesh.common.remote.job.JobType; + +import java.util.List; +import java.util.Map; + +import lombok.Data; + +/** + * Description: create task without task id, otherwise update task + */ +@Data +public class CreateTaskRequest { + + private String taskId; + + // task name + private String taskName; + + // task description + private String taskDesc; + + // task owner or updater + private String uid; + + private List jobs; + + // task source region + private String sourceRegion; + + // task target region + private String targetRegion; + + // mark request send by other region admin, default is false + private boolean flag = false; + + @Data + public static class JobDetail { + + private String jobId; + + private String jobDesc; + + // full/increase/check + private JobType jobType; + + private Map sourceDataSource; + + private String sourceConnectorDesc; + + private Map sinkDataSource; + + private String sinkConnectorDesc; + + private TransportType transportType; + + // job request from region + private String fromRegion; + + // job actually running region + private String runningRegion; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/FetchJobRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/FetchJobRequest.java new file mode 100644 index 0000000000..2693a4a3aa --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/FetchJobRequest.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FetchJobRequest extends BaseRemoteRequest { + private String jobID; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/FetchPositionRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/FetchPositionRequest.java new file mode 100644 index 0000000000..90563251ab --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/FetchPositionRequest.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FetchPositionRequest extends BaseRemoteRequest { + + private String jobID; + + private String address; + + private RecordPosition recordPosition; + + private DataSourceType dataSourceType; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/QueryTaskInfoRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/QueryTaskInfoRequest.java new file mode 100644 index 0000000000..c0973cf63d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/QueryTaskInfoRequest.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QueryTaskInfoRequest { + + private String taskDesc; + + private String taskID; + + private String jobType; + + private String sourceDataID; + + private String targetDataID; + + private String ip; + + private String sourceTableName; + + private String taskMathID; + + private Integer currentPage; + + private Integer pageSize; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/QueryTaskMonitorRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/QueryTaskMonitorRequest.java new file mode 100644 index 0000000000..cd777d5019 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/QueryTaskMonitorRequest.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class QueryTaskMonitorRequest extends BaseRemoteRequest { + private String taskID; + private String jobID; + private long limit; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/RecordPositionRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/RecordPositionRequest.java new file mode 100644 index 0000000000..b04a6f1041 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/RecordPositionRequest.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class RecordPositionRequest extends BaseRemoteRequest { + + private String fullJobID; + + private String increaseJobID; + // prepare to update job state to current state + private JobState updateState; + + private String address; + + private DataSourceType dataSourceType; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportHeartBeatRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportHeartBeatRequest.java new file mode 100644 index 0000000000..fb61ca3618 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportHeartBeatRequest.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ReportHeartBeatRequest extends BaseRemoteRequest { + + private String address; + + private String reportedTimeStamp; + + private String jobID; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportJobRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportJobRequest.java new file mode 100644 index 0000000000..aec33e4616 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportJobRequest.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.remote.JobState; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class ReportJobRequest extends BaseRemoteRequest { + + private String jobID; + + private JobState state; + + private String address; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportMonitorRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportMonitorRequest.java new file mode 100644 index 0000000000..12278df27f --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportMonitorRequest.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class ReportMonitorRequest extends BaseRemoteRequest { + private String taskID; + private String jobID; + private String address; + private String connectorStage; + private String transportType; + private long totalReqNum; + private long totalTimeCost; + private long maxTimeCost; + private long avgTimeCost; + private double tps; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportPositionRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportPositionRequest.java new file mode 100644 index 0000000000..42694d5675 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportPositionRequest.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class ReportPositionRequest extends BaseRemoteRequest { + + private String jobID; + + private List recordPositionList; + + private TaskState state; + + private String address; + + private DataSourceType dataSourceType; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportVerifyRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportVerifyRequest.java new file mode 100644 index 0000000000..bd38881c3d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/ReportVerifyRequest.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class ReportVerifyRequest extends BaseRemoteRequest { + + private String taskID; + + private String jobID; + + private String recordID; + + private String recordSig; + + private String connectorName; + + private String connectorStage; + + private String position; +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/TaskBachRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/TaskBachRequest.java new file mode 100644 index 0000000000..306badc156 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/TaskBachRequest.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; + +@Data +public class TaskBachRequest { + + private String taskID; + + private String taskName; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/TaskIDRequest.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/TaskIDRequest.java new file mode 100644 index 0000000000..37a72916ff --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/request/TaskIDRequest.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.request; + +import lombok.Data; + +@Data +public class TaskIDRequest { + + private String taskID; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/BaseRemoteResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/BaseRemoteResponse.java new file mode 100644 index 0000000000..84ea3661bd --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/BaseRemoteResponse.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import org.apache.eventmesh.common.remote.payload.IPayload; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Getter; +import lombok.Setter; + +@Getter +public abstract class BaseRemoteResponse implements IPayload { + @Setter + private boolean success = true; + @Setter + private int errorCode; + @Setter + private String desc; + + private Map header = new HashMap<>(); + @Setter + private T data; + + public void addHeader(String key, String value) { + if (key == null || value == null) { + return; + } + header.put(key, value); + } + + public void addHeaders(Map map) { + if (map == null || map.isEmpty()) { + return; + } + map.forEach((k, v) -> { + if (k == null || v == null) { + return; + } + this.header.put(k, v); + }); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/CreateTaskResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/CreateTaskResponse.java new file mode 100644 index 0000000000..24e7871e04 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/CreateTaskResponse.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import org.apache.eventmesh.common.remote.request.CreateTaskRequest; + +import java.util.List; + +import lombok.Data; + +@Data +public class CreateTaskResponse { + + private String taskId; + + private List jobIdList; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/FetchJobResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/FetchJobResponse.java new file mode 100644 index 0000000000..95d2d157e0 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/FetchJobResponse.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.TransportType; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.job.JobConnectorConfig; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FetchJobResponse extends BaseRemoteResponse { + + private String id; + + private TransportType transportType; + + private JobConnectorConfig connectorConfig; + + private List position; + + private TaskState state; + + private JobType type; + + public static FetchJobResponse successResponse() { + FetchJobResponse response = new FetchJobResponse(); + response.setSuccess(true); + response.setErrorCode(ErrorCode.SUCCESS); + return response; + } + + public static FetchJobResponse failResponse(int code, String desc) { + FetchJobResponse response = new FetchJobResponse(); + response.setSuccess(false); + response.setErrorCode(code); + response.setDesc(desc); + return response; + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/FetchPositionResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/FetchPositionResponse.java new file mode 100644 index 0000000000..613623d654 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/FetchPositionResponse.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FetchPositionResponse extends BaseRemoteResponse { + + private List recordPosition; + + public static FetchPositionResponse successResponse() { + FetchPositionResponse response = new FetchPositionResponse(); + response.setSuccess(true); + response.setErrorCode(ErrorCode.SUCCESS); + return response; + } + + public static FetchPositionResponse successResponse(List recordPosition) { + FetchPositionResponse response = successResponse(); + response.setRecordPosition(recordPosition); + return response; + } + + public static FetchPositionResponse failResponse(int code, String desc) { + FetchPositionResponse response = new FetchPositionResponse(); + response.setSuccess(false); + response.setErrorCode(code); + response.setDesc(desc); + return response; + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/HttpResponseResult.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/HttpResponseResult.java new file mode 100644 index 0000000000..b6ca8cef0d --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/HttpResponseResult.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HttpResponseResult { + + private Integer code; + + private String message; + + private T data; + + public HttpResponseResult(Integer code, String message) { + this.code = code; + this.message = message; + } + + public HttpResponseResult(Integer code, T data) { + this.code = code; + this.data = data; + } + + public static HttpResponseResult success() { + return new HttpResponseResult<>(200, "success"); + } + + public static HttpResponseResult success(T data) { + return new HttpResponseResult<>(200, "success", data); + } + + public static HttpResponseResult failed() { + return new HttpResponseResult<>(500, "failed"); + } + + public static HttpResponseResult failed(T data) { + return new HttpResponseResult<>(500, "failed", data); + } + + public static HttpResponseResult exception(T data) { + return new HttpResponseResult<>(300, data); + } + +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/QueryTaskInfoResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/QueryTaskInfoResponse.java new file mode 100644 index 0000000000..4c0c536eae --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/QueryTaskInfoResponse.java @@ -0,0 +1,152 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import java.util.Date; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QueryTaskInfoResponse { + + // event_mesh_task_info + private Integer id; + + private String taskID; + + private String taskName; + + private String taskDesc; + + private String taskState; + + private String sourceRegion; + + private String targetRegion; + + private String createUid; + + private String updateUid; + + private Date createTime; + + private Date updateTime; + + List eventMeshJobInfoList; + + @Data + public static class EventMeshJobInfo { + // event_mesh_job_info + private Integer id; + + private String jobID; + + private String jobDesc; + + private String taskID; + + private String transportType; + + private Integer sourceData; + + private Integer targetData; + + private String jobState; + + private String jobType; + + // job request from region + private String fromRegion; + + // job actually running region + private String runningRegion; + + private String createUid; + + private String updateUid; + + private Date createTime; + + private Date updateTime; + + // private List eventMeshDataSource; + + private EventMeshDataSource dataSource; + + private EventMeshDataSource dataSink; + + private EventMeshMysqlPosition eventMeshMysqlPosition; + + } + + @Data + public static class EventMeshDataSource { + + private Integer id; + + private String dataType; + + private String description; + + private String configuration; + + private String configurationClass; + + private String region; + + private String createUid; + + private String updateUid; + + private Date createTime; + + private Date updateTime; + } + + @Data + public static class EventMeshMysqlPosition { + + private Integer id; + + private String jobID; + + private String serverUUID; + + private String address; + + private Long position; + + private String gtid; + + private String currentGtid; + + private Long timestamp; + + private String journalName; + + private Date createTime; + + private Date updateTime; + } + +} \ No newline at end of file diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/QueryTaskMonitorResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/QueryTaskMonitorResponse.java new file mode 100644 index 0000000000..432729a995 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/QueryTaskMonitorResponse.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import org.apache.eventmesh.common.remote.task.TaskMonitor; + +import java.util.List; + +import lombok.Data; + +@Data +public class QueryTaskMonitorResponse { + + private List taskMonitors; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/SimpleResponse.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/SimpleResponse.java new file mode 100644 index 0000000000..a4cdd52f99 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/response/SimpleResponse.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.response; + +import org.apache.eventmesh.common.remote.exception.ErrorCode; + +public class SimpleResponse extends BaseRemoteResponse { + /** + * just mean remote received or process success + */ + public static SimpleResponse success() { + return new SimpleResponse(); + } + + public static SimpleResponse fail(int errorCode, String msg) { + SimpleResponse response = new SimpleResponse(); + response.setErrorCode(errorCode); + response.setDesc(msg); + response.setSuccess(false); + return response; + } + + + /** + * build an error response. + * + * @param exception exception + * @return response + */ + public static SimpleResponse fail(Throwable exception) { + return fail(ErrorCode.INTERNAL_ERR, exception.getMessage()); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/task/TaskMonitor.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/task/TaskMonitor.java new file mode 100644 index 0000000000..6d303eec3b --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/remote/task/TaskMonitor.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.remote.task; + +import java.io.Serializable; +import java.util.Date; + +import lombok.Data; + +@Data +public class TaskMonitor implements Serializable { + private String taskID; + private String jobID; + private String address; + private String transportType; + private String connectorStage; + private long totalReqNum; + private long totalTimeCost; + private long maxTimeCost; + private long avgTimeCost; + private double tps; + private Date createTime; + private static final long serialVersionUID = 1L; + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/stubs/HeaderStub.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/stubs/HeaderStub.java new file mode 100644 index 0000000000..1782d46dd6 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/stubs/HeaderStub.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.stubs; + +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.utils.HttpConvertsUtils; + +import java.util.Map; + +public class HeaderStub extends Header { + + public String code; + public String eventmeshenv; + + @Override + public Map toMap() { + return new HttpConvertsUtils().httpMapConverts(this, new ProtocolKey(), new ProtocolKey.EventMeshInstanceKey()); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/AssertUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/AssertUtils.java new file mode 100644 index 0000000000..a9445ba505 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/AssertUtils.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Objects; + +/** + * Assert + */ +public final class AssertUtils { + + /** + * Assert obj is not null + * + * @param obj Object to test + * @param message error message + */ + public static void notNull(final Object obj, final String message) { + isTrue(Objects.nonNull(obj), message); + } + + /** + * Assert condition is true + * + * @param condition boolean to test + * @param message error message + */ + public static void isTrue(final Boolean condition, final String message) { + if (!Boolean.TRUE.equals(condition)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert str is not blank + * + * @param str String to test + * @param message error message + */ + public static void notBlank(final String str, final String message) { + isTrue(StringUtils.isNoneBlank(str), message); + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ConfigurationContextUtil.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ConfigurationContextUtil.java index 7478970d17..fede64d650 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ConfigurationContextUtil.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ConfigurationContextUtil.java @@ -17,6 +17,11 @@ package org.apache.eventmesh.common.utils; +import static org.apache.eventmesh.common.Constants.ADMIN; +import static org.apache.eventmesh.common.Constants.GRPC; +import static org.apache.eventmesh.common.Constants.HTTP; +import static org.apache.eventmesh.common.Constants.TCP; + import org.apache.eventmesh.common.config.CommonConfiguration; import java.util.List; @@ -32,13 +37,7 @@ public class ConfigurationContextUtil { private static final ConcurrentHashMap CONFIGURATION_MAP = new ConcurrentHashMap<>(); - public static final String HTTP = "HTTP"; - - public static final String TCP = "TCP"; - public static final String GRPC = "GRPC"; - - public static final List KEYS = Lists.newArrayList(HTTP, TCP, GRPC); - + public static final List KEYS = Lists.newArrayList(HTTP, TCP, GRPC, ADMIN); /** * Save http, tcp, grpc configuration at startup for global use. @@ -57,13 +56,12 @@ public static void putIfAbsent(String key, CommonConfiguration configuration) { * Get the configuration of the specified key mapping. * * @param key - * @return + * @return configuration of the specified key mapping */ public static CommonConfiguration get(String key) { return CONFIGURATION_MAP.get(key); } - /** * Removes all of the mappings from this map. */ diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/HttpConvertsUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/HttpConvertsUtils.java new file mode 100644 index 0000000000..7ac10bb862 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/HttpConvertsUtils.java @@ -0,0 +1,217 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; +import org.apache.eventmesh.common.protocol.http.header.Header; + +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpConvertsUtils { + + public Map httpMapConverts(Header header, ProtocolKey protocolKey) { + Map map = new HashMap<>(); + Class headerClass = header.getClass(); + Class protocolKeyClass = protocolKey.getClass(); + Field[] headerFields = headerClass.getDeclaredFields(); + Field[] protocolKeyFields = protocolKeyClass.getDeclaredFields(); + for (Field headerField : headerFields) { + headerField.setAccessible(true); + try { + final String headerFieldName = headerField.getName(); + final Object headerFieldValue = headerField.get(header); + for (Field protocolKeyField : protocolKeyFields) { + protocolKeyField.setAccessible(true); + final String protocolKeyValue = protocolKeyField.get(protocolKey).toString(); + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, protocolKeyValue)) { + map.put(protocolKeyValue, headerFieldValue); + } + } + + EnumSet clientInstanceKeys = EnumSet.allOf(ProtocolKey.ClientInstanceKey.class); + for (ProtocolKey.ClientInstanceKey clientInstanceKey : clientInstanceKeys) { + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, clientInstanceKey.getKey())) { + map.put(clientInstanceKey.getKey(), headerFieldValue); + } + } + } catch (IllegalAccessException e) { + log.error("http map conversion failed.", e); + } + } + return map; + } + + public Map httpMapConverts(Header header, ProtocolKey protocolKey, + ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey) { + Map map = new HashMap<>(); + Class headerClass = header.getClass(); + Class protocolKeyClass = protocolKey.getClass(); + Class eventMeshInstanceKeyClass = eventMeshInstanceKey.getClass(); + Field[] headerFields = headerClass.getDeclaredFields(); + Field[] protocolKeyFields = protocolKeyClass.getDeclaredFields(); + Field[] eventMeshInstanceKeyFields = eventMeshInstanceKeyClass.getDeclaredFields(); + for (Field headerField : headerFields) { + headerField.setAccessible(true); + try { + final String headerFieldName = headerField.getName(); + final Object headerFieldValue = headerField.get(header); + for (Field protocolKeyField : protocolKeyFields) { + protocolKeyField.setAccessible(true); + final String protocolKeyFieldValue = protocolKeyField.get(protocolKey).toString(); + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, protocolKeyFieldValue)) { + map.put(protocolKeyFieldValue, headerFieldValue); + } + } + + for (Field eventMeshInstanceKeyField : eventMeshInstanceKeyFields) { + eventMeshInstanceKeyField.setAccessible(true); + final String eventMeshInstanceKeyValue = eventMeshInstanceKeyField.get(eventMeshInstanceKey).toString(); + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, eventMeshInstanceKeyValue)) { + map.put(eventMeshInstanceKeyValue, headerFieldValue); + } + } + } catch (IllegalAccessException e) { + log.error("http map conversion failed.", e); + } + } + return map; + } + + public Header httpHeaderConverts(Header header, Map headerParam) { + Class headerClass = header.getClass(); + ProtocolKey protocolKey = new ProtocolKey(); + Class protocolKeyClass = protocolKey.getClass(); + Field[] protocolKeyFields = protocolKeyClass.getDeclaredFields(); + Field[] headerFields = headerClass.getDeclaredFields(); + + for (Field headerField : headerFields) { + headerField.setAccessible(true); + String headerFieldName = headerField.getName(); + try { + setFiledValue(header, headerParam, protocolKey, protocolKeyFields, headerField, headerFieldName); + + EnumSet clientInstanceKeys = EnumSet.allOf(ProtocolKey.ClientInstanceKey.class); + for (ProtocolKey.ClientInstanceKey clientInstanceKey : clientInstanceKeys) { + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, clientInstanceKey.getKey())) { + headerField.set(header, MapUtils.getString(headerParam, clientInstanceKey.getKey())); + } + } + } catch (IllegalAccessException e) { + log.error("http header builder conversion failed.", e); + } + } + return header; + } + + public Header httpHeaderConverts(Header header, Map headerParam, ProtocolKey.EventMeshInstanceKey eventMeshInstanceKey) { + Class headerClass = header.getClass(); + ProtocolKey protocolKey = new ProtocolKey(); + Class protocolKeyClass = protocolKey.getClass(); + Class eventMeshInstanceKeyClass = eventMeshInstanceKey.getClass(); + Field[] protocolKeyFields = protocolKeyClass.getDeclaredFields(); + Field[] headerFields = headerClass.getDeclaredFields(); + Field[] eventMeshInstanceKeyFields = eventMeshInstanceKeyClass.getDeclaredFields(); + for (Field headerField : headerFields) { + headerField.setAccessible(true); + String headerFieldName = headerField.getName(); + try { + setFiledValue(header, headerParam, protocolKey, protocolKeyFields, headerField, headerFieldName); + + for (Field eventMeshInstanceKeyField : eventMeshInstanceKeyFields) { + eventMeshInstanceKeyField.setAccessible(true); + final String eventMeshInstanceKeyValue = eventMeshInstanceKeyField.get(eventMeshInstanceKey).toString(); + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, eventMeshInstanceKeyValue)) { + headerField.set(header, MapUtils.getString(headerParam, eventMeshInstanceKeyValue)); + } + } + + } catch (IllegalAccessException e) { + log.error("http header builder conversion failed.", e); + } + } + return header; + } + + private void setFiledValue(Header header, Map headerParam, ProtocolKey protocolKey, + Field[] protocolKeyFields, Field headerField, + String headerFieldName) throws IllegalAccessException { + for (Field protocolKeyField : protocolKeyFields) { + protocolKeyField.setAccessible(true); + switch (headerFieldName) { + case ProtocolKey.VERSION: + ProtocolVersion protocolVersion = ProtocolVersion.get(MapUtils.getString(headerParam, ProtocolKey.VERSION)); + if (Objects.nonNull(protocolVersion)) { + headerField.set(header, protocolVersion); + } + break; + case ProtocolKey.LANGUAGE: + String language = StringUtils.isBlank(MapUtils.getString(headerParam, ProtocolKey.LANGUAGE)) + ? Constants.LANGUAGE_JAVA + : MapUtils.getString(headerParam, ProtocolKey.LANGUAGE); + headerField.set(header, language); + break; + default: + String protocolKeyValue = protocolKeyField.get(protocolKey).toString(); + // Use the attribute name to compare with the key value to achieve one-to-one correspondence and ignore case. + if (StringUtils.equalsIgnoreCase(headerFieldName, protocolKeyValue)) { + Object value = getValue(headerParam, protocolKeyValue); + if (Objects.nonNull(value)) { + headerField.set(header, value); + } + } + break; + } + } + } + + /** + * map.get(key) gets the value and determines the data type for the corresponding operation. + * @param headerParam map + * @param protocolKeyValue key + * @return value + */ + private Object getValue(Map headerParam, String protocolKeyValue) { + Object mapValue = headerParam.get(protocolKeyValue); + Object value = null; + if (mapValue instanceof Integer) { + value = MapUtils.getIntValue(headerParam, protocolKeyValue); + } else if (mapValue instanceof String) { + value = MapUtils.getString(headerParam, protocolKeyValue); + } + return value; + } + +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/IPUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/IPUtils.java index 2ee98daed0..dcef8f8243 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/IPUtils.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/IPUtils.java @@ -28,25 +28,29 @@ import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + import inet.ipaddr.HostName; import inet.ipaddr.IPAddress; import inet.ipaddr.IPAddressString; +@Slf4j public class IPUtils { - private static final Logger logger = LoggerFactory.getLogger(IPUtils.class); + @Getter + public static String localAddress = init(); - public static String getLocalAddress() { + private static String init() { // if the progress works under docker environment // return the host ip about this docker located from environment value String dockerHostIp = System.getenv("docker_host_ip"); @@ -54,25 +58,25 @@ public static String getLocalAddress() { return dockerHostIp; } - //priority of networkInterface when generating client ip + // priority of networkInterface when generating client ip String priority = System.getProperty("networkInterface.priority", "eth0 preferList = new ArrayList(); - for (String eth : priority.split("<")) { - preferList.add(eth); - } + List list = Arrays.asList(priority.split("<")); + ArrayList preferList = new ArrayList<>(list); NetworkInterface preferNetworkInterface = null; + boolean isInterfacePreferred = false; try { Enumeration enumeration1 = NetworkInterface.getNetworkInterfaces(); while (enumeration1.hasMoreElements()) { final NetworkInterface networkInterface = enumeration1.nextElement(); - if (!preferList.contains(networkInterface.getName())) { - continue; - } else if (preferNetworkInterface == null) { + String interfaceName = networkInterface.getName(); + if (!isInterfacePreferred && preferList.contains(interfaceName)) { + isInterfacePreferred = true; + } + if (preferNetworkInterface == null) { preferNetworkInterface = networkInterface; - } else if (preferList.indexOf(networkInterface.getName()) //get the networkInterface that has higher priority - > preferList.indexOf(preferNetworkInterface.getName())) { + } else if (preferList.indexOf(interfaceName) // get the networkInterface that has higher priority + > preferList.indexOf(preferNetworkInterface.getName())) { preferNetworkInterface = networkInterface; } } @@ -81,7 +85,7 @@ public static String getLocalAddress() { ArrayList ipv4Result = new ArrayList(); ArrayList ipv6Result = new ArrayList(); - if (preferNetworkInterface != null) { + if (preferNetworkInterface != null && isInterfacePreferred) { final Enumeration en = preferNetworkInterface.getInetAddresses(); getIpResult(ipv4Result, ipv6Result, en); } else { @@ -96,41 +100,34 @@ public static String getLocalAddress() { // prefer ipv4 if (!ipv4Result.isEmpty()) { for (String ip : ipv4Result) { - if (ip.startsWith("127.0") || ip.startsWith("192.168") || !isValidIPV4Address(ip)) { - continue; + if (isValidIPV4Address(ip) && !ip.startsWith("127.0") && !ip.startsWith("192.168")) { + return ip; } - - return ip; } return ipv4Result.get(ipv4Result.size() - 1); } else if (!ipv6Result.isEmpty()) { return ipv6Result.get(0); } - //If failed to find,fall back to localhost + // If failed to find,fall back to localhost final InetAddress localHost = InetAddress.getLocalHost(); return normalizeHostAddress(localHost); - } catch (SocketException e) { - e.printStackTrace(); - } catch (UnknownHostException e) { - e.printStackTrace(); + } catch (SocketException | UnknownHostException e) { + log.error("socket or unknown host exception:", e); } - return null; } public static boolean isValidIPV4Address(String ip) { // Regex for digit from 0 to 255. - String zeroTo255 - = "(\\d{1,2}|(0|1)\\" - + "d{2}|2[0-4]\\d|25[0-5])"; + String zeroTo255 = "(\\d{1,2}|(0|1)\\" + + "d{2}|2[0-4]\\d|25[0-5])"; - String regex - = zeroTo255 + "\\." - + zeroTo255 + "\\." - + zeroTo255 + "\\." - + zeroTo255; + String regex = zeroTo255 + "\\." + + zeroTo255 + "\\." + + zeroTo255 + "\\." + + zeroTo255; // Compile the ReGex Pattern p = Pattern.compile(regex); @@ -146,8 +143,7 @@ public static boolean isValidIPV4Address(String ip) { return m.matches(); } - private static void getIpResult(ArrayList ipv4Result, ArrayList ipv6Result, - Enumeration en) { + private static void getIpResult(Collection ipv4Result, Collection ipv6Result, Enumeration en) { while (en.hasMoreElements()) { final InetAddress address = en.nextElement(); if (!address.isLoopbackAddress()) { @@ -168,9 +164,8 @@ private static String normalizeHostAddress(final InetAddress localHost) { } } - public static String parseChannelRemoteAddr(final Channel channel) { - if (null == channel) { + if (channel == null) { return ""; } SocketAddress remote = channel.remoteAddress(); @@ -214,7 +209,7 @@ public static boolean isValidIp(String url) { return new IPAddressString(new URL(url).getHost()).isValid(); } } catch (Exception e) { - logger.warn("Invalid URL format url={}", url, e); + log.warn("Invalid URL format url={}", url, e); return false; } return true; @@ -229,7 +224,7 @@ public static IPAddress domain2Ip(String url) { String host = new URL(url).getHost(); return new HostName(host).getAddress(); } catch (MalformedURLException e) { - logger.error("Invalid URL format url={}", url, e); + log.error("Invalid URL format url={}", url, e); return null; } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonPathUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonPathUtils.java new file mode 100644 index 0000000000..175b322a80 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonPathUtils.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.exception.JsonException; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Strings; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.InvalidPathException; +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.ReadContext; +import com.jayway.jsonpath.internal.path.CompiledPath; +import com.jayway.jsonpath.internal.path.PathCompiler; +import com.jayway.jsonpath.spi.json.JacksonJsonProvider; + +public class JsonPathUtils { + + public static final String JSONPATH_SPLIT = "\\."; + public static final String JSONPATH_PREFIX = "$"; + public static final String JSONPATH_PREFIX_WITH_POINT = "$."; + public static final String JSONPATH_DATA = "$.data"; + private static final ObjectMapper STRICT_OBJECT_MAPPER = new ObjectMapper(); + + private static final Configuration JSON_PATH_CONFIG = Configuration.builder() + .jsonProvider(new JacksonJsonProvider(STRICT_OBJECT_MAPPER)) + .build(); + + public static boolean isEmptyJsonObject(String jsonString) { + try { + JsonNode jsonNode = STRICT_OBJECT_MAPPER.readTree(jsonString); + return jsonNode.isObject() && jsonNode.isEmpty(); + } catch (Exception e) { + throw new JsonException("INVALID_JSON_STRING", e); + } + } + + public static JsonNode parseStrict(String json) throws JsonException { + try { + JsonParser parser = STRICT_OBJECT_MAPPER.getFactory().createParser(json); + JsonNode result = STRICT_OBJECT_MAPPER.readTree(parser); + if (parser.nextToken() != null) { + // Check if there are more tokens after reading the root object + throw new JsonException("Additional tokens found after parsing: " + json); + } + return result; + } catch (Exception e) { + throw new JsonException("Json is not valid in strict way: " + json, e); + } + } + + public static String buildJsonString(String key, Object value) { + Map map = new HashMap<>(); + map.put(key, value); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(map); + } catch (JsonProcessingException e) { + return null; + } + } + + public static boolean isValidAndDefinite(String jsonPath) { + if (Strings.isNullOrEmpty(jsonPath) || !jsonPath.startsWith(JSONPATH_PREFIX)) { + return Boolean.FALSE; + } + CompiledPath compiledPath = null; + try { + compiledPath = (CompiledPath) PathCompiler.compile(jsonPath); + } catch (InvalidPathException e) { + return Boolean.FALSE; + } + return compiledPath.isDefinite(); + } + + public static String getJsonPathValue(String content, String jsonPath) { + if (Strings.isNullOrEmpty(content) || Strings.isNullOrEmpty(jsonPath)) { + throw new EventMeshException("invalid config" + jsonPath); + } + Object obj = null; + try { + obj = JsonPath.using(JSON_PATH_CONFIG).parse(content).read(jsonPath, JsonNode.class); + } catch (InvalidPathException invalidPathException) { + return null; + } + return obj.toString(); + } + + public static JsonNode convertToJsonNode(String object) throws JsonProcessingException { + return STRICT_OBJECT_MAPPER.readValue(object, JsonNode.class); + } + + public static String matchJsonPathValueWithString(String jsonString, String jsonPath) { + Object obj = jsonPathParse(jsonString, jsonPath); + + if (obj == null) { + return "null"; + } + + return obj.toString(); + } + + public static Object jsonPathParse(String jsonString, String jsonPath) { + if (Strings.isNullOrEmpty(jsonPath) || Strings.isNullOrEmpty(jsonString)) { + throw new EventMeshException("invalid config" + jsonPath); + } + Object obj = null; + try { + final ReadContext readContext = JsonPath.using(JSON_PATH_CONFIG).parse(jsonString); + obj = readContext.read(jsonPath); + } catch (InvalidPathException invalidPathException) { + return null; + } + return obj; + } + + public static String matchJsonPathValue(String jsonString, String jsonPath) throws JsonProcessingException { + Object obj = jsonPathParse(jsonString, jsonPath); + return STRICT_OBJECT_MAPPER.writer().writeValueAsString(obj); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonUtils.java index a9c3fc1154..9b1bfe6f4e 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonUtils.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/JsonUtils.java @@ -17,12 +17,26 @@ package org.apache.eventmesh.common.utils; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshDateFormat; import org.apache.eventmesh.common.exception.JsonException; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; /** * Json serialize or deserialize utils. @@ -32,7 +46,36 @@ public class JsonUtils { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); static { - OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + OBJECT_MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + OBJECT_MAPPER.setDateFormat(new EventMeshDateFormat(Constants.DATE_FORMAT_DEFAULT)); + OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); + OBJECT_MAPPER.registerModule(new JavaTimeModule()); + } + + public static T convertValue(Object fromValue, Class toValueType) { + return OBJECT_MAPPER.convertValue(fromValue, toValueType); + } + + public static T convertValue(Object fromValue, TypeReference toValueTypeRef) { + return OBJECT_MAPPER.convertValue(fromValue, toValueTypeRef); + } + + public static T mapToObject(Map map, Class beanClass) { + if (map == null) { + return null; + } + Object obj = OBJECT_MAPPER.convertValue(map, beanClass); + return beanClass.cast(obj); + } + + public static Map objectToMap(Object obj) { + if (obj == null) { + return null; + } + return OBJECT_MAPPER.convertValue(obj, new TypeReference>() { + }); } /** @@ -41,7 +84,10 @@ public class JsonUtils { * @param obj obj * @return json string */ - public static String serialize(Object obj) { + public static String toJSONString(Object obj) { + if (Objects.isNull(obj)) { + return null; + } try { return OBJECT_MAPPER.writeValueAsString(obj); } catch (JsonProcessingException e) { @@ -49,35 +95,126 @@ public static String serialize(Object obj) { } } + public static byte[] toJSONBytes(Object obj) { + if (Objects.isNull(obj)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsBytes(obj); + } catch (JsonProcessingException e) { + throw new JsonException("serialize to json error", e); + } + } + /** - * Deserialize json string to object. + * parse json string to object. * - * @param str json string - * @param clz object class - * @param object type + * @param text json string + * @param clazz object class + * @param object type * @return object */ - public static T deserialize(String str, Class clz) { + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (JsonProcessingException e) { + throw new JsonException("deserialize json string to object error", e); + } + } + + public static T parseObject(InputStream inputStream, Class clazz) { + try { + return OBJECT_MAPPER.readValue(inputStream, clazz); + } catch (IOException e) { + throw new JsonException("deserialize input stream to object error", e); + } + } + + public static T parseObject(String text, Type type) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + TypeReference typeReference = new TypeReference() { + + @Override + public Type getType() { + return type; + } + }; + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (JsonProcessingException e) { + throw new JsonException("deserialize json string to object error", e); + } + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (bytes == null || bytes.length == 0) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new JsonException(String.format("parse bytes to %s error", clazz), e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isEmpty(text)) { + return null; + } try { - return OBJECT_MAPPER.readValue(str, clz); + return OBJECT_MAPPER.readValue(text, typeReference); } catch (JsonProcessingException e) { throw new JsonException("deserialize json string to object error", e); } } /** - * Deserialize json string to object. + * parse json string to object. * - * @param str json string + * @param text json string * @param typeReference object type reference * @param object type * @return object */ - public static T deserialize(String str, TypeReference typeReference) { + public static T parseTypeReferenceObject(String text, TypeReference typeReference) { + if (StringUtils.isEmpty(text)) { + return null; + } try { - return OBJECT_MAPPER.readValue(str, typeReference); + return OBJECT_MAPPER.readValue(text, typeReference); } catch (JsonProcessingException e) { - throw new JsonException("deserialize json string to object error", e); + throw new JsonException("deserialize json string to typeReference error", e); + } + } + + public static T parseTypeReferenceObject(Object object, TypeReference typeReference) { + if (object == null) { + return null; + } + return convertValue(object, typeReference); + } + + public static T parseTypeReferenceObject(byte[] text, TypeReference typeReference) { + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new JsonException("deserialize json string to typeReference error", e); + } + } + + public static JsonNode getJsonNode(String text) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readTree(text); + } catch (JsonProcessingException e) { + throw new JsonException("deserialize json string to JsonNode error", e); } } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/LogUtil.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/LogUtil.java new file mode 100644 index 0000000000..8c8dec2122 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/LogUtil.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.util.function.Supplier; + +import org.slf4j.Logger; +import org.slf4j.spi.CallerBoundaryAware; +import org.slf4j.spi.LoggingEventBuilder; + +import lombok.experimental.UtilityClass; + +/** + * This class provides logging methods that encapsulate SLF4J and Supplier. + * If the log level is not enabled, the passed Supplier is invoked lazily, + * thereby avoiding unnecessary method execution time. + *

+ * The statement + *

+ * {@code
+ * LogUtil.debug(log, "A time-consuming method: {}", () -> myMethod());
+ * }
+ * 
+ * is equivalent to: + *
+ * {@code
+ * if (logger.isDebugEnabled()) {
+ *     logger.debug("A time-consuming method: {}", myMethod());
+ * }
+ * }
+ * 
+ * If no object parameters are passed or existing objects are referenced, use + *
+ * {@code
+ * log.debug("No time-consuming methods: {}", myObject);
+ * }
+ * 
+ * instead. + */ + +@UtilityClass +public final class LogUtil { + + private static final String FQCN = LogUtil.class.getName(); + + public static void debug(Logger logger, String format, Supplier objectSupplier) { + final LoggingEventBuilder builder = logger.atDebug(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + builder.addArgument(objectSupplier).log(format); + } + + public static void debug(Logger logger, String format, Supplier objectSupplier, Throwable t) { + final LoggingEventBuilder builder = logger.atDebug(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + builder.addArgument(objectSupplier).setCause(t).log(format); + } + + public static void debug(Logger logger, String format, Supplier... objectSuppliers) { + LoggingEventBuilder builder = logger.atDebug(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + for (Supplier objectSupplier : objectSuppliers) { + builder = builder.addArgument(objectSupplier); + } + builder.log(format); + } + + public static void info(Logger logger, String format, Supplier objectSupplier) { + final LoggingEventBuilder builder = logger.atInfo(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + builder.addArgument(objectSupplier).log(format); + } + + public static void info(Logger logger, String format, Supplier objectSupplier, Throwable t) { + final LoggingEventBuilder builder = logger.atInfo(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + builder.addArgument(objectSupplier).setCause(t).log(format); + } + + public static void info(Logger logger, String format, Supplier... objectSuppliers) { + LoggingEventBuilder builder = logger.atInfo(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + for (Supplier objectSupplier : objectSuppliers) { + builder = builder.addArgument(objectSupplier); + } + builder.log(format); + } + + public static void warn(Logger logger, String format, Supplier objectSupplier) { + final LoggingEventBuilder builder = logger.atWarn(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + builder.addArgument(objectSupplier).log(format); + } + + public static void warn(Logger logger, String format, Supplier objectSupplier, Throwable t) { + final LoggingEventBuilder builder = logger.atWarn(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + builder.addArgument(objectSupplier).setCause(t).log(format); + } + + public static void warn(Logger logger, String format, Supplier... objectSuppliers) { + LoggingEventBuilder builder = logger.atWarn(); + if (builder instanceof CallerBoundaryAware) { + ((CallerBoundaryAware) builder).setCallerBoundary(FQCN); + } + for (Supplier objectSupplier : objectSuppliers) { + builder = builder.addArgument(objectSupplier); + } + builder.log(format); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java new file mode 100644 index 0000000000..2683deaa84 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/NetUtils.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.eventmesh.common.Constants; + +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; + +/** + * NetUtils + */ +@Slf4j +public class NetUtils { + + /** + * Transform the url form string to Map + * + * @param formData + * @return url parameters map + */ + public static Map formData2Dic(String formData) { + if (StringUtils.isBlank(formData)) { + return new HashMap<>(); + } + final String[] items = formData.split(Constants.AND); + Map result = new HashMap<>(items.length); + Arrays.stream(items).forEach(item -> { + final String[] keyAndVal = item.split(Constants.EQ); + if (keyAndVal.length == 2) { + try { + final String key = URLDecoder.decode(keyAndVal[0], Constants.DEFAULT_CHARSET.name()); + final String val = URLDecoder.decode(keyAndVal[1], Constants.DEFAULT_CHARSET.name()); + result.put(key, val); + } catch (UnsupportedEncodingException e) { + log.warn("formData2Dic:param decode failed...", e); + } + } + }); + return result; + } + + public static String addressToString(Collection clients) { + if (clients.isEmpty()) { + return "no session had been closed"; + } + StringBuilder sb = new StringBuilder(); + for (InetSocketAddress addr : clients) { + sb.append(addr).append(Constants.VERTICAL_LINE); + } + return sb.toString(); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/PagedList.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/PagedList.java new file mode 100644 index 0000000000..322c585f04 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/PagedList.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.util.List; + +public class PagedList { + private int totalSize; + private int totalPage; + private int size; + private int page; + + private List data; + + public int getTotalSize() { + return totalSize; + } + + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public int getPage() { + return page; + } + + public void setPage(int page) { + this.page = page; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/PropertiesUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/PropertiesUtils.java new file mode 100644 index 0000000000..ba7880ad04 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/PropertiesUtils.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.eventmesh.common.Constants; + +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Properties; + +import com.google.common.base.Preconditions; + +public class PropertiesUtils { + + public static Properties getPropertiesByPrefix(final Properties from, final String prefix) { + + Properties to = new Properties(); + if (StringUtils.isBlank(prefix) || from == null) { + return to; + } + + from.forEach((key, value) -> { + String keyStr = String.valueOf(key); + if (StringUtils.startsWith(keyStr, prefix)) { + String realKey = StringUtils.substring(keyStr, prefix.length()); + String[] hierarchicalKeys = StringUtils.split(realKey, Constants.DOT); + if (hierarchicalKeys != null) { + Properties hierarchical = to; + for (int idx = 0; idx < hierarchicalKeys.length; idx++) { + String hierarchicalKey = hierarchicalKeys[idx]; + if (StringUtils.isBlank(hierarchicalKey)) { + return; + } + if (idx < hierarchicalKeys.length - 1) { + Object pending = hierarchical.get(hierarchicalKey); + if (pending == null) { + hierarchical.put(hierarchicalKey, hierarchical = new Properties()); + } else if (pending instanceof Properties) { + hierarchical = (Properties) pending; + } else { + // Not Properties No need to parse anymore. + return; + } + } else { + hierarchical.put(hierarchicalKey, value); + } + } + } + } + }); + return to; + } + + /** + * Load properties from file when file is exist + * + * @param properties + * @param path + * @param cs + * @throws IOException Exception when loading properties, like illegal content, file permission denies + */ + public static void loadPropertiesWhenFileExist(Properties properties, String path, Charset cs) throws IOException { + Preconditions.checkNotNull(properties, "Properties can not be null"); + File file = new File(path); + if (!file.exists()) { + return; + } + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(file), cs))) { + properties.load(reader); + } + } + + /** + * Load properties from file when file is exist + * + * @param properties + * @param path + * @throws IOException Exception when loading properties, like illegal content, file permission denies + */ + public static void loadPropertiesWhenFileExist(Properties properties, String path) throws IOException { + loadPropertiesWhenFileExist(properties, path, StandardCharsets.UTF_8); + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/RandomStringUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/RandomStringUtils.java index bc14554196..195d721809 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/RandomStringUtils.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/RandomStringUtils.java @@ -19,13 +19,19 @@ import org.apache.commons.text.RandomStringGenerator; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + public class RandomStringUtils { - private static final RandomStringGenerator RANDOM_NUM_GENERATOR = new RandomStringGenerator.Builder() - .withinRange('0', '9').build(); + private static final RandomStringGenerator RANDOM_NUM_GENERATOR = new RandomStringGenerator.Builder().withinRange('0', '9').build(); public static String generateNum(int length) { return RANDOM_NUM_GENERATOR.generate(length); } + public static String generateUUID() { + return new UUID(ThreadLocalRandom.current().nextLong(), ThreadLocalRandom.current().nextLong()).toString(); + } + } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ReflectUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ReflectUtils.java new file mode 100644 index 0000000000..7dd1205684 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ReflectUtils.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class ReflectUtils { + + /** + * Look up not private fields inherited from the parent class. + * + * @param clazz + * @param fieldName + * @return + */ + public static Field lookUpFieldByParentClass(Class clazz, String fieldName) { + Class superClass = clazz.getSuperclass(); + while (superClass != null) { + Field[] superFields = superClass.getDeclaredFields(); + for (Field superField : superFields) { + if (!Modifier.isPrivate(superField.getModifiers()) && superField.getName().equals(fieldName)) { + return superField; + } + } + superClass = superClass.getSuperclass(); + } + return null; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/SystemUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/SystemUtils.java new file mode 100644 index 0000000000..c01dc8c2be --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/SystemUtils.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; + +public abstract class SystemUtils { + + public static final String OS_NAME = System.getProperty("os.name"); + + private static boolean isLinuxPlatform = false; + + private static boolean isWindowsPlatform = false; + + static { + if (OS_NAME != null && OS_NAME.toLowerCase().contains("linux")) { + isLinuxPlatform = true; + } + + if (OS_NAME != null && OS_NAME.toLowerCase().contains("windows")) { + isWindowsPlatform = true; + } + } + + private SystemUtils() { + + } + + public static boolean isLinuxPlatform() { + return isLinuxPlatform; + } + + public static boolean isWindowsPlatform() { + return isWindowsPlatform; + } + + public static String getProcessId() { + try { + // likely works on most platforms + final Class managementFactoryClass = Class.forName("java.lang.management.ManagementFactory"); + final Method getRuntimeMXBean = managementFactoryClass.getDeclaredMethod("getRuntimeMXBean"); + final Class runtimeMXBeanClass = Class.forName("java.lang.management.RuntimeMXBean"); + final Method getName = runtimeMXBeanClass.getDeclaredMethod("getName"); + + final Object runtimeMXBean = getRuntimeMXBean.invoke(null); + final String name = (String) getName.invoke(runtimeMXBean); + + return name.split("@")[0]; + } catch (final Exception ex) { + try { + // try a Linux-specific way + return new File("/proc/self").getCanonicalFile().getName(); + } catch (final IOException ignoredUseDefault) { + // Ignore exception. + } + } + return "-1"; + } +} diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ThreadUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ThreadUtils.java index af69f08508..72447509e1 100644 --- a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ThreadUtils.java +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/ThreadUtils.java @@ -17,23 +17,49 @@ package org.apache.eventmesh.common.utils; -import org.apache.logging.log4j.util.ProcessIdUtil; - import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; public class ThreadUtils { private static volatile long currentPID = -1; - public static void randomSleep(int min, int max) throws Exception { + public static void randomPause(long min, long max) { + randomPause(min, max, TimeUnit.MILLISECONDS); + } + + public static void randomPause(long min, long max, TimeUnit timeUnit) { // nextInt is normally exclusive of the top value, so add 1 to make it inclusive - int random = ThreadLocalRandom.current().nextInt(min, max + 1); - Thread.sleep(random); + try { + long timeout = ThreadLocalRandom.current().nextLong(min, max + 1); + timeUnit.sleep(timeout); + } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + } + } + public static void randomPause(long max) { + randomPause(1, max); } - public static void randomSleep(int max) throws Exception { - randomSleep(1, max); + @Deprecated + public static void sleep(long timeout) { + sleep(timeout, TimeUnit.MILLISECONDS); + } + + public static void sleep(long timeout, TimeUnit timeUnit) { + try { + sleepWithThrowException(timeout, timeUnit); + } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + } + } + + public static void sleepWithThrowException(long timeout, TimeUnit timeUnit) throws InterruptedException { + if (timeUnit == null) { + return; + } + timeUnit.sleep(timeout); } /** @@ -45,7 +71,7 @@ public static long getPID() { if (currentPID == -1) { synchronized (ThreadUtils.class) { if (currentPID == -1) { - currentPID = Long.parseLong(ProcessIdUtil.getProcessId()); + currentPID = Long.parseLong(SystemUtils.getProcessId()); } } } diff --git a/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/TypeUtils.java b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/TypeUtils.java new file mode 100644 index 0000000000..bac2365a81 --- /dev/null +++ b/eventmesh-common/src/main/java/org/apache/eventmesh/common/utils/TypeUtils.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.util.HashSet; +import java.util.Set; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class TypeUtils { + + public static Set castSet(Object obj, Class clazz) { + Set result = new HashSet<>(); + if (obj instanceof Set) { + for (Object o : (Set) obj) { + result.add(clazz.cast(o)); + } + return result; + } + return null; + } +} diff --git a/eventmesh-common/src/main/resources/META-INF/services/org.apache.eventmesh.common.remote.payload.IPayload b/eventmesh-common/src/main/resources/META-INF/services/org.apache.eventmesh.common.remote.payload.IPayload new file mode 100644 index 0000000000..433cf57ed1 --- /dev/null +++ b/eventmesh-common/src/main/resources/META-INF/services/org.apache.eventmesh.common.remote.payload.IPayload @@ -0,0 +1,23 @@ +# 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. + +org.apache.eventmesh.common.remote.request.FetchJobRequest +org.apache.eventmesh.common.remote.response.FetchJobResponse +org.apache.eventmesh.common.remote.request.ReportPositionRequest +org.apache.eventmesh.common.remote.request.ReportJobRequest +org.apache.eventmesh.common.remote.request.ReportVerifyRequest +org.apache.eventmesh.common.remote.request.ReportHeartBeatRequest +org.apache.eventmesh.common.remote.request.FetchPositionRequest +org.apache.eventmesh.common.remote.response.FetchPositionResponse \ No newline at end of file diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshMessageTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshMessageTest.java index b0df5405f3..d6a9a22325 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshMessageTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshMessageTest.java @@ -20,55 +20,53 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class EventMeshMessageTest { @Test public void testGetProp() { - EventMeshMessage message = createLiteMessage(); - Assert.assertEquals(2L, message.getProp().size()); + EventMeshMessage message = createEventMeshMessage(); + Assertions.assertEquals(2L, message.getProp().size()); } @Test public void testSetProp() { - EventMeshMessage message = createLiteMessage(); + EventMeshMessage message = createEventMeshMessage(); Map prop = new HashMap<>(); prop.put("key3", "value3"); message.setProp(prop); - Assert.assertEquals(1L, message.getProp().size()); - Assert.assertEquals("value3", message.getProp("key3")); + Assertions.assertEquals(1L, message.getProp().size()); + Assertions.assertEquals("value3", message.getProp("key3")); } @Test public void testAddProp() { - EventMeshMessage message = createLiteMessage(); + EventMeshMessage message = createEventMeshMessage(); message.addProp("key3", "value3"); - Assert.assertEquals(3L, message.getProp().size()); - Assert.assertEquals("value1", message.getProp("key1")); + Assertions.assertEquals(3L, message.getProp().size()); + Assertions.assertEquals("value1", message.getProp("key1")); } @Test public void testGetPropKey() { - EventMeshMessage message = createLiteMessage(); - Assert.assertEquals("value1", message.getProp("key1")); + EventMeshMessage message = createEventMeshMessage(); + Assertions.assertEquals("value1", message.getProp("key1")); } @Test public void testRemoveProp() { - EventMeshMessage message = createLiteMessage(); + EventMeshMessage message = createEventMeshMessage(); message.removePropIfPresent("key1"); - Assert.assertEquals(1L, message.getProp().size()); - Assert.assertNull(message.getProp("key1")); + Assertions.assertEquals(1L, message.getProp().size()); + Assertions.assertNull(message.getProp("key1")); } - private EventMeshMessage createLiteMessage() { + private EventMeshMessage createEventMeshMessage() { Map prop = new HashMap<>(); prop.put("key1", "value1"); prop.put("key2", "value2"); - return EventMeshMessage.builder() - .prop(prop) - .build(); + return EventMeshMessage.builder().prop(prop).build(); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshThreadFactoryTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshThreadFactoryTest.java new file mode 100644 index 0000000000..d0cd7d1d18 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/EventMeshThreadFactoryTest.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class EventMeshThreadFactoryTest { + + @Test + public void testGetThreadNamePrefix() { + final String threadNamePrefix = "threadNamePrefix"; + EventMeshThreadFactory factory = new EventMeshThreadFactory(threadNamePrefix, false); + Assertions.assertEquals(threadNamePrefix, factory.getThreadNamePrefix()); + } + + @Test + public void testNewThread() { + final String threadNamePrefix = "threadNamePrefix"; + EventMeshThreadFactory factory = new EventMeshThreadFactory(threadNamePrefix, true); + Thread t = factory.newThread(() -> { + + }); + Assertions.assertNotNull(t); + Assertions.assertEquals(threadNamePrefix + "-1", t.getName()); + Assertions.assertTrue(t.isDaemon()); + } +} \ No newline at end of file diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/ResetCountDownLatchTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/ResetCountDownLatchTest.java new file mode 100644 index 0000000000..5b8cdce510 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/ResetCountDownLatchTest.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +public class ResetCountDownLatchTest { + + @Test + public void testConstructorParameterError() { + IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class, () -> new ResetCountDownLatch(-1)); + Assertions.assertEquals(e.getMessage(), "count must be greater than or equal to 0"); + ResetCountDownLatch resetCountDownLatch = new ResetCountDownLatch(1); + Assertions.assertEquals(1, resetCountDownLatch.getCount()); + } + + @Test + public void testAwaitTimeout() throws InterruptedException { + ResetCountDownLatch latch = new ResetCountDownLatch(1); + boolean await = latch.await(5, TimeUnit.MILLISECONDS); + Assertions.assertFalse(await); + latch.countDown(); + await = latch.await(5, TimeUnit.MILLISECONDS); + Assertions.assertTrue(await); + } + + @Test + @Timeout(1000) + public void testCountDownAndGetCount() throws InterruptedException { + int count = 2; + ResetCountDownLatch resetCountDownLatch = new ResetCountDownLatch(count); + Assertions.assertEquals(count, resetCountDownLatch.getCount()); + resetCountDownLatch.countDown(); + Assertions.assertEquals(count - 1, resetCountDownLatch.getCount()); + resetCountDownLatch.countDown(); + resetCountDownLatch.await(); + Assertions.assertEquals(0, resetCountDownLatch.getCount()); + } + + @Test + public void testReset() throws InterruptedException { + int count = 2; + ResetCountDownLatch resetCountDownLatch = new ResetCountDownLatch(count); + resetCountDownLatch.countDown(); + Assertions.assertEquals(count - 1, resetCountDownLatch.getCount()); + resetCountDownLatch.reset(); + Assertions.assertEquals(count, resetCountDownLatch.getCount()); + resetCountDownLatch.countDown(); + resetCountDownLatch.countDown(); + resetCountDownLatch.await(); + Assertions.assertEquals(0, resetCountDownLatch.getCount()); + resetCountDownLatch.countDown(); + Assertions.assertEquals(0, resetCountDownLatch.getCount()); + resetCountDownLatch.reset(); + resetCountDownLatch.countDown(); + Assertions.assertEquals(1, resetCountDownLatch.getCount()); + + } +} \ No newline at end of file diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/ThreadWrapperTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/ThreadWrapperTest.java new file mode 100644 index 0000000000..a4f2a60f73 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/ThreadWrapperTest.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ThreadWrapperTest { + + @Test + public void getThreadName() { + ThreadWrapper wrapper = createThreadWrapper(false); + wrapper.start(); + Assertions.assertEquals("EventMesh-Wrapper-mxsm", wrapper.thread.getName()); + } + + @Test + public void start() { + ThreadWrapper wrapper = createThreadWrapper(false); + wrapper.start(); + Assertions.assertTrue(wrapper.isStated()); + } + + @Test + @Timeout(1000) + public void await() { + ThreadWrapper wrapper = createThreadWrapper(false); + wrapper.start(); + wrapper.await(1, TimeUnit.MILLISECONDS); + Assertions.assertFalse(wrapper.hasWakeup.get()); + wrapper.wakeup(); + Assertions.assertTrue(wrapper.hasWakeup.get()); + wrapper.await(); + Assertions.assertFalse(wrapper.hasWakeup.get()); + wrapper.await(2, TimeUnit.MILLISECONDS); + + } + + @Test + public void wakeup() { + } + + @Test + public void shutdown() { + AtomicInteger counter = new AtomicInteger(); + ThreadWrapper wrapper = new ThreadWrapper() { + + @Override + public String getThreadName() { + return "EventMesh-Wrapper-mxsm"; + } + + @Override + public void run() { + try { + TimeUnit.MILLISECONDS.sleep(500); + } catch (InterruptedException e) { + log.error("[ThreadWrapperTest][shutdown] InterruptedException", e); + } + counter.set(100); + } + }; + wrapper.start(); + wrapper.shutdown(); + Assertions.assertEquals(100, counter.get()); + } + + @Test + public void shutdownImmediately() { + AtomicInteger counter = new AtomicInteger(); + ThreadWrapper wrapper = new ThreadWrapper() { + + @Override + public String getThreadName() { + return "EventMesh-Wrapper-mxsm"; + } + + @Override + public void run() { + try { + TimeUnit.SECONDS.sleep(100); + } catch (InterruptedException e) { + return; + } + counter.set(100); + } + }; + wrapper.start(); + wrapper.shutdownImmediately(); + Assertions.assertEquals(0, counter.get()); + } + + @Test + public void setDaemon() { + ThreadWrapper threadWrapper = createThreadWrapper(true); + threadWrapper.start(); + Assertions.assertTrue(threadWrapper.thread.isDaemon()); + + ThreadWrapper threadWrapper1 = createThreadWrapper(false); + threadWrapper1.start(); + Assertions.assertFalse(threadWrapper1.thread.isDaemon()); + } + + private ThreadWrapper createThreadWrapper(boolean daemon) { + ThreadWrapper wrapper = new ThreadWrapper() { + + @Override + public String getThreadName() { + return "EventMesh-Wrapper-mxsm"; + } + + @Override + public void run() { + // nothing to do + } + }; + wrapper.setDaemon(daemon); + return wrapper; + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/CommonConfigurationTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/CommonConfigurationTest.java index 68ee8659ca..ce173d3ffe 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/CommonConfigurationTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/CommonConfigurationTest.java @@ -17,29 +17,57 @@ package org.apache.eventmesh.common.config; -import java.io.File; +import java.util.ArrayList; +import java.util.List; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class CommonConfigurationTest { - private CommonConfiguration configuration; + public CommonConfiguration config; - @Before - public void before() { - String file = ConfigurationWrapperTest.class.getResource("/configuration.properties").getFile(); - File f = new File(file); - ConfigurationWrapper wraper = new ConfigurationWrapper(f.getParent(), f.getName(), false); - configuration = new CommonConfiguration(wraper); + @BeforeEach + public void beforeCommonConfigurationTest() throws Exception { + ConfigService configService = ConfigService.getInstance(); + configService.setRootConfig("classPath://configuration.properties"); + + config = configService.buildConfigInstance(CommonConfiguration.class); + + testGetCommonConfiguration(); } @Test - public void testInit() { - configuration.init(); - Assert.assertEquals("value1", configuration.eventMeshEnv); - Assert.assertEquals("value2", configuration.eventMeshIDC); - Assert.assertEquals("3", configuration.sysID); + public void testGetCommonConfiguration() { + Assertions.assertEquals("env-succeed!!!", config.getEventMeshEnv()); + Assertions.assertEquals("idc-succeed!!!", config.getEventMeshIDC()); + Assertions.assertEquals("cluster-succeed!!!", config.getEventMeshCluster()); + Assertions.assertEquals("name-succeed!!!", config.getEventMeshName()); + Assertions.assertEquals("816", config.getSysID()); + Assertions.assertEquals("storage-succeed!!!", config.getEventMeshStoragePluginType()); + Assertions.assertEquals("storage-succeed!!!", config.getEventMeshStoragePluginType()); + Assertions.assertEquals("security-succeed!!!", config.getEventMeshSecurityPluginType()); + Assertions.assertEquals("metaStorage-succeed!!!", config.getEventMeshMetaStoragePluginType()); + Assertions.assertEquals("trace-succeed!!!", config.getEventMeshTracePluginType()); + Assertions.assertEquals("hostIp-succeed!!!", config.getEventMeshServerIp()); + Assertions.assertEquals("username-succeed!!!", config.getEventMeshMetaStoragePluginUsername()); + Assertions.assertEquals("password-succeed!!!", config.getEventMeshMetaStoragePluginPassword()); + + List list = new ArrayList<>(); + list.add("metrics-succeed1!!!"); + list.add("metrics-succeed2!!!"); + list.add("metrics-succeed3!!!"); + Assertions.assertEquals(list, config.getEventMeshMetricsPluginType()); + + List list1 = new ArrayList<>(); + list1.add("TCP"); + list1.add("HTTP"); + list1.add("GRPC"); + Assertions.assertEquals(list1, config.getEventMeshProvideServerProtocols()); + + Assertions.assertTrue(config.isEventMeshServerSecurityEnable()); + Assertions.assertTrue(config.isEventMeshServerMetaStorageEnable()); + Assertions.assertTrue(config.isEventMeshServerTraceEnable()); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/ConfigServiceTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/ConfigServiceTest.java new file mode 100644 index 0000000000..992800625c --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/ConfigServiceTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config; + +import static org.apache.eventmesh.common.config.ConfigService.CLASS_PATH_PREFIX; +import static org.apache.eventmesh.common.config.ConfigService.FILE_PATH_PREFIX; + +import java.io.File; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ConfigServiceTest { + + private final String configFileName = "configuration.properties"; + + @Test + public void getConfigByRootConfig() throws Exception { + + ConfigService configService = ConfigService.getInstance(); + configService.setRootConfig(CLASS_PATH_PREFIX + configFileName); + + ConfigInfo configInfo = new ConfigInfo(); + configInfo.setClazz(CommonConfiguration.class); + configInfo.setPrefix(CommonConfiguration.class.getAnnotation(Config.class).prefix()); + + CommonConfiguration config = configService.getConfig(configInfo); + assertCommonConfiguration(config); + } + + @Test + public void getConfigByClassPath() throws Exception { + ConfigService configService = ConfigService.getInstance(); + + ConfigInfo configInfo = new ConfigInfo(); + configInfo.setPath(CLASS_PATH_PREFIX + configFileName); + configInfo.setClazz(CommonConfiguration.class); + configInfo.setPrefix(CommonConfiguration.class.getAnnotation(Config.class).prefix()); + + CommonConfiguration config = configService.getConfig(configInfo); + assertCommonConfiguration(config); + } + + @Test + public void getConfigByFilePath() throws Exception { + ConfigService configService = ConfigService.getInstance(); + String rootPath = new File(this.getClass().getResource("/" + configFileName).getPath()).getParent(); + + ConfigInfo configInfo = new ConfigInfo(); + configInfo.setPath(FILE_PATH_PREFIX + rootPath + "/" + configFileName); + configInfo.setClazz(CommonConfiguration.class); + configInfo.setPrefix(CommonConfiguration.class.getAnnotation(Config.class).prefix()); + + CommonConfiguration config = configService.getConfig(configInfo); + assertCommonConfiguration(config); + } + + @Test + public void getConfigByConfigPath() throws Exception { + ConfigService configService = ConfigService.getInstance(); + String configPath = new File(this.getClass().getResource("/" + configFileName).getPath()).getParent(); + + configService.setConfigPath(configPath); + ConfigInfo configInfo = new ConfigInfo(); + configInfo.setPath("/" + configFileName); + configInfo.setClazz(CommonConfiguration.class); + configInfo.setPrefix(CommonConfiguration.class.getAnnotation(Config.class).prefix()); + + CommonConfiguration config = configService.getConfig(configInfo); + assertCommonConfiguration(config); + } + + public void assertCommonConfiguration(CommonConfiguration config) { + Assertions.assertEquals("env-succeed!!!", config.getEventMeshEnv()); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/ConfigurationWrapperTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/ConfigurationWrapperTest.java deleted file mode 100644 index 73503dc1ea..0000000000 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/ConfigurationWrapperTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.common.config; - -import java.io.File; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ConfigurationWrapperTest { - - private ConfigurationWrapper wraper; - - @Before - public void before() { - String file = ConfigurationWrapperTest.class.getResource("/configuration.properties").getFile(); - File f = new File(file); - wraper = new ConfigurationWrapper(f.getParent(), f.getName(), false); - } - - @Test - public void testGetProp() { - Assert.assertEquals("value1", wraper.getProp("eventMesh.server.env")); - Assert.assertEquals("value2", wraper.getProp("eventMesh.server.idc")); - } -} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/convert/converter/ObjectConverterTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/convert/converter/ObjectConverterTest.java new file mode 100644 index 0000000000..30cc4bad92 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/config/convert/converter/ObjectConverterTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.config.convert.converter; + +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.common.config.ConfigInfo; +import org.apache.eventmesh.common.config.convert.ConvertInfo; + +import java.lang.reflect.Field; +import java.util.Properties; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import lombok.Data; + +public class ObjectConverterTest { + + @Test + public void testConvert() { + Properties properties = new Properties(); + properties.put("name", "test"); + properties.put("age", "18"); + + ConfigInfo configInfo = new ConfigInfo(); + + ConvertInfo convertInfo = new ConvertInfo(); + convertInfo.setProperties(properties); + convertInfo.setConfigInfo(configInfo); + convertInfo.setClazz(User.class); + + ObjectConverter converter = new ObjectConverter(); + Object converted = converter.convert(convertInfo); + Assertions.assertTrue(converted instanceof User); + User user = (User) converted; + Assertions.assertEquals("test", user.getName()); + Assertions.assertEquals(18, user.getAge()); + } + + @Test + public void testConvertWithField() throws NoSuchFieldException { + Properties properties = new Properties(); + properties.put("name", "test"); + properties.put("age", "18"); + + ConfigInfo configInfo = new ConfigInfo(); + + ConvertInfo convertInfo = new ConvertInfo(); + convertInfo.setProperties(properties); + convertInfo.setConfigInfo(configInfo); + + Field field = Config.class.getDeclaredField("user"); + convertInfo.setField(field); + convertInfo.setClazz(User.class); + + ObjectConverter converter = new ObjectConverter(); + Object converted = converter.convert(convertInfo); + Assertions.assertTrue(converted instanceof User); + User user = (User) converted; + Assertions.assertEquals("test", user.getName()); + Assertions.assertEquals(18, user.getAge()); + } + + @Data + public static class User { + @ConfigField(field = "name") + private String name; + @ConfigField(field = "age") + private int age; + } + + @Data + public static class Config { + @ConfigField(field = "") + private User user; + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/file/WatchFileManagerTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/file/WatchFileManagerTest.java index 614138a4a3..0d3163de44 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/file/WatchFileManagerTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/file/WatchFileManagerTest.java @@ -22,37 +22,48 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; import java.util.Properties; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentMatcher; +import org.mockito.Mockito; public class WatchFileManagerTest { + @TempDir + File tempConfigDir; + @Test public void testWatchFile() throws IOException, InterruptedException { String file = WatchFileManagerTest.class.getResource("/configuration.properties").getFile(); - File f = new File(file); - final FileChangeListener fileChangeListener = new FileChangeListener() { - @Override - public void onChanged(FileChangeContext changeContext) { - Assert.assertEquals(f.getName(), changeContext.getFileName()); - Assert.assertEquals(f.getParent(), changeContext.getDirectoryPath()); - } - - @Override - public boolean support(FileChangeContext changeContext) { - return changeContext.getWatchEvent().context().toString().contains(f.getName()); - } - }; - WatchFileManager.registerFileChangeListener(f.getParent(), fileChangeListener); + File configFile = new File(file); + File tempConfigFile = new File(tempConfigDir, "configuration.properties"); + Files.copy(configFile.toPath(), tempConfigFile.toPath()); + + final FileChangeListener mockFileChangeListener = Mockito.mock(FileChangeListener.class); + Mockito.when(mockFileChangeListener.support( + Mockito.argThat(isFileUnderTest(tempConfigFile.getParent(), tempConfigFile.getName()))) + ).thenReturn(true); + + WatchFileManager.registerFileChangeListener(tempConfigFile.getParent(), mockFileChangeListener); Properties properties = new Properties(); - properties.load(new BufferedReader(new FileReader(file))); - properties.setProperty("eventMesh.server.newAdd", "newAdd"); - FileWriter fw = new FileWriter(file); - properties.store(fw, "newAdd"); + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(tempConfigFile))) { + properties.load(bufferedReader); + } + + try (FileWriter fw = new FileWriter(tempConfigFile)) { + properties.setProperty("eventMesh.server.newAdd", "newAdd"); + properties.store(fw, "newAdd"); + } + + Mockito.verify(mockFileChangeListener, Mockito.timeout(15_000).atLeastOnce()) + .onChanged(Mockito.argThat(isFileUnderTest(tempConfigFile.getParent(), tempConfigFile.getName()))); + } - Thread.sleep(500); + private ArgumentMatcher isFileUnderTest(String directoryPath, String fileName) { + return argument -> argument.getDirectoryPath().equals(directoryPath) && argument.getFileName().equals(fileName); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelectorTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelectorTest.java index 728244117d..8f5c457264 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelectorTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/RandomLoadBalanceSelectorTest.java @@ -22,20 +22,19 @@ import java.util.List; import java.util.Map; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class RandomLoadBalanceSelectorTest { private RandomLoadBalanceSelector randomLoadBalanceSelector; - private Logger logger = LoggerFactory.getLogger(RandomLoadBalanceSelectorTest.class); - - @Before - public void befor() { + @BeforeEach + public void before() { List address = new ArrayList<>(); address.add("A"); address.add("B"); @@ -43,7 +42,6 @@ public void befor() { randomLoadBalanceSelector = new RandomLoadBalanceSelector<>(address); } - @Test public void testSelect() { Map addressToNum = new HashMap<>(); @@ -51,13 +49,13 @@ public void testSelect() { String select = randomLoadBalanceSelector.select(); addressToNum.put(select, addressToNum.getOrDefault(select, 0) + 1); } - addressToNum.forEach((key, value) -> logger.info("{} : {}", key, value)); + addressToNum.forEach((key, value) -> log.info("{} : {}", key, value)); // just assert success if no exception - Assert.assertTrue(true); + Assertions.assertTrue(true); } @Test public void testGetType() { - Assert.assertEquals(LoadBalanceType.RANDOM, randomLoadBalanceSelector.getType()); + Assertions.assertEquals(LoadBalanceType.RANDOM, randomLoadBalanceSelector.getType()); } -} \ No newline at end of file +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelectorTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelectorTest.java index beb5e659e1..89aaa7fbe4 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelectorTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRandomLoadBalanceSelectorTest.java @@ -27,14 +27,13 @@ import java.util.function.Function; import java.util.stream.IntStream; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class WeightRandomLoadBalanceSelectorTest { +import lombok.extern.slf4j.Slf4j; - private Logger logger = LoggerFactory.getLogger(WeightRandomLoadBalanceSelectorTest.class); +@Slf4j +public class WeightRandomLoadBalanceSelectorTest { @Test public void testSelect() throws Exception { @@ -43,19 +42,19 @@ public void testSelect() throws Exception { weightList.add(new Weight<>("192.168.0.2", 20)); weightList.add(new Weight<>("192.168.0.3", 40)); WeightRandomLoadBalanceSelector weightRandomLoadBalanceSelector = new WeightRandomLoadBalanceSelector<>(weightList); - Assert.assertEquals(LoadBalanceType.WEIGHT_RANDOM, weightRandomLoadBalanceSelector.getType()); + Assertions.assertEquals(LoadBalanceType.WEIGHT_RANDOM, weightRandomLoadBalanceSelector.getType()); int testRange = 100_000; Map addressToNum = IntStream.range(0, testRange) - .mapToObj(i -> weightRandomLoadBalanceSelector.select()) - .collect(groupingBy(Function.identity(), summingInt(i -> 1))); + .mapToObj(i -> weightRandomLoadBalanceSelector.select()) + .collect(groupingBy(Function.identity(), summingInt(i -> 1))); addressToNum.forEach((key, value) -> { - logger.info("{}: {}", key, value); + log.info("{}: {}", key, value); }); - System.out.printf(addressToNum.toString()); + log.info("addressToNum: {}", addressToNum); // the error less than 5% - Assert.assertTrue(Math.abs(addressToNum.get("192.168.0.3") - addressToNum.get("192.168.0.2") * 2) < testRange / 20); - Assert.assertTrue(Math.abs(addressToNum.get("192.168.0.3") - addressToNum.get("192.168.0.1") * 4) < testRange / 20); + Assertions.assertTrue(Math.abs(addressToNum.get("192.168.0.3") - addressToNum.get("192.168.0.2") * 2) < testRange / 20); + Assertions.assertTrue(Math.abs(addressToNum.get("192.168.0.3") - addressToNum.get("192.168.0.1") * 4) < testRange / 20); } @Test @@ -65,22 +64,22 @@ public void testSameWeightSelect() throws Exception { weightList.add(new Weight<>("192.168.0.2", 10)); weightList.add(new Weight<>("192.168.0.3", 10)); WeightRandomLoadBalanceSelector weightRandomLoadBalanceSelector = new WeightRandomLoadBalanceSelector<>(weightList); - Assert.assertEquals(LoadBalanceType.WEIGHT_RANDOM, weightRandomLoadBalanceSelector.getType()); + Assertions.assertEquals(LoadBalanceType.WEIGHT_RANDOM, weightRandomLoadBalanceSelector.getType()); int testRange = 100_000; Map addressToNum = IntStream.range(0, testRange) - .mapToObj(i -> weightRandomLoadBalanceSelector.select()) - .collect(groupingBy(Function.identity(), summingInt(i -> 1))); + .mapToObj(i -> weightRandomLoadBalanceSelector.select()) + .collect(groupingBy(Function.identity(), summingInt(i -> 1))); Field field = WeightRandomLoadBalanceSelector.class.getDeclaredField("sameWeightGroup"); field.setAccessible(true); boolean sameWeightGroup = (boolean) field.get(weightRandomLoadBalanceSelector); - Assert.assertTrue(sameWeightGroup); + Assertions.assertTrue(sameWeightGroup); addressToNum.forEach((key, value) -> { - logger.info("{}: {}", key, value); + log.info("{}: {}", key, value); }); // the error less than 5% - Assert.assertTrue(Math.abs(addressToNum.get("192.168.0.3") - addressToNum.get("192.168.0.2")) < testRange / 20); + Assertions.assertTrue(Math.abs(addressToNum.get("192.168.0.3") - addressToNum.get("192.168.0.2")) < testRange / 20); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelectorTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelectorTest.java index cf43ee48ef..dd49395711 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelectorTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightRoundRobinLoadBalanceSelectorTest.java @@ -22,19 +22,18 @@ import java.util.List; import java.util.Map; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class WeightRoundRobinLoadBalanceSelectorTest { +import lombok.extern.slf4j.Slf4j; - private Logger logger = LoggerFactory.getLogger(WeightRoundRobinLoadBalanceSelectorTest.class); +@Slf4j +public class WeightRoundRobinLoadBalanceSelectorTest { private WeightRoundRobinLoadBalanceSelector weightRoundRobinLoadBalanceSelector; - @Before + @BeforeEach public void before() { List> weightList = new ArrayList<>(); weightList.add(new Weight<>("A", 10)); @@ -51,14 +50,14 @@ public void testSelect() { addressToNum.put(select, addressToNum.getOrDefault(select, 0) + 1); } addressToNum.forEach((key, value) -> { - logger.info("{}: {}", key, value); + log.info("{}: {}", key, value); }); - Assert.assertTrue(addressToNum.get("B") > addressToNum.get("A")); - Assert.assertTrue(addressToNum.get("C") > addressToNum.get("B")); + Assertions.assertTrue(addressToNum.get("B") > addressToNum.get("A")); + Assertions.assertTrue(addressToNum.get("C") > addressToNum.get("B")); } @Test public void testGetType() { - Assert.assertEquals(LoadBalanceType.WEIGHT_ROUND_ROBIN, weightRoundRobinLoadBalanceSelector.getType()); + Assertions.assertEquals(LoadBalanceType.WEIGHT_ROUND_ROBIN, weightRoundRobinLoadBalanceSelector.getType()); } -} \ No newline at end of file +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightTest.java index bdf7a845f2..0aebc8bbdd 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/loadbalance/WeightTest.java @@ -17,8 +17,8 @@ package org.apache.eventmesh.common.loadbalance; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class WeightTest { @@ -26,19 +26,19 @@ public class WeightTest { public void testDecreaseTotal() { Weight weight = new Weight(null, 0); weight.decreaseTotal(1); - Assert.assertEquals(-1, weight.getCurrentWeight().get()); + Assertions.assertEquals(-1, weight.getCurrentWeight().get()); } @Test public void testIncreaseCurrentWeight() { Weight weight = new Weight(null, 10); weight.increaseCurrentWeight(); - Assert.assertEquals(10, weight.getCurrentWeight().get()); + Assertions.assertEquals(10, weight.getCurrentWeight().get()); } @Test public void testGetCurrentWeight() { Weight weight = new Weight(null, 0); - Assert.assertEquals(0, weight.getCurrentWeight().get()); + Assertions.assertEquals(0, weight.getCurrentWeight().get()); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventUtilsTest.java new file mode 100644 index 0000000000..15c1af8a5d --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/grpc/common/EventMeshCloudEventUtilsTest.java @@ -0,0 +1,271 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.grpc.common; + +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; + +import java.net.URI; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.google.protobuf.Timestamp; + + +public class EventMeshCloudEventUtilsTest { + + private CloudEvent cloudEvent; + + @BeforeEach + public void init() { + + final Map attributeValueMap = new HashMap<>(64); + attributeValueMap.put(ProtocolKey.ENV, CloudEventAttributeValue.newBuilder().setCeString("dev").build()); + attributeValueMap.put(ProtocolKey.IDC, CloudEventAttributeValue.newBuilder().setCeString("eventmesh").build()); + attributeValueMap.put(ProtocolKey.IP, CloudEventAttributeValue.newBuilder().setCeString("127.0.0.1").build()); + attributeValueMap.put(ProtocolKey.PID, CloudEventAttributeValue.newBuilder().setCeString("1243").build()); + attributeValueMap.put(ProtocolKey.SYS, CloudEventAttributeValue.newBuilder().setCeString("eventmesh").build()); + attributeValueMap.put(ProtocolKey.LANGUAGE, CloudEventAttributeValue.newBuilder().setCeString("java").build()); + attributeValueMap.put(ProtocolKey.USERNAME, CloudEventAttributeValue.newBuilder().setCeString("mxsm").build()); + attributeValueMap.put(ProtocolKey.PASSWD, CloudEventAttributeValue.newBuilder().setCeString("mxsm").build()); + attributeValueMap.put(ProtocolKey.PROTOCOL_DESC, CloudEventAttributeValue.newBuilder().setCeString("version 1.0").build()); + attributeValueMap.put(ProtocolKey.SEQ_NUM, CloudEventAttributeValue.newBuilder().setCeString("100").build()); + attributeValueMap.put(ProtocolKey.UNIQUE_ID, CloudEventAttributeValue.newBuilder().setCeString("100").build()); + attributeValueMap.put(ProtocolKey.TTL, CloudEventAttributeValue.newBuilder().setCeString("100").build()); + attributeValueMap.put(ProtocolKey.PRODUCERGROUP, CloudEventAttributeValue.newBuilder().setCeString("mxsm_producer_group").build()); + attributeValueMap.put(ProtocolKey.TAG, CloudEventAttributeValue.newBuilder().setCeString("tag").build()); + attributeValueMap.put(ProtocolKey.SUBJECT, CloudEventAttributeValue.newBuilder().setCeString("topic").build()); + attributeValueMap.put(ProtocolKey.CLIENT_TYPE, CloudEventAttributeValue.newBuilder().setCeInteger(ClientType.SUB.getType()).build()); + attributeValueMap.put(ProtocolKey.GRPC_RESPONSE_CODE, CloudEventAttributeValue.newBuilder().setCeString("0").build()); + Instant instant = LocalDateTime.of(2023, 4, 11, 19, 7, 0).toInstant(ZoneOffset.UTC); + attributeValueMap.put(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + attributeValueMap.put(ProtocolKey.GRPC_RESPONSE_MESSAGE, CloudEventAttributeValue.newBuilder().setCeString("0").build()); + attributeValueMap.put(ProtocolKey.PROPERTY_MESSAGE_CLUSTER, CloudEventAttributeValue.newBuilder().setCeString("DefaultCluster").build()); + attributeValueMap.put(ProtocolKey.URL, CloudEventAttributeValue.newBuilder().setCeString("http://127.0.0.1").build()); + attributeValueMap.put(ProtocolKey.CONSUMERGROUP, CloudEventAttributeValue.newBuilder().setCeString("ConsumerGroup").build()); + attributeValueMap.put(ProtocolKey.DATA_CONTENT_TYPE, CloudEventAttributeValue.newBuilder().setCeString("text/plain").build()); + attributeValueMap.put(ProtocolKey.CONTENT_TYPE, CloudEventAttributeValue.newBuilder().setCeString("text/plain").build()); + attributeValueMap.put(ProtocolKey.PROTOCOL_TYPE, + CloudEventAttributeValue.newBuilder().setCeString(EventMeshProtocolType.CLOUD_EVENTS.protocolTypeName()).build()); + attributeValueMap.put(ProtocolKey.PROTOCOL_VERSION, CloudEventAttributeValue.newBuilder().setCeString("1.0").build()); + cloudEvent = CloudEvent.newBuilder().putAllAttributes(attributeValueMap).setId("123").setSource(URI.create("/").toString()) + .setType("eventmesh") + .setSpecVersion("1.0").setTextData("mxsm").build(); + } + + @Test + public void testGetEnv() { + Assertions.assertEquals("dev", EventMeshCloudEventUtils.getEnv(cloudEvent)); + Assertions.assertEquals("dev", EventMeshCloudEventUtils.getEnv(cloudEvent, "test")); + Assertions.assertEquals("test", EventMeshCloudEventUtils.getEnv(CloudEvent.newBuilder().build(), "test")); + } + + @Test + public void testGetIdc() { + Assertions.assertEquals("eventmesh", EventMeshCloudEventUtils.getIdc(cloudEvent)); + Assertions.assertEquals("eventmesh", EventMeshCloudEventUtils.getIdc(cloudEvent, "test")); + Assertions.assertEquals("test", EventMeshCloudEventUtils.getIdc(CloudEvent.newBuilder().build(), "test")); + } + + @Test + public void testGetSys() { + Assertions.assertEquals("eventmesh", EventMeshCloudEventUtils.getSys(cloudEvent)); + Assertions.assertEquals("eventmesh", EventMeshCloudEventUtils.getSys(cloudEvent, "test")); + Assertions.assertEquals("Linux", EventMeshCloudEventUtils.getSys(CloudEvent.newBuilder().build(), "Linux")); + } + + @Test + public void testGetPid() { + Assertions.assertEquals("1243", EventMeshCloudEventUtils.getPid(cloudEvent)); + Assertions.assertEquals("1243", EventMeshCloudEventUtils.getPid(cloudEvent, "test")); + Assertions.assertEquals("987", EventMeshCloudEventUtils.getPid(CloudEvent.newBuilder().build(), "987")); + } + + @Test + public void testGetIp() { + Assertions.assertEquals("127.0.0.1", EventMeshCloudEventUtils.getIp(cloudEvent)); + Assertions.assertEquals("127.0.0.1", EventMeshCloudEventUtils.getIp(cloudEvent, "127.0.0.2")); + Assertions.assertEquals("192.168.1.1", EventMeshCloudEventUtils.getIp(CloudEvent.newBuilder().build(), "192.168.1.1")); + } + + @Test + public void testGetUserName() { + Assertions.assertEquals("mxsm", EventMeshCloudEventUtils.getUserName(cloudEvent)); + Assertions.assertEquals("mxsm", EventMeshCloudEventUtils.getUserName(cloudEvent, "mxsm1")); + Assertions.assertEquals("root", EventMeshCloudEventUtils.getUserName(CloudEvent.newBuilder().build(), "root")); + } + + @Test + public void testGetPassword() { + Assertions.assertEquals("mxsm", EventMeshCloudEventUtils.getPassword(cloudEvent)); + Assertions.assertEquals("mxsm", EventMeshCloudEventUtils.getPassword(cloudEvent, "mxsm1")); + Assertions.assertEquals("root", EventMeshCloudEventUtils.getPassword(CloudEvent.newBuilder().build(), "root")); + } + + @Test + public void testGetLanguage() { + Assertions.assertEquals("java", EventMeshCloudEventUtils.getLanguage(cloudEvent)); + Assertions.assertEquals("java", EventMeshCloudEventUtils.getLanguage(cloudEvent, "Go")); + Assertions.assertEquals("Go", EventMeshCloudEventUtils.getLanguage(CloudEvent.newBuilder().build(), "Go")); + } + + @Test + public void testGetProtocolType() { + Assertions.assertEquals(EventMeshProtocolType.CLOUD_EVENTS.protocolTypeName(), EventMeshCloudEventUtils.getProtocolType(cloudEvent)); + Assertions.assertEquals(EventMeshProtocolType.CLOUD_EVENTS.protocolTypeName(), EventMeshCloudEventUtils.getProtocolType(cloudEvent, "Go")); + Assertions.assertEquals("eventmeshMessage", EventMeshCloudEventUtils.getProtocolType(CloudEvent.newBuilder().build(), "eventmeshMessage")); + } + + @Test + public void testGetProtocolVersion() { + Assertions.assertEquals("1.0", EventMeshCloudEventUtils.getProtocolVersion(cloudEvent)); + Assertions.assertEquals("1.0", EventMeshCloudEventUtils.getProtocolVersion(cloudEvent, "1.1")); + Assertions.assertEquals("1.2", EventMeshCloudEventUtils.getProtocolVersion(CloudEvent.newBuilder().build(), "1.2")); + } + + @Test + public void testGetProtocolDesc() { + Assertions.assertEquals("version 1.0", EventMeshCloudEventUtils.getProtocolDesc(cloudEvent)); + Assertions.assertEquals("version 1.0", EventMeshCloudEventUtils.getProtocolDesc(cloudEvent, "version 1.1")); + Assertions.assertEquals("version 1.2", EventMeshCloudEventUtils.getProtocolDesc(CloudEvent.newBuilder().build(), "version 1.2")); + } + + @Test + public void testGetSeqNum() { + Assertions.assertEquals("100", EventMeshCloudEventUtils.getSeqNum(cloudEvent)); + Assertions.assertEquals("100", EventMeshCloudEventUtils.getSeqNum(cloudEvent, "200")); + Assertions.assertEquals("200", EventMeshCloudEventUtils.getSeqNum(CloudEvent.newBuilder().build(), "200")); + } + + @Test + public void testGetUniqueId() { + Assertions.assertEquals("100", EventMeshCloudEventUtils.getUniqueId(cloudEvent)); + Assertions.assertEquals("100", EventMeshCloudEventUtils.getUniqueId(cloudEvent, "200")); + Assertions.assertEquals("200", EventMeshCloudEventUtils.getUniqueId(CloudEvent.newBuilder().build(), "200")); + } + + @Test + public void testGetTtl() { + Assertions.assertEquals("100", EventMeshCloudEventUtils.getTtl(cloudEvent)); + Assertions.assertEquals("100", EventMeshCloudEventUtils.getTtl(cloudEvent, "200")); + Assertions.assertEquals("200", EventMeshCloudEventUtils.getTtl(CloudEvent.newBuilder().build(), "200")); + } + + @Test + public void testGetProducerGroup() { + Assertions.assertEquals("mxsm_producer_group", EventMeshCloudEventUtils.getProducerGroup(cloudEvent)); + Assertions.assertEquals("mxsm_producer_group", EventMeshCloudEventUtils.getProducerGroup(cloudEvent, "mxsm_producer_group")); + Assertions.assertEquals("mxsm_producer_group1", + EventMeshCloudEventUtils.getProducerGroup(CloudEvent.newBuilder().build(), "mxsm_producer_group1")); + } + + @Test + public void testGetTag() { + Assertions.assertEquals("tag", EventMeshCloudEventUtils.getTag(cloudEvent)); + Assertions.assertEquals("tag", EventMeshCloudEventUtils.getTag(cloudEvent, "tag1")); + Assertions.assertEquals("tag1", EventMeshCloudEventUtils.getTag(CloudEvent.newBuilder().build(), "tag1")); + } + + @Test + public void testGetContentType() { + Assertions.assertEquals("text/plain", EventMeshCloudEventUtils.getContentType(cloudEvent)); + Assertions.assertEquals("text/plain", EventMeshCloudEventUtils.getContentType(cloudEvent, "application/json")); + Assertions.assertEquals("application/json", EventMeshCloudEventUtils.getContentType(CloudEvent.newBuilder().build(), "application/json")); + } + + @Test + public void testGetSubject() { + Assertions.assertEquals("topic", EventMeshCloudEventUtils.getSubject(cloudEvent)); + Assertions.assertEquals("topic", EventMeshCloudEventUtils.getSubject(cloudEvent, "topic12")); + Assertions.assertEquals("mxsm-topic", EventMeshCloudEventUtils.getSubject(CloudEvent.newBuilder().build(), "mxsm-topic")); + } + + @Test + public void testGetDataContentType() { + Assertions.assertEquals("text/plain", EventMeshCloudEventUtils.getDataContentType(cloudEvent)); + Assertions.assertEquals("text/plain", EventMeshCloudEventUtils.getDataContentType(cloudEvent, "application/json")); + Assertions.assertEquals("application/json", EventMeshCloudEventUtils.getDataContentType(CloudEvent.newBuilder().build(), "application/json")); + } + + @Test + public void testGetResponseCode() { + Assertions.assertEquals("0", EventMeshCloudEventUtils.getResponseCode(cloudEvent)); + Assertions.assertEquals("0", EventMeshCloudEventUtils.getResponseCode(cloudEvent, "1")); + Assertions.assertEquals("1", EventMeshCloudEventUtils.getResponseCode(CloudEvent.newBuilder().build(), "1")); + } + + @Test + public void testGetResponseMessage() { + Assertions.assertEquals("0", EventMeshCloudEventUtils.getResponseMessage(cloudEvent)); + Assertions.assertEquals("0", EventMeshCloudEventUtils.getResponseMessage(cloudEvent, "1")); + Assertions.assertEquals("1", EventMeshCloudEventUtils.getResponseMessage(CloudEvent.newBuilder().build(), "1")); + } + + @Test + public void testGetResponseTime() { + Assertions.assertEquals("2023-04-11T19:07Z", EventMeshCloudEventUtils.getResponseTime(cloudEvent)); + Assertions.assertEquals("2023-04-11T19:07Z", EventMeshCloudEventUtils.getResponseTime(cloudEvent, "2023-04-11 17:45:10")); + Assertions.assertEquals("1970-01-01T00:00Z", EventMeshCloudEventUtils.getResponseTime(CloudEvent.newBuilder().build(), "1970-01-01T00:00Z")); + } + + @Test + public void testGetCluster() { + Assertions.assertEquals("DefaultCluster", EventMeshCloudEventUtils.getCluster(cloudEvent)); + Assertions.assertEquals("DefaultCluster", EventMeshCloudEventUtils.getCluster(cloudEvent, "DefaultCluster1")); + Assertions.assertEquals("DefaultCluster1", EventMeshCloudEventUtils.getCluster(CloudEvent.newBuilder().build(), "DefaultCluster1")); + } + + @Test + public void testGetConsumerGroup() { + Assertions.assertEquals("ConsumerGroup", EventMeshCloudEventUtils.getConsumerGroup(cloudEvent)); + Assertions.assertEquals("ConsumerGroup", EventMeshCloudEventUtils.getConsumerGroup(cloudEvent, "ConsumerGroup111")); + Assertions.assertEquals("ConsumerGroup111", EventMeshCloudEventUtils.getConsumerGroup(CloudEvent.newBuilder().build(), "ConsumerGroup111")); + } + + @Test + public void testGetClientType() { + Assertions.assertEquals(ClientType.SUB, EventMeshCloudEventUtils.getClientType(cloudEvent)); + Assertions.assertEquals(ClientType.SUB, EventMeshCloudEventUtils.getClientType(cloudEvent, ClientType.PUB)); + Assertions.assertEquals(ClientType.PUB, EventMeshCloudEventUtils.getClientType(CloudEvent.newBuilder().build(), ClientType.PUB)); + } + + @Test + public void testGetURL() { + Assertions.assertEquals("http://127.0.0.1", EventMeshCloudEventUtils.getURL(cloudEvent)); + Assertions.assertEquals("http://127.0.0.1", EventMeshCloudEventUtils.getURL(cloudEvent, "http://127.0.0.2")); + Assertions.assertEquals("http://127.0.0.2", EventMeshCloudEventUtils.getURL(CloudEvent.newBuilder().build(), "http://127.0.0.2")); + } + + @Test + public void testGetDataContent() { + Assertions.assertEquals("mxsm", EventMeshCloudEventUtils.getDataContent(cloudEvent)); + Assertions.assertEquals("mxsm", EventMeshCloudEventUtils.getDataContent(cloudEvent, "http://127.0.0.2")); + Assertions.assertEquals("http://127.0.0.2", EventMeshCloudEventUtils.getDataContent(CloudEvent.newBuilder().build(), "http://127.0.0.2")); + } + + +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpCommandTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpCommandTest.java index 962d6c7a79..ff1ec236ff 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpCommandTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpCommandTest.java @@ -20,22 +20,23 @@ import static org.mockito.Mockito.when; import org.apache.eventmesh.common.protocol.http.body.Body; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.header.Header; import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +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 org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class HttpCommandTest { @Mock @@ -46,7 +47,7 @@ public class HttpCommandTest { private HttpCommand httpCommand; - @Before + @BeforeEach public void before() { httpCommand = new HttpCommand("POST", "1.1", "200"); } @@ -57,36 +58,45 @@ public void testCreateHttpCommandResponseWithHeaderAndBody() { Map headerMap = new HashMap<>(); headerMap.put("key1", "value1"); when(header.toMap()).thenReturn(headerMap); - Assert.assertEquals("1.1", command.getHttpVersion()); - Assert.assertEquals("POST", command.getHttpMethod()); - Assert.assertEquals("200", command.getRequestCode()); - Assert.assertEquals("value1", command.getHeader().toMap().get("key1")); + Assertions.assertEquals("1.1", command.getHttpVersion()); + Assertions.assertEquals("POST", command.getHttpMethod()); + Assertions.assertEquals("200", command.getRequestCode()); + Assertions.assertEquals("value1", command.getHeader().toMap().get("key1")); } @Test public void testAbstractDesc() { HttpCommand command = httpCommand.createHttpCommandResponse(header, body); String desc = command.abstractDesc(); - Assert.assertTrue(desc.startsWith("httpCommand")); + Assertions.assertTrue(desc.startsWith("httpCommand")); } @Test public void testSimpleDesc() { HttpCommand command = httpCommand.createHttpCommandResponse(header, body); String desc = command.simpleDesc(); - Assert.assertTrue(desc.startsWith("httpCommand")); + Assertions.assertTrue(desc.startsWith("httpCommand")); } @Test public void testHttpResponse() throws Exception { HttpCommand command = httpCommand.createHttpCommandResponse(header, body); DefaultFullHttpResponse response = command.httpResponse(); - Assert.assertEquals("keep-alive", response.headers().get(HttpHeaderNames.CONNECTION)); + Assertions.assertEquals("keep-alive", response.headers().get(HttpHeaderNames.CONNECTION)); } @Test public void testHttpResponseWithREQCmdType() throws Exception { DefaultFullHttpResponse response = httpCommand.httpResponse(); - Assert.assertNull(response); + Assertions.assertNull(response); + } + + @Test + public void testCreateHttpCommandResponse() { + HttpCommand command = new HttpCommand(); + HttpCommand response = command.createHttpCommandResponse(EventMeshRetCode.SUCCESS); + Assertions.assertNotNull(response); + Assertions.assertEquals("0", response.getRequestCode()); + } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapperTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapperTest.java new file mode 100644 index 0000000000..d86ee09416 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/HttpEventWrapperTest.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.http; + +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.util.HashMap; +import java.util.Map; + +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 org.mockito.junit.jupiter.MockitoExtension; + +import io.netty.handler.codec.http.DefaultFullHttpResponse; + +@ExtendWith(MockitoExtension.class) +public class HttpEventWrapperTest { + + private HttpEventWrapper httpEventWrapper; + + @BeforeEach + public void setUp() { + httpEventWrapper = new HttpEventWrapper("POST", "1.1", "hello"); + } + + @Test + public void testCreateHttpResponse() { + HashMap headMap = new HashMap<>(); + headMap.put("String", "responseHeaderMap"); + HashMap responseBodyMap = new HashMap<>(); + responseBodyMap.put("String", "responseBodyMap"); + HttpEventWrapper result = httpEventWrapper.createHttpResponse(headMap, responseBodyMap); + Assertions.assertEquals("1.1", result.getHttpVersion()); + Assertions.assertEquals("POST", result.getHttpMethod()); + Assertions.assertEquals("hello", result.getRequestURI()); + Assertions.assertEquals("responseHeaderMap", result.getHeaderMap().get("String")); + Map responseMap = JsonUtils.parseObject(new String(result.getBody()), Map.class); + Assertions.assertEquals("responseBodyMap", responseMap.get("String")); + } + + @Test + public void testCreateHttpResponse2() { + HttpEventWrapper result = httpEventWrapper.createHttpResponse(EventMeshRetCode.SUCCESS); + Map responseMap = JsonUtils.parseObject(new String(result.getBody()), Map.class); + Assertions.assertEquals(EventMeshRetCode.SUCCESS.getRetCode(), responseMap.get("retCode")); + Assertions.assertEquals(EventMeshRetCode.SUCCESS.getErrMsg(), responseMap.get("retMessage")); + } + + @Test + public void testGetBody() { + byte[] bodyArray = new byte[]{'0'}; + httpEventWrapper.setBody(bodyArray); + byte[] result = httpEventWrapper.getBody(); + Assertions.assertNotNull(result); + Assertions.assertEquals(result[0], '0'); + } + + @Test + public void testSetBody() { + httpEventWrapper.setBody(new byte[]{(byte) 0}); + } + + @Test + public void testHttpResponse() throws Exception { + httpEventWrapper.setBody(new byte[]{(byte) 0}); + DefaultFullHttpResponse result = httpEventWrapper.httpResponse(); + Assertions.assertNotNull(result); + } + + @Test + public void testBuildSysHeaderForClient() { + httpEventWrapper.buildSysHeaderForClient(); + } + + @Test + public void testBuildSysHeaderForCE() { + httpEventWrapper.buildSysHeaderForCE(); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java index 4a8850ba09..1564c41608 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BaseResponseBodyTest.java @@ -17,12 +17,10 @@ package org.apache.eventmesh.common.protocol.http.body; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class BaseResponseBodyTest { @@ -31,10 +29,10 @@ public void testToMap() { BaseResponseBody body = new BaseResponseBody(); body.setRetCode(200); body.setRetMsg("SUCCESS"); - Assert.assertTrue(body.toMap().containsKey(ProtocolKey.RETCODE)); - Assert.assertTrue(body.toMap().containsKey(ProtocolKey.RETMSG)); - Assert.assertTrue(body.toMap().containsKey(ProtocolKey.RESTIME)); - Assert.assertThat(body.toMap().get(ProtocolKey.RETCODE), is(200)); - Assert.assertThat(body.toMap().get(ProtocolKey.RETMSG), is("SUCCESS")); + Assertions.assertTrue(body.toMap().containsKey(ProtocolKey.RETCODE)); + Assertions.assertTrue(body.toMap().containsKey(ProtocolKey.RETMSG)); + Assertions.assertTrue(body.toMap().containsKey(ProtocolKey.RESTIME)); + Assertions.assertEquals(200, body.toMap().get(ProtocolKey.RETCODE)); + Assertions.assertEquals("SUCCESS", body.toMap().get(ProtocolKey.RETMSG)); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BodyTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BodyTest.java new file mode 100644 index 0000000000..7a26953ad8 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/body/BodyTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.http.body; + +import org.apache.eventmesh.common.protocol.http.body.client.HeartbeatRequestBody; +import org.apache.eventmesh.common.protocol.http.body.client.RegRequestBody; +import org.apache.eventmesh.common.protocol.http.body.client.SubscribeRequestBody; +import org.apache.eventmesh.common.protocol.http.body.client.UnRegRequestBody; +import org.apache.eventmesh.common.protocol.http.body.client.UnSubscribeRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.ReplyMessageRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BodyTest { + + private Map originalMap; + + @BeforeEach + public void before() { + originalMap = new HashMap<>(); + } + + @Test + public void testBuildBody() throws Exception { + Assertions.assertThrows(Exception.class, () -> Body.buildBody("-1", originalMap)); + Body sendMessageBatchRequestBody = Body.buildBody(String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageBatchRequestBody); + Assertions.assertEquals(sendMessageBatchRequestBody.getClass(), SendMessageBatchRequestBody.class); + Body sendMessageBatchV2RequestBody = Body.buildBody(String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageBatchV2RequestBody); + Assertions.assertEquals(sendMessageBatchV2RequestBody.getClass(), SendMessageBatchV2RequestBody.class); + Body sendMessageRequestBodySync = Body.buildBody(String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageRequestBodySync); + Assertions.assertEquals(sendMessageRequestBodySync.getClass(), SendMessageRequestBody.class); + Body sendMessageRequestBodyAsync = Body.buildBody(String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageRequestBodyAsync); + Assertions.assertEquals(sendMessageRequestBodyAsync.getClass(), SendMessageRequestBody.class); + Body pushMessageRequestBodySync = Body.buildBody(String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(pushMessageRequestBodySync); + Assertions.assertEquals(pushMessageRequestBodySync.getClass(), PushMessageRequestBody.class); + Body pushMessageRequestBodyAsync = Body.buildBody(String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(pushMessageRequestBodyAsync); + Assertions.assertEquals(pushMessageRequestBodyAsync.getClass(), PushMessageRequestBody.class); + Body regRequestBody = Body.buildBody(String.valueOf(RequestCode.REGISTER.getRequestCode()), originalMap); + Assertions.assertNotNull(regRequestBody); + Assertions.assertEquals(regRequestBody.getClass(), RegRequestBody.class); + Body unRegRequestBody = Body.buildBody(String.valueOf(RequestCode.UNREGISTER.getRequestCode()), originalMap); + Assertions.assertNotNull(unRegRequestBody); + Assertions.assertEquals(unRegRequestBody.getClass(), UnRegRequestBody.class); + Body subscribeRequestBody = Body.buildBody(String.valueOf(RequestCode.SUBSCRIBE.getRequestCode()), originalMap); + Assertions.assertNotNull(subscribeRequestBody); + Assertions.assertEquals(subscribeRequestBody.getClass(), SubscribeRequestBody.class); + Body unSubscribeRequestBody = Body.buildBody(String.valueOf(RequestCode.UNSUBSCRIBE.getRequestCode()), originalMap); + Assertions.assertNotNull(unSubscribeRequestBody); + Assertions.assertEquals(unSubscribeRequestBody.getClass(), UnSubscribeRequestBody.class); + Body heartbeatRequestBody = Body.buildBody(String.valueOf(RequestCode.HEARTBEAT.getRequestCode()), originalMap); + Assertions.assertNotNull(heartbeatRequestBody); + Assertions.assertEquals(heartbeatRequestBody.getClass(), HeartbeatRequestBody.class); + Body replyMessageRequestBody = Body.buildBody(String.valueOf(RequestCode.REPLY_MESSAGE.getRequestCode()), originalMap); + Assertions.assertNotNull(replyMessageRequestBody); + Assertions.assertEquals(replyMessageRequestBody.getClass(), ReplyMessageRequestBody.class); + Body baseRequestBody = Body.buildBody(String.valueOf(RequestCode.ADMIN_SHUTDOWN.getRequestCode()), originalMap); + Assertions.assertNotNull(baseRequestBody); + Assertions.assertEquals(baseRequestBody.getClass(), BaseRequestBody.class); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeaderTest.java index 4768963908..557807bfa8 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseRequestHeaderTest.java @@ -17,16 +17,13 @@ package org.apache.eventmesh.common.protocol.http.header; - -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class BaseRequestHeaderTest { @@ -35,7 +32,7 @@ public void testToMap() { Map headerParam = new HashMap<>(); headerParam.put(ProtocolKey.REQUEST_CODE, "200"); BaseRequestHeader header = BaseRequestHeader.buildHeader(headerParam); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is("200")); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals("200", header.toMap().get(ProtocolKey.REQUEST_CODE)); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeaderTest.java index 23dc6540be..4d4021eb34 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/BaseResponseHeaderTest.java @@ -17,19 +17,17 @@ package org.apache.eventmesh.common.protocol.http.header; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class BaseResponseHeaderTest { @Test public void testToMap() { BaseResponseHeader header = BaseResponseHeader.buildHeader("200"); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is("200")); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals("200", header.toMap().get(ProtocolKey.REQUEST_CODE)); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/HeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/HeaderTest.java new file mode 100644 index 0000000000..691e7d66e4 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/HeaderTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.protocol.http.header; + +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.protocol.http.header.client.HeartbeatRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.client.RegRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.client.SubscribeRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.client.UnRegRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.client.UnSubscribeRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.message.PushMessageRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.message.ReplyMessageRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.message.SendMessageBatchRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.message.SendMessageBatchV2RequestHeader; +import org.apache.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class HeaderTest { + + private Map originalMap; + + @BeforeEach + public void before() { + originalMap = new HashMap<>(); + } + + @Test + public void testBuildHeader() throws Exception { + Assertions.assertThrows(Exception.class, () -> Header.buildHeader("-1", originalMap)); + Header messageBatchRequestHeader = Header.buildHeader(String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()), originalMap); + Assertions.assertNotNull(messageBatchRequestHeader); + Assertions.assertEquals(messageBatchRequestHeader.getClass(), SendMessageBatchRequestHeader.class); + Header sendMessageBatchV2RequestHeader = Header.buildHeader(String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageBatchV2RequestHeader); + Assertions.assertEquals(sendMessageBatchV2RequestHeader.getClass(), SendMessageBatchV2RequestHeader.class); + Header sendMessageRequestHeaderSync = Header.buildHeader(String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageRequestHeaderSync); + Assertions.assertEquals(sendMessageRequestHeaderSync.getClass(), SendMessageRequestHeader.class); + Header sendMessageRequestHeaderAsync = Header.buildHeader(String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(sendMessageRequestHeaderAsync); + Assertions.assertEquals(sendMessageRequestHeaderAsync.getClass(), SendMessageRequestHeader.class); + Header pushMessageRequestHeaderSync = Header.buildHeader(String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(pushMessageRequestHeaderSync); + Assertions.assertEquals(pushMessageRequestHeaderSync.getClass(), PushMessageRequestHeader.class); + Header pushMessageRequestHeaderAsync = Header.buildHeader(String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()), originalMap); + Assertions.assertNotNull(pushMessageRequestHeaderAsync); + Assertions.assertEquals(pushMessageRequestHeaderAsync.getClass(), PushMessageRequestHeader.class); + Header regRequestHeader = Header.buildHeader(String.valueOf(RequestCode.REGISTER.getRequestCode()), originalMap); + Assertions.assertNotNull(regRequestHeader); + Assertions.assertEquals(regRequestHeader.getClass(), RegRequestHeader.class); + Header unRegRequestHeader = Header.buildHeader(String.valueOf(RequestCode.UNREGISTER.getRequestCode()), originalMap); + Assertions.assertNotNull(unRegRequestHeader); + Assertions.assertEquals(unRegRequestHeader.getClass(), UnRegRequestHeader.class); + Header subscribeRequestHeader = Header.buildHeader(String.valueOf(RequestCode.SUBSCRIBE.getRequestCode()), originalMap); + Assertions.assertNotNull(subscribeRequestHeader); + Assertions.assertEquals(subscribeRequestHeader.getClass(), SubscribeRequestHeader.class); + Header unSubscribeRequestHeader = Header.buildHeader(String.valueOf(RequestCode.UNSUBSCRIBE.getRequestCode()), originalMap); + Assertions.assertNotNull(unSubscribeRequestHeader); + Assertions.assertEquals(unSubscribeRequestHeader.getClass(), UnSubscribeRequestHeader.class); + Header heartbeatRequestHeader = Header.buildHeader(String.valueOf(RequestCode.HEARTBEAT.getRequestCode()), originalMap); + Assertions.assertNotNull(heartbeatRequestHeader); + Assertions.assertEquals(heartbeatRequestHeader.getClass(), HeartbeatRequestHeader.class); + Header replyMessageRequestHeader = Header.buildHeader(String.valueOf(RequestCode.REPLY_MESSAGE.getRequestCode()), originalMap); + Assertions.assertNotNull(replyMessageRequestHeader); + Assertions.assertEquals(replyMessageRequestHeader.getClass(), ReplyMessageRequestHeader.class); + Header baseRequestHeader = Header.buildHeader(String.valueOf(RequestCode.ADMIN_SHUTDOWN.getRequestCode()), originalMap); + Assertions.assertNotNull(baseRequestHeader); + Assertions.assertEquals(baseRequestHeader.getClass(), BaseRequestHeader.class); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractRequestHeaderTest.java index 0726e6f07f..1d1ebc5925 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractRequestHeaderTest.java @@ -20,20 +20,20 @@ import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; -import org.junit.Assert; +import org.junit.jupiter.api.Assertions; public class AbstractRequestHeaderTest { public void assertMapContent(Header header) { - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.LANGUAGE)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.VERSION)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.ENV)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.IDC)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.SYS)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.PID)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.IP)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.USERNAME)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.PASSWD)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.LANGUAGE)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.VERSION)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.ENV.getKey())); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.IDC.getKey())); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.SYS.getKey())); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.PID.getKey())); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.IP.getKey())); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.USERNAME.getKey())); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.ClientInstanceKey.PASSWD.getKey())); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractResponseHeaderTest.java index 54e1f0c35d..d046321329 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/AbstractResponseHeaderTest.java @@ -17,25 +17,23 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.header.Header; -import org.junit.Assert; +import org.junit.jupiter.api.Assertions; public class AbstractResponseHeaderTest { public void assertMapContent(Header header) { - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV)); - Assert.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC)); - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is(200)); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER), is("CLUSTER")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP), is("127.0.0.1")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV), is("DEV")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC), is("IDC")); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.REQUEST_CODE)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV)); + Assertions.assertTrue(header.toMap().containsKey(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC)); + Assertions.assertEquals(200, header.toMap().get(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals("CLUSTER", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER)); + Assertions.assertEquals("127.0.0.1", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP)); + Assertions.assertEquals("DEV", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV)); + Assertions.assertEquals("IDC", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC)); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeaderTest.java index c09359e3f5..7a9f4c06cf 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatRequestHeaderTest.java @@ -17,10 +17,9 @@ package org.apache.eventmesh.common.protocol.http.header.client; - import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class HeartbeatRequestHeaderTest extends AbstractRequestHeaderTest { diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeaderTest.java index a437b8f707..e4c208dc30 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/HeartbeatResponseHeaderTest.java @@ -17,14 +17,14 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class HeartbeatResponseHeaderTest extends AbstractResponseHeaderTest { @Test public void testToMap() { HeartbeatResponseHeader header = HeartbeatResponseHeader.buildHeader(200, - "CLUSTER", "127.0.0.1", "DEV", "IDC"); + "CLUSTER", "127.0.0.1", "DEV", "IDC"); assertMapContent(header); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeaderTest.java index 24f7eb3855..2a6eb76759 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegRequestHeaderTest.java @@ -19,7 +19,7 @@ import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RegRequestHeaderTest extends AbstractRequestHeaderTest { diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeaderTest.java index 503c6425ed..6f7ccfe868 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/RegResponseHeaderTest.java @@ -17,14 +17,14 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RegResponseHeaderTest extends AbstractResponseHeaderTest { @Test public void testToMap() { RegResponseHeader header = RegResponseHeader.buildHeader(200, - "CLUSTER", "127.0.0.1", "DEV", "IDC"); + "CLUSTER", "127.0.0.1", "DEV", "IDC"); assertMapContent(header); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeaderTest.java index af79ff03fe..61b4dcba07 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeRequestHeaderTest.java @@ -19,7 +19,7 @@ import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class SubscribeRequestHeaderTest extends AbstractRequestHeaderTest { diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeaderTest.java index 9d646338dd..3c9acba885 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/SubscribeResponseHeaderTest.java @@ -17,15 +17,14 @@ package org.apache.eventmesh.common.protocol.http.header.client; - -import org.junit.Test; +import org.junit.jupiter.api.Test; public class SubscribeResponseHeaderTest extends AbstractResponseHeaderTest { @Test public void testToMap() { SubscribeResponseHeader header = SubscribeResponseHeader.buildHeader(200, - "CLUSTER", "127.0.0.1", "DEV", "IDC"); + "CLUSTER", "127.0.0.1", "DEV", "IDC"); assertMapContent(header); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeaderTest.java index 50b8e8d6ea..90c1e3c164 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegRequestHeaderTest.java @@ -17,10 +17,9 @@ package org.apache.eventmesh.common.protocol.http.header.client; - import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class UnRegRequestHeaderTest extends AbstractRequestHeaderTest { diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeaderTest.java index 0c7b016417..6f30934f8d 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnRegResponseHeaderTest.java @@ -17,14 +17,14 @@ package org.apache.eventmesh.common.protocol.http.header.client; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class UnRegResponseHeaderTest extends AbstractResponseHeaderTest { @Test public void testToMap() { UnRegResponseHeader header = UnRegResponseHeader.buildHeader(200, - "CLUSTER", "127.0.0.1", "DEV", "IDC"); + "CLUSTER", "127.0.0.1", "DEV", "IDC"); assertMapContent(header); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeaderTest.java index 562d92d83d..34d01d8f8f 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeRequestHeaderTest.java @@ -19,7 +19,7 @@ import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class UnSubscribeRequestHeaderTest extends AbstractRequestHeaderTest { diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeaderTest.java index 3e8cb70ed4..f3b0e009a0 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/client/UnSubscribeResponseHeaderTest.java @@ -17,15 +17,14 @@ package org.apache.eventmesh.common.protocol.http.header.client; - -import org.junit.Test; +import org.junit.jupiter.api.Test; public class UnSubscribeResponseHeaderTest extends AbstractResponseHeaderTest { @Test public void testToMap() { UnSubscribeResponseHeader header = UnSubscribeResponseHeader.buildHeader(200, - "CLUSTER", "127.0.0.1", "DEV", "IDC"); + "CLUSTER", "127.0.0.1", "DEV", "IDC"); assertMapContent(header); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeaderTest.java index d683789578..05151d4dbe 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageRequestHeaderTest.java @@ -17,8 +17,6 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; @@ -26,15 +24,15 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class PushMessageRequestHeaderTest { private PushMessageRequestHeader header; - @Before + @BeforeEach public void before() { Map headerParam = new HashMap<>(); headerParam.put(ProtocolKey.REQUEST_CODE, 200); @@ -49,12 +47,12 @@ public void before() { @Test public void testToMap() { - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is(200)); - Assert.assertThat(header.toMap().get(ProtocolKey.LANGUAGE), is(Constants.LANGUAGE_JAVA)); - Assert.assertThat(header.toMap().get(ProtocolKey.VERSION), is(ProtocolVersion.V1)); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER), is("default cluster")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP), is("127.0.0.1")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV), is("DEV")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC), is("IDC")); + Assertions.assertEquals(200, header.toMap().get(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals(Constants.LANGUAGE_JAVA, header.toMap().get(ProtocolKey.LANGUAGE)); + Assertions.assertEquals(ProtocolVersion.V1, header.toMap().get(ProtocolKey.VERSION)); + Assertions.assertEquals("default cluster", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER)); + Assertions.assertEquals("127.0.0.1", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP)); + Assertions.assertEquals("DEV", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV)); + Assertions.assertEquals("IDC", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC)); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeaderTest.java index 3446ef0e2d..a23a5b7489 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/PushMessageResponseHeaderTest.java @@ -17,28 +17,26 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class PushMessageResponseHeaderTest { @Test public void testToMap() { PushMessageResponseHeader header = PushMessageResponseHeader.buildHeader(100, "DEV", - "IDC", "SYSID", "PID", "127.0.0.1"); - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is(100)); - Assert.assertThat(header.toMap().get(ProtocolKey.LANGUAGE), is(Constants.LANGUAGE_JAVA)); - Assert.assertThat(header.toMap().get(ProtocolKey.VERSION), is(ProtocolVersion.V1)); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.ENV), is("DEV")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.IDC), is("IDC")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.SYS), is("SYSID")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.PID), is("PID")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.IP), is("127.0.0.1")); + "IDC", "SYSID", "PID", "127.0.0.1"); + Assertions.assertEquals(100, header.toMap().get(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals(Constants.LANGUAGE_JAVA, header.toMap().get(ProtocolKey.LANGUAGE)); + Assertions.assertEquals(ProtocolVersion.V1, header.toMap().get(ProtocolKey.VERSION)); + Assertions.assertEquals("DEV", header.toMap().get(ProtocolKey.ClientInstanceKey.ENV.getKey())); + Assertions.assertEquals("IDC", header.toMap().get(ProtocolKey.ClientInstanceKey.IDC.getKey())); + Assertions.assertEquals("SYSID", header.toMap().get(ProtocolKey.ClientInstanceKey.SYS.getKey())); + Assertions.assertEquals("PID", header.toMap().get(ProtocolKey.ClientInstanceKey.PID.getKey())); + Assertions.assertEquals("127.0.0.1", header.toMap().get(ProtocolKey.ClientInstanceKey.IP.getKey())); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeaderTest.java index eec5d1854d..a7a2049ba6 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageRequestHeaderTest.java @@ -17,8 +17,6 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; @@ -26,37 +24,37 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class ReplyMessageRequestHeaderTest { private ReplyMessageRequestHeader header; - @Before + @BeforeEach public void before() { Map headerParam = new HashMap<>(); headerParam.put(ProtocolKey.REQUEST_CODE, "200"); headerParam.put(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA); headerParam.put(ProtocolKey.VERSION, "1.0"); - headerParam.put(ProtocolKey.ClientInstanceKey.ENV, "DEV"); - headerParam.put(ProtocolKey.ClientInstanceKey.IDC, "IDC"); - headerParam.put(ProtocolKey.ClientInstanceKey.SYS, "SYS"); - headerParam.put(ProtocolKey.ClientInstanceKey.PID, "PID"); - headerParam.put(ProtocolKey.ClientInstanceKey.IP, "127.0.0.1"); + headerParam.put(ProtocolKey.ClientInstanceKey.ENV.getKey(), "DEV"); + headerParam.put(ProtocolKey.ClientInstanceKey.IDC.getKey(), "IDC"); + headerParam.put(ProtocolKey.ClientInstanceKey.SYS.getKey(), "SYS"); + headerParam.put(ProtocolKey.ClientInstanceKey.PID.getKey(), "PID"); + headerParam.put(ProtocolKey.ClientInstanceKey.IP.getKey(), "127.0.0.1"); header = ReplyMessageRequestHeader.buildHeader(headerParam); } @Test public void testToMap() { - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is("200")); - Assert.assertThat(header.toMap().get(ProtocolKey.LANGUAGE), is(Constants.LANGUAGE_JAVA)); - Assert.assertThat(header.toMap().get(ProtocolKey.VERSION), is(ProtocolVersion.V1)); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.ENV), is("DEV")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.IDC), is("IDC")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.SYS), is("SYS")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.PID), is("PID")); - Assert.assertThat(header.toMap().get(ProtocolKey.ClientInstanceKey.IP), is("127.0.0.1")); + Assertions.assertEquals("200", header.toMap().get(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals(Constants.LANGUAGE_JAVA, header.toMap().get(ProtocolKey.LANGUAGE)); + Assertions.assertEquals(ProtocolVersion.V1, header.toMap().get(ProtocolKey.VERSION)); + Assertions.assertEquals("DEV", header.toMap().get(ProtocolKey.ClientInstanceKey.ENV.getKey())); + Assertions.assertEquals("IDC", header.toMap().get(ProtocolKey.ClientInstanceKey.IDC.getKey())); + Assertions.assertEquals("SYS", header.toMap().get(ProtocolKey.ClientInstanceKey.SYS.getKey())); + Assertions.assertEquals("PID", header.toMap().get(ProtocolKey.ClientInstanceKey.PID.getKey())); + Assertions.assertEquals("127.0.0.1", header.toMap().get(ProtocolKey.ClientInstanceKey.IP.getKey())); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeaderTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeaderTest.java index a6714a885b..976c5529b7 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeaderTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/http/header/message/ReplyMessageResponseHeaderTest.java @@ -17,23 +17,21 @@ package org.apache.eventmesh.common.protocol.http.header.message; -import static org.hamcrest.CoreMatchers.is; - import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class ReplyMessageResponseHeaderTest { @Test public void testToMap() { ReplyMessageResponseHeader header = ReplyMessageResponseHeader.buildHeader(100, - "Cluster", "127.0.0.1", "DEV", "IDC"); - Assert.assertThat(header.toMap().get(ProtocolKey.REQUEST_CODE), is(100)); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER), is("Cluster")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP), is("127.0.0.1")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV), is("DEV")); - Assert.assertThat(header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC), is("IDC")); + "Cluster", "127.0.0.1", "DEV", "IDC"); + Assertions.assertEquals(100, header.toMap().get(ProtocolKey.REQUEST_CODE)); + Assertions.assertEquals("Cluster", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER)); + Assertions.assertEquals("127.0.0.1", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP)); + Assertions.assertEquals("DEV", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV)); + Assertions.assertEquals("IDC", header.toMap().get(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC)); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/tcp/codec/CodecTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/tcp/codec/CodecTest.java index bb66e5c04b..19907ffd2b 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/tcp/codec/CodecTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/protocol/tcp/codec/CodecTest.java @@ -20,11 +20,11 @@ import org.apache.eventmesh.common.protocol.tcp.Command; import org.apache.eventmesh.common.protocol.tcp.Header; import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.codec.Codec.Decoder; +import org.apache.eventmesh.common.protocol.tcp.codec.Codec.Encoder; -import java.util.ArrayList; - -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import io.netty.buffer.ByteBuf; import io.netty.buffer.PooledByteBufAllocator; @@ -37,14 +37,12 @@ public void testCodec() throws Exception { header.setCmd(Command.HELLO_REQUEST); Package testP = new Package(header); testP.setBody(new Object()); - Codec.Encoder ce = new Codec.Encoder(); + Encoder ce = new Codec.Encoder(); ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer(); ce.encode(null, testP, buf); - Codec.Decoder cd = new Codec.Decoder(); - ArrayList result = new ArrayList<>(); - cd.decode(null, buf, result); - Assert.assertNotNull(result.get(0)); - Assert.assertEquals(testP.getHeader(), ((Package) result.get(0)).getHeader()); + Decoder cd = new Codec.Decoder(); + final Package decode = (Package) cd.decode(null, buf); + Assertions.assertEquals(testP.getHeader(), decode.getHeader()); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/AssertUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/AssertUtilsTest.java new file mode 100644 index 0000000000..28040a76f6 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/AssertUtilsTest.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * test {@link AssertUtils} + */ +public class AssertUtilsTest { + + @Test + public void testNotNull() { + Assertions.assertThrows(IllegalArgumentException.class, () -> AssertUtils.notNull(null, "error message")); + } + + @Test + public void testIsTrue() { + Assertions.assertThrows(IllegalArgumentException.class, () -> AssertUtils.isTrue(false, "error message")); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ConfigurationContextUtilTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ConfigurationContextUtilTest.java new file mode 100644 index 0000000000..6ab7847d24 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ConfigurationContextUtilTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import static org.apache.eventmesh.common.Constants.GRPC; +import static org.apache.eventmesh.common.Constants.TCP; + +import org.apache.eventmesh.common.config.CommonConfiguration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ConfigurationContextUtilTest { + + private CommonConfiguration grpcConfig; + + @BeforeEach + public void setUp() { + grpcConfig = new CommonConfiguration(); + grpcConfig.setEventMeshName("grpc"); + ConfigurationContextUtil.putIfAbsent(GRPC, grpcConfig); + } + + @Test + public void testPutIfAbsent() { + CommonConfiguration tcpConfig = new CommonConfiguration(); + tcpConfig.setEventMeshName("tpc"); + ConfigurationContextUtil.putIfAbsent(TCP, tcpConfig); + CommonConfiguration get = ConfigurationContextUtil.get(TCP); + Assertions.assertNotNull(get); + Assertions.assertEquals(tcpConfig, get); + CommonConfiguration newGrpc = new CommonConfiguration(); + newGrpc.setEventMeshName("newGrpc"); + ConfigurationContextUtil.putIfAbsent(GRPC, newGrpc); + CommonConfiguration getGrpc = ConfigurationContextUtil.get(GRPC); + Assertions.assertNotNull(getGrpc); + Assertions.assertEquals(grpcConfig, getGrpc); + Assertions.assertNotEquals(newGrpc, getGrpc); + } + + @Test + public void testGet() { + CommonConfiguration result = ConfigurationContextUtil.get(GRPC); + Assertions.assertNotNull(result); + Assertions.assertEquals(grpcConfig, result); + } + + @Test + public void testClear() { + CommonConfiguration result0 = ConfigurationContextUtil.get(GRPC); + Assertions.assertNotNull(result0); + ConfigurationContextUtil.clear(); + CommonConfiguration result = ConfigurationContextUtil.get(GRPC); + Assertions.assertNull(result); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/HttpConvertsUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/HttpConvertsUtilsTest.java new file mode 100644 index 0000000000..253b1de926 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/HttpConvertsUtilsTest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey.EventMeshInstanceKey; +import org.apache.eventmesh.common.protocol.http.header.Header; +import org.apache.eventmesh.common.stubs.HeaderStub; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class HttpConvertsUtilsTest { + + private final HeaderStub headerStub = new HeaderStub(); + private final ProtocolKey mockedProtocolKey = new ProtocolKey(); + private final EventMeshInstanceKey mockedEventMeshProtocolKey = new EventMeshInstanceKey(); + + @Test + void httpMapConverts() { + Map httpMapConverts = new HttpConvertsUtils().httpMapConverts(headerStub, mockedProtocolKey); + Assertions.assertEquals(httpMapConverts.get(headerStub.code), headerStub.code); + } + + @Test + void testHttpMapConverts() { + Map httpMapConverts = new HttpConvertsUtils().httpMapConverts(headerStub, mockedProtocolKey, mockedEventMeshProtocolKey); + Assertions.assertEquals(httpMapConverts.get(headerStub.code), headerStub.code); + Assertions.assertEquals(httpMapConverts.get(headerStub.eventmeshenv), headerStub.eventmeshenv); + } + + @Test + void httpHeaderConverts() { + HashMap headerParams = new HashMap<>(); + String code = "test"; + headerParams.put("code", code); + Header header = new HttpConvertsUtils().httpHeaderConverts(headerStub, headerParams); + Assertions.assertEquals(code, header.toMap().get("code")); + } + + @Test + void testHttpHeaderConverts() { + HashMap headerParams = new HashMap<>(); + String env = "test"; + headerParams.put("eventmeshenv", env); + Header header = new HttpConvertsUtils().httpHeaderConverts(headerStub, headerParams, mockedEventMeshProtocolKey); + Assertions.assertEquals(env, header.toMap().get("eventmeshenv")); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/IPUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/IPUtilsTest.java index 4adff4475d..757486dd89 100644 --- a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/IPUtilsTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/IPUtilsTest.java @@ -17,22 +17,14 @@ package org.apache.eventmesh.common.utils; -import org.junit.Assert; -import org.junit.Test; -import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class IPUtilsTest { - @Test - public void testDockerIP() { - EnvironmentVariables environmentVariables = new EnvironmentVariables(); - environmentVariables.set("docker_host_ip", "dockHostIP"); - Assert.assertEquals("dockHostIP", IPUtils.getLocalAddress()); - } - @Test public void testLocalhostIP() { - Assert.assertNotNull(IPUtils.getLocalAddress()); + Assertions.assertNotNull(IPUtils.getLocalAddress()); } } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/JsonPathUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/JsonPathUtilsTest.java new file mode 100644 index 0000000000..e66b8d711a --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/JsonPathUtilsTest.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; + +public class JsonPathUtilsTest { + + @Test + public void tesTisEmptyJsonObject() { + String emptyJsonObject = "{}"; + assertTrue(JsonPathUtils.isEmptyJsonObject(emptyJsonObject)); + + String jsonObject = "{\"key\": \"value\"}"; + assertFalse(JsonPathUtils.isEmptyJsonObject(jsonObject)); + + String emptyJsonArray = "[]"; + assertFalse(JsonPathUtils.isEmptyJsonObject(emptyJsonArray)); + + String jsonArray = "[{\"key\": \"value\"}]"; + assertFalse(JsonPathUtils.isEmptyJsonObject(jsonArray)); + + String empty = ""; + assertFalse(JsonPathUtils.isEmptyJsonObject(empty)); + } + + @Test + public void testParseStrict() { + String json = "{\"key\": \"value\"}"; + JsonNode result = JsonPathUtils.parseStrict(json); + assertNotNull(result); + assertEquals("value", result.get("key").asText()); + + String emptyJsonObject = "{}"; + JsonNode result2 = JsonPathUtils.parseStrict(emptyJsonObject); + assertNotNull(result2); + assertTrue(result2.isEmpty()); + + } + + @Test + public void testBuildJsonString() { + Map person = new HashMap<>(); + person.put("name", "John"); + person.put("age", "30"); + String actual = JsonPathUtils.buildJsonString("person", person); + String excepted = "{\"person\":{\"name\":\"John\",\"age\":\"30\"}}"; + assertNotNull(actual); + assertEquals(excepted, actual); + } + + @Test + public void testIsValidAndDefinite() { + String jsonPath = "$.person[0].name"; + String jsonPath2 = "$.person[*].address.city"; + String jsonPath3 = "person.job[0].title"; + + assertTrue(JsonPathUtils.isValidAndDefinite(jsonPath)); + assertFalse(JsonPathUtils.isValidAndDefinite(jsonPath2)); + assertFalse(JsonPathUtils.isValidAndDefinite(jsonPath3)); + + String jsonPath4 = null; + String jsonPath5 = ""; + + assertFalse(JsonPathUtils.isValidAndDefinite(jsonPath4)); + assertFalse(JsonPathUtils.isValidAndDefinite(jsonPath5)); + } + + + @Test + public void testGetJsonPathValue() { + String jsonContent = "{ \"person\": { \"name\": \"John Doe\", \"age\": 30, \"address\": { \"city\": \"New York\" } } }"; + + String jsonPath1 = "$.person.name"; + String jsonPath2 = "$.person.address.city"; + String jsonPath3 = "$.person.age"; + + assertEquals("John Doe", JsonPathUtils.getJsonPathValue(jsonContent, jsonPath1)); + assertEquals("New York", JsonPathUtils.getJsonPathValue(jsonContent, jsonPath2)); + assertEquals("30", JsonPathUtils.getJsonPathValue(jsonContent, jsonPath3)); + + } + + @Test + public void testConvertToJsonNode() throws JsonProcessingException { + String jsonString1 = "{\"name\": \"John Doe\", \"age\": 30, \"address\": { \"city\": \"New York\" }}"; + + JsonNode node1 = JsonPathUtils.convertToJsonNode(jsonString1); + assertEquals("John Doe", node1.get("name").asText()); + assertEquals("New York", node1.get("address").get("city").asText()); + assertEquals("30", node1.get("age").asText()); + } + + @Test + public void testMatchJsonPathValueWithString() { + String jsonString = "{\"name\": \"John Doe\", \"age\": 30, \"address\": { \"city\": \"New York\" }}"; + + String jsonPath1 = "$.name"; + String result1 = JsonPathUtils.matchJsonPathValueWithString(jsonString, jsonPath1); + assertEquals("John Doe", result1); + + String jsonPath2 = "$.age"; + String result2 = JsonPathUtils.matchJsonPathValueWithString(jsonString, jsonPath2); + assertEquals("30", result2); // Age should be returned as a string + + String jsonPath3 = "$.address.city"; + String result3 = JsonPathUtils.matchJsonPathValueWithString(jsonString, jsonPath3); + assertEquals("New York", result3); + + String jsonPath4 = "$.job"; + String result4 = JsonPathUtils.matchJsonPathValueWithString(jsonString, jsonPath4); + assertEquals("null", result4); + } + + @Test + public void testJsonPathParse() { + String jsonString = "{\"name\": \"John Doe\", \"age\": 30, \"address\": { \"city\": \"New York\" }}"; + + String jsonPath1 = "$.name"; + Object result1 = JsonPathUtils.jsonPathParse(jsonString, jsonPath1); + assertNotNull(result1); + assertEquals("John Doe", result1); + + String jsonPath2 = "$.address.city"; + Object result2 = JsonPathUtils.jsonPathParse(jsonString, jsonPath2); + assertNotNull(result2); + assertEquals("New York", result2); + } + + @Test + public void testMatchJsonPathValue() throws JsonProcessingException { + String jsonString = "{\"name\": \"John Doe\", \"age\": 30, \"address\": { \"city\": \"New York\" }}"; + String jsonPath1 = "$.name"; + String result1 = JsonPathUtils.matchJsonPathValue(jsonString, jsonPath1); + assertEquals("\"John Doe\"", result1); + + String jsonPath2 = "$.address.city"; + String result2 = JsonPathUtils.matchJsonPathValue(jsonString, jsonPath2); + assertEquals("\"New York\"", result2); + + String jsonPath3 = "$.job"; + String result3 = JsonPathUtils.matchJsonPathValue(jsonString, jsonPath3); + assertEquals("null", result3); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/JsonUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/JsonUtilsTest.java new file mode 100644 index 0000000000..264281a9a4 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/JsonUtilsTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; + +import lombok.Data; + +public class JsonUtilsTest { + + @Test + public void toJSONString() { + Map map = new HashMap<>(); + String jsonString = JsonUtils.toJSONString(map); + Assertions.assertEquals("{}", jsonString); + map.put("mxsm", "2"); + jsonString = JsonUtils.toJSONString(map); + Assertions.assertEquals("{\"mxsm\":\"2\"}", jsonString); + + Map maps = new HashMap<>(); + maps.put("mxsm", LocalDate.of(2013, 6, 28)); + jsonString = JsonUtils.toJSONString(maps); + Assertions.assertEquals("{\"mxsm\":\"2013-06-28\"}", jsonString); + } + + @Test + public void testToBytes() { + Map map = new HashMap<>(); + map.put("mxsm", "2"); + Assertions.assertArrayEquals("{\"mxsm\":\"2\"}".getBytes(StandardCharsets.UTF_8), JsonUtils.toJSONBytes(map)); + } + + @Test + public void testParseObject() { + + String json = "{\"mxsm\":\"2\",\"date\":\"2022-02-12 21:36:01\"}"; + Map map = JsonUtils.parseTypeReferenceObject(json, new TypeReference>() { + + }); + Assertions.assertNotNull(map); + Assertions.assertEquals("2", map.get("mxsm")); + EventMesh mxsm = JsonUtils.parseObject(json, EventMesh.class); + Assertions.assertNotNull(mxsm); + Assertions.assertEquals("2", mxsm.mxsm); + Assertions.assertEquals(new GregorianCalendar(2022, 1, 12, 21, 36, 01).getTime().getTime(), mxsm.date.getTime()); + EventMesh mxsm1 = JsonUtils.parseObject(json.getBytes(StandardCharsets.UTF_8), EventMesh.class); + Assertions.assertNotNull(mxsm1); + Assertions.assertEquals("2", mxsm1.mxsm); + } + + @Test + public void getJsonNode() { + String json = "{\"mxsm\":\"2\",\"date\":\"2022-02-12 21:36:01\"}"; + JsonNode jsonNode = JsonUtils.getJsonNode(json); + Assertions.assertNotNull(jsonNode); + Assertions.assertEquals("2", jsonNode.findValue("mxsm").asText()); + } + + @Data + public static class EventMesh { + + private String mxsm; + + private Date date; + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/LogUtilTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/LogUtilTest.java new file mode 100644 index 0000000000..03c52dadad --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/LogUtilTest.java @@ -0,0 +1,199 @@ +/* + * 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. + */ + + +package org.apache.eventmesh.common.utils; + +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.function.Supplier; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.Logger; +import org.slf4j.spi.LoggingEventBuilder; + +@ExtendWith(MockitoExtension.class) +class LogUtilTest { + + private Logger mockLogger; + private LoggingEventBuilder mockEventBuilder; + private Supplier supplier; + private String logMessage; + + @BeforeEach + void setUp() { + + mockLogger = mock(Logger.class); + mockEventBuilder = mock(LoggingEventBuilder.class); + + supplier = () -> "{\"orderId\": 12345, \"amount\": 100}"; + logMessage = "Processing order with data: {}"; + } + + @Test + void testDebugLogsWithSupplier() { + + doReturn(mockEventBuilder).when(mockLogger).atDebug(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + + LogUtil.debug(mockLogger, logMessage, supplier); + + verify(mockLogger).atDebug(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).log(logMessage); + + } + + @Test + void testDebugLogsWithSupplierAndException() { + Throwable throwable = new RuntimeException("Order processing failed"); + + + doReturn(mockEventBuilder).when(mockLogger).atDebug(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + doReturn(mockEventBuilder).when(mockEventBuilder).setCause(throwable); + + LogUtil.debug(mockLogger, logMessage, supplier, throwable); + + verify(mockLogger).atDebug(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).setCause(throwable); + verify(mockEventBuilder).log(logMessage); + } + + @Test + void testDebugLogsWithSuppliers() { + + Supplier supplier2 = () -> "{\"orderId\": 67890, \"amount\": 200}"; + + doReturn(mockEventBuilder).when(mockLogger).atDebug(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier2)); + + LogUtil.debug(mockLogger, logMessage, supplier, supplier2); + + verify(mockLogger).atDebug(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).addArgument(same(supplier2)); + verify(mockEventBuilder).log(logMessage); + } + + @Test + void testInfoLogsWithSupplier() { + + doReturn(mockEventBuilder).when(mockLogger).atInfo(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + + LogUtil.info(mockLogger, logMessage, supplier); + + verify(mockLogger).atInfo(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).log(logMessage); + + } + + @Test + void testInfoLogsWithSupplierAndException() { + + Throwable throwable = new RuntimeException("Order processing failed"); + + doReturn(mockEventBuilder).when(mockLogger).atInfo(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + doReturn(mockEventBuilder).when(mockEventBuilder).setCause(throwable); + + LogUtil.info(mockLogger, logMessage, supplier, throwable); + + verify(mockLogger).atInfo(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).setCause(throwable); + verify(mockEventBuilder).log(logMessage); + + } + + @Test + void testInfoLogsWithSuppliers() { + + Supplier supplier2 = () -> "{\"orderId\": 67890, \"amount\": 200}"; + + doReturn(mockEventBuilder).when(mockLogger).atInfo(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier2)); + + LogUtil.info(mockLogger, logMessage, supplier, supplier2); + + verify(mockLogger).atInfo(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).addArgument(same(supplier2)); + verify(mockEventBuilder).log(logMessage); + } + + @Test + void testWarnLogsWithSupplier() { + + doReturn(mockEventBuilder).when(mockLogger).atWarn(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + + LogUtil.warn(mockLogger, logMessage, supplier); + + verify(mockLogger).atWarn(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).log(logMessage); + + } + + @Test + void testWarnLogsWithSupplierAndException() { + + Throwable throwable = new RuntimeException("Order processing failed"); + + doReturn(mockEventBuilder).when(mockLogger).atWarn(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + doReturn(mockEventBuilder).when(mockEventBuilder).setCause(throwable); + + LogUtil.warn(mockLogger, logMessage, supplier, throwable); + + verify(mockLogger).atWarn(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).setCause(throwable); + verify(mockEventBuilder).log(logMessage); + + } + + @Test + void testWarnLogsWithSuppliers() { + + Supplier supplier2 = () -> "{\"orderId\": 67890, \"amount\": 200}"; + + doReturn(mockEventBuilder).when(mockLogger).atWarn(); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier)); + doReturn(mockEventBuilder).when(mockEventBuilder).addArgument(same(supplier2)); + + LogUtil.warn(mockLogger, logMessage, supplier, supplier2); + + verify(mockLogger).atWarn(); + verify(mockEventBuilder).addArgument(same(supplier)); + verify(mockEventBuilder).addArgument(same(supplier2)); + verify(mockEventBuilder).log(logMessage); + } + +} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/NetUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/NetUtilsTest.java similarity index 80% rename from eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/NetUtilsTest.java rename to eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/NetUtilsTest.java index 26e87d7aa2..fd8bf595af 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/NetUtilsTest.java +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/NetUtilsTest.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package org.apache.eventmesh.runtime.util; +package org.apache.eventmesh.common.utils; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class NetUtilsTest { @@ -31,22 +31,23 @@ public class NetUtilsTest { public void testFormData2Dic() { String formData = ""; Map result = NetUtils.formData2Dic(formData); - Assert.assertTrue(result.isEmpty()); + Assertions.assertTrue(result.isEmpty()); formData = "item_id=10081&item_name=test item name"; result = NetUtils.formData2Dic(formData); - Assert.assertEquals(result.get("item_id"), "10081"); + Assertions.assertEquals("10081", result.get("item_id")); } @Test public void testAddressToString() { List clients = new ArrayList<>(); String result = NetUtils.addressToString(clients); - Assert.assertEquals(result, "no session had been closed"); + Assertions.assertEquals("no session had been closed", result); InetSocketAddress localAddress = new InetSocketAddress(80); clients.add(localAddress); result = NetUtils.addressToString(clients); - Assert.assertEquals(result, localAddress + "|"); + Assertions.assertEquals(localAddress + "|", result); } + } diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/PropertiesUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/PropertiesUtilsTest.java new file mode 100644 index 0000000000..1df563cf39 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/PropertiesUtilsTest.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.eventmesh.common.config.ConfigService; + +import java.util.Properties; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PropertiesUtilsTest { + + private static final String PREFIX = "test."; + + @Test + public void testGetPropertiesByPrefix() { + Properties from = new Properties(); + from.put("a", 2); + from.put(PREFIX + "a", 1); + from.put(PREFIX + "b", 1.0); + from.put(PREFIX + "c.d", "inner d"); + from.put(PREFIX + "c.f", "inner f"); + Properties to = PropertiesUtils.getPropertiesByPrefix(from, PREFIX); + + Assertions.assertEquals(3, to.size()); + Assertions.assertEquals(2, ((Properties) to.get("c")).size()); + } + + @Test + public void testLoadPropertiesWhenFileExist() throws Exception { + Properties properties = new Properties(); + ConfigService configService = ConfigService.getInstance(); + configService.setRootConfig("classPath://configuration.properties"); + properties = configService.getRootConfig(); + String path = configService.getRootPath(); + PropertiesUtils.loadPropertiesWhenFileExist(properties, path); + Assertions.assertEquals("env-succeed!!!", properties.get("eventMesh.server.env").toString()); + Assertions.assertEquals("idc-succeed!!!", properties.get("eventMesh.server.idc").toString()); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/RandomStringUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/RandomStringUtilsTest.java new file mode 100644 index 0000000000..6356c2a303 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/RandomStringUtilsTest.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.apache.commons.lang3.math.NumberUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RandomStringUtilsTest { + + @Test + public void testGenerateNum() { + String result = RandomStringUtils.generateNum(2); + Assertions.assertTrue(NumberUtils.isDigits(result)); + Assertions.assertEquals(2, result.length()); + } + + @Test + public void testGenerateUUID() { + String result = RandomStringUtils.generateUUID(); + Assertions.assertTrue(result.matches("^\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}$")); + } + +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ReflectUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ReflectUtilsTest.java new file mode 100644 index 0000000000..769a40f336 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ReflectUtilsTest.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.lang.reflect.Field; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ReflectUtilsTest { + + public static class TestParent { + + private String age; + + public String tel; + + } + + public static class TestObj extends TestParent { + + private String name; + + private String password; + } + + @Test + public void testLookUpFieldByParentClass() { + Field fieldName = ReflectUtils.lookUpFieldByParentClass(TestObj.class, "name"); + Field fieldAge = ReflectUtils.lookUpFieldByParentClass(TestObj.class, "age"); + Field fieldTel = ReflectUtils.lookUpFieldByParentClass(TestObj.class, "tel"); + Assertions.assertNull(fieldName); + Assertions.assertNull(fieldAge); + Assertions.assertNotNull(fieldTel); + Assertions.assertEquals("tel", fieldTel.getName()); + } + +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/SystemUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/SystemUtilsTest.java new file mode 100644 index 0000000000..32f4ae946e --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/SystemUtilsTest.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class SystemUtilsTest { + + @Test + public void isLinuxPlatform() { + if (SystemUtils.OS_NAME != null && SystemUtils.OS_NAME.toLowerCase().contains("linux")) { + Assertions.assertTrue(SystemUtils.isLinuxPlatform()); + Assertions.assertFalse(SystemUtils.isWindowsPlatform()); + } + } + + @Test + public void isWindowsPlatform() { + if (SystemUtils.OS_NAME != null && SystemUtils.OS_NAME.toLowerCase().contains("windows")) { + Assertions.assertFalse(SystemUtils.isLinuxPlatform()); + Assertions.assertTrue(SystemUtils.isWindowsPlatform()); + } + } + + @Test + public void getProcessId() { + Assertions.assertNotEquals("-1", SystemUtils.getProcessId()); + } +} diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ThreadUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ThreadUtilsTest.java new file mode 100644 index 0000000000..0cba2a6ad9 --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/ThreadUtilsTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + + +package org.apache.eventmesh.common.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +class ThreadUtilsTest { + + @Test + void testRandomPauseBetweenMinAndMax() { + + long min = 1000; + long max = 5000; + + long start = System.currentTimeMillis(); + ThreadUtils.randomPause(min, max, TimeUnit.MILLISECONDS); + long end = System.currentTimeMillis(); + + long pause = end - start; + + assertTrue(pause >= min && pause <= max, "Pause time should be between min and max"); + } + + @Test + void testRandomPauseWithInterruption() { + + Thread.currentThread().interrupt(); + ThreadUtils.randomPause(1000, 2000, TimeUnit.MILLISECONDS); + assertTrue(Thread.currentThread().isInterrupted()); + } + + @Test + void testDeprecatedSleep() { + + ThreadUtils.sleep(1000); + assertTrue(true, "Method should execute without any exception"); + } + + @Test + void testSleepWithTimeOutAndTimeUnit() throws InterruptedException { + + ThreadUtils.sleepWithThrowException(5000, TimeUnit.MILLISECONDS); + assertTrue(true, "Method should execute without any exception"); + } + + @Test + void testSleepWithNullTimeUnit() throws InterruptedException { + + ThreadUtils.sleepWithThrowException(5000, null); + assertTrue(true, "Method should not throw any exception with null TimeUnit"); + } + + @Test + void testSleepWithThrowExceptionInterruption() { + Thread.currentThread().interrupt(); + + assertThrows(InterruptedException.class, () -> { + ThreadUtils.sleepWithThrowException(5000, TimeUnit.MILLISECONDS); + }); + } + + @Test + void testGetPIDWithRealProcessId() { + + long pid = ThreadUtils.getPID(); + assertTrue(pid > 0); + + long cashedPId = ThreadUtils.getPID(); + assertEquals(pid, cashedPId); + } + + @Test + void testGetPIDWithMultiThread() throws InterruptedException { + + final long[] pid1 = new long[1]; + final long[] pid2 = new long[1]; + + Thread thread1 = new Thread(() -> { + pid1[0] = ThreadUtils.getPID(); + assertTrue(pid1[0] > 0); + }); + + Thread thread2 = new Thread(() -> { + pid2[0] = ThreadUtils.getPID(); + assertTrue(pid2[0] > 0); + }); + + thread1.start(); + thread2.start(); + + thread1.join(); + thread2.join(); + + assertEquals(pid1[0], pid2[0]); + } +} \ No newline at end of file diff --git a/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/TypeUtilsTest.java b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/TypeUtilsTest.java new file mode 100644 index 0000000000..fcd83642ec --- /dev/null +++ b/eventmesh-common/src/test/java/org/apache/eventmesh/common/utils/TypeUtilsTest.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.common.utils; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TypeUtilsTest { + + @Test + public void testCastSet() { + Set set = new HashSet<>(Arrays.asList("1", "2", "3")); + Set newSet = TypeUtils.castSet(set, String.class); + for (String s : set) { + Assertions.assertTrue(newSet.contains(s)); + } + Assertions.assertEquals(set.size(), newSet.size()); + } +} diff --git a/eventmesh-common/src/test/resources/configuration.properties b/eventmesh-common/src/test/resources/configuration.properties index fe3f749a1b..f53a7680f0 100644 --- a/eventmesh-common/src/test/resources/configuration.properties +++ b/eventmesh-common/src/test/resources/configuration.properties @@ -14,16 +14,23 @@ # See the License for the specific language governing permissions and # limitations under the License. # -eventMesh.server.env=value1 -eventMesh.server.idc=value2 -eventMesh.sysid=3 -eventMesh.server.cluster=value4 -eventMesh.server.name=value5 -eventMesh.server.hostIp=value6 -eventMesh.connector.plugin.type=rocketmq -eventMesh.security.plugin.type=acl -eventMesh.registry.plugin.type=namesrv -eventMesh.registry.plugin.server-addr=127.0.0.1:8848 -eventMesh.registry.plugin.username=nacos -eventMesh.registry.plugin.password=nacos -eventMesh.trace.plugin=zipkin \ No newline at end of file +eventMesh.server.env=env-succeed!!! +eventMesh.server.idc=idc-succeed!!! +eventMesh.sysid=816 +eventMesh.server.cluster=cluster-succeed!!! +eventMesh.server.name=name-succeed!!! +eventMesh.server.hostIp=hostIp-succeed!!! +eventMesh.storage.plugin.type=storage-succeed!!! +eventMesh.security.plugin.type=security-succeed!!! +eventMesh.metaStorage.plugin.type=metaStorage-succeed!!! +eventMesh.trace.plugin=trace-succeed!!! +eventMesh.metrics.plugin=metrics-succeed1!!!,metrics-succeed2!!!,metrics-succeed3!!! +eventMesh.metaStorage.plugin.server-addr=server-addr-succeed1!!! + +eventMesh.server.security.enabled=true +eventMesh.metaStorage.plugin.enabled=true +eventMesh.server.trace.enabled=true + +eventMesh.server.provide.protocols=TCP,HTTP,GRPC +eventMesh.metaStorage.plugin.username=username-succeed!!! +eventMesh.metaStorage.plugin.password=password-succeed!!! diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-api/build.gradle deleted file mode 100644 index 8ccfa87825..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-api/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -dependencies { - api project(":eventmesh-spi") - implementation project(":eventmesh-common") - api 'io.cloudevents:cloudevents-core' - api 'io.dropwizard.metrics:metrics-core' - api "io.dropwizard.metrics:metrics-healthchecks" - api "io.dropwizard.metrics:metrics-annotation" - api "io.dropwizard.metrics:metrics-json" - - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' - - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' - -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/SendResult.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/SendResult.java deleted file mode 100644 index 1a68132c6b..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/SendResult.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.api; - -public class SendResult { - private String messageId; - - private String topic; - - public String getMessageId() { - return messageId; - } - - public void setMessageId(String messageId) { - this.messageId = messageId; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - @Override - public String toString() { - return "SendResult[topic=" + topic + ", messageId=" + messageId + ']'; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/connector/ConnectorResourceService.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/connector/ConnectorResourceService.java deleted file mode 100644 index 8b6cff71ca..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/connector/ConnectorResourceService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.api.connector; - -import org.apache.eventmesh.spi.EventMeshExtensionType; -import org.apache.eventmesh.spi.EventMeshSPI; - -/** - * ConnectorResourceService - */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.CONNECTOR) -public interface ConnectorResourceService { - - /** - * Resource initialization in connector,such as,some public threadpool if exist - * - * @throws Exception - */ - void init() throws Exception; - - /** - * Resource release in connector,such as,some public threadpool if exist - * - * @throws Exception - */ - void release() throws Exception; -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/exception/ConnectorRuntimeException.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/exception/ConnectorRuntimeException.java deleted file mode 100644 index 0efe513652..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/exception/ConnectorRuntimeException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.api.exception; - -public class ConnectorRuntimeException extends RuntimeException { - - public ConnectorRuntimeException() { - - } - - public ConnectorRuntimeException(String message) { - super(message); - } - - public ConnectorRuntimeException(Throwable throwable) { - super(throwable); - } - - public ConnectorRuntimeException(String message, Throwable throwable) { - super(message, throwable); - } - -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/factory/ConnectorPluginFactory.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/factory/ConnectorPluginFactory.java deleted file mode 100644 index 0793634771..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/factory/ConnectorPluginFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to 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. Apache Software Foundation (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. - */ - -package org.apache.eventmesh.api.factory; - -import org.apache.eventmesh.api.consumer.Consumer; -import org.apache.eventmesh.api.producer.Producer; -import org.apache.eventmesh.spi.EventMeshExtensionFactory; - -/** - * The factory to get connector {@link Producer} and {@link Consumer} - */ -public class ConnectorPluginFactory { - - /** - * Get MeshMQProducer instance by plugin name - * - * @param connectorPluginName plugin name - * @return MeshMQProducer instance - */ - public static Producer getMeshMQProducer(String connectorPluginName) { - return EventMeshExtensionFactory.getExtension(Producer.class, connectorPluginName); - } - - /** - * Get MeshMQPushConsumer instance by plugin name - * - * @param connectorPluginName plugin name - * @return MeshMQPushConsumer instance - */ - public static Consumer getMeshMQPushConsumer(String connectorPluginName) { - return EventMeshExtensionFactory.getExtension(Consumer.class, connectorPluginName); - } - - private static T getPlugin(Class pluginType, String pluginName) { - return EventMeshExtensionFactory.getExtension(pluginType, pluginName); - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle deleted file mode 100644 index 45e6bdd40c..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ - -configurations { - implementation.exclude group: 'ch.qos.logback', module: 'logback-classic' - implementation.exclude group: 'log4j', module: 'log4j' -} - -List rocketmq = [ - "org.apache.rocketmq:rocketmq-client:$rocketmq_version", - "org.apache.rocketmq:rocketmq-broker:$rocketmq_version", - "org.apache.rocketmq:rocketmq-common:$rocketmq_version", - "org.apache.rocketmq:rocketmq-store:$rocketmq_version", - "org.apache.rocketmq:rocketmq-namesrv:$rocketmq_version", - "org.apache.rocketmq:rocketmq-tools:$rocketmq_version", - "org.apache.rocketmq:rocketmq-remoting:$rocketmq_version", - "org.apache.rocketmq:rocketmq-logging:$rocketmq_version", - "org.apache.rocketmq:rocketmq-test:$rocketmq_version", - "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", - "org.apache.rocketmq:rocketmq-filter:$rocketmq_version", - "org.apache.rocketmq:rocketmq-acl:$rocketmq_version", - "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", - -] - -dependencies { - implementation project(":eventmesh-common") - implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") - implementation rocketmq - - testImplementation project(":eventmesh-connector-plugin:eventmesh-connector-api") - testImplementation project(":eventmesh-common") - - testImplementation "org.mockito:mockito-core" - testImplementation "org.powermock:powermock-module-junit4" - testImplementation "org.powermock:powermock-api-mockito2" - - testImplementation rocketmq - - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' - - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/gradle.properties b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/gradle.properties deleted file mode 100644 index 2138704df0..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# 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. -# - -rocketmq_version=4.9.3 - -pluginType=connector -pluginName=rocketmq \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/admin/command/Command.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/admin/command/Command.java deleted file mode 100644 index 9f3b5e9e60..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/admin/command/Command.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.admin.command; - -import org.apache.eventmesh.connector.rocketmq.config.ClientConfiguration; - -import org.apache.rocketmq.acl.common.AclClientRPCHook; -import org.apache.rocketmq.acl.common.SessionCredentials; -import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; - -import java.util.UUID; - -public abstract class Command { - protected DefaultMQAdminExt adminExt; - - protected String nameServerAddr; - protected String clusterName; - - public void init() { - final ClientConfiguration clientConfiguration = new ClientConfiguration(); - clientConfiguration.init(); - - nameServerAddr = clientConfiguration.namesrvAddr; - clusterName = clientConfiguration.clusterName; - String accessKey = clientConfiguration.accessKey; - String secretKey = clientConfiguration.secretKey; - - RPCHook rpcHook = new AclClientRPCHook(new SessionCredentials(accessKey, secretKey)); - adminExt = new DefaultMQAdminExt(rpcHook); - String groupId = UUID.randomUUID().toString(); - adminExt.setAdminExtGroup("admin_ext_group-" + groupId); - adminExt.setNamesrvAddr(nameServerAddr); - } - - public abstract void execute() throws Exception; -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/admin/command/CreateTopicCommand.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/admin/command/CreateTopicCommand.java deleted file mode 100644 index f1e325e552..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/admin/command/CreateTopicCommand.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.admin.command; - -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.TopicConfig; -import org.apache.rocketmq.tools.command.CommandUtil; - -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CreateTopicCommand extends Command { - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private int numOfQueue = 4; - private int queuePermission = 6; - private String topicName = ""; - - @Override - public void execute() throws Exception { - if (StringUtils.isBlank(topicName)) { - logger.error("Topic name can not be blank."); - throw new Exception("Topic name can not be blank."); - } - try { - init(); - adminExt.start(); - Set brokersAddr = CommandUtil.fetchMasterAddrByClusterName( - adminExt, clusterName); - for (String masterAddr : brokersAddr) { - TopicConfig topicConfig = new TopicConfig(); - topicConfig.setTopicName(topicName); - topicConfig.setReadQueueNums(numOfQueue); - topicConfig.setWriteQueueNums(numOfQueue); - topicConfig.setPerm(queuePermission); - adminExt.createAndUpdateTopicConfig(masterAddr, topicConfig); - logger.info("Topic {} is created for RocketMQ broker {}", topicName, masterAddr); - } - } finally { - adminExt.shutdown(); - } - } - - public int getNumOfQueue() { - return numOfQueue; - } - - public int getQueuePermission() { - return queuePermission; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public void setNumOfQueue(int numOfQueue) { - this.numOfQueue = numOfQueue; - } - - public void setQueuePermission(int permission) { - this.queuePermission = permission; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/RocketMQMessageFactory.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/RocketMQMessageFactory.java deleted file mode 100644 index 24699ef9fe..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/RocketMQMessageFactory.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.cloudevent; - -import org.apache.eventmesh.connector.rocketmq.cloudevent.impl.RocketMQBinaryMessageReader; -import org.apache.eventmesh.connector.rocketmq.cloudevent.impl.RocketMQHeaders; -import org.apache.eventmesh.connector.rocketmq.cloudevent.impl.RocketMQMessageWriter; - -import org.apache.rocketmq.common.message.Message; - -import java.util.Map; - -import javax.annotation.ParametersAreNonnullByDefault; - -import io.cloudevents.core.message.MessageReader; -import io.cloudevents.core.message.MessageWriter; -import io.cloudevents.core.message.impl.MessageUtils; -import io.cloudevents.lang.Nullable; -import io.cloudevents.rw.CloudEventRWException; -import io.cloudevents.rw.CloudEventWriter; - - -@ParametersAreNonnullByDefault -public final class RocketMQMessageFactory { - - private RocketMQMessageFactory() { - // prevent instantiation - } - - public static MessageReader createReader(final Message message) throws CloudEventRWException { - return createReader(message.getProperties(), message.getBody()); - } - - - public static MessageReader createReader(final Map props, - @Nullable final byte[] body) - throws CloudEventRWException { - - return MessageUtils.parseStructuredOrBinaryMessage( - () -> null, - format -> null, - () -> props.get(RocketMQHeaders.SPEC_VERSION), - sv -> new RocketMQBinaryMessageReader(sv, props, body) - ); - } - - - public static MessageWriter, Message> createWriter(String topic) { - return new RocketMQMessageWriter<>(topic); - } - - public static MessageWriter, Message> createWriter(String topic, - String keys) { - return new RocketMQMessageWriter<>(topic, keys); - } - - public static MessageWriter, Message> createWriter(String topic, - String keys, - String tags) { - return new RocketMQMessageWriter<>(topic, keys, tags); - } - -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQBinaryMessageReader.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQBinaryMessageReader.java deleted file mode 100644 index 07888a6a72..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQBinaryMessageReader.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.cloudevent.impl; - -import java.util.Map; -import java.util.Objects; -import java.util.function.BiConsumer; - -import io.cloudevents.SpecVersion; -import io.cloudevents.core.data.BytesCloudEventData; -import io.cloudevents.core.message.impl.BaseGenericBinaryMessageReaderImpl; - -public class RocketMQBinaryMessageReader - extends BaseGenericBinaryMessageReaderImpl { - - private final Map headers; - - public RocketMQBinaryMessageReader(SpecVersion version, Map headers, - byte[] payload) { - super(version, - payload != null && payload.length > 0 ? BytesCloudEventData.wrap(payload) : null); - - Objects.requireNonNull(headers); - this.headers = headers; - } - - @Override - protected boolean isContentTypeHeader(String key) { - return key.equals(RocketMQHeaders.CONTENT_TYPE); - } - - @Override - protected boolean isCloudEventsHeader(String key) { - return true; - } - - @Override - protected String toCloudEventsKey(String key) { - return key.toLowerCase(); - } - - @Override - protected void forEachHeader(BiConsumer fn) { - this.headers.forEach((k, v) -> fn.accept(k, v)); - } - - @Override - protected String toCloudEventsValue(String value) { - return value; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQHeaders.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQHeaders.java deleted file mode 100644 index 793092355d..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQHeaders.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.cloudevent.impl; - -import java.util.Map; - -import io.cloudevents.core.message.impl.MessageUtils; -import io.cloudevents.core.v1.CloudEventV1; - -public class RocketMQHeaders { - - public static final String CE_PREFIX = "CE_"; - - protected static final Map ATTRIBUTES_TO_HEADERS = - MessageUtils.generateAttributesToHeadersMapping(v -> v); - - public static final String CONTENT_TYPE = - ATTRIBUTES_TO_HEADERS.get(CloudEventV1.DATACONTENTTYPE); - - public static final String SPEC_VERSION = ATTRIBUTES_TO_HEADERS.get(CloudEventV1.SPECVERSION); - - -} - diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQMessageWriter.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQMessageWriter.java deleted file mode 100644 index 6900c44cee..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/cloudevent/impl/RocketMQMessageWriter.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.cloudevent.impl; - -import org.apache.rocketmq.common.message.Message; - -import io.cloudevents.CloudEventData; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.message.MessageWriter; -import io.cloudevents.rw.CloudEventContextWriter; -import io.cloudevents.rw.CloudEventRWException; -import io.cloudevents.rw.CloudEventWriter; - - -public final class RocketMQMessageWriter - implements MessageWriter, Message>, CloudEventWriter { - - private Message message; - - - public RocketMQMessageWriter(String topic) { - message = new Message(); - message.setTopic(topic); - } - - public RocketMQMessageWriter(String topic, String keys) { - message = new Message(); - - message.setTopic(topic); - - if (keys != null && keys.length() > 0) { - message.setKeys(keys); - } - } - - public RocketMQMessageWriter(String topic, String keys, String tags) { - message = new Message(); - - message.setTopic(topic); - - if (tags != null && tags.length() > 0) { - message.setTags(tags); - } - - if (keys != null && keys.length() > 0) { - message.setKeys(keys); - } - } - - - @Override - public CloudEventContextWriter withContextAttribute(String name, String value) - throws CloudEventRWException { - message.putUserProperty(name, value); - return this; - } - - @Override - public RocketMQMessageWriter create(final SpecVersion version) { - message.putUserProperty(RocketMQHeaders.SPEC_VERSION, version.toString()); - return this; - } - - @Override - public Message setEvent(final EventFormat format, final byte[] value) - throws CloudEventRWException { - message.putUserProperty(RocketMQHeaders.CONTENT_TYPE, format.serializedContentType()); - message.setBody(value); - return message; - } - - @Override - public Message end(final CloudEventData data) throws CloudEventRWException { - message.setBody(data.toBytes()); - return message; - } - - @Override - public Message end() { - message.setBody(null); - return message; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/common/EventMeshConstants.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/common/EventMeshConstants.java deleted file mode 100644 index 1206ef9f33..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/common/EventMeshConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.common; - -public class EventMeshConstants { - - public static final String EVENTMESH_CONF_FILE = "rocketmq-client.properties"; - - public static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; - - public static final String STORE_TIMESTAMP = "storetime"; -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ClientConfig.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ClientConfig.java deleted file mode 100644 index f03a38a4a9..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ClientConfig.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.config; - - -import org.apache.eventmesh.connector.rocketmq.domain.NonStandardKeys; - -public class ClientConfig implements NonStandardKeys { - private String driverImpl; - private String accessPoints; - private String namespace; - private String producerId; - private String consumerId; - private int operationTimeout = 5000; - private String region; - private String routingSource; - private String routingDestination; - private String routingExpression; - private String rmqConsumerGroup; - private String rmqProducerGroup = "__OMS_PRODUCER_DEFAULT_GROUP"; - private int rmqMaxRedeliveryTimes = 16; - private int rmqMessageConsumeTimeout = 15; //In minutes - private int rmqMaxConsumeThreadNums = 64; - private int rmqMinConsumeThreadNums = 20; - private String rmqMessageDestination; - private int rmqPullMessageBatchNums = 32; - private int rmqPullMessageCacheCapacity = 1000; - private String messageModel; - - public String getDriverImpl() { - return driverImpl; - } - - public void setDriverImpl(final String driverImpl) { - this.driverImpl = driverImpl; - } - - public String getAccessPoints() { - return accessPoints; - } - - public void setAccessPoints(final String accessPoints) { - this.accessPoints = accessPoints; - } - - public String getNamespace() { - return namespace; - } - - public void setNamespace(final String namespace) { - this.namespace = namespace; - } - - public String getProducerId() { - return producerId; - } - - public void setProducerId(final String producerId) { - this.producerId = producerId; - } - - public String getConsumerId() { - return consumerId; - } - - public void setConsumerId(final String consumerId) { - this.consumerId = consumerId; - } - - public int getOperationTimeout() { - return operationTimeout; - } - - public void setOperationTimeout(final int operationTimeout) { - this.operationTimeout = operationTimeout; - } - - public String getRoutingSource() { - return routingSource; - } - - public void setRoutingSource(final String routingSource) { - this.routingSource = routingSource; - } - - public String getRmqConsumerGroup() { - return rmqConsumerGroup; - } - - public void setRmqConsumerGroup(final String rmqConsumerGroup) { - this.rmqConsumerGroup = rmqConsumerGroup; - } - - public String getRmqProducerGroup() { - return rmqProducerGroup; - } - - public void setRmqProducerGroup(final String rmqProducerGroup) { - this.rmqProducerGroup = rmqProducerGroup; - } - - public int getRmqMaxRedeliveryTimes() { - return rmqMaxRedeliveryTimes; - } - - public void setRmqMaxRedeliveryTimes(final int rmqMaxRedeliveryTimes) { - this.rmqMaxRedeliveryTimes = rmqMaxRedeliveryTimes; - } - - public int getRmqMessageConsumeTimeout() { - return rmqMessageConsumeTimeout; - } - - public void setRmqMessageConsumeTimeout(final int rmqMessageConsumeTimeout) { - this.rmqMessageConsumeTimeout = rmqMessageConsumeTimeout; - } - - public int getRmqMaxConsumeThreadNums() { - return rmqMaxConsumeThreadNums; - } - - public void setRmqMaxConsumeThreadNums(final int rmqMaxConsumeThreadNums) { - this.rmqMaxConsumeThreadNums = rmqMaxConsumeThreadNums; - } - - public int getRmqMinConsumeThreadNums() { - return rmqMinConsumeThreadNums; - } - - public void setRmqMinConsumeThreadNums(final int rmqMinConsumeThreadNums) { - this.rmqMinConsumeThreadNums = rmqMinConsumeThreadNums; - } - - public String getRmqMessageDestination() { - return rmqMessageDestination; - } - - public void setRmqMessageDestination(final String rmqMessageDestination) { - this.rmqMessageDestination = rmqMessageDestination; - } - - public int getRmqPullMessageBatchNums() { - return rmqPullMessageBatchNums; - } - - public void setRmqPullMessageBatchNums(final int rmqPullMessageBatchNums) { - this.rmqPullMessageBatchNums = rmqPullMessageBatchNums; - } - - public int getRmqPullMessageCacheCapacity() { - return rmqPullMessageCacheCapacity; - } - - public void setRmqPullMessageCacheCapacity(final int rmqPullMessageCacheCapacity) { - this.rmqPullMessageCacheCapacity = rmqPullMessageCacheCapacity; - } - - public String getRegion() { - return region; - } - - public void setRegion(String region) { - this.region = region; - } - - public String getRoutingDestination() { - return routingDestination; - } - - public void setRoutingDestination(String routingDestination) { - this.routingDestination = routingDestination; - } - - public String getRoutingExpression() { - return routingExpression; - } - - public void setRoutingExpression(String routingExpression) { - this.routingExpression = routingExpression; - } - - public String getMessageModel() { - return messageModel; - } - - public void setMessageModel(String messageModel) { - this.messageModel = messageModel; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ClientConfiguration.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ClientConfiguration.java deleted file mode 100644 index 53f7e5f2cf..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ClientConfiguration.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.config; - -import org.apache.commons.lang3.StringUtils; - -import com.google.common.base.Preconditions; - -public class ClientConfiguration { - - public String namesrvAddr = ""; - public String clientUserName = "username"; - public String clientPass = "password"; - public Integer consumeThreadMin = 2; - public Integer consumeThreadMax = 2; - public Integer consumeQueueSize = 10000; - public Integer pullBatchSize = 32; - public Integer ackWindow = 1000; - public Integer pubWindow = 100; - public long consumeTimeout = 0L; - public Integer pollNameServerInterval = 10 * 1000; - public Integer heartbeatBrokerInterval = 30 * 1000; - public Integer rebalanceInterval = 20 * 1000; - public String clusterName = ""; - public String accessKey = ""; - public String secretKey = ""; - - public void init() { - - String clientUserNameStr = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_USERNAME); - if (StringUtils.isNotBlank(clientUserNameStr)) { - clientUserName = StringUtils.trim(clientUserNameStr); - } - - String clientPassStr = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_PASSWORD); - if (StringUtils.isNotBlank(clientPassStr)) { - clientPass = StringUtils.trim(clientPassStr); - } - - String namesrvAddrStr = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_NAMESRV_ADDR); - Preconditions.checkState(StringUtils.isNotEmpty(namesrvAddrStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_NAMESRV_ADDR)); - namesrvAddr = StringUtils.trim(namesrvAddrStr); - - String consumeThreadPoolMinStr = - ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_MIN); - if (StringUtils.isNotEmpty(consumeThreadPoolMinStr)) { - Preconditions.checkState(StringUtils.isNumeric(consumeThreadPoolMinStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_MIN)); - consumeThreadMin = Integer.valueOf(consumeThreadPoolMinStr); - } - - String consumeThreadPoolMaxStr = - ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_MAX); - if (StringUtils.isNotEmpty(consumeThreadPoolMaxStr)) { - Preconditions.checkState(StringUtils.isNumeric(consumeThreadPoolMaxStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_MAX)); - consumeThreadMax = Integer.valueOf(consumeThreadPoolMaxStr); - } - - String consumerThreadPoolQueueSizeStr = - ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_QUEUESIZE); - if (StringUtils.isNotEmpty(consumerThreadPoolQueueSizeStr)) { - Preconditions.checkState(StringUtils.isNumeric(consumerThreadPoolQueueSizeStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_QUEUESIZE)); - consumeQueueSize = Integer.valueOf(consumerThreadPoolQueueSizeStr); - } - - String clientAckWindowStr = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_ACK_WINDOW); - if (StringUtils.isNotEmpty(clientAckWindowStr)) { - Preconditions.checkState(StringUtils.isNumeric(clientAckWindowStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_ACK_WINDOW)); - ackWindow = Integer.valueOf(clientAckWindowStr); - } - - String clientPubWindowStr = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_PUB_WINDOW); - if (StringUtils.isNotEmpty(clientPubWindowStr)) { - Preconditions.checkState(StringUtils.isNumeric(clientPubWindowStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_PUB_WINDOW)); - pubWindow = Integer.valueOf(clientPubWindowStr); - } - - String consumeTimeoutStr = - ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_CONSUME_TIMEOUT); - if (StringUtils.isNotBlank(consumeTimeoutStr)) { - Preconditions.checkState(StringUtils.isNumeric(consumeTimeoutStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_CONSUME_TIMEOUT)); - consumeTimeout = Long.parseLong(consumeTimeoutStr); - } - - String clientPullBatchSizeStr = - ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_PULL_BATCHSIZE); - if (StringUtils.isNotEmpty(clientPullBatchSizeStr)) { - Preconditions.checkState(StringUtils.isNumeric(clientPullBatchSizeStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_PULL_BATCHSIZE)); - pullBatchSize = Integer.valueOf(clientPullBatchSizeStr); - } - - String clientPollNamesrvIntervalStr = - ConfigurationWrapper.getProp( - ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_POLL_NAMESRV_INTERVAL); - if (StringUtils.isNotEmpty(clientPollNamesrvIntervalStr)) { - Preconditions.checkState(StringUtils.isNumeric(clientPollNamesrvIntervalStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_POLL_NAMESRV_INTERVAL)); - pollNameServerInterval = Integer.valueOf(clientPollNamesrvIntervalStr); - } - - String clientHeartbeatBrokerIntervalStr = - ConfigurationWrapper.getProp( - ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_HEARTBEAT_BROKER_INTERVAL); - if (StringUtils.isNotEmpty(clientHeartbeatBrokerIntervalStr)) { - Preconditions.checkState(StringUtils.isNumeric(clientHeartbeatBrokerIntervalStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_HEARTBEAT_BROKER_INTERVAL)); - heartbeatBrokerInterval = Integer.valueOf(clientHeartbeatBrokerIntervalStr); - } - - String clientRebalanceIntervalIntervalStr = - ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_REBALANCE_INTERVAL); - if (StringUtils.isNotEmpty(clientRebalanceIntervalIntervalStr)) { - Preconditions.checkState(StringUtils.isNumeric(clientRebalanceIntervalIntervalStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLIENT_REBALANCE_INTERVAL)); - rebalanceInterval = Integer.valueOf(clientRebalanceIntervalIntervalStr); - } - - String cluster = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_CLUSTER); - if (StringUtils.isNotBlank(cluster)) { - clusterName = cluster; - } - - String ak = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_ACCESS_KEY); - if (StringUtils.isNotBlank(ak)) { - accessKey = ak; - } - - String sk = ConfigurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ROCKETMQ_SECRET_KEY); - if (StringUtils.isNotBlank(sk)) { - secretKey = sk; - } - } - - static class ConfKeys { - - public static final String KEYS_EVENTMESH_ROCKETMQ_NAMESRV_ADDR = "eventMesh.server.rocketmq.namesrvAddr"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_USERNAME = "eventMesh.server.rocketmq.username"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_PASSWORD = "eventMesh.server.rocketmq.password"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_MIN = - "eventMesh.server.rocketmq.client.consumeThreadMin"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_MAX = - "eventMesh.server.rocketmq.client.consumeThreadMax"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CONSUME_THREADPOOL_QUEUESIZE = - "eventMesh.server.rocketmq.client.consumeThreadPoolQueueSize"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_ACK_WINDOW = "eventMesh.server.rocketmq.client.ackwindow"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_PUB_WINDOW = "eventMesh.server.rocketmq.client.pubwindow"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_CONSUME_TIMEOUT = - "eventMesh.server.rocketmq.client.comsumeTimeoutInMin"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_PULL_BATCHSIZE = - "eventMesh.server.rocketmq.client.pullBatchSize"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_POLL_NAMESRV_INTERVAL = - "eventMesh.server.rocketmq.client.pollNameServerInterval"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_HEARTBEAT_BROKER_INTERVAL = - "eventMesh.server.rocketmq.client.heartbeatBrokerInterval"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLIENT_REBALANCE_INTERVAL = - "eventMesh.server.rocketmq.client.rebalanceInterval"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_CLUSTER = "eventMesh.server.rocketmq.cluster"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_ACCESS_KEY = - "eventMesh.server.rocketmq.accessKey"; - - public static final String KEYS_EVENTMESH_ROCKETMQ_SECRET_KEY = - "eventMesh.server.rocketmq.secretKey"; - - } -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ConfigurationWrapper.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ConfigurationWrapper.java deleted file mode 100644 index 83036bb36b..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/ConfigurationWrapper.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.config; - -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.connector.rocketmq.common.EventMeshConstants; - -import org.apache.commons.lang3.StringUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@UtilityClass -public class ConfigurationWrapper { - - private static final Properties properties = new Properties(); - - static { - loadProperties(); - } - - public String getProp(String key) { - return StringUtils.isEmpty(key) ? null : properties.getProperty(key, null); - } - - /** - * Load rocketmq properties file from classpath and conf home. - * The properties defined in conf home will override classpath. - */ - private void loadProperties() { - try (InputStream resourceAsStream = ConfigurationWrapper.class.getResourceAsStream( - "/" + EventMeshConstants.EVENTMESH_CONF_FILE)) { - if (resourceAsStream != null) { - properties.load(resourceAsStream); - } - } catch (IOException e) { - throw new RuntimeException(String.format("Load %s.properties file from classpath error", EventMeshConstants.EVENTMESH_CONF_FILE)); - } - try { - String configPath = Constants.EVENTMESH_CONF_HOME + File.separator + EventMeshConstants.EVENTMESH_CONF_FILE; - if (new File(configPath).exists()) { - properties.load(new BufferedReader(new FileReader(configPath))); - } - } catch (IOException e) { - throw new IllegalArgumentException(String.format("Cannot load %s file from conf", EventMeshConstants.EVENTMESH_CONF_FILE)); - } - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/connector/ConnectorResourceServiceRocketmqImpl.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/connector/ConnectorResourceServiceRocketmqImpl.java deleted file mode 100644 index f26747e9db..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/connector/ConnectorResourceServiceRocketmqImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.connector; - -import org.apache.eventmesh.api.connector.ConnectorResourceService; - -public class ConnectorResourceServiceRocketmqImpl implements ConnectorResourceService { - @Override - public void init() throws Exception { - - } - - @Override - public void release() throws Exception { - - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/consumer/PushConsumerImpl.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/consumer/PushConsumerImpl.java deleted file mode 100644 index 71f921fddb..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/consumer/PushConsumerImpl.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.consumer; - -import org.apache.eventmesh.api.AbstractContext; -import org.apache.eventmesh.api.AsyncConsumeContext; -import org.apache.eventmesh.api.EventListener; -import org.apache.eventmesh.api.EventMeshAction; -import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.connector.rocketmq.cloudevent.RocketMQMessageFactory; -import org.apache.eventmesh.connector.rocketmq.common.EventMeshConstants; -import org.apache.eventmesh.connector.rocketmq.config.ClientConfig; -import org.apache.eventmesh.connector.rocketmq.domain.NonStandardKeys; -import org.apache.eventmesh.connector.rocketmq.patch.EventMeshConsumeConcurrentlyContext; -import org.apache.eventmesh.connector.rocketmq.patch.EventMeshConsumeConcurrentlyStatus; -import org.apache.eventmesh.connector.rocketmq.patch.EventMeshMessageListenerConcurrently; -import org.apache.eventmesh.connector.rocketmq.utils.BeanUtils; -import org.apache.eventmesh.connector.rocketmq.utils.CloudEventUtils; -import org.apache.eventmesh.connector.rocketmq.utils.OMSUtil; - -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; -import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -import org.apache.rocketmq.remoting.protocol.LanguageCode; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class PushConsumerImpl { - private final DefaultMQPushConsumer rocketmqPushConsumer; - private final Properties properties; - private AtomicBoolean started = new AtomicBoolean(false); - private EventListener eventListener; - private final ClientConfig clientConfig; - - public PushConsumerImpl(final Properties properties) { - this.rocketmqPushConsumer = new DefaultMQPushConsumer(); - this.properties = properties; - this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); - - String accessPoints = clientConfig.getAccessPoints(); - if (accessPoints == null || accessPoints.isEmpty()) { - throw new ConnectorRuntimeException("OMS AccessPoints is null or empty."); - } - this.rocketmqPushConsumer.setNamesrvAddr(accessPoints.replace(',', ';')); - String consumerGroup = clientConfig.getConsumerId(); - if (null == consumerGroup || consumerGroup.isEmpty()) { - throw new ConnectorRuntimeException( - "Consumer Group is necessary for RocketMQ, please set it."); - } - this.rocketmqPushConsumer.setConsumerGroup(consumerGroup); - this.rocketmqPushConsumer.setMaxReconsumeTimes(clientConfig.getRmqMaxRedeliveryTimes()); - this.rocketmqPushConsumer.setConsumeTimeout(clientConfig.getRmqMessageConsumeTimeout()); - this.rocketmqPushConsumer.setConsumeThreadMax(clientConfig.getRmqMaxConsumeThreadNums()); - this.rocketmqPushConsumer.setConsumeThreadMin(clientConfig.getRmqMinConsumeThreadNums()); - this.rocketmqPushConsumer.setMessageModel( - MessageModel.valueOf(clientConfig.getMessageModel())); - - String consumerId = OMSUtil.buildInstanceName(); - //this.rocketmqPushConsumer.setInstanceName(consumerId); - this.rocketmqPushConsumer.setInstanceName(properties.getProperty("instanceName")); - properties.put("CONSUMER_ID", consumerId); - this.rocketmqPushConsumer.setLanguage(LanguageCode.OMS); - - if (clientConfig.getMessageModel().equalsIgnoreCase(MessageModel.BROADCASTING.name())) { - rocketmqPushConsumer.registerMessageListener(new BroadCastingMessageListener()); - } else { - rocketmqPushConsumer.registerMessageListener(new ClusteringMessageListener()); - } - } - - public Properties attributes() { - return properties; - } - - - public void start() { - if (this.started.compareAndSet(false, true)) { - try { - this.rocketmqPushConsumer.start(); - } catch (Exception e) { - throw new ConnectorRuntimeException(e.getMessage()); - } - } - } - - - public synchronized void shutdown() { - if (this.started.compareAndSet(true, false)) { - this.rocketmqPushConsumer.shutdown(); - } - } - - - public boolean isStarted() { - return this.started.get(); - } - - - public boolean isClosed() { - return !this.isStarted(); - } - - public DefaultMQPushConsumer getRocketmqPushConsumer() { - return rocketmqPushConsumer; - } - - public void subscribe(String topic, String subExpression) { - try { - this.rocketmqPushConsumer.subscribe(topic, subExpression); - } catch (MQClientException e) { - throw new ConnectorRuntimeException(String.format("RocketMQ push consumer can't attach to %s.", topic)); - } - } - - - public void unsubscribe(String topic) { - try { - this.rocketmqPushConsumer.unsubscribe(topic); - } catch (Exception e) { - throw new ConnectorRuntimeException(String.format("RocketMQ push consumer fails to unsubscribe topic: %s", topic)); - } - } - - public void updateOffset(List cloudEvents, AbstractContext context) { - ConsumeMessageService consumeMessageService = rocketmqPushConsumer - .getDefaultMQPushConsumerImpl().getConsumeMessageService(); - List msgExtList = new ArrayList<>(cloudEvents.size()); - for (CloudEvent msg : cloudEvents) { - msgExtList.add(CloudEventUtils.msgConvertExt( - RocketMQMessageFactory.createWriter(msg.getSubject()).writeBinary(msg))); - } - ((ConsumeMessageConcurrentlyService) consumeMessageService) - .updateOffset(msgExtList, (EventMeshConsumeConcurrentlyContext) context); - } - - - private class BroadCastingMessageListener extends EventMeshMessageListenerConcurrently { - - @Override - public EventMeshConsumeConcurrentlyStatus handleMessage(MessageExt msg, - EventMeshConsumeConcurrentlyContext context) { - if (msg == null) { - return EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS; - } - - msg.putUserProperty(Constants.PROPERTY_MESSAGE_BORN_TIMESTAMP, - String.valueOf(msg.getBornTimestamp())); - msg.putUserProperty(Constants.PROPERTY_MESSAGE_STORE_TIMESTAMP, - String.valueOf(msg.getStoreTimestamp())); - - //for rr request/reply - CloudEvent cloudEvent = - RocketMQMessageFactory.createReader(CloudEventUtils.msgConvert(msg)).toEvent(); - - CloudEventBuilder cloudEventBuilder = null; - for (String sysPropKey : MessageConst.STRING_HASH_SET) { - if (StringUtils.isNotEmpty(msg.getProperty(sysPropKey))) { - String prop = msg.getProperty(sysPropKey); - sysPropKey = sysPropKey.toLowerCase().replaceAll("_", Constants.MESSAGE_PROP_SEPARATOR); - cloudEventBuilder = CloudEventBuilder.from(cloudEvent).withExtension(sysPropKey, prop); - } - } - if (cloudEventBuilder != null) { - cloudEvent = cloudEventBuilder.build(); - } - - if (eventListener == null) { - throw new ConnectorRuntimeException(String.format("The topic/queue %s isn't attached to this consumer", - msg.getTopic())); - } - - final Properties contextProperties = new Properties(); - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); - EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = new EventMeshAsyncConsumeContext() { - @Override - public void commit(EventMeshAction action) { - switch (action) { - case CommitMessage: - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS.name()); - break; - case ReconsumeLater: - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); - break; - case ManualAck: - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.CONSUME_FINISH.name()); - break; - default: - break; - } - } - }; - - eventMeshAsyncConsumeContext.setAbstractContext(context); - - eventListener.consume(cloudEvent, eventMeshAsyncConsumeContext); - - return EventMeshConsumeConcurrentlyStatus.valueOf( - contextProperties.getProperty(NonStandardKeys.MESSAGE_CONSUME_STATUS)); - } - - - } - - private class ClusteringMessageListener extends EventMeshMessageListenerConcurrently { - - @Override - public EventMeshConsumeConcurrentlyStatus handleMessage(MessageExt msg, - EventMeshConsumeConcurrentlyContext context) { - if (msg == null) { - return EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS; - } - - msg.putUserProperty(Constants.PROPERTY_MESSAGE_BORN_TIMESTAMP, - String.valueOf(msg.getBornTimestamp())); - msg.putUserProperty(EventMeshConstants.STORE_TIMESTAMP, - String.valueOf(msg.getStoreTimestamp())); - - CloudEvent cloudEvent = - RocketMQMessageFactory.createReader(CloudEventUtils.msgConvert(msg)).toEvent(); - - CloudEventBuilder cloudEventBuilder = null; - - for (String sysPropKey : MessageConst.STRING_HASH_SET) { - if (StringUtils.isNotEmpty(msg.getProperty(sysPropKey))) { - String prop = msg.getProperty(sysPropKey); - sysPropKey = sysPropKey.toLowerCase().replaceAll("_", Constants.MESSAGE_PROP_SEPARATOR); - cloudEventBuilder = CloudEventBuilder.from(cloudEvent).withExtension(sysPropKey, prop); - } - } - if (cloudEventBuilder != null) { - cloudEvent = cloudEventBuilder.build(); - } - - if (eventListener == null) { - throw new ConnectorRuntimeException(String.format("The topic/queue %s isn't attached to this consumer", - msg.getTopic())); - } - - final Properties contextProperties = new Properties(); - - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); - - EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = new EventMeshAsyncConsumeContext() { - @Override - public void commit(EventMeshAction action) { - switch (action) { - case CommitMessage: - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS.name()); - break; - case ReconsumeLater: - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); - break; - case ManualAck: - contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, - EventMeshConsumeConcurrentlyStatus.CONSUME_FINISH.name()); - break; - default: - break; - } - } - }; - - eventMeshAsyncConsumeContext.setAbstractContext(context); - - eventListener.consume(cloudEvent, eventMeshAsyncConsumeContext); - - return EventMeshConsumeConcurrentlyStatus.valueOf( - contextProperties.getProperty(NonStandardKeys.MESSAGE_CONSUME_STATUS)); - } - } - - public void registerEventListener(EventListener listener) { - this.eventListener = listener; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/consumer/RocketMQConsumerImpl.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/consumer/RocketMQConsumerImpl.java deleted file mode 100644 index a2630652ad..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/consumer/RocketMQConsumerImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.consumer; - -import org.apache.eventmesh.api.AbstractContext; -import org.apache.eventmesh.api.EventListener; -import org.apache.eventmesh.api.consumer.Consumer; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.connector.rocketmq.config.ClientConfiguration; - -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; - -import java.util.List; -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class RocketMQConsumerImpl implements Consumer { - - public Logger messageLogger = LoggerFactory.getLogger("message"); - - private PushConsumerImpl pushConsumer; - - @Override - public synchronized void init(Properties keyValue) throws Exception { - final ClientConfiguration clientConfiguration = new ClientConfiguration(); - clientConfiguration.init(); - boolean isBroadcast = Boolean.parseBoolean(keyValue.getProperty(Constants.IS_BROADCAST)); - - String consumerGroup = keyValue.getProperty(Constants.CONSUMER_GROUP); - if (isBroadcast) { - consumerGroup = Constants.BROADCAST_PREFIX + consumerGroup; - } - - String namesrvAddr = clientConfiguration.namesrvAddr; - String instanceName = keyValue.getProperty(Constants.INSTANCE_NAME); - Properties properties = new Properties(); - properties.put(Constants.ACCESS_POINTS, namesrvAddr); - properties.put(Constants.REGION, Constants.NAMESPACE); - properties.put(Constants.INSTANCE_NAME, instanceName); - properties.put(Constants.CONSUMER_ID, consumerGroup); - if (isBroadcast) { - properties.put(Constants.MESSAGE_MODEL, MessageModel.BROADCASTING.name()); - } else { - properties.put(Constants.MESSAGE_MODEL, MessageModel.CLUSTERING.name()); - } - - pushConsumer = new PushConsumerImpl(properties); - } - - @Override - public void subscribe(String topic) throws Exception { - pushConsumer.subscribe(topic, "*"); - } - - @Override - public boolean isStarted() { - return pushConsumer.isStarted(); - } - - @Override - public boolean isClosed() { - return pushConsumer.isClosed(); - } - - @Override - public synchronized void start() { - pushConsumer.start(); - } - - @Override - public void updateOffset(List cloudEvents, AbstractContext context) { - pushConsumer.updateOffset(cloudEvents, context); - } - - @Override - public void unsubscribe(String topic) { - pushConsumer.unsubscribe(topic); - } - - @Override - public void registerEventListener(EventListener listener) { - pushConsumer.registerEventListener(listener); - } - - @Override - public synchronized void shutdown() { - pushConsumer.shutdown(); - } - - public Properties attributes() { - return pushConsumer.attributes(); - } - -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/AbstractProducer.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/AbstractProducer.java deleted file mode 100644 index ade88f5a7d..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/AbstractProducer.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.producer; - -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.connector.rocketmq.config.ClientConfig; -import org.apache.eventmesh.connector.rocketmq.exception.RMQMessageFormatException; -import org.apache.eventmesh.connector.rocketmq.exception.RMQTimeoutException; -import org.apache.eventmesh.connector.rocketmq.utils.BeanUtils; -import org.apache.eventmesh.connector.rocketmq.utils.OMSUtil; - -import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl; -import org.apache.rocketmq.client.log.ClientLogger; -import org.apache.rocketmq.client.producer.DefaultMQProducer; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.remoting.exception.RemotingConnectException; -import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; -import org.apache.rocketmq.remoting.protocol.LanguageCode; - -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; - -public abstract class AbstractProducer { - - static final InternalLogger log = ClientLogger.getLog(); - final Properties properties; - final DefaultMQProducer rocketmqProducer; - protected final AtomicBoolean started = new AtomicBoolean(false); - // private boolean started = false; - private final ClientConfig clientConfig; - - AbstractProducer(final Properties properties) { - this.properties = properties; - this.rocketmqProducer = new DefaultMQProducer(); - this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); - - String accessPoints = clientConfig.getAccessPoints(); - if (accessPoints == null || accessPoints.isEmpty()) { - throw new ConnectorRuntimeException("OMS AccessPoints is null or empty."); - } - - this.rocketmqProducer.setNamesrvAddr(accessPoints.replace(',', ';')); - - this.rocketmqProducer.setProducerGroup(clientConfig.getRmqProducerGroup()); - - String producerId = OMSUtil.buildInstanceName(); - this.rocketmqProducer.setSendMsgTimeout(clientConfig.getOperationTimeout()); - this.rocketmqProducer.setInstanceName(producerId); - this.rocketmqProducer.setMaxMessageSize(1024 * 1024 * 4); - this.rocketmqProducer.setLanguage(LanguageCode.OMS); - properties.put(Constants.PRODUCER_ID, producerId); - } - - public synchronized void start() { - if (!started.get()) { - try { - this.rocketmqProducer.start(); - } catch (MQClientException e) { - throw new ConnectorRuntimeException("-1", e); - } - } - this.started.set(true); - } - - public synchronized void shutdown() { - if (this.started.get()) { - this.rocketmqProducer.shutdown(); - } - this.started.set(false); - } - - public boolean isStarted() { - return this.started.get(); - } - - public boolean isClosed() { - return !this.isStarted(); - } - - ConnectorRuntimeException checkProducerException(String topic, String msgId, Throwable e) { - if (e instanceof MQClientException) { - if (e.getCause() != null) { - if (e.getCause() instanceof RemotingTimeoutException) { - return new RMQTimeoutException( - String.format("Send message to broker timeout, %dms, Topic=%s, msgId=%s", - this.rocketmqProducer.getSendMsgTimeout(), topic, msgId), e); - } else if (e.getCause() instanceof MQBrokerException - || e.getCause() instanceof RemotingConnectException) { - if (e.getCause() instanceof MQBrokerException) { - MQBrokerException brokerException = (MQBrokerException) e.getCause(); - return new ConnectorRuntimeException( - String.format("Received a broker exception, Topic=%s, msgId=%s, %s", - topic, msgId, brokerException.getErrorMessage()), e); - } - - if (e.getCause() instanceof RemotingConnectException) { - RemotingConnectException connectException = - (RemotingConnectException) e.getCause(); - return new ConnectorRuntimeException( - String.format( - "Network connection experiences failures. Topic=%s, msgId=%s, %s", - topic, msgId, connectException.getMessage()), e); - } - } - } else { - // Exception thrown by local. - MQClientException clientException = (MQClientException) e; - if (-1 == clientException.getResponseCode()) { - return new ConnectorRuntimeException( - String.format("Topic does not exist, Topic=%s, msgId=%s", - topic, msgId), e); - } else if (ResponseCode.MESSAGE_ILLEGAL == clientException.getResponseCode()) { - return new RMQMessageFormatException( - String.format("A illegal message for RocketMQ, Topic=%s, msgId=%s", - topic, msgId), e); - } - } - } - return new ConnectorRuntimeException("Send message to RocketMQ broker failed.", e); - } - - protected void checkProducerServiceState(DefaultMQProducerImpl producer) { - switch (producer.getServiceState()) { - case CREATE_JUST: - throw new ConnectorRuntimeException( - String.format("You do not have start the producer, %s", - producer.getServiceState())); - case SHUTDOWN_ALREADY: - throw new ConnectorRuntimeException( - String.format("Your producer has been shut down, %s", - producer.getServiceState())); - case START_FAILED: - throw new ConnectorRuntimeException( - String.format("When you start your service throws an exception, %s", - producer.getServiceState())); - case RUNNING: - default: - } - } - - public DefaultMQProducer getRocketmqProducer() { - return rocketmqProducer; - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/ProducerImpl.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/ProducerImpl.java deleted file mode 100644 index fd4cecc710..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/ProducerImpl.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.producer; - -import org.apache.eventmesh.api.RequestReplyCallback; -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.connector.rocketmq.cloudevent.RocketMQMessageFactory; -import org.apache.eventmesh.connector.rocketmq.utils.CloudEventUtils; - -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.client.producer.RequestCallback; -import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.message.MessageAccessor; -import org.apache.rocketmq.common.message.MessageClientIDSetter; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.remoting.exception.RemotingException; - -import java.util.Properties; - -import io.cloudevents.CloudEvent; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@SuppressWarnings("deprecation") -public class ProducerImpl extends AbstractProducer { - - public static final int eventMeshServerAsyncAccumulationThreshold = 1000; - - public ProducerImpl(final Properties properties) { - super(properties); - } - - public Properties attributes() { - return properties; - } - - public void setExtFields() { - super.getRocketmqProducer().setRetryTimesWhenSendFailed(0); - super.getRocketmqProducer().setRetryTimesWhenSendAsyncFailed(0); - super.getRocketmqProducer().setPollNameServerInterval(60000); - - super.getRocketmqProducer().getDefaultMQProducerImpl().getmQClientFactory().getNettyClientConfig() - .setClientAsyncSemaphoreValue(eventMeshServerAsyncAccumulationThreshold); - super.getRocketmqProducer().setCompressMsgBodyOverHowmuch(10); - } - - - public SendResult send(CloudEvent cloudEvent) { - this.checkProducerServiceState(rocketmqProducer.getDefaultMQProducerImpl()); - org.apache.rocketmq.common.message.Message msg = - RocketMQMessageFactory.createWriter(cloudEvent.getSubject()).writeBinary(cloudEvent); - msg = supplySysProp(msg, cloudEvent); - String messageId = null; - try { - org.apache.rocketmq.client.producer.SendResult sendResultRmq = this.rocketmqProducer.send(msg); - SendResult sendResult = new SendResult(); - sendResult.setTopic(sendResultRmq.getMessageQueue().getTopic()); - messageId = sendResultRmq.getMsgId(); - sendResult.setMessageId(messageId); - return sendResult; - } catch (Exception e) { - log.error(String.format("Send message Exception, %s", msg), e); - throw this.checkProducerException(msg.getTopic(), messageId, e); - } - } - - - public void sendOneway(CloudEvent cloudEvent) { - this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); - org.apache.rocketmq.common.message.Message msg = - RocketMQMessageFactory.createWriter(cloudEvent.getSubject()).writeBinary(cloudEvent); - msg = supplySysProp(msg, cloudEvent); - try { - this.rocketmqProducer.sendOneway(msg); - } catch (Exception e) { - log.error(String.format("Send message oneway Exception, %s", msg), e); - throw this.checkProducerException(msg.getTopic(), MessageClientIDSetter.getUniqID(msg), e); - } - } - - - public void sendAsync(CloudEvent cloudEvent, SendCallback sendCallback) { - this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); - org.apache.rocketmq.common.message.Message msg = - RocketMQMessageFactory.createWriter(cloudEvent.getSubject()).writeBinary(cloudEvent); - msg = supplySysProp(msg, cloudEvent); - try { - this.rocketmqProducer.send(msg, this.sendCallbackConvert(msg, sendCallback)); - } catch (Exception e) { - log.error(String.format("Send message async Exception, %s", msg), e); - throw this.checkProducerException(msg.getTopic(), MessageClientIDSetter.getUniqID(msg), e); - } - } - - public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) - throws InterruptedException, RemotingException, MQClientException, MQBrokerException { - - this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); - org.apache.rocketmq.common.message.Message msg = - RocketMQMessageFactory.createWriter(cloudEvent.getSubject()).writeBinary(cloudEvent); - - msg = supplySysProp(msg, cloudEvent); - - rocketmqProducer.request(msg, rrCallbackConvert(msg, rrCallback), timeout); - } - - public boolean reply(final CloudEvent cloudEvent, final SendCallback sendCallback) { - this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); - org.apache.rocketmq.common.message.Message msg = - RocketMQMessageFactory.createWriter(cloudEvent.getSubject()).writeBinary(cloudEvent); - MessageAccessor.putProperty(msg, MessageConst.PROPERTY_MESSAGE_TYPE, MixAll.REPLY_MESSAGE_FLAG); - msg = supplySysProp(msg, cloudEvent); - - try { - this.rocketmqProducer.send(msg, this.sendCallbackConvert(msg, sendCallback)); - } catch (Exception e) { - log.error(String.format("Send message async Exception, %s", msg), e); - throw this.checkProducerException(msg.getTopic(), MessageClientIDSetter.getUniqID(msg), e); - } - return true; - - } - - private Message supplySysProp(Message msg, CloudEvent cloudEvent) { - for (String sysPropKey : MessageConst.STRING_HASH_SET) { - String ceKey = sysPropKey.toLowerCase().replaceAll("_", Constants.MESSAGE_PROP_SEPARATOR); - if (cloudEvent.getExtension(ceKey) != null && StringUtils.isNotEmpty(cloudEvent.getExtension(ceKey).toString())) { - MessageAccessor.putProperty(msg, sysPropKey, cloudEvent.getExtension(ceKey).toString()); - msg.getProperties().remove(ceKey); - } - } - return msg; - } - - private RequestCallback rrCallbackConvert(final Message message, final RequestReplyCallback rrCallback) { - return new RequestCallback() { - @Override - public void onSuccess(org.apache.rocketmq.common.message.Message message) { - // clean the message property to lowercase - for (String sysPropKey : MessageConst.STRING_HASH_SET) { - if (StringUtils.isNotEmpty(message.getProperty(sysPropKey))) { - String prop = message.getProperty(sysPropKey); - String tmpPropKey = sysPropKey.toLowerCase().replaceAll("_", Constants.MESSAGE_PROP_SEPARATOR); - MessageAccessor.putProperty(message, tmpPropKey, prop); - message.getProperties().remove(sysPropKey); - } - } - CloudEvent event = RocketMQMessageFactory.createReader(message).toEvent(); - rrCallback.onSuccess(event); - } - - @Override - public void onException(Throwable e) { - String topic = message.getTopic(); - ConnectorRuntimeException onsEx = ProducerImpl.this.checkProducerException(topic, null, e); - OnExceptionContext context = new OnExceptionContext(); - context.setTopic(topic); - context.setException(onsEx); - rrCallback.onException(e); - - } - }; - } - - private org.apache.rocketmq.client.producer.SendCallback sendCallbackConvert(final Message message, - final SendCallback sendCallback) { - org.apache.rocketmq.client.producer.SendCallback rmqSendCallback = - new org.apache.rocketmq.client.producer.SendCallback() { - @Override - public void onSuccess(org.apache.rocketmq.client.producer.SendResult sendResult) { - sendCallback.onSuccess(CloudEventUtils.convertSendResult(sendResult)); - } - - @Override - public void onException(Throwable e) { - String topic = message.getTopic(); - ConnectorRuntimeException onsEx = ProducerImpl.this.checkProducerException(topic, null, e); - OnExceptionContext context = new OnExceptionContext(); - context.setTopic(topic); - context.setException(onsEx); - sendCallback.onException(context); - } - }; - return rmqSendCallback; - } - -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/RocketMQProducerImpl.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/RocketMQProducerImpl.java deleted file mode 100644 index 220cbfdf42..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/producer/RocketMQProducerImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.producer; - -import org.apache.eventmesh.api.RequestReplyCallback; -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.producer.Producer; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.connector.rocketmq.common.EventMeshConstants; -import org.apache.eventmesh.connector.rocketmq.config.ClientConfiguration; - -import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.remoting.exception.RemotingException; - -import java.util.Properties; - -import io.cloudevents.CloudEvent; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@SuppressWarnings("deprecation") -public class RocketMQProducerImpl implements Producer { - - private ProducerImpl producer; - - @Override - public synchronized void init(Properties keyValue) { - final ClientConfiguration clientConfiguration = new ClientConfiguration(); - clientConfiguration.init(); - String producerGroup = keyValue.getProperty(Constants.PRODUCER_GROUP); - - String omsNamesrv = clientConfiguration.namesrvAddr; - Properties properties = new Properties(); - properties.put(Constants.ACCESS_POINTS, omsNamesrv); - properties.put(Constants.REGION, Constants.NAMESPACE); - properties.put(Constants.RMQ_PRODUCER_GROUP, producerGroup); - properties.put(Constants.OPERATION_TIMEOUT, 3000); - properties.put(Constants.PRODUCER_ID, producerGroup); - - producer = new ProducerImpl(properties); - - } - - @Override - public boolean isStarted() { - return producer.isStarted(); - } - - @Override - public boolean isClosed() { - return producer.isClosed(); - } - - @Override - public void start() { - producer.start(); - } - - @Override - public synchronized void shutdown() { - producer.shutdown(); - } - - @Override - public void publish(CloudEvent message, SendCallback sendCallback) throws Exception { - producer.sendAsync(message, sendCallback); - } - - @Override - public void request(CloudEvent message, RequestReplyCallback rrCallback, long timeout) - throws InterruptedException, RemotingException, MQClientException, MQBrokerException { - producer.request(message, rrCallback, timeout); - } - - @Override - public boolean reply(final CloudEvent message, final SendCallback sendCallback) throws Exception { - producer.reply(message, sendCallback); - return true; - } - - @Override - public void checkTopicExist(String topic) throws Exception { - this.producer.getRocketmqProducer().getDefaultMQProducerImpl().getmQClientFactory().getMQClientAPIImpl() - .getDefaultTopicRouteInfoFromNameServer(topic, EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); - } - - @Override - public void setExtFields() { - producer.setExtFields(); - } - - - @Override - public void sendOneway(CloudEvent message) { - producer.sendOneway(message); - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/CloudEventUtils.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/CloudEventUtils.java deleted file mode 100644 index dbf1175e9c..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/CloudEventUtils.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.utils; - -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.common.Constants; - -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.message.MessageAccessor; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; - -import java.util.Map; -import java.util.Set; - -public class CloudEventUtils { - - public static SendResult convertSendResult( - org.apache.rocketmq.client.producer.SendResult rmqResult) { - SendResult sendResult = new SendResult(); - sendResult.setTopic(rmqResult.getMessageQueue().getTopic()); - sendResult.setMessageId(rmqResult.getMsgId()); - return sendResult; - } - - - public static Message msgConvert(MessageExt rmqMsg) { - Message message = new Message(); - if (rmqMsg.getTopic() != null) { - message.setTopic(rmqMsg.getTopic()); - } - - if (rmqMsg.getKeys() != null) { - message.setKeys(rmqMsg.getKeys()); - } - - if (rmqMsg.getTags() != null) { - message.setTags(rmqMsg.getTags()); - } - - if (rmqMsg.getBody() != null) { - message.setBody(rmqMsg.getBody()); - } - - final Set> entries = rmqMsg.getProperties().entrySet(); - - for (final Map.Entry entry : entries) { - MessageAccessor.putProperty(message, entry.getKey(), entry.getValue()); - } - - if (rmqMsg.getMsgId() != null) { - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_MESSAGE_ID), - rmqMsg.getMsgId()); - } - - if (rmqMsg.getTopic() != null) { - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_DESTINATION), - rmqMsg.getTopic()); - } - - // - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_BORN_HOST), - String.valueOf(rmqMsg.getBornHost())); - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_BORN_TIMESTAMP), - String.valueOf(rmqMsg.getBornTimestamp())); - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_STORE_HOST), - String.valueOf(rmqMsg.getStoreHost())); - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_STORE_TIMESTAMP), - String.valueOf(rmqMsg.getStoreTimestamp())); - - //use in manual ack - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_QUEUE_ID), - String.valueOf(rmqMsg.getQueueId())); - MessageAccessor.putProperty(message, buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_QUEUE_OFFSET), - String.valueOf(rmqMsg.getQueueOffset())); - - for (String sysPropKey : MessageConst.STRING_HASH_SET) { - if (StringUtils.isNotEmpty(message.getProperty(sysPropKey))) { - String prop = message.getProperty(sysPropKey); - String tmpPropKey = sysPropKey.toLowerCase().replaceAll("_", Constants.MESSAGE_PROP_SEPARATOR); - MessageAccessor.putProperty(message, tmpPropKey, prop); - message.getProperties().remove(sysPropKey); - } - } - - return message; - } - - - private static String buildCloudEventPropertyKey(String propName) { - return propName; - } - - public static org.apache.rocketmq.common.message.MessageExt msgConvertExt(Message message) { - - org.apache.rocketmq.common.message.MessageExt rmqMessageExt = - new org.apache.rocketmq.common.message.MessageExt(); - try { - if (message.getKeys() != null) { - rmqMessageExt.setKeys(message.getKeys()); - } - if (message.getTags() != null) { - rmqMessageExt.setTags(message.getTags()); - } - - - if (message.getBody() != null) { - rmqMessageExt.setBody(message.getBody()); - } - - - //All destinations in RocketMQ use Topic - rmqMessageExt.setTopic(message.getTopic()); - - int queueId = - Integer.parseInt(message.getProperty(buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_QUEUE_ID))); - long queueOffset = Long.parseLong( - message.getProperty(buildCloudEventPropertyKey(Constants.PROPERTY_MESSAGE_QUEUE_OFFSET))); - //use in manual ack - rmqMessageExt.setQueueId(queueId); - rmqMessageExt.setQueueOffset(queueOffset); - Map properties = message.getProperties(); - for (final Map.Entry entry : properties.entrySet()) { - MessageAccessor.putProperty(rmqMessageExt, entry.getKey(), entry.getValue()); - } - } catch (Exception e) { - e.printStackTrace(); - } - return rmqMessageExt; - - } - - -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.connector.ConnectorResourceService b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.connector.ConnectorResourceService deleted file mode 100644 index fadf0de344..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.connector.ConnectorResourceService +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -rocketmq=org.apache.eventmesh.connector.rocketmq.connector.ConnectorResourceServiceRocketmqImpl \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer deleted file mode 100644 index 0df2e286d7..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -rocketmq=org.apache.eventmesh.connector.rocketmq.consumer.RocketMQConsumerImpl \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer deleted file mode 100644 index ef4959d994..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -rocketmq=org.apache.eventmesh.connector.rocketmq.producer.RocketMQProducerImpl \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/config/ConfigurationWrapperTest.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/config/ConfigurationWrapperTest.java deleted file mode 100644 index 6d25baf7cf..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/config/ConfigurationWrapperTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.rocketmq.config; - -import org.junit.Assert; -import org.junit.Test; - -public class ConfigurationWrapperTest { - - @Test - public void getProp() { - String namesrcAddr = ConfigurationWrapper.getProp("eventMesh.server.rocketmq.namesrvAddr"); - Assert.assertNotNull(namesrcAddr); - } -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/producer/DefaultProducerImplTest.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/producer/DefaultProducerImplTest.java deleted file mode 100644 index 3114c54f0e..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/producer/DefaultProducerImplTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.producer; - - -import org.junit.After; -import org.junit.Before; - -public class DefaultProducerImplTest { - - @Before - public void before() { - } - - - @After - public void after() { - //TBD:Remove topic - } - - //@Test - //public void testCreate_EmptyTopic() { - // MeshMQProducer meshPub = new RocketMQProducerImpl(); - // try { - // meshPub.createTopic(" "); - // } catch (OMSRuntimeException e) { - // assertThat(e.getMessage()).isEqualToIgnoringWhitespace("RocketMQ can not create topic"); - // } - //} - // - //@Test - //public void testCreate_NullTopic() { - // MeshMQProducer meshPub = new RocketMQProducerImpl(); - // try { - // meshPub.createTopic(null); - // } catch (OMSRuntimeException e) { - // String errorMessage = e.getMessage(); - // assertThat(errorMessage).isEqualTo("RocketMQ can not create topic null"); - // } - //} -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/consumer/PushConsumerImplTest.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/consumer/PushConsumerImplTest.java deleted file mode 100644 index 683183bc21..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/consumer/PushConsumerImplTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - */ - -package org.apache.rocketmq.consumer; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.apache.eventmesh.api.EventListener; -import org.apache.eventmesh.api.EventMeshAction; -import org.apache.eventmesh.connector.rocketmq.consumer.PushConsumerImpl; -import org.apache.eventmesh.connector.rocketmq.domain.NonStandardKeys; - -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; -import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; -import org.apache.rocketmq.common.message.MessageExt; - -import java.lang.reflect.Field; -import java.util.Collections; -import java.util.Properties; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -import io.cloudevents.CloudEvent; - -@RunWith(MockitoJUnitRunner.class) -public class PushConsumerImplTest { - private PushConsumerImpl consumer; - - @Mock - private DefaultMQPushConsumer rocketmqPushConsumer; - - @Before - public void before() throws Exception { - Properties consumerProp = new Properties(); - //consumerProp.setProperty(OMSBuiltinKeys.DRIVER_IMPL, - // "org.apache.eventmesh.connector.rocketmq.MessagingAccessPointImpl"); - consumerProp.setProperty("access_points", "IP1:9876,IP2:9876"); - //final MessagingAccessPoint messagingAccessPoint = OMS.builder().build(consumerProp); - // .endpoint("oms:rocketmq://IP1:9876,IP2:9876/namespace").build(config); - - consumerProp.setProperty("message.model", "CLUSTERING"); - - //Properties consumerProp = new Properties(); - consumerProp.put("CONSUMER_ID", "TestGroup"); - consumer = new PushConsumerImpl(consumerProp); - - - Field field = PushConsumerImpl.class.getDeclaredField("rocketmqPushConsumer"); - field.setAccessible(true); - DefaultMQPushConsumer innerConsumer = (DefaultMQPushConsumer) field.get(consumer); - field.set(consumer, rocketmqPushConsumer); //Replace - - Mockito.when(rocketmqPushConsumer.getMessageListener()).thenReturn(innerConsumer.getMessageListener()); - consumer.start(); - } - - @After - public void after() throws Exception { - Mockito.verify(rocketmqPushConsumer).getMessageListener(); - consumer.shutdown(); - } - - @Test - public void testConsumeMessage() { - final byte[] testBody = new byte[]{'a', 'b'}; - - MessageExt consumedMsg = new MessageExt(); - consumedMsg.setMsgId("NewMsgId"); - consumedMsg.setBody(testBody); - consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC"); - consumedMsg.setTopic("HELLO_QUEUE"); - consumer.subscribe("HELLO_QUEUE", "*"); - ((MessageListenerConcurrently) rocketmqPushConsumer - .getMessageListener()).consumeMessage(Collections.singletonList(consumedMsg), null); - - - } -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/promise/DefaultPromiseTest.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/promise/DefaultPromiseTest.java deleted file mode 100644 index 3d4c8c2ab3..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/promise/DefaultPromiseTest.java +++ /dev/null @@ -1,121 +0,0 @@ -///* -// * 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. -// */ -//package rocketmq.promise; -// -//import org.apache.eventmesh.connector.rocketmq.promise.DefaultPromise; -//import io.openmessaging.Future; -//import io.openmessaging.FutureListener; -//import io.openmessaging.Promise; -//import io.openmessaging.exception.OMSRuntimeException; -//import org.junit.Before; -//import org.junit.Test; -// -//import static org.assertj.core.api.Assertions.assertThat; -//import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown; -// -//public class DefaultPromiseTest { -// private Promise promise; -// -// @Before -// public void init() { -// promise = new DefaultPromise<>(); -// } -// -// @Test -// public void testIsCancelled() throws Exception { -// assertThat(promise.isCancelled()).isEqualTo(false); -// } -// -// @Test -// public void testIsDone() throws Exception { -// assertThat(promise.isDone()).isEqualTo(false); -// promise.set("Done"); -// assertThat(promise.isDone()).isEqualTo(true); -// } -// -// @Test -// public void testGet() throws Exception { -// promise.set("Done"); -// assertThat(promise.get()).isEqualTo("Done"); -// } -// -// @Test -// public void testGet_WithTimeout() throws Exception { -// try { -// promise.get(100); -// failBecauseExceptionWasNotThrown(OMSRuntimeException.class); -// } catch (OMSRuntimeException e) { -// assertThat(e).hasMessageContaining("Get request result is timeout or interrupted"); -// } -// } -// -// @Test -// public void testAddListener() throws Exception { -// promise.addListener(new FutureListener() { -// @Override -// public void operationComplete(Future future) { -// assertThat(promise.get()).isEqualTo("Done"); -// -// } -// }); -// promise.set("Done"); -// } -// -// @Test -// public void testAddListener_ListenerAfterSet() throws Exception { -// promise.set("Done"); -// promise.addListener(new FutureListener() { -// @Override -// public void operationComplete(Future future) { -// assertThat(future.get()).isEqualTo("Done"); -// } -// }); -// } -// -// @Test -// public void testAddListener_WithException_ListenerAfterSet() throws Exception { -// final Throwable exception = new OMSRuntimeException("-1", "Test Error"); -// promise.setFailure(exception); -// promise.addListener(new FutureListener() { -// @Override -// public void operationComplete(Future future) { -// assertThat(promise.getThrowable()).isEqualTo(exception); -// } -// }); -// } -// -// @Test -// public void testAddListener_WithException() throws Exception { -// final Throwable exception = new OMSRuntimeException("-1", "Test Error"); -// promise.addListener(new FutureListener() { -// @Override -// public void operationComplete(Future future) { -// assertThat(promise.getThrowable()).isEqualTo(exception); -// } -// }); -// promise.setFailure(exception); -// } -// -// @Test -// public void getThrowable() throws Exception { -// assertThat(promise.getThrowable()).isNull(); -// Throwable exception = new OMSRuntimeException("-1", "Test Error"); -// promise.setFailure(exception); -// assertThat(promise.getThrowable()).isEqualTo(exception); -// } -// -//} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/utils/BeanUtilsTest.java b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/utils/BeanUtilsTest.java deleted file mode 100644 index 1a7f52c0e5..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/utils/BeanUtilsTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. - */ - -package org.apache.rocketmq.utils; - -import org.apache.eventmesh.connector.rocketmq.config.ClientConfig; -import org.apache.eventmesh.connector.rocketmq.domain.NonStandardKeys; -import org.apache.eventmesh.connector.rocketmq.utils.BeanUtils; - -import java.util.Properties; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class BeanUtilsTest { - private Properties properties = new Properties(); - - public static class CustomizedConfig extends ClientConfig { - static final String STRING_TEST = "string.test"; - String stringTest = "foobar"; - - static final String DOUBLE_TEST = "double.test"; - double doubleTest = 123.0; - - static final String LONG_TEST = "long.test"; - long longTest = 123L; - - String getStringTest() { - return stringTest; - } - - public void setStringTest(String stringTest) { - this.stringTest = stringTest; - } - - double getDoubleTest() { - return doubleTest; - } - - public void setDoubleTest(final double doubleTest) { - this.doubleTest = doubleTest; - } - - long getLongTest() { - return longTest; - } - - public void setLongTest(final long longTest) { - this.longTest = longTest; - } - - public CustomizedConfig() { - } - } - - @Before - public void before() { - properties.put(NonStandardKeys.MAX_REDELIVERY_TIMES, 120); - properties.put(CustomizedConfig.STRING_TEST, "kaka"); - properties.put(NonStandardKeys.CONSUMER_GROUP, "Default_Consumer_Group"); - properties.put(NonStandardKeys.MESSAGE_CONSUME_TIMEOUT, 101); - - properties.put(CustomizedConfig.LONG_TEST, 1234567890L); - properties.put(CustomizedConfig.DOUBLE_TEST, 10.234); - } - - @Test - public void testPopulate() { - CustomizedConfig config = BeanUtils.populate(properties, CustomizedConfig.class); - - //RemotingConfig config = BeanUtils.populate(properties, RemotingConfig.class); - Assert.assertEquals(config.getRmqMaxRedeliveryTimes(), 120); - Assert.assertEquals(config.getStringTest(), "kaka"); - Assert.assertEquals(config.getRmqConsumerGroup(), "Default_Consumer_Group"); - Assert.assertEquals(config.getRmqMessageConsumeTimeout(), 101); - Assert.assertEquals(config.getLongTest(), 1234567890L); - Assert.assertEquals(config.getDoubleTest(), 10.234, 0.000001); - } - - @Test - public void testPopulate_ExistObj() { - CustomizedConfig config = new CustomizedConfig(); - config.setConsumerId("NewConsumerId"); - - Assert.assertEquals(config.getConsumerId(), "NewConsumerId"); - - config = BeanUtils.populate(properties, config); - - //RemotingConfig config = BeanUtils.populate(properties, RemotingConfig.class); - Assert.assertEquals(config.getRmqMaxRedeliveryTimes(), 120); - Assert.assertEquals(config.getStringTest(), "kaka"); - Assert.assertEquals(config.getRmqConsumerGroup(), "Default_Consumer_Group"); - Assert.assertEquals(config.getRmqMessageConsumeTimeout(), 101); - Assert.assertEquals(config.getLongTest(), 1234567890L); - Assert.assertEquals(config.getDoubleTest(), 10.234, 0.000001); - } - -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer deleted file mode 100644 index bf0a8ddc29..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer +++ /dev/null @@ -1,20 +0,0 @@ -# -# 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. -# - -org.apache.eventmesh.connector.rocketmq.producer.ProducerImpl \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/resources/rocketmq-client.properties b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/resources/rocketmq-client.properties deleted file mode 100644 index 1261f30e2c..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/resources/rocketmq-client.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# 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. -# -#######################rocketmq-client################## -eventMesh.server.rocketmq.namesrvAddr=127.0.0.1:9876;127.0.0.1:9876 diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-standalone/build.gradle deleted file mode 100644 index c178f455a1..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -dependencies { - implementation project(":eventmesh-common") - implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/gradle.properties b/eventmesh-connector-plugin/eventmesh-connector-standalone/gradle.properties deleted file mode 100644 index 9499e382cb..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/gradle.properties +++ /dev/null @@ -1,18 +0,0 @@ -# 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. -# - -pluginType=connector -pluginName=standalone \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/MessageQueue.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/MessageQueue.java deleted file mode 100644 index ddac489d4d..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/MessageQueue.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.broker; - -import org.apache.eventmesh.connector.standalone.broker.model.MessageEntity; - -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -import com.google.common.base.Preconditions; - -/** - * This is a block queue, can get entity by offset. - * The queue is a FIFO data structure. - */ -public class MessageQueue { - - public MessageEntity[] items; - - private int takeIndex; - - private int putIndex; - - private int count; - - private final ReentrantLock lock; - - private final Condition notEmpty; - - private final Condition notFull; - - - public MessageQueue() { - this(2 << 10); - } - - public MessageQueue(int capacity) { - if (capacity <= 0) { - throw new IllegalArgumentException("capacity is illegal"); - } - this.items = new MessageEntity[capacity]; - this.lock = new ReentrantLock(); - this.notEmpty = lock.newCondition(); - this.notFull = lock.newCondition(); - } - - /** - * Insert the message at the tail of this queue, waiting for space to become available if the queue is full - * - * @param messageEntity - */ - public void put(MessageEntity messageEntity) throws InterruptedException { - Preconditions.checkNotNull(messageEntity); - ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - while (count == items.length) { - notFull.await(); - } - enqueue(messageEntity); - } finally { - lock.unlock(); - } - } - - /** - * Get the first message at this queue, waiting for the message is available if the queue is empty, - * this method will not remove the message - * - * @return MessageEntity - * @throws InterruptedException - */ - public MessageEntity take() throws InterruptedException { - ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - while (count == 0) { - notEmpty.await(); - } - return dequeue(); - } finally { - lock.unlock(); - } - } - - /** - * Get the first message at this queue, if the queue is empty return null immediately - * - * @return MessageEntity - */ - public MessageEntity peek() { - ReentrantLock lock = this.lock; - lock.lock(); - try { - return itemAt(takeIndex); - } finally { - lock.unlock(); - } - } - - /** - * Get the head in this queue - * - * @return MessageEntity - */ - public MessageEntity getHead() { - return peek(); - } - - /** - * Get the tail in this queue - * - * @return MessageEntity - */ - public MessageEntity getTail() { - ReentrantLock lock = this.lock; - lock.lock(); - try { - if (count == 0) { - return null; - } - int tailIndex = putIndex - 1; - if (tailIndex < 0) { - tailIndex += items.length; - } - return itemAt(tailIndex); - } finally { - lock.unlock(); - } - } - - /** - * Get the message by offset, since the offset is increment, so we can get the first message in this queue - * and calculate the index of this offset - * - * @param offset - * @return MessageEntity - */ - public MessageEntity getByOffset(long offset) { - ReentrantLock lock = this.lock; - lock.lock(); - try { - MessageEntity head = getHead(); - if (head == null) { - return null; - } - if (head.getOffset() > offset) { - throw new RuntimeException(String.format("The message has been deleted, offset: %s", offset)); - } - MessageEntity tail = getTail(); - if (tail == null || tail.getOffset() < offset) { - return null; - } - int offsetDis = (int) (head.getOffset() - offset); - int offsetIndex = takeIndex - offsetDis; - if (offsetIndex < 0) { - offsetIndex += items.length; - } - return itemAt(offsetIndex); - } finally { - lock.unlock(); - } - } - - public void removeHead() { - ReentrantLock lock = this.lock; - lock.lock(); - try { - if (count == 0) { - return; - } - items[takeIndex++] = null; - if (takeIndex == items.length) { - takeIndex = 0; - } - notFull.signal(); - } finally { - lock.unlock(); - } - } - - public int getSize() { - return count; - } - - - private MessageEntity itemAt(int index) { - return items[index]; - } - - private void enqueue(MessageEntity messageEntity) { - items[putIndex++] = messageEntity; - if (putIndex == items.length) { - putIndex = 0; - } - count++; - notEmpty.signal(); - } - - private MessageEntity dequeue() { - MessageEntity item = items[takeIndex++]; - if (takeIndex == items.length) { - takeIndex = 0; - } - notFull.signal(); - return item; - } - -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/StandaloneBroker.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/StandaloneBroker.java deleted file mode 100644 index 2e715e35b5..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/StandaloneBroker.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.broker; - -import org.apache.eventmesh.connector.standalone.broker.model.MessageEntity; -import org.apache.eventmesh.connector.standalone.broker.model.TopicMetadata; -import org.apache.eventmesh.connector.standalone.broker.task.HistoryMessageClearTask; - -import org.apache.commons.lang3.tuple.Pair; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; - -import io.cloudevents.CloudEvent; - -/** - * This broker used to store event, it just support standalone mode, you shouldn't use this module in production environment - */ -public class StandaloneBroker { - - private final ConcurrentHashMap messageContainer; - - // todo: move the offset manage to consumer - private final ConcurrentHashMap offsetMap; - - private StandaloneBroker() { - this.messageContainer = new ConcurrentHashMap<>(); - this.offsetMap = new ConcurrentHashMap<>(); - startHistoryMessageCleanTask(); - } - - public static StandaloneBroker getInstance() { - return StandaloneBrokerInstanceHolder.instance; - } - - /** - * put message - * - * @param topicName topic name - * @param message message - * @throws InterruptedException - */ - public MessageEntity putMessage(String topicName, CloudEvent message) throws InterruptedException { - Pair pair = createTopicIfAbsent(topicName); - AtomicLong topicOffset = pair.getRight(); - MessageQueue messageQueue = pair.getLeft(); - - MessageEntity messageEntity = new MessageEntity( - new TopicMetadata(topicName), message, topicOffset.getAndIncrement(), System.currentTimeMillis()); - messageQueue.put(messageEntity); - - return messageEntity; - } - - /** - * Get the message, if the queue is empty then await - * - * @param topicName - */ - public CloudEvent takeMessage(String topicName) throws InterruptedException { - TopicMetadata topicMetadata = new TopicMetadata(topicName); - return messageContainer.computeIfAbsent(topicMetadata, k -> new MessageQueue()).take().getMessage(); - } - - /** - * Get the message, if the queue is empty return null - * - * @param topicName - */ - public CloudEvent getMessage(String topicName) { - TopicMetadata topicMetadata = new TopicMetadata(topicName); - MessageEntity head = messageContainer.computeIfAbsent(topicMetadata, k -> new MessageQueue()).getHead(); - if (head == null) { - return null; - } - return head.getMessage(); - } - - /** - * Get the message by offset - * - * @param topicName topic name - * @param offset offset - * @return CloudEvent - */ - public CloudEvent getMessage(String topicName, long offset) { - TopicMetadata topicMetadata = new TopicMetadata(topicName); - MessageEntity messageEntity = messageContainer.computeIfAbsent(topicMetadata, k -> new MessageQueue()).getByOffset(offset); - if (messageEntity == null) { - return null; - } - return messageEntity.getMessage(); - } - - - private void startHistoryMessageCleanTask() { - Thread thread = new Thread(new HistoryMessageClearTask(messageContainer)); - thread.setDaemon(true); - thread.setName("StandaloneBroker-HistoryMessageCleanTask"); - thread.start(); - } - - public boolean checkTopicExist(String topicName) { - return messageContainer.containsKey(new TopicMetadata(topicName)); - } - - /** - * if topic not exist, create a topic - * - * @param topicName topicName - * @return messageQueue and offset - */ - public Pair createTopicIfAbsent(String topicName) { - TopicMetadata topicMetadata = new TopicMetadata(topicName); - MessageQueue messageQueue = messageContainer.computeIfAbsent(topicMetadata, k -> new MessageQueue()); - AtomicLong offset = offsetMap.computeIfAbsent(topicMetadata, k -> new AtomicLong()); - return Pair.of(messageQueue, offset); - } - - public void updateOffset(TopicMetadata topicMetadata, long offset) { - offsetMap.computeIfPresent(topicMetadata, (k, v) -> { - v.set(offset); - return v; - }); - } - - private static class StandaloneBrokerInstanceHolder { - private static final StandaloneBroker instance = new StandaloneBroker(); - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/task/HistoryMessageClearTask.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/task/HistoryMessageClearTask.java deleted file mode 100644 index 5499f331f2..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/task/HistoryMessageClearTask.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.broker.task; - -import org.apache.eventmesh.connector.standalone.broker.MessageQueue; -import org.apache.eventmesh.connector.standalone.broker.model.MessageEntity; -import org.apache.eventmesh.connector.standalone.broker.model.TopicMetadata; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This task used to clear the history message, the element in message queue can only be cleaned by this task. - */ -public class HistoryMessageClearTask implements Runnable { - - - private final Logger logger = LoggerFactory.getLogger(HistoryMessageClearTask.class); - - private final ConcurrentHashMap messageContainer; - - /** - * If the currentTimeMills - messageCreateTimeMills >= MESSAGE_STORE_WINDOW, then the message will be clear - */ - private static final long MESSAGE_STORE_WINDOW = 60 * 60 * 1000; - - public HistoryMessageClearTask(ConcurrentHashMap messageContainer) { - this.messageContainer = messageContainer; - } - - @Override - public void run() { - while (true) { - messageContainer.forEach((topicMetadata, messageQueue) -> { - long currentTimeMillis = System.currentTimeMillis(); - MessageEntity oldestMessage = messageQueue.getHead(); - if (oldestMessage == null) { - return; - } - if (currentTimeMillis - oldestMessage.getCreateTimeMills() >= MESSAGE_STORE_WINDOW) { - messageQueue.removeHead(); - } - }); - try { - Thread.sleep(TimeUnit.SECONDS.toMillis(1)); - } catch (InterruptedException e) { - logger.error("Thread is interrupted, thread name: {}", Thread.currentThread().getName(), e); - Thread.currentThread().interrupt(); - } - } - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/task/SubScribeTask.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/task/SubScribeTask.java deleted file mode 100644 index 81f1e2bfc7..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/task/SubScribeTask.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.broker.task; - -import org.apache.eventmesh.api.EventListener; -import org.apache.eventmesh.api.EventMeshAction; -import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; -import org.apache.eventmesh.connector.standalone.broker.StandaloneBroker; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class SubScribeTask implements Runnable { - - private String topicName; - private StandaloneBroker standaloneBroker; - private EventListener listener; - private volatile boolean isRunning; - - private AtomicInteger offset; - - private final Logger logger = LoggerFactory.getLogger(SubScribeTask.class); - - public SubScribeTask(String topicName, - StandaloneBroker standaloneBroker, - EventListener listener) { - this.topicName = topicName; - this.standaloneBroker = standaloneBroker; - this.listener = listener; - this.isRunning = true; - } - - @Override - public void run() { - while (isRunning) { - try { - logger.debug("execute subscribe task, topic: {}, offset: {}", topicName, offset); - if (offset == null) { - CloudEvent message = standaloneBroker.getMessage(topicName); - if (message != null) { - if (message.getExtension("offset") != null) { - offset = new AtomicInteger((int) message.getExtension("offset")); - } else { - offset = new AtomicInteger(0); - } - - } - } - if (offset != null) { - CloudEvent message = standaloneBroker.getMessage(topicName, offset.get()); - if (message != null) { - EventMeshAsyncConsumeContext consumeContext = new EventMeshAsyncConsumeContext() { - @Override - public void commit(EventMeshAction action) { - switch (action) { - case CommitMessage: - // update offset - logger.info("message commit, topic: {}, current offset:{}", topicName, - offset.get()); - break; - case ReconsumeLater: - // don't update offset - break; - case ManualAck: - // update offset - offset.incrementAndGet(); - logger - .info("message ack, topic: {}, current offset:{}", topicName, offset.get()); - break; - default: - - } - } - }; - listener.consume(message, consumeContext); - } - } - - } catch (Exception ex) { - logger.error("consumer error, topic: {}, offset: {}", topicName, offset == null ? null : offset.get(), - ex); - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - logger.error("Thread is interrupted, topic: {}, offset: {} thread name: {}", - topicName, offset == null ? null : offset.get(), Thread.currentThread().getName(), e); - Thread.currentThread().interrupt(); - } - } - } - - public void shutdown() { - isRunning = false; - } - -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumer.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumer.java deleted file mode 100644 index f56fc2b20d..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumer.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.consumer; - -import org.apache.eventmesh.api.AbstractContext; -import org.apache.eventmesh.api.EventListener; -import org.apache.eventmesh.api.consumer.Consumer; -import org.apache.eventmesh.common.ThreadPoolFactory; -import org.apache.eventmesh.connector.standalone.broker.StandaloneBroker; -import org.apache.eventmesh.connector.standalone.broker.model.TopicMetadata; -import org.apache.eventmesh.connector.standalone.broker.task.SubScribeTask; - -import java.util.List; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; - -import io.cloudevents.CloudEvent; - -public class StandaloneConsumer implements Consumer { - - private StandaloneBroker standaloneBroker; - - private EventListener listener; - - private AtomicBoolean isStarted; - - private final ConcurrentHashMap subscribeTaskTable; - - private ExecutorService consumeExecutorService; - - public StandaloneConsumer(Properties properties) { - this.standaloneBroker = StandaloneBroker.getInstance(); - this.subscribeTaskTable = new ConcurrentHashMap<>(16); - this.isStarted = new AtomicBoolean(false); - this.consumeExecutorService = ThreadPoolFactory.createThreadPoolExecutor( - Runtime.getRuntime().availableProcessors() * 2, - Runtime.getRuntime().availableProcessors() * 2, - "StandaloneConsumerThread" - ); - } - - @Override - public boolean isStarted() { - return isStarted.get(); - } - - @Override - public boolean isClosed() { - return !isStarted.get(); - } - - @Override - public void start() { - isStarted.compareAndSet(false, true); - } - - @Override - public void shutdown() { - isStarted.compareAndSet(true, false); - subscribeTaskTable.forEach(((topic, subScribeTask) -> subScribeTask.shutdown())); - subscribeTaskTable.clear(); - } - - @Override - public void init(Properties keyValue) throws Exception { - - } - - @Override - public void updateOffset(List cloudEvents, AbstractContext context) { - cloudEvents.forEach(cloudEvent -> standaloneBroker.updateOffset( - new TopicMetadata(cloudEvent.getSubject()), (Long) cloudEvent.getExtension("offset")) - ); - - } - - @Override - public void subscribe(String topic) throws Exception { - - if (subscribeTaskTable.containsKey(topic)) { - return; - } - synchronized (subscribeTaskTable) { - standaloneBroker.createTopicIfAbsent(topic); - SubScribeTask subScribeTask = new SubScribeTask(topic, standaloneBroker, listener); - subscribeTaskTable.put(topic, subScribeTask); - consumeExecutorService.execute(subScribeTask); - } - } - - @Override - public void unsubscribe(String topic) { - if (!subscribeTaskTable.containsKey(topic)) { - return; - } - synchronized (subscribeTaskTable) { - SubScribeTask subScribeTask = subscribeTaskTable.get(topic); - subScribeTask.shutdown(); - subscribeTaskTable.remove(topic); - } - } - - @Override - public void registerEventListener(EventListener listener) { - this.listener = listener; - } -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/resource/StandaloneConnectorResourceService.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/resource/StandaloneConnectorResourceService.java deleted file mode 100644 index 877d12f3ba..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/resource/StandaloneConnectorResourceService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.resource; - -import org.apache.eventmesh.api.connector.ConnectorResourceService; - -public class StandaloneConnectorResourceService implements ConnectorResourceService { - - @Override - public void init() throws Exception { - - } - - @Override - public void release() throws Exception { - - } -} diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.connector.ConnectorResourceService b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.connector.ConnectorResourceService deleted file mode 100644 index 7b8e948112..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.connector.ConnectorResourceService +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -standalone=org.apache.eventmesh.connector.standalone.resource.StandaloneConnectorResourceService \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer deleted file mode 100644 index 5ceb0eda96..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -standalone=org.apache.eventmesh.connector.standalone.consumer.StandaloneConsumerAdaptor \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer deleted file mode 100644 index 1b30d9837b..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -standalone=org.apache.eventmesh.connector.standalone.producer.StandaloneProducerAdaptor \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/test/java/org/apache/eventmesh/connector/standalone/broker/StandaloneBrokerTest.java b/eventmesh-connector-plugin/eventmesh-connector-standalone/src/test/java/org/apache/eventmesh/connector/standalone/broker/StandaloneBrokerTest.java deleted file mode 100644 index 1e66b0fffd..0000000000 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/test/java/org/apache/eventmesh/connector/standalone/broker/StandaloneBrokerTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.connector.standalone.broker; - -import org.apache.eventmesh.connector.standalone.broker.model.MessageEntity; - -import java.net.URI; - -import org.junit.Assert; -import org.junit.Test; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class StandaloneBrokerTest { - - @Test - public void getInstance() { - Assert.assertNotNull(StandaloneBroker.getInstance()); - } - - @Test - public void putMessage() throws InterruptedException { - StandaloneBroker instance = StandaloneBroker.getInstance(); - CloudEvent cloudEvent = CloudEventBuilder.v1() - .withId("test") - .withSource(URI.create("testsource")) - .withType("testType") - .build(); - MessageEntity messageEntity = instance.putMessage("test-topic", cloudEvent); - Assert.assertNotNull(messageEntity); - } - - @Test - public void takeMessage() throws InterruptedException { - StandaloneBroker instance = StandaloneBroker.getInstance(); - CloudEvent cloudEvent = CloudEventBuilder.v1() - .withId("test") - .withSource(URI.create("testsource")) - .withType("testType") - .build(); - instance.putMessage("test-topic", cloudEvent); - CloudEvent message = instance.takeMessage("test-topic"); - Assert.assertNotNull(message); - } - - @Test - public void getMessage() { - } - - @Test - public void testGetMessage() { - } - - @Test - public void checkTopicExist() { - } -} \ No newline at end of file diff --git a/eventmesh-connector-plugin/build.gradle b/eventmesh-connectors/build.gradle similarity index 100% rename from eventmesh-connector-plugin/build.gradle rename to eventmesh-connectors/build.gradle diff --git a/eventmesh-connectors/eventmesh-connector-canal/build.gradle b/eventmesh-connectors/eventmesh-connector-canal/build.gradle new file mode 100644 index 0000000000..6beeac41eb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/build.gradle @@ -0,0 +1,35 @@ +/* + * 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. + */ + +List canal = [ + "com.alibaba.otter:canal.instance.manager:$canal_version", + "com.alibaba.otter:canal.parse:$canal_version", + "com.alibaba.otter:canal.server:$canal_version" +] + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation "org.locationtech.jts:jts-core" + implementation project(":eventmesh-common") + implementation canal + implementation "com.alibaba:druid" + compileOnly 'com.mysql:mysql-connector-j' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-canal/gradle.properties b/eventmesh-connectors/eventmesh-connector-canal/gradle.properties new file mode 100644 index 0000000000..a439bdacf9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# +canal_version=1.1.7 +pluginType=connector +pluginName=MySQL \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/ByteArrayConverter.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/ByteArrayConverter.java new file mode 100644 index 0000000000..350b678856 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/ByteArrayConverter.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal; + +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.beanutils.Converter; +import org.apache.commons.beanutils.converters.ArrayConverter; +import org.apache.commons.beanutils.converters.ByteConverter; + +import java.nio.charset.StandardCharsets; + + +public class ByteArrayConverter implements Converter { + + public static final Converter SQL_BYTES = new ByteArrayConverter(null); + private static final Converter converter = new ArrayConverter(byte[].class, new ByteConverter()); + + protected final Object defaultValue; + protected final boolean useDefault; + + public ByteArrayConverter() { + this.defaultValue = null; + this.useDefault = false; + } + + public ByteArrayConverter(Object defaultValue) { + this.defaultValue = defaultValue; + this.useDefault = true; + } + + public Object convert(Class type, Object value) { + if (value == null) { + if (useDefault) { + return (defaultValue); + } else { + throw new ConversionException("No value specified"); + } + } + + if (value instanceof byte[]) { + return (value); + } + + if (value instanceof String) { + try { + return ((String) value).getBytes(StandardCharsets.ISO_8859_1); + } catch (Exception e) { + throw new ConversionException(e); + } + } + + return converter.convert(type, value); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/CanalConnectRecord.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/CanalConnectRecord.java new file mode 100644 index 0000000000..6f112081e8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/CanalConnectRecord.java @@ -0,0 +1,284 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal; + +import org.apache.eventmesh.common.remote.job.SyncConsistency; +import org.apache.eventmesh.common.remote.job.SyncMode; +import org.apache.eventmesh.connector.canal.model.EventColumn; +import org.apache.eventmesh.connector.canal.model.EventType; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import lombok.Data; + +@Data +public class CanalConnectRecord implements Serializable { + + private static final long serialVersionUID = 1L; + + private String schemaName; + + private String tableName; + + // mysql instance gtid range + private String gtid; + + private String currentGtid; + + /** + * The business type of the changed data (I/U/D/C/A/E), consistent with the EventType defined in EntryProtocol in canal. + */ + private EventType eventType; + + /** + * The business time of the changed data. + */ + private long executeTime; + + /** + * The primary key value before the change, if it is insert/delete, the primary key value before and after the change is the same. + */ + private List oldKeys = new ArrayList(); + + /** + * The primary key value after the change, if it is insert/delete, the primary key value before and after the change is the same. + */ + private List keys = new ArrayList(); + + /** + * Other fields that are not primary keys + */ + private List columns = new ArrayList(); + + // ====================== Additional properties of the data during the running process ============================= + /** + * The expected size, based on the estimation of the binlog event + */ + private long size = 1024; + + /** + * The id of the synchronization mapping relationship + */ + private long pairId = -1; + + /** + * When eventType = CREATE/ALTER/ERASE, it is the corresponding SQL statement, other situations are dynamically generated INSERT/UPDATE/DELETE sql + */ + private String sql; + + /** + * The schemaName of ddl/query, there will be cross-database ddl, need to keep the current schemaName of executing ddl + */ + private String ddlSchemaName; + + /** + * Custom synchronization mode, allows to override the default pipeline parameter, such as for remedial data synchronization + */ + private SyncMode syncMode; + + /** + * Custom synchronization consistency, allows to override the default pipeline parameter, + * such as forcing the database to be queried for field groups + */ + private SyncConsistency syncConsistency; + + /** + * Whether it is remedy data, such as data automatically generated by loopback remedy, or manual correction data produced by freedom + */ + private boolean remedy = false; + + /** + * Generate the corresponding hint content + */ + private String hint; + + /** + * Whether to ignore the schema when generating SQL, such as for tddl/drds, need to ignore the schema + */ + private boolean withoutSchema = false; + + private String journalName; + + private long binLogOffset; + + public CanalConnectRecord() { + super(); + } + + // ======================== helper method ================= + + /** + * Return all fields to be changed + */ + public List getUpdatedColumns() { + List columns = new ArrayList(); + for (EventColumn column : this.columns) { + if (column.isUpdate()) { + columns.add(column); + } + } + + return columns; + } + + /** + * Return all changed primary key fields + */ + public List getUpdatedKeys() { + List columns = new ArrayList(); + for (EventColumn column : this.keys) { + if (column.isUpdate()) { + columns.add(column); + } + } + + return columns; + } + + private List cloneColumn(List columns) { + if (columns == null) { + return null; + } + + List cloneColumns = new ArrayList(); + for (EventColumn column : columns) { + cloneColumns.add(column.clone()); + } + + return cloneColumns; + } + + public CanalConnectRecord clone() { + CanalConnectRecord record = new CanalConnectRecord(); + record.setTableName(tableName); + record.setSchemaName(schemaName); + record.setDdlSchemaName(ddlSchemaName); + record.setEventType(eventType); + record.setExecuteTime(executeTime); + record.setKeys(cloneColumn(keys)); + record.setColumns(cloneColumn(columns)); + record.setOldKeys(cloneColumn(oldKeys)); + record.setSize(size); + record.setPairId(pairId); + record.setSql(sql); + record.setSyncMode(syncMode); + record.setSyncConsistency(syncConsistency); + record.setRemedy(remedy); + record.setHint(hint); + record.setWithoutSchema(withoutSchema); + return record; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((columns == null) ? 0 : columns.hashCode()); + result = prime * result + ((eventType == null) ? 0 : eventType.hashCode()); + result = prime * result + (int) (executeTime ^ (executeTime >>> 32)); + result = prime * result + ((keys == null) ? 0 : keys.hashCode()); + result = prime * result + ((oldKeys == null) ? 0 : oldKeys.hashCode()); + result = prime * result + (int) (pairId ^ (pairId >>> 32)); + result = prime * result + ((schemaName == null) ? 0 : schemaName.hashCode()); + result = prime * result + ((tableName == null) ? 0 : tableName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + CanalConnectRecord other = (CanalConnectRecord) obj; + if (columns == null) { + if (other.columns != null) { + return false; + } + } else if (!columns.equals(other.columns)) { + return false; + } + if (eventType != other.eventType) { + return false; + } + if (executeTime != other.executeTime) { + return false; + } + if (keys == null) { + if (other.keys != null) { + return false; + } + } else if (!keys.equals(other.keys)) { + return false; + } + if (oldKeys == null) { + if (other.oldKeys != null) { + return false; + } + } else if (!oldKeys.equals(other.oldKeys)) { + return false; + } + if (pairId != other.pairId) { + return false; + } + if (schemaName == null) { + if (other.schemaName != null) { + return false; + } + } else if (!schemaName.equals(other.schemaName)) { + return false; + } + if (tableName == null) { + if (other.tableName != null) { + return false; + } + } else if (!tableName.equals(other.tableName)) { + return false; + } + return true; + } + + @Override + public String toString() { + return "CanalConnectRecord{" + + "tableName='" + tableName + '\'' + + ", schemaName='" + schemaName + '\'' + + ", eventType=" + eventType + + ", executeTime=" + executeTime + + ", oldKeys=" + oldKeys + + ", keys=" + keys + + ", columns=" + columns + + ", size=" + size + + ", pairId=" + pairId + + ", sql='" + sql + '\'' + + ", ddlSchemaName='" + ddlSchemaName + '\'' + + ", syncMode=" + syncMode + + ", syncConsistency=" + syncConsistency + + ", remedy=" + remedy + + ", hint='" + hint + '\'' + + ", withoutSchema=" + withoutSchema + + '}'; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/DatabaseConnection.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/DatabaseConnection.java new file mode 100644 index 0000000000..0310e5434c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/DatabaseConnection.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal; + + +import org.apache.eventmesh.common.config.connector.rdb.canal.SinkConnectorConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.SourceConnectorConfig; + +import java.sql.Connection; +import java.sql.SQLException; + +import com.alibaba.druid.pool.DruidDataSource; + +public class DatabaseConnection { + + public static DruidDataSource sourceDataSource; + + public static DruidDataSource sinkDataSource; + + public static SourceConnectorConfig sourceConfig; + + public static SinkConnectorConfig sinkConfig; + + public static DruidDataSource createDruidDataSource(String url, String userName, String passWord) { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl(url); + dataSource.setUsername(userName); + dataSource.setPassword(passWord); + dataSource.setInitialSize(5); + dataSource.setMinIdle(5); + dataSource.setMaxActive(20); + dataSource.setMaxWait(60000); + dataSource.setTimeBetweenEvictionRunsMillis(60000); + dataSource.setMinEvictableIdleTimeMillis(300000); + dataSource.setValidationQuery("SELECT 1"); + dataSource.setTestWhileIdle(true); + dataSource.setTestOnBorrow(false); + dataSource.setTestOnReturn(false); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(20); + return dataSource; + } + + public static void initSourceConnection() { + sourceDataSource = createDruidDataSource(sourceConfig.getUrl(), + sourceConfig.getUserName(), + sourceConfig.getPassWord()); + } + + public static void initSinkConnection() { + sinkDataSource = createDruidDataSource(sinkConfig.getUrl(), + sinkConfig.getUserName(), + sinkConfig.getPassWord()); + } + + + public static Connection getSourceConnection() throws SQLException { + return sourceDataSource.getConnection(); + } + + public static Connection getSinkConnection() throws SQLException { + return sinkDataSource.getConnection(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/SqlTimestampConverter.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/SqlTimestampConverter.java new file mode 100644 index 0000000000..8df0b1c097 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/SqlTimestampConverter.java @@ -0,0 +1,155 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal; + +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.beanutils.Converter; +import org.apache.commons.lang.time.DateFormatUtils; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +public class SqlTimestampConverter implements Converter { + + /** + * Field description + */ + public static final String[] DATE_FORMATS = new String[] {"yyyy-MM-dd", "HH:mm:ss", "yyyy-MM-dd HH:mm:ss", + "yyyy-MM-dd hh:mm:ss.fffffffff", "EEE MMM dd HH:mm:ss zzz yyyy", + DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), + DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), + DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), }; + + public static final Converter SQL_TIMESTAMP = new SqlTimestampConverter(null); + + /** + * The default value specified to our Constructor, if any. + */ + private final Object defaultValue; + + /** + * Should we return the default value on conversion errors? + */ + private final boolean useDefault; + + /** + * Create a {@link Converter} that will throw a {@link ConversionException} if a conversion error occurs. + */ + public SqlTimestampConverter() { + this.defaultValue = null; + this.useDefault = false; + } + + /** + * Create a {@link Converter} that will return the specified default value if a conversion error occurs. + * + * @param defaultValue The default value to be returned + */ + public SqlTimestampConverter(Object defaultValue) { + this.defaultValue = defaultValue; + this.useDefault = true; + } + + /** + * Convert the specified input object into an output object of the specified type. + * + * @param type Data type to which this value should be converted + * @param value The input value to be converted + * @throws ConversionException if conversion cannot be performed successfully + */ + public Object convert(Class type, Object value) { + if (value == null) { + if (useDefault) { + return (defaultValue); + } else { + throw new ConversionException("No value specified"); + } + } + + if (value instanceof java.sql.Date && java.sql.Date.class.equals(type)) { + return value; + } else if (value instanceof java.sql.Time && java.sql.Time.class.equals(type)) { + return value; + } else if (value instanceof Timestamp && Timestamp.class.equals(type)) { + return value; + } else { + try { + if (java.sql.Date.class.equals(type)) { + return new java.sql.Date(convertTimestamp2TimeMillis(value.toString())); + } else if (java.sql.Time.class.equals(type)) { + return new java.sql.Time(convertTimestamp2TimeMillis(value.toString())); + } else if (Timestamp.class.equals(type)) { + return new Timestamp(convertTimestamp2TimeMillis(value.toString())); + } else { + return new Timestamp(convertTimestamp2TimeMillis(value.toString())); + } + } catch (Exception e) { + throw new ConversionException("Value format invalid: " + e.getMessage(), e); + } + } + + } + + private Long convertTimestamp2TimeMillis(String input) { + if (input == null) { + return null; + } + + try { + return Timestamp.valueOf(input).getTime(); + } catch (Exception nfe) { + try { + try { + return parseDate(input, Locale.ENGLISH).getTime(); + } catch (Exception err) { + return parseDate(input, Locale.getDefault()).getTime(); + } + } catch (Exception err) { + return Long.parseLong(input); + } + } + } + + private Date parseDate(String str, Locale locale) throws ParseException { + if ((str == null) || (SqlTimestampConverter.DATE_FORMATS == null)) { + throw new IllegalArgumentException("Date and Patterns must not be null"); + } + + SimpleDateFormat parser = null; + ParsePosition pos = new ParsePosition(0); + + for (int i = 0; i < SqlTimestampConverter.DATE_FORMATS.length; i++) { + if (i == 0) { + parser = new SimpleDateFormat(SqlTimestampConverter.DATE_FORMATS[0], locale); + } else { + parser.applyPattern(SqlTimestampConverter.DATE_FORMATS[i]); + } + pos.setIndex(0); + Date date = parser.parse(str, pos); + if ((date != null) && (pos.getIndex() == str.length())) { + return date; + } + } + + throw new ParseException("Unable to parse the date: " + str, -1); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/SqlUtils.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/SqlUtils.java new file mode 100644 index 0000000000..273f5cde4c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/SqlUtils.java @@ -0,0 +1,921 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal; + +import static org.apache.eventmesh.connector.canal.ByteArrayConverter.SQL_BYTES; +import static org.apache.eventmesh.connector.canal.SqlTimestampConverter.SQL_TIMESTAMP; + +import org.apache.commons.beanutils.ConvertUtilsBean; +import org.apache.commons.lang.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.JDBCType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.temporal.Temporal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.io.WKBReader; +import org.locationtech.jts.io.WKTReader; + +import com.mysql.cj.Constants; +import com.mysql.cj.MysqlType; +import com.taobao.tddl.dbsync.binlog.LogBuffer; + +public class SqlUtils { + + public static final String REQUIRED_FIELD_NULL_SUBSTITUTE = " "; + private static final Map> sqlTypeToJavaTypeMap = new HashMap>(); + private static final ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean(); + private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(); + private static final WKBReader WKB_READER = new WKBReader(GEOMETRY_FACTORY); + private static final BigDecimal NANO_SEC = new BigDecimal(LogBuffer.DIG_BASE); + private static final LocalDateTime BASE = LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0); + private static final long ONE_HOUR = 3600; + private static final long ONE_MINUTE = 60; + + static { + // regist Converter + convertUtilsBean.register(SQL_TIMESTAMP, Date.class); + convertUtilsBean.register(SQL_TIMESTAMP, Time.class); + convertUtilsBean.register(SQL_TIMESTAMP, Timestamp.class); + convertUtilsBean.register(SQL_BYTES, byte[].class); + + // bool + sqlTypeToJavaTypeMap.put(Types.BOOLEAN, Boolean.class); + + // int + sqlTypeToJavaTypeMap.put(Types.TINYINT, Integer.class); + sqlTypeToJavaTypeMap.put(Types.SMALLINT, Integer.class); + sqlTypeToJavaTypeMap.put(Types.INTEGER, Integer.class); + + // long + sqlTypeToJavaTypeMap.put(Types.BIGINT, Long.class); + // mysql bit + sqlTypeToJavaTypeMap.put(Types.BIT, BigInteger.class); + + // decimal + sqlTypeToJavaTypeMap.put(Types.REAL, Float.class); + sqlTypeToJavaTypeMap.put(Types.FLOAT, Float.class); + sqlTypeToJavaTypeMap.put(Types.DOUBLE, Double.class); + sqlTypeToJavaTypeMap.put(Types.NUMERIC, BigDecimal.class); + sqlTypeToJavaTypeMap.put(Types.DECIMAL, BigDecimal.class); + + // date + sqlTypeToJavaTypeMap.put(Types.DATE, Date.class); + sqlTypeToJavaTypeMap.put(Types.TIME, Time.class); + sqlTypeToJavaTypeMap.put(Types.TIMESTAMP, Timestamp.class); + + // blob + sqlTypeToJavaTypeMap.put(Types.BLOB, byte[].class); + + // byte[] + sqlTypeToJavaTypeMap.put(Types.REF, byte[].class); + sqlTypeToJavaTypeMap.put(Types.OTHER, byte[].class); + sqlTypeToJavaTypeMap.put(Types.ARRAY, byte[].class); + sqlTypeToJavaTypeMap.put(Types.STRUCT, byte[].class); + sqlTypeToJavaTypeMap.put(Types.SQLXML, byte[].class); + sqlTypeToJavaTypeMap.put(Types.BINARY, byte[].class); + sqlTypeToJavaTypeMap.put(Types.DATALINK, byte[].class); + sqlTypeToJavaTypeMap.put(Types.DISTINCT, byte[].class); + sqlTypeToJavaTypeMap.put(Types.VARBINARY, byte[].class); + sqlTypeToJavaTypeMap.put(Types.JAVA_OBJECT, byte[].class); + sqlTypeToJavaTypeMap.put(Types.LONGVARBINARY, byte[].class); + + // String + sqlTypeToJavaTypeMap.put(Types.CHAR, String.class); + sqlTypeToJavaTypeMap.put(Types.VARCHAR, String.class); + sqlTypeToJavaTypeMap.put(Types.LONGVARCHAR, String.class); + sqlTypeToJavaTypeMap.put(Types.LONGNVARCHAR, String.class); + sqlTypeToJavaTypeMap.put(Types.NCHAR, String.class); + sqlTypeToJavaTypeMap.put(Types.NVARCHAR, String.class); + sqlTypeToJavaTypeMap.put(Types.NCLOB, String.class); + sqlTypeToJavaTypeMap.put(Types.CLOB, String.class); + } + + public static String genPrepareSqlOfInClause(int size) { + StringBuilder sql = new StringBuilder(); + sql.append("("); + for (int i = 0; i < size; i++) { + sql.append("?"); + if (i < size - 1) { + sql.append(","); + } + } + sql.append(")"); + return sql.toString(); + } + + public static void setInClauseParameters(PreparedStatement preparedStatement, List params) throws SQLException { + setInClauseParameters(preparedStatement, 0, params); + } + + public static void setInClauseParameters(PreparedStatement preparedStatement, int paramIndexStart, List params) throws SQLException { + for (int i = 0; i < params.size(); i++) { + preparedStatement.setString(paramIndexStart + i, params.get(i)); + } + } + + public static String sqlValueToString(ResultSet rs, int index, int sqlType) throws SQLException { + Class requiredType = sqlTypeToJavaTypeMap.get(sqlType); + if (requiredType == null) { + throw new IllegalArgumentException("unknow java.sql.Types - " + sqlType); + } + + return getResultSetValue(rs, index, requiredType); + } + + public static Object stringToSqlValue(String value, int sqlType, boolean isRequired, boolean isEmptyStringNulled) { + if (SqlUtils.isTextType(sqlType)) { + if ((value == null) || (StringUtils.isEmpty(value) && isEmptyStringNulled)) { + return isRequired ? REQUIRED_FIELD_NULL_SUBSTITUTE : null; + } else { + return value; + } + } else { + if (StringUtils.isEmpty(value)) { + return isEmptyStringNulled ? null : value; + } else { + Class requiredType = sqlTypeToJavaTypeMap.get(sqlType); + if (requiredType == null) { + throw new IllegalArgumentException("unknow java.sql.Types - " + sqlType); + } else if (requiredType.equals(String.class)) { + return value; + } else if (isNumeric(sqlType)) { + return convertUtilsBean.convert(value.trim(), requiredType); + } else { + return convertUtilsBean.convert(value, requiredType); + } + } + } + } + + public static String encoding(String source, int sqlType, String sourceEncoding, String targetEncoding) { + switch (sqlType) { + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.NCHAR: + case Types.NVARCHAR: + case Types.LONGNVARCHAR: + case Types.CLOB: + case Types.NCLOB: + if (!StringUtils.isEmpty(source)) { + String fromEncoding = StringUtils.isBlank(sourceEncoding) ? "UTF-8" : sourceEncoding; + String toEncoding = StringUtils.isBlank(targetEncoding) ? "UTF-8" : targetEncoding; + + // if (false == StringUtils.equalsIgnoreCase(fromEncoding, + // toEncoding)) { + try { + return new String(source.getBytes(fromEncoding), toEncoding); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + // } + } + break; + default: + throw new IllegalStateException("Unexpected value: " + sqlType); + } + + return source; + } + + /** + * Retrieve a JDBC column value from a ResultSet, using the specified value type. + *

+ * Uses the specifically typed ResultSet accessor methods, falling back to {@link #getResultSetValue(ResultSet, int)} for unknown types. + *

+ * Note that the returned value may not be assignable to the specified required type, in case of an unknown type. Calling code needs to deal with + * this case appropriately, e.g. throwing a corresponding exception. + * + * @param rs is the ResultSet holding the data + * @param index is the column index + * @param requiredType the required value type (may be null) + * @return the value object + * @throws SQLException if thrown by the JDBC API + */ + private static String getResultSetValue(ResultSet rs, int index, Class requiredType) throws SQLException { + if (requiredType == null) { + return getResultSetValue(rs, index); + } + + Object value = null; + boolean wasNullCheck = false; + + // Explicitly extract typed value, as far as possible. + if (String.class.equals(requiredType)) { + value = rs.getString(index); + } else if (boolean.class.equals(requiredType) || Boolean.class.equals(requiredType)) { + value = rs.getBoolean(index); + wasNullCheck = true; + } else if (byte.class.equals(requiredType) || Byte.class.equals(requiredType)) { + value = rs.getByte(index); + wasNullCheck = true; + } else if (short.class.equals(requiredType) || Short.class.equals(requiredType)) { + value = rs.getShort(index); + wasNullCheck = true; + } else if (int.class.equals(requiredType) || Integer.class.equals(requiredType)) { + value = rs.getLong(index); + wasNullCheck = true; + } else if (long.class.equals(requiredType) || Long.class.equals(requiredType)) { + value = rs.getBigDecimal(index); + wasNullCheck = true; + } else if (float.class.equals(requiredType) || Float.class.equals(requiredType)) { + value = rs.getFloat(index); + wasNullCheck = true; + } else if (double.class.equals(requiredType) || Double.class.equals(requiredType) || Number.class.equals(requiredType)) { + value = rs.getDouble(index); + wasNullCheck = true; + } else if (Time.class.equals(requiredType)) { + value = rs.getString(index); + } else if (Timestamp.class.equals(requiredType) || Date.class.equals(requiredType)) { + value = rs.getString(index); + } else if (BigDecimal.class.equals(requiredType)) { + value = rs.getBigDecimal(index); + } else if (BigInteger.class.equals(requiredType)) { + value = rs.getBigDecimal(index); + } else if (Blob.class.equals(requiredType)) { + value = rs.getBlob(index); + } else if (Clob.class.equals(requiredType)) { + value = rs.getClob(index); + } else if (byte[].class.equals(requiredType)) { + byte[] bytes = rs.getBytes(index); + if (bytes != null) { + value = new String(bytes, StandardCharsets.ISO_8859_1); + } + } else { + // Some unknown type desired -> rely on getObject. + value = getResultSetValue(rs, index); + } + + // Perform was-null check if demanded (for results that the + // JDBC driver returns as primitives). + if (wasNullCheck && (value != null) && rs.wasNull()) { + value = null; + } + + return (value == null) ? null : convertUtilsBean.convert(value); + } + + /** + * Retrieve a JDBC column value from a ResultSet, using the most appropriate value type. The returned value should be a detached value object, not + * having any ties to the active ResultSet: in particular, it should not be a Blob or Clob object but rather a byte array respectively String + * representation. + *

+ * Uses the getObject(index) method, but includes additional "hacks" to get around Oracle 10g returning a non-standard object for its + * TIMESTAMP datatype and a java.sql.Date for DATE columns leaving out the time portion: These columns will explicitly be extracted + * as standard java.sql.Timestamp object. + * + * @param rs is the ResultSet holding the data + * @param index is the column index + * @return the value object + * @throws SQLException if thrown by the JDBC API + * @see Blob + * @see Clob + * @see Timestamp + */ + private static String getResultSetValue(ResultSet rs, int index) throws SQLException { + Object obj = rs.getObject(index); + return (obj == null) ? null : convertUtilsBean.convert(obj); + } + + // private static Object convertTimestamp(Timestamp timestamp) { + // return (timestamp == null) ? null : timestamp.getTime(); + // } + + /** + * Check whether the given SQL type is numeric. + */ + public static boolean isNumeric(int sqlType) { + return (Types.BIT == sqlType) || (Types.BIGINT == sqlType) || (Types.DECIMAL == sqlType) || (Types.DOUBLE == sqlType) + || (Types.FLOAT == sqlType) || (Types.INTEGER == sqlType) || (Types.NUMERIC == sqlType) || (Types.REAL == sqlType) + || (Types.SMALLINT == sqlType) || (Types.TINYINT == sqlType); + } + + public static boolean isTextType(int sqlType) { + return sqlType == Types.CHAR || sqlType == Types.VARCHAR || sqlType == Types.CLOB || sqlType == Types.LONGVARCHAR || sqlType == Types.NCHAR + || sqlType == Types.NVARCHAR || sqlType == Types.NCLOB || sqlType == Types.LONGNVARCHAR; + } + + public static JDBCType toJDBCType(String connectorDataType) { + MysqlType mysqlType = MysqlType.getByName(connectorDataType); + return JDBCType.valueOf(mysqlType.getJdbcType()); + } + + public static BigDecimal toBigDecimal(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + String strValue = (String) value; + if (!org.apache.commons.lang3.StringUtils.isNotBlank(strValue)) { + return null; + } + try { + return new BigDecimal(strValue); + } catch (Exception e) { + if ("true".equals(strValue)) { + return BigDecimal.ONE; + } + if ("false".equals(strValue)) { + return BigDecimal.ZERO; + } + return new BigDecimal(strValue); + } + } else if (value instanceof Number) { + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + if (value instanceof Integer) { + return BigDecimal.valueOf(((Integer) value).longValue()); + } + if (value instanceof Long) { + return BigDecimal.valueOf(((Long) value)); + } + if (value instanceof Double) { + return BigDecimal.valueOf(((Double) value)); + } + if (value instanceof Float) { + return BigDecimal.valueOf(((Float) value).doubleValue()); + } + if (value instanceof BigInteger) { + return new BigDecimal((BigInteger) value); + } + if (value instanceof Byte) { + return BigDecimal.valueOf(((Byte) value).longValue()); + } + if (value instanceof Short) { + return BigDecimal.valueOf(((Short) value).longValue()); + } + return null; + } else if (value instanceof Boolean) { + return Boolean.TRUE.equals(value) ? BigDecimal.ONE : BigDecimal.ZERO; + } else { + throw new UnsupportedOperationException("class " + value.getClass() + ", value '" + value + "' , parse to big decimal failed."); + } + } + + public static Double toDouble(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + String strValue = (String) value; + if (org.apache.commons.lang3.StringUtils.isBlank(strValue)) { + return null; + } + try { + return Double.parseDouble(strValue); + } catch (Exception e) { + if ("true".equals(strValue)) { + return 1.0d; + } + if ("false".equals(strValue)) { + return 0.0d; + } + return new BigDecimal(strValue).doubleValue(); + } + } else if (value instanceof Number) { + return ((Number) value).doubleValue(); + } else { + if (value instanceof Boolean) { + return Boolean.TRUE.equals(value) ? 1.0d : 0.0d; + } + throw new UnsupportedOperationException("class " + value.getClass() + ", value '" + value + "' , parse to double failed."); + } + } + + public static Long toLong(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + String strValue = (String) value; + if (org.apache.commons.lang3.StringUtils.isBlank(strValue)) { + return null; + } + try { + return Long.parseLong(strValue); + } catch (Exception e) { + try { + return Long.decode(strValue); + } catch (Exception e2) { + if ("true".equals(strValue)) { + return 1L; + } + if ("false".equals(strValue)) { + return 0L; + } + return new BigDecimal(strValue).longValue(); + } + } + } else if (value instanceof Number) { + return ((Number) value).longValue(); + } else { + if (value instanceof Boolean) { + return Boolean.TRUE.equals(value) ? 1L : 0L; + } + throw new UnsupportedOperationException(value.getClass() + ", value '" + value + "' , parse to long failed."); + } + } + + public static boolean isZeroTime(Object value) { + if (value == null || org.apache.commons.lang3.StringUtils.isBlank(value.toString())) { + return false; + } + return value.toString().startsWith("0000-00-00"); + } + + public static String removeZone(String datetime) { + if (datetime == null || datetime.length() == 0) { + return datetime; + } + int len = datetime.length(); + if (datetime.charAt(len - 1) == 'Z' || datetime.charAt(len - 1) == 'z') { + return datetime.substring(0, len - 1).trim(); + } + if (len >= 7) { + char checkCharAt1 = datetime.charAt(len - 2); + if ((checkCharAt1 == '+' || checkCharAt1 == '-') && len >= 10) { + return datetime.substring(0, len - 2).trim(); + } + char checkCharAt2 = datetime.charAt(len - 3); + if ((checkCharAt2 == '+' || checkCharAt2 == '-') && len >= 11) { + return datetime.substring(0, len - 3).trim(); + } + char checkCharAt3 = datetime.charAt(len - 6); + if ((checkCharAt3 == '+' || checkCharAt3 == '-') && checkCharAt2 == ':') { + return datetime.substring(0, len - 6).trim(); + } + char checkCharAt4 = datetime.charAt(len - 5); + if ((checkCharAt4 == '+' || checkCharAt4 == '-') && checkCharAt2 == ':') { + return datetime.substring(0, len - 5).trim(); + } + char checkCharAt5 = len >= 9 ? datetime.charAt(len - 9) : ' '; + if ((checkCharAt5 == '+' || checkCharAt5 == '-') && checkCharAt2 == ':' && checkCharAt3 == ':') { + return datetime.substring(0, len - 9).trim(); + } + char checkCharAt6 = datetime.charAt(len - 7); + if (checkCharAt6 == '+' || checkCharAt6 == '-') { + return datetime.substring(0, len - 7).trim(); + } + if (checkCharAt4 == '+' || checkCharAt4 == '-') { + return datetime.substring(0, len - 5).trim(); + } + } + return datetime; + } + + + + public static String bytes2hex(byte[] b) { + if (b == null) { + return null; + } + if (b.length == 0) { + return ""; + } + StringBuilder hs = new StringBuilder(); + for (byte element : b) { + String stmp = Integer.toHexString(element & 255).toUpperCase(); + if (stmp.length() == 1) { + hs.append(Constants.CJ_MINOR_VERSION); + hs.append(stmp); + } else { + hs.append(stmp); + } + } + return hs.toString(); + } + + public static String convertToString(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + return (String) value; + } + if (value instanceof BigInteger) { + return value.toString(); + } + if (value instanceof BigDecimal) { + return ((BigDecimal) value).toPlainString(); + } + if (value instanceof Number) { + return new BigDecimal(value.toString()).toPlainString(); + } + if (value instanceof Boolean) { + return Boolean.TRUE.equals(value) ? "1" : "0"; + } + if (value instanceof byte[]) { + return "0x" + bytes2hex((byte[]) value); + } + if (value instanceof Timestamp) { + long nanos = ((Timestamp) value).getNanos(); + value = Instant.ofEpochMilli(((Timestamp) value).getTime() - (nanos / 1000000)).plusNanos(nanos).atZone(ZoneId.systemDefault()) + .toLocalDateTime(); + } else if (value instanceof Date) { + value = ((Date) value).toLocalDate().atTime(0, 0); + } else if (value instanceof Time) { + value = LocalDateTime.of(LocalDate.of(1970, 1, 1), + Instant.ofEpochMilli(((Time) value).getTime()).atZone(ZoneId.systemDefault()).toLocalTime()); + } else if (value instanceof java.util.Date) { + value = ((java.util.Date) value).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + if (value instanceof LocalDateTime) { + return coverLocalDateTime2String((LocalDateTime) value); + } else if (value instanceof OffsetDateTime) { + OffsetDateTime zone = (OffsetDateTime) value; + String datetimeStr = coverLocalDateTime2String(zone.toLocalDateTime()); + String zonedStr = zone.getOffset().toString(); + if ("Z".equals(zonedStr)) { + return datetimeStr + "+00:00"; + } + return datetimeStr + zonedStr; + } else if (!(value instanceof LocalTime)) { + return value.toString(); + } else { + LocalTime local3 = (LocalTime) value; + return String.format("%02d:%02d:%02d", local3.getHour(), local3.getMinute(), local3.getSecond()); + } + } + + + private static String coverLocalDateTime2String(LocalDateTime localDateTime) { + LocalDate localDate = localDateTime.toLocalDate(); + LocalTime localTime = localDateTime.toLocalTime(); + int year = localDate.getYear(); + int month = localDate.getMonthValue(); + int day = localDate.getDayOfMonth(); + int hour = localTime.getHour(); + int minute = localTime.getMinute(); + int second = localTime.getSecond(); + int nano = localTime.getNano(); + return nano == 0 ? String.format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second) : + String.format("%04d-%02d-%02d %02d:%02d:%02d.%s", year, month, day, hour, minute, second, + new BigDecimal(nano).divide(NANO_SEC).toPlainString().substring(2)); + } + + public static String toMySqlTime(Object value) { + if (value == null || StringUtils.isBlank(value.toString())) { + return null; + } + if (value instanceof String) { + return value.toString(); + } + LocalDateTime localTime = toLocalDateTime(value); + if (BASE.isBefore(localTime) || BASE.isEqual(localTime)) { + long diffHours = Duration.between(BASE, localTime).toHours(); + if (localTime.getNano() == 0) { + return String.format("%02d:%02d:%02d", diffHours, localTime.getMinute(), localTime.getSecond()); + } + return String.format("%02d:%02d:%02d.%s", diffHours, localTime.getMinute(), localTime.getSecond(), + Integer.parseInt(trimEnd(String.valueOf(localTime.getNano()), '0'))); + } + Duration duration = Duration.between(localTime, BASE); + long totalSecond = duration.getSeconds(); + long hours = totalSecond / ONE_HOUR; + long remaining = totalSecond - (hours * ONE_HOUR); + long minutes = remaining / ONE_MINUTE; + remaining = remaining - (minutes * ONE_MINUTE); + if (duration.getNano() == 0) { + return String.format("-%02d:%02d:%02d", hours, minutes, remaining); + } + return String.format("-%02d:%02d:%02d.%s", hours, minutes, remaining, Integer.parseInt(trimEnd(String.valueOf(duration.getNano()), '0'))); + } + + public static String trimEnd(String str, char trimChar) { + if (str == null || str.isEmpty()) { + return str; + } + char[] val = str.toCharArray(); + int len = val.length; + while (0 < len && val[len - 1] == trimChar) { + len--; + } + return len < val.length ? str.substring(0, len) : str; + } + + public static byte[] numberToBinaryArray(Number number) { + BigInteger bigInt = BigInteger.valueOf(number.longValue()); + int size = (bigInt.bitLength() + 7) / 8; + byte[] result = new byte[size]; + byte[] bigIntBytes = bigInt.toByteArray(); + int start = bigInt.bitLength() % 8 == 0 ? 1 : 0; + int length = Math.min(bigIntBytes.length - start, size); + System.arraycopy(bigIntBytes, start, result, size - length, length); + return result; + } + + public static Integer toInt(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + String strValue = ((String) value).toLowerCase(); + if (StringUtils.isBlank(strValue)) { + return null; + } + try { + return Integer.parseInt(strValue); + } catch (Exception e) { + try { + return Integer.decode(strValue); + } catch (Exception e2) { + if ("true".equals(strValue)) { + return 1; + } + if ("false".equals(strValue)) { + return 0; + } + return new BigDecimal(strValue).intValue(); + } + } + } else if (value instanceof Number) { + return ((Number) value).intValue(); + } else { + if (value instanceof Boolean) { + return Boolean.TRUE.equals(value) ? 1 : 0; + } + throw new UnsupportedOperationException("class " + value.getClass() + ", value '" + value + "' , parse to int failed."); + } + } + + private static LocalDateTime toLocalDateTime(String value) { + if (value.trim().length() >= 4) { + String dateStr2 = removeZone(value); + int len = dateStr2.length(); + if (len == 4) { + return LocalDateTime.of(Integer.parseInt(dateStr2), 1, 1, 0, 0, 0, 0); + } + if (dateStr2.charAt(4) == '-') { + switch (len) { + case 7: + String[] dataParts = dateStr2.split("-"); + return LocalDateTime.of(Integer.parseInt(dataParts[0]), Integer.parseInt(dataParts[1]), 1, 0, 0, 0, 0); + case 8: + case 9: + case 11: + case 12: + case 14: + case 15: + case 17: + case 18: + default: + String[] dataTime = dateStr2.split(" "); + String[] dataParts2 = dataTime[0].split("-"); + String[] timeParts = dataTime[1].split(":"); + String[] secondParts = timeParts[2].split("\\."); + secondParts[1] = StringUtils.rightPad(secondParts[1], 9, Constants.CJ_MINOR_VERSION); + return LocalDateTime.of(Integer.parseInt(dataParts2[0]), Integer.parseInt(dataParts2[1]), Integer.parseInt(dataParts2[2]), + Integer.parseInt(timeParts[0]), Integer.parseInt(timeParts[1]), Integer.parseInt(secondParts[0]), + Integer.parseInt(secondParts[1])); + case 10: + String[] dataParts3 = dateStr2.split("-"); + return LocalDateTime.of(Integer.parseInt(dataParts3[0]), Integer.parseInt(dataParts3[1]), Integer.parseInt(dataParts3[2]), 0, + 0, 0, 0); + case 13: + String[] dataTime2 = dateStr2.split(" "); + String[] dataParts4 = dataTime2[0].split("-"); + return LocalDateTime.of(Integer.parseInt(dataParts4[0]), Integer.parseInt(dataParts4[1]), Integer.parseInt(dataParts4[2]), + Integer.parseInt(dataTime2[1]), 0, 0, 0); + case 16: + String[] dataTime3 = dateStr2.split(" "); + String[] dataParts5 = dataTime3[0].split("-"); + String[] timeParts2 = dataTime3[1].split(":"); + return LocalDateTime.of(Integer.parseInt(dataParts5[0]), Integer.parseInt(dataParts5[1]), Integer.parseInt(dataParts5[2]), + Integer.parseInt(timeParts2[0]), Integer.parseInt(timeParts2[1]), 0, 0); + case 19: + String[] dataTime4 = dateStr2.split(" "); + String[] dataParts6 = dataTime4[0].split("-"); + String[] timeParts3 = dataTime4[1].split(":"); + return LocalDateTime.of(Integer.parseInt(dataParts6[0]), Integer.parseInt(dataParts6[1]), Integer.parseInt(dataParts6[2]), + Integer.parseInt(timeParts3[0]), Integer.parseInt(timeParts3[1]), Integer.parseInt(timeParts3[2]), 0); + } + } else if (dateStr2.charAt(2) == ':') { + switch (len) { + case 5: + String[] timeParts4 = dateStr2.split(":"); + return LocalDateTime.of(0, 1, 1, Integer.parseInt(timeParts4[0]), Integer.parseInt(timeParts4[1]), 0, 0); + case 8: + String[] timeParts5 = dateStr2.split(":"); + return LocalDateTime.of(0, 1, 1, Integer.parseInt(timeParts5[0]), Integer.parseInt(timeParts5[1]), + Integer.parseInt(timeParts5[2]), 0); + default: + String[] timeParts6 = dateStr2.split(":"); + String[] secondParts2 = timeParts6[2].split("\\."); + secondParts2[1] = StringUtils.rightPad(secondParts2[1], 9, Constants.CJ_MINOR_VERSION); + return LocalDateTime.of(0, 1, 1, Integer.parseInt(timeParts6[0]), Integer.parseInt(timeParts6[1]), + Integer.parseInt(secondParts2[0]), Integer.parseInt(secondParts2[1])); + } + } else { + throw new UnsupportedOperationException(value.getClass() + ", value '" + value + "' , parse to local date time failed."); + } + } else if (StringUtils.isNumeric(value)) { + return LocalDateTime.of(Integer.parseInt(value), 1, 1, 0, 0, 0, 0); + } else { + throw new DateTimeException(value + " format error."); + } + } + + public static LocalDateTime toLocalDateTime(Object value) { + if (value == null || StringUtils.isBlank(value.toString())) { + return null; + } + if (value instanceof Temporal) { + if (value instanceof LocalDateTime) { + return (LocalDateTime) value; + } + if (value instanceof OffsetDateTime) { + return ((OffsetDateTime) value).toLocalDateTime(); + } + if (value instanceof LocalTime) { + return LocalDateTime.of(LocalDate.of(1970, 1, 1), (LocalTime) value); + } else if (value instanceof LocalDate) { + return LocalDateTime.of((LocalDate) value, LocalTime.of(0, 0)); + } else { + throw new UnsupportedOperationException(value.getClass() + ", value '" + value + "' , parse local date time failed."); + } + } else if (!(value instanceof java.util.Date)) { + return toLocalDateTime(value.toString()); + } else { + if (value instanceof Timestamp) { + long nanos = ((Timestamp) value).getNanos(); + return Instant.ofEpochMilli(((Timestamp) value).getTime() - (nanos / 1000000)).plusNanos(nanos).atZone(ZoneId.systemDefault()) + .toLocalDateTime(); + } else if (value instanceof Date) { + return ((Date) value).toLocalDate().atTime(0, 0); + } else { + if (!(value instanceof Time)) { + return ((java.util.Date) value).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + return LocalDateTime.of(LocalDate.of(1970, 1, 1), + Instant.ofEpochMilli(((Time) value).getTime()).atZone(ZoneId.systemDefault()).toLocalTime()); + } + } + } + + public static boolean isHexNumber(String str) { + boolean flag = true; + if (str.startsWith("0x") || str.startsWith("0X")) { + str = str.substring(2); + } + int i = 0; + while (true) { + if (i < str.length()) { + char cc = str.charAt(i); + if (cc != '0' && cc != '1' && cc != '2' && cc != '3' && cc != '4' && cc != '5' && cc != '6' && cc != '7' && cc != '8' && cc != '9' + && cc != 'A' && cc != 'B' && cc != 'C' && cc != 'D' && cc != 'E' && cc != 'F' && cc != 'a' && cc != 'b' && cc != 'c' && cc != 'd' + && cc != 'e' && cc != 'f') { + flag = false; + break; + } + i++; + } else { + break; + } + } + return flag; + } + + public static byte[] toBytes(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + String strVal = (String) value; + if ((strVal.startsWith("0x") || strVal.startsWith("0X")) && isHexNumber(strVal)) { + return hex2bytes(strVal.substring(2)); + } + return ((String) value).getBytes(StandardCharsets.ISO_8859_1); + } else if (value instanceof byte[]) { + return (byte[]) value; + } else { + throw new UnsupportedOperationException("class " + value.getClass() + ", value '" + value + "' , parse to bytes failed."); + } + } + + public static String toGeometry(Object value) throws Exception { + if (value == null) { + return null; + } + if (value instanceof String) { + String strVal = (String) value; + if (!strVal.startsWith("0x") && !strVal.startsWith("0X")) { + return (String) value; + } + return new WKTReader().read((String) value).toText(); + } else if (value instanceof byte[]) { + // mysql add 4 byte in header of geometry + byte[] bytes = (byte[]) value; + if (bytes.length > 4) { + byte[] dst = new byte[bytes.length - 4]; + System.arraycopy(bytes, 4, dst, 0, bytes.length - 4); + return new WKBReader().read(dst).toText(); + } + return new WKBReader().read(bytes).toText(); + } else { + throw new UnsupportedOperationException("class " + value.getClass() + ", value '" + value + "' , " + "parse to geometry failed."); + } + } + + public static byte[] hex2bytes(String hexStr) { + if (hexStr == null) { + return null; + } + if (org.apache.commons.lang3.StringUtils.isBlank(hexStr)) { + return new byte[0]; + } + + if (hexStr.length() % 2 == 1) { + hexStr = "0" + hexStr; + } + + int count = hexStr.length() / 2; + byte[] ret = new byte[count]; + for (int i = 0; i < count; i++) { + int index = i * 2; + char c1 = hexStr.charAt(index); + char c2 = hexStr.charAt(index + 1); + ret[i] = (byte) (toByte(c1) << 4); + ret[i] = (byte) (ret[i] | toByte(c2)); + } + return ret; + } + + private static byte toByte(char src) { + switch (Character.toUpperCase(src)) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'A': + return 10; + case 'B': + return 11; + case 'C': + return 12; + case 'D': + return 13; + case 'E': + return 14; + case 'F': + return 15; + default: + throw new IllegalStateException("0-F"); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/config/CanalServerConfig.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/config/CanalServerConfig.java new file mode 100644 index 0000000000..b28982f7b6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/config/CanalServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CanalServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/AbstractDbDialect.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/AbstractDbDialect.java new file mode 100644 index 0000000000..4cf0f82ec9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/AbstractDbDialect.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.dialect; + +import org.apache.eventmesh.connector.canal.template.SqlTemplate; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jdbc.support.lob.LobHandler; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public abstract class AbstractDbDialect implements DbDialect { + + protected int databaseMajorVersion; + protected int databaseMinorVersion; + protected String databaseName; + protected SqlTemplate sqlTemplate; + protected JdbcTemplate jdbcTemplate; + protected TransactionTemplate transactionTemplate; + protected LobHandler lobHandler; + + public AbstractDbDialect(final JdbcTemplate jdbcTemplate, LobHandler lobHandler) { + this.jdbcTemplate = jdbcTemplate; + this.lobHandler = lobHandler; + + this.transactionTemplate = new TransactionTemplate(); + transactionTemplate.setTransactionManager(new DataSourceTransactionManager(jdbcTemplate.getDataSource())); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + } + + public AbstractDbDialect(JdbcTemplate jdbcTemplate, LobHandler lobHandler, String name, int majorVersion, + int minorVersion) { + this.jdbcTemplate = jdbcTemplate; + this.lobHandler = lobHandler; + + this.transactionTemplate = new TransactionTemplate(); + transactionTemplate.setTransactionManager(new DataSourceTransactionManager(jdbcTemplate.getDataSource())); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + this.databaseName = name; + this.databaseMajorVersion = majorVersion; + this.databaseMinorVersion = minorVersion; + + } + + public String getName() { + return databaseName; + } + + public int getMajorVersion() { + return databaseMajorVersion; + } + + @Override + public int getMinorVersion() { + return databaseMinorVersion; + } + + public String getVersion() { + return databaseMajorVersion + "." + databaseMinorVersion; + } + + public LobHandler getLobHandler() { + return lobHandler; + } + + public JdbcTemplate getJdbcTemplate() { + return jdbcTemplate; + } + + public TransactionTemplate getTransactionTemplate() { + return transactionTemplate; + } + + public SqlTemplate getSqlTemplate() { + return sqlTemplate; + } + + public String getShardColumns(String schema, String table) { + return null; + } + + public void destory() { + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/DbDialect.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/DbDialect.java new file mode 100644 index 0000000000..781c2fe954 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/DbDialect.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.dialect; + +import org.apache.eventmesh.connector.canal.template.SqlTemplate; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.lob.LobHandler; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * DbDialect + */ +public interface DbDialect { + + public String getName(); + + public String getVersion(); + + public int getMajorVersion(); + + public int getMinorVersion(); + + public String getDefaultSchema(); + + public String getDefaultCatalog(); + + public boolean isCharSpacePadded(); + + public boolean isCharSpaceTrimmed(); + + public boolean isEmptyStringNulled(); + + public boolean isSupportMergeSql(); + + public LobHandler getLobHandler(); + + public JdbcTemplate getJdbcTemplate(); + + public TransactionTemplate getTransactionTemplate(); + + public SqlTemplate getSqlTemplate(); + + public String getShardColumns(String schema, String table); + + public void destory(); +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/MysqlDialect.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/MysqlDialect.java new file mode 100644 index 0000000000..bfe5628716 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/dialect/MysqlDialect.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.dialect; + +import org.apache.eventmesh.connector.canal.template.MysqlSqlTemplate; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.lob.LobHandler; + + +public class MysqlDialect extends AbstractDbDialect { + + public MysqlDialect(JdbcTemplate jdbcTemplate, LobHandler lobHandler) { + super(jdbcTemplate, lobHandler); + sqlTemplate = new MysqlSqlTemplate(); + } + + public boolean isCharSpacePadded() { + return false; + } + + public boolean isCharSpaceTrimmed() { + return true; + } + + public boolean isEmptyStringNulled() { + return false; + } + + public boolean isSupportMergeSql() { + return true; + } + + public String getDefaultSchema() { + return null; + } + + public String getDefaultCatalog() { + return jdbcTemplate.queryForObject("select database()", String.class); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/interceptor/SqlBuilderLoadInterceptor.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/interceptor/SqlBuilderLoadInterceptor.java new file mode 100644 index 0000000000..1d7bd35b94 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/interceptor/SqlBuilderLoadInterceptor.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.interceptor; + +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkIncrementConfig; +import org.apache.eventmesh.connector.canal.CanalConnectRecord; +import org.apache.eventmesh.connector.canal.dialect.DbDialect; +import org.apache.eventmesh.connector.canal.model.EventColumn; +import org.apache.eventmesh.connector.canal.model.EventType; +import org.apache.eventmesh.connector.canal.template.SqlTemplate; + +import java.util.List; + +import org.springframework.util.CollectionUtils; + +import lombok.Getter; +import lombok.Setter; + +/** + * compute latest sql + */ +public class SqlBuilderLoadInterceptor { + + @Getter + @Setter + private DbDialect dbDialect; + + public boolean before(CanalSinkIncrementConfig sinkConfig, CanalConnectRecord record) { + // build sql + SqlTemplate sqlTemplate = dbDialect.getSqlTemplate(); + EventType type = record.getEventType(); + String sql = null; + + String schemaName = (record.isWithoutSchema() ? null : record.getSchemaName()); + + String shardColumns = null; + + if (type.isInsert()) { + sql = sqlTemplate.getMergeSql(schemaName, + record.getTableName(), + buildColumnNames(record.getKeys()), + buildColumnNames(record.getColumns()), + new String[] {}, + true, + shardColumns); + } else if (type.isUpdate()) { + boolean existOldKeys = !CollectionUtils.isEmpty(record.getOldKeys()); + boolean rowMode = sinkConfig.getSyncMode().isRow(); + String[] keyColumns = null; + String[] otherColumns = null; + if (existOldKeys) { + // update table xxx set pk = newPK where pk = oldPk + keyColumns = buildColumnNames(record.getOldKeys()); + otherColumns = buildColumnNames(record.getUpdatedColumns(), record.getKeys()); + } else { + keyColumns = buildColumnNames(record.getKeys()); + otherColumns = buildColumnNames(record.getUpdatedColumns()); + } + + // not support the column default not null for merge sql + // if (rowMode && !existOldKeys) { + // sql = sqlTemplate.getMergeSql(schemaName, + // record.getTableName(), + // keyColumns, + // otherColumns, + // new String[] {}, + // true, + // shardColumns); + // } else { + // sql = sqlTemplate.getUpdateSql(schemaName, record.getTableName(), keyColumns, otherColumns, true, shardColumns); + // } + sql = sqlTemplate.getUpdateSql(schemaName, record.getTableName(), keyColumns, otherColumns, true, shardColumns); + } else if (type.isDelete()) { + sql = sqlTemplate.getDeleteSql(schemaName, + record.getTableName(), + buildColumnNames(record.getKeys())); + } + + if (record.getHint() != null) { + record.setSql(record.getHint() + sql); + } else { + record.setSql(sql); + } + return false; + } + + private String[] buildColumnNames(List columns) { + String[] result = new String[columns.size()]; + for (int i = 0; i < columns.size(); i++) { + EventColumn column = columns.get(i); + result[i] = column.getColumnName(); + } + return result; + } + + private String[] buildColumnNames(List columns1, List columns2) { + String[] result = new String[columns1.size() + columns2.size()]; + int i = 0; + for (i = 0; i < columns1.size(); i++) { + EventColumn column = columns1.get(i); + result[i] = column.getColumnName(); + } + + for (; i < columns1.size() + columns2.size(); i++) { + EventColumn column = columns2.get(i - columns1.size()); + result[i] = column.getColumnName(); + } + return result; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventColumn.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventColumn.java new file mode 100644 index 0000000000..352fc060a0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventColumn.java @@ -0,0 +1,163 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.model; + +import java.io.Serializable; + +import lombok.Getter; +import lombok.Setter; + +public class EventColumn implements Serializable { + + @Setter + @Getter + private int index; + + @Getter + @Setter + private int columnType; + + @Getter + @Setter + private String columnName; + + /** + * timestamp,Datetime is long + */ + @Setter + private String columnValue; + + private boolean isNull; + + private boolean isKey; + + private boolean isUpdate = true; + + public String getColumnValue() { + if (isNull) { + columnValue = null; + return null; + } else { + return columnValue; + } + } + + public boolean isNull() { + return isNull; + } + + public void setNull(boolean isNull) { + this.isNull = isNull; + } + + public boolean isKey() { + return isKey; + } + + public void setKey(boolean isKey) { + this.isKey = isKey; + } + + public boolean isUpdate() { + return isUpdate; + } + + public void setUpdate(boolean isUpdate) { + this.isUpdate = isUpdate; + } + + public EventColumn clone() { + EventColumn column = new EventColumn(); + column.setIndex(index); + column.setColumnName(columnName); + column.setColumnType(columnType); + column.setColumnValue(columnValue); + column.setKey(isKey); + column.setNull(isNull); + column.setUpdate(isUpdate); + return column; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((columnName == null) ? 0 : columnName.hashCode()); + result = prime * result + columnType; + result = prime * result + ((columnValue == null) ? 0 : columnValue.hashCode()); + result = prime * result + index; + result = prime * result + (isKey ? 1231 : 1237); + result = prime * result + (isNull ? 1231 : 1237); + result = prime * result + (isUpdate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EventColumn other = (EventColumn) obj; + if (columnName == null) { + if (other.columnName != null) { + return false; + } + } else if (!columnName.equals(other.columnName)) { + return false; + } + if (columnType != other.columnType) { + return false; + } + if (columnValue == null) { + if (other.columnValue != null) { + return false; + } + } else if (!columnValue.equals(other.columnValue)) { + return false; + } + if (index != other.index) { + return false; + } + if (isKey != other.isKey) { + return false; + } + if (isNull != other.isNull) { + return false; + } + return isUpdate == other.isUpdate; + } + + @Override + public String toString() { + return "EventColumn{" + + "index=" + index + + ", columnType=" + columnType + + ", columnName='" + columnName + '\'' + + ", columnValue='" + columnValue + '\'' + + ", isNull=" + isNull + + ", isKey=" + isKey + + ", isUpdate=" + isUpdate + + '}'; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventColumnIndexComparable.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventColumnIndexComparable.java new file mode 100644 index 0000000000..ca55f57292 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventColumnIndexComparable.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.model; + +import java.util.Comparator; + +public class EventColumnIndexComparable implements Comparator { + + public int compare(EventColumn o1, EventColumn o2) { + return Integer.compare(o1.getIndex(), o2.getIndex()); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventType.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventType.java new file mode 100644 index 0000000000..a1537c9f58 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/model/EventType.java @@ -0,0 +1,156 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.model; + +/** + * chang the eventtype num to I/U/D/C/A/E. + */ +public enum EventType { + + /** + * Insert row. + */ + INSERT("I"), + + /** + * Update row. + */ + UPDATE("U"), + + /** + * Delete row. + */ + DELETE("D"), + + /** + * Create table. + */ + CREATE("C"), + + /** + * Alter table. + */ + ALTER("A"), + + /** + * Erase table. + */ + ERASE("E"), + + /** + * Query. + */ + QUERY("Q"), + + /** + * Truncate. + */ + TRUNCATE("T"), + + /** + * rename. + */ + RENAME("R"), + + /** + * create index. + */ + CINDEX("CI"), + + /** + * drop index. + */ + DINDEX("DI"); + + private String value; + + private EventType(String value) { + this.value = value; + } + + public boolean isInsert() { + return this.equals(EventType.INSERT); + } + + public boolean isUpdate() { + return this.equals(EventType.UPDATE); + } + + public boolean isDelete() { + return this.equals(EventType.DELETE); + } + + public boolean isCreate() { + return this.equals(EventType.CREATE); + } + + public boolean isAlter() { + return this.equals(EventType.ALTER); + } + + public boolean isErase() { + return this.equals(EventType.ERASE); + } + + public boolean isQuery() { + return this.equals(EventType.QUERY); + } + + public boolean isTruncate() { + return this.equals(EventType.TRUNCATE); + } + + public boolean isRename() { + return this.equals(EventType.RENAME); + } + + public boolean isCindex() { + return this.equals(EventType.CINDEX); + } + + public boolean isDindex() { + return this.equals(EventType.DINDEX); + } + + public boolean isDdl() { + return isCreate() || isAlter() || isErase() || isTruncate() || isRename() || isCindex() || isDindex(); + } + + public boolean isDml() { + return isInsert() || isUpdate() || isDelete(); + } + + public static EventType valuesOf(String value) { + EventType[] eventTypes = values(); + for (EventType eventType : eventTypes) { + if (eventType.value.equalsIgnoreCase(value)) { + return eventType; + } + } + return null; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/server/CanalConnectServer.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/server/CanalConnectServer.java new file mode 100644 index 0000000000..6cc3d013dd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/server/CanalConnectServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.server; + +import org.apache.eventmesh.connector.canal.config.CanalServerConfig; +import org.apache.eventmesh.connector.canal.sink.connector.CanalSinkConnector; +import org.apache.eventmesh.connector.canal.source.connector.CanalSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalConnectServer { + + public static void main(String[] args) throws Exception { + + CanalServerConfig serverConfig = ConfigUtil.parse(CanalServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application canalSourceApp = new Application(); + canalSourceApp.run(CanalSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application canalSinkApp = new Application(); + canalSinkApp.run(CanalSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadContext.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadContext.java new file mode 100644 index 0000000000..3498e87e7b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadContext.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink; + +import org.apache.eventmesh.connector.canal.CanalConnectRecord; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import lombok.Data; + +@Data +public class DbLoadContext { + + private String gtid; + + private List lastProcessedRecords; + + private List prepareRecords; + + private List processedRecords; + + private List failedRecords; + + public DbLoadContext() { + lastProcessedRecords = Collections.synchronizedList(new LinkedList<>()); + prepareRecords = Collections.synchronizedList(new LinkedList<>()); + processedRecords = Collections.synchronizedList(new LinkedList<>()); + failedRecords = Collections.synchronizedList(new LinkedList<>()); + } + + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadData.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadData.java new file mode 100644 index 0000000000..ea48de7749 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadData.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink; + +import org.apache.eventmesh.connector.canal.CanalConnectRecord; +import org.apache.eventmesh.connector.canal.model.EventType; + +import java.util.ArrayList; +import java.util.List; + +/** + * Classify the data according to the table and insert/update/delete types. + * + *

+ * Purpose of classification: to optimize the insert statement in batches.
+ * 1. Due to the restrictions of MySQL indexes, concurrent execution of insert statements needs to be avoided.
+ * 
+ */ +public class DbLoadData { + + private List tables = new ArrayList(); + + public DbLoadData() { + // nothing + } + + public DbLoadData(List records) { + for (CanalConnectRecord record : records) { + merge(record); + } + } + + public void merge(CanalConnectRecord record) { + TableLoadData tableData = findTableData(record); + + EventType type = record.getEventType(); + if (type.isInsert()) { + tableData.getInsertDatas().add(record); + } else if (type.isUpdate()) { + tableData.getUpdateDatas().add(record); + } else if (type.isDelete()) { + tableData.getDeleteDatas().add(record); + } + } + + public List getTables() { + return tables; + } + + private synchronized TableLoadData findTableData(CanalConnectRecord record) { + for (TableLoadData table : tables) { + if (table.getSchemaName().equals(record.getSchemaName()) + && table.getTableName().equals(record.getTableName())) { + return table; + } + } + + TableLoadData data = new TableLoadData(record.getSchemaName(), record.getTableName()); + tables.add(data); + return data; + } + + /** + * classify by table + */ + public static class TableLoadData { + + private String schemaName; + + private String tableName; + private List insertDatas = new ArrayList<>(); + private List upadateDatas = new ArrayList<>(); + private List deleteDatas = new ArrayList<>(); + + public TableLoadData(String schemaName, String tableName) { + this.schemaName = schemaName; + this.tableName = tableName; + } + + public List getInsertDatas() { + return insertDatas; + } + + public void setInsertDatas(List insertDatas) { + this.insertDatas = insertDatas; + } + + public List getUpdateDatas() { + return upadateDatas; + } + + public void setUpdateDatas(List upadateDatas) { + this.upadateDatas = upadateDatas; + } + + public List getDeleteDatas() { + return deleteDatas; + } + + public void setDeleteDatas(List deleteDatas) { + this.deleteDatas = deleteDatas; + } + + public String getSchemaName() { + return schemaName; + } + + public void setSchemaName(String schemaName) { + this.schemaName = schemaName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadMerger.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadMerger.java new file mode 100644 index 0000000000..af53532dd8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/DbLoadMerger.java @@ -0,0 +1,280 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink; + +import org.apache.eventmesh.connector.canal.CanalConnectRecord; +import org.apache.eventmesh.connector.canal.model.EventColumn; +import org.apache.eventmesh.connector.canal.model.EventColumnIndexComparable; +import org.apache.eventmesh.connector.canal.model.EventType; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.util.CollectionUtils; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + + +/** + *
+ * merge the same schema-table change record.
+ * The result of merging multiple change data with the same primary key (pk) is:
+ * 1, I
+ * 2, U
+ * 3, D
+ * If there is one "I" (Insert) and multiple "U" (Update), merge into "I";
+ * If there are multiple "U" (Update), take the latest one;
+ * 
+ */ +@Slf4j +public class DbLoadMerger { + + /** + * Merge a batch of data based on table and primary key information, + * ensuring that there is only one record for each primary key in a table + * + * @param eventDatas + * @return + */ + public static List merge(List eventDatas) { + Map result = new LinkedHashMap(); + for (CanalConnectRecord eventData : eventDatas) { + merge(eventData, result); + } + return new LinkedList<>(result.values()); + } + + public static void merge(CanalConnectRecord record, Map result) { + EventType eventType = record.getEventType(); + switch (eventType) { + case INSERT: + mergeInsert(record, result); + break; + case UPDATE: + mergeUpdate(record, result); + break; + case DELETE: + mergeDelete(record, result); + break; + default: + break; + } + } + + private static void mergeInsert(CanalConnectRecord record, Map result) { + RowKey rowKey = new RowKey(record.getSchemaName(), record.getTableName(), + record.getKeys()); + if (!result.containsKey(rowKey)) { + result.put(rowKey, record); + } else { + CanalConnectRecord oldRecord = result.get(rowKey); + record.setSize(oldRecord.getSize() + record.getSize()); + if (oldRecord.getEventType() == EventType.DELETE) { + result.put(rowKey, record); + } else if (record.getEventType() == EventType.UPDATE + || record.getEventType() == EventType.INSERT) { + log.warn("update-insert/insert-insert happend. before[{}] , after[{}]", oldRecord, record); + CanalConnectRecord mergeEventData = replaceColumnValue(record, oldRecord); + mergeEventData.getOldKeys().clear(); + result.put(rowKey, mergeEventData); + } + } + } + + private static void mergeUpdate(CanalConnectRecord record, Map result) { + RowKey rowKey = new RowKey(record.getSchemaName(), record.getTableName(), record.getKeys()); + if (!CollectionUtils.isEmpty(record.getOldKeys())) { + RowKey oldKey = new RowKey(record.getSchemaName(), record.getTableName(), + record.getOldKeys()); + if (!result.containsKey(oldKey)) { + result.put(rowKey, record); + } else { + CanalConnectRecord oldRecord = result.get(oldKey); + record.setSize(oldRecord.getSize() + record.getSize()); + if (oldRecord.getEventType() == EventType.INSERT) { + record.setEventType(EventType.INSERT); + result.remove(oldKey); + + CanalConnectRecord mergeEventData = replaceColumnValue(record, oldRecord); + mergeEventData.getOldKeys().clear(); + result.put(rowKey, mergeEventData); + } else if (oldRecord.getEventType() == EventType.UPDATE) { + result.remove(oldKey); + CanalConnectRecord mergeEventData = replaceColumnValue(record, oldRecord); + result.put(rowKey, mergeEventData); + } else { + throw new RuntimeException("delete(has old pks) + update impossible happed!"); + } + } + } else { + if (!result.containsKey(rowKey)) { + result.put(rowKey, record); + } else { + CanalConnectRecord oldRecord = result.get(rowKey); + if (oldRecord.getEventType() == EventType.INSERT) { + oldRecord.setEventType(EventType.INSERT); + + CanalConnectRecord mergeEventData = replaceColumnValue(record, oldRecord); + result.put(rowKey, mergeEventData); + } else if (oldRecord.getEventType() == EventType.UPDATE) { + CanalConnectRecord mergeEventData = replaceColumnValue(record, oldRecord); + result.put(rowKey, mergeEventData); + } else if (oldRecord.getEventType() == EventType.DELETE) { + result.put(rowKey, record); + } + } + } + } + + private static void mergeDelete(CanalConnectRecord record, Map result) { + RowKey rowKey = new RowKey(record.getSchemaName(), record.getTableName(), + record.getKeys()); + if (!result.containsKey(rowKey)) { + result.put(rowKey, record); + } else { + CanalConnectRecord oldRecord = result.get(rowKey); + record.setSize(oldRecord.getSize() + record.getSize()); + if (!CollectionUtils.isEmpty(oldRecord.getOldKeys())) { + record.setKeys(oldRecord.getOldKeys()); + record.getOldKeys().clear(); + + result.remove(rowKey); + result.put(new RowKey(record.getSchemaName(), record.getTableName(), + record.getKeys()), record); + } else { + record.getOldKeys().clear(); + result.put(rowKey, record); + } + + } + } + + /** + * Merge the old value that exists in the old record and does not exist in the new record into the new record, + * and save the old primary key of the last change to the old primary key of this change. + * + * @param newRecord + * @param oldRecord + * @return + */ + private static CanalConnectRecord replaceColumnValue(CanalConnectRecord newRecord, CanalConnectRecord oldRecord) { + List newColumns = newRecord.getColumns(); + List oldColumns = oldRecord.getColumns(); + List temp = new ArrayList<>(); + for (EventColumn oldColumn : oldColumns) { + boolean contain = false; + for (EventColumn newColumn : newColumns) { + if (oldColumn.getColumnName().equalsIgnoreCase(newColumn.getColumnName())) { + newColumn.setUpdate(newColumn.isUpdate() || oldColumn.isUpdate()); + contain = true; + } + } + + if (!contain) { + temp.add(oldColumn); + } + } + newColumns.addAll(temp); + Collections.sort(newColumns, new EventColumnIndexComparable()); + newRecord.setOldKeys(oldRecord.getOldKeys()); + if (oldRecord.getSyncConsistency() != null) { + newRecord.setSyncConsistency(oldRecord.getSyncConsistency()); + } + if (oldRecord.getSyncMode() != null) { + newRecord.setSyncMode(oldRecord.getSyncMode()); + } + + if (oldRecord.isRemedy()) { + newRecord.setRemedy(true); + } + newRecord.setSize(oldRecord.getSize() + newRecord.getSize()); + return newRecord; + } + + @Setter + @Getter + public static class RowKey implements Serializable { + + private String schemaName; + private String tableName; + + public RowKey(String schemaName, String tableName, List keys) { + this.schemaName = schemaName; + this.tableName = tableName; + this.keys = keys; + } + + public RowKey(List keys) { + this.keys = keys; + } + + private List keys = new ArrayList(); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((keys == null) ? 0 : keys.hashCode()); + result = prime * result + ((schemaName == null) ? 0 : schemaName.hashCode()); + result = prime * result + ((tableName == null) ? 0 : tableName.hashCode()); + return result; + } + + @SuppressWarnings("checkstyle:NeedBraces") + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof RowKey)) { + return false; + } + RowKey other = (RowKey) obj; + if (keys == null) { + if (other.keys != null) { + return false; + } + } else if (!keys.equals(other.keys)) { + return false; + } + if (schemaName == null) { + if (other.schemaName != null) { + return false; + } + } else if (!schemaName.equals(other.schemaName)) { + return false; + } + if (tableName == null) { + return other.tableName == null; + } else { + return tableName.equals(other.tableName); + } + } + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/GtidBatch.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/GtidBatch.java new file mode 100644 index 0000000000..dd6559b832 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/GtidBatch.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink; + +import org.apache.eventmesh.connector.canal.CanalConnectRecord; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class GtidBatch { + private int totalBatches; + private List> batches; + private int receivedBatchCount; + + public GtidBatch(int totalBatches) { + this.totalBatches = totalBatches; + this.batches = new CopyOnWriteArrayList<>(new List[totalBatches]); + this.receivedBatchCount = 0; + } + + public void addBatch(int batchIndex, List batchRecords) { + batches.set(batchIndex, batchRecords); + receivedBatchCount++; + } + + public List> getBatches() { + return batches; + } + + public boolean isComplete() { + return receivedBatchCount == totalBatches; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/GtidBatchManager.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/GtidBatchManager.java new file mode 100644 index 0000000000..30060aa8f5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/GtidBatchManager.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink; + +import org.apache.eventmesh.connector.canal.CanalConnectRecord; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class GtidBatchManager { + + private static ConcurrentHashMap gtidBatchMap = new ConcurrentHashMap<>(); + + public static void addBatch(String gtid, int batchIndex, int totalBatches, List batchRecords) { + gtidBatchMap.computeIfAbsent(gtid, k -> new GtidBatch(totalBatches)).addBatch(batchIndex, batchRecords); + } + + public static GtidBatch getGtidBatch(String gtid) { + return gtidBatchMap.get(gtid); + } + + public static boolean isComplete(String gtid) { + GtidBatch batch = gtidBatchMap.get(gtid); + return batch != null && batch.isComplete(); + } + + public static void removeGtidBatch(String gtid) { + gtidBatchMap.remove(gtid); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalCheckConsumer.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalCheckConsumer.java new file mode 100644 index 0000000000..fb9a33b49f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalCheckConsumer.java @@ -0,0 +1,540 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink.connector; + +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalMySQLType; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkFullConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.Constants; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLColumnDef; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordOffset; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.SqlUtils; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.text.MessageFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +import com.alibaba.druid.pool.DruidPooledConnection; +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class CanalCheckConsumer { + private BlockingQueue> queue; + private RdbTableMgr tableMgr; + private CanalSinkFullConfig config; + private final DateTimeFormatter dataTimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"); + + + public CanalCheckConsumer(BlockingQueue> queue, RdbTableMgr tableMgr, CanalSinkFullConfig config) { + this.config = config; + this.queue = queue; + this.tableMgr = tableMgr; + } + + + public void start(AtomicBoolean flag) { + while (flag.get()) { + List sinkRecords = null; + try { + sinkRecords = queue.poll(2, TimeUnit.SECONDS); + if (sinkRecords == null || sinkRecords.isEmpty()) { + continue; + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + ConnectRecord record = sinkRecords.get(0); + Map dataMap = + JsonUtils.parseTypeReferenceObject((byte[]) record.getData(), new TypeReference>() { + }); + + List> sourceRows = JsonUtils.parseObject(dataMap.get("data").toString(), List.class); + + if (sourceRows == null || sourceRows.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("[{}] got rows data is none", this.getClass()); + } + return; + } + CanalFullRecordOffset offset = JsonUtils.parseObject(dataMap.get("offset").toString(), CanalFullRecordOffset.class); + if (offset == null || offset.getPosition() == null) { + if (log.isDebugEnabled()) { + log.debug("[{}] got canal full offset is none", this.getClass()); + } + return; + } + + MySQLTableDef tableDefinition = (MySQLTableDef) tableMgr.getTable(offset.getPosition().getSchema(), offset.getPosition().getTableName()); + if (tableDefinition == null) { + log.warn("target schema [{}] table [{}] is not exists", offset.getPosition().getSchema(), offset.getPosition().getTableName()); + return; + } + + String sql = genTargetPkInSql(tableDefinition, sourceRows.size(), Constants.MySQLQuot, Constants.MySQLQuot, "*"); + DruidPooledConnection connection = null; + PreparedStatement statement = null; + try { + connection = DatabaseConnection.sinkDataSource.getConnection(); + statement = + connection.prepareStatement(sql); + setPrepareParams(statement, sourceRows, tableDefinition); + log.debug("select sql {}", statement.toString()); + ResultSet resultSet = statement.executeQuery(); + List> targetRows = new LinkedList<>(); + while (resultSet.next()) { + Map columnValues = new LinkedHashMap<>(); + for (Map.Entry col : + tableDefinition.getColumnDefinitions().entrySet()) { + columnValues.put(col.getKey(), readColumn(resultSet, col.getKey(), + col.getValue().getType())); + } + targetRows.add(columnValues); + } + compareData(sourceRows, targetRows, tableDefinition); + record.getCallback().onSuccess(convertToSendResult(record)); + } catch (SQLException e) { + log.warn("check sink process schema [{}] table [{}] connector check fail", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), + e); + LockSupport.parkNanos(3000 * 1000L); + record.getCallback().onException(buildSendExceptionContext(record, e)); + } catch (Exception e) { + log.error("check sink process schema [{}] table [{}] catch unknown exception", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), e); + record.getCallback().onException(buildSendExceptionContext(record, e)); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + log.error("close prepare statement fail", e); + } + } + + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + log.error("close db connection fail", e); + } + } + } + } + } + + private void compareData(List> sourceRows, List> targetRows, MySQLTableDef tableDefinition) { + List> differenceSource = new ArrayList<>(sourceRows); + List> differenceTarget = new ArrayList<>(targetRows); + // Find common elements and remove from difference lists + for (Map source : sourceRows) { + for (Map target : targetRows) { + if (source.equals(target)) { + differenceSource.remove(source); + differenceTarget.remove(target); + break; + } + } + } + if (!differenceSource.isEmpty()) { + log.error("source rows is not equals target rows, source rows are [{}]", differenceSource); + } + + if (!differenceTarget.isEmpty()) { + log.error("source rows is not equals target rows, target rows are [{}]", differenceTarget); + } + } + + private void setPrepareParams(PreparedStatement preparedStatement, List> rows, MySQLTableDef tableDef) throws Exception { + List cols = new ArrayList<>(tableDef.getColumnDefinitions().values()); + int index = 0; + for (Map col : rows) { + for (MySQLColumnDef mySQLColumnDef : cols) { + if (tableDef.getPrimaryKeys().contains(mySQLColumnDef.getName())) { + index++; + writeColumn(preparedStatement, index, mySQLColumnDef, col.get(mySQLColumnDef.getName())); + } + } + } + } + + public Object readColumn(ResultSet rs, String colName, CanalMySQLType colType) throws Exception { + switch (colType) { + case TINYINT: + case SMALLINT: + case MEDIUMINT: + case INT: + Long valueLong = rs.getLong(colName); + if (rs.wasNull()) { + return null; + } + if (valueLong.compareTo((long) Integer.MAX_VALUE) > 0) { + return valueLong; + } + return valueLong.intValue(); + case BIGINT: + String v = rs.getString(colName); + if (v == null) { + return null; + } + BigDecimal valueBigInt = new BigDecimal(v); + if (valueBigInt.compareTo(BigDecimal.valueOf(Long.MAX_VALUE)) > 0) { + return valueBigInt; + } + return valueBigInt.longValue(); + case FLOAT: + case DOUBLE: + case DECIMAL: + return rs.getBigDecimal(colName); + case DATE: + return rs.getObject(colName, LocalDate.class).toString(); + case TIME: + return rs.getObject(colName, LocalTime.class).toString(); + case DATETIME: + case TIMESTAMP: + return rs.getObject(colName, LocalDateTime.class).toString(); + case YEAR: + int year = rs.getInt(colName); + if (rs.wasNull()) { + return null; + } + return year; + case CHAR: + case VARCHAR: + case TINYTEXT: + case TEXT: + case MEDIUMTEXT: + case LONGTEXT: + case ENUM: + case SET: + case JSON: + return rs.getString(colName); + case BIT: + case BINARY: + case VARBINARY: + case TINYBLOB: + case BLOB: + case MEDIUMBLOB: + case LONGBLOB: + return rs.getBytes(colName); + case GEOMETRY: + case GEOMETRY_COLLECTION: + case GEOM_COLLECTION: + case POINT: + case LINESTRING: + case POLYGON: + case MULTIPOINT: + case MULTILINESTRING: + case MULTIPOLYGON: + byte[] geo = rs.getBytes(colName); + if (geo == null) { + return null; + } + return SqlUtils.toGeometry(geo); + default: + return rs.getObject(colName); + } + } + + public void writeColumn(PreparedStatement ps, int index, MySQLColumnDef colType, Object value) throws Exception { + if (colType == null) { + String colVal = null; + if (value != null) { + colVal = value.toString(); + } + if (colVal == null) { + ps.setNull(index, Types.VARCHAR); + } else { + ps.setString(index, colVal); + } + } else if (value == null) { + ps.setNull(index, colType.getJdbcType().getVendorTypeNumber()); + } else { + switch (colType.getType()) { + case TINYINT: + case SMALLINT: + case MEDIUMINT: + case INT: + Long longValue = SqlUtils.toLong(value); + if (longValue == null) { + ps.setNull(index, 4); + return; + } else { + ps.setLong(index, longValue); + return; + } + case BIGINT: + case DECIMAL: + BigDecimal bigDecimalValue = SqlUtils.toBigDecimal(value); + if (bigDecimalValue == null) { + ps.setNull(index, 3); + return; + } else { + ps.setBigDecimal(index, bigDecimalValue); + return; + } + case FLOAT: + case DOUBLE: + Double doubleValue = SqlUtils.toDouble(value); + if (doubleValue == null) { + ps.setNull(index, 8); + } else { + ps.setDouble(index, doubleValue); + } + return; + case DATE: + case DATETIME: + case TIMESTAMP: + LocalDateTime dateValue = null; + if (!SqlUtils.isZeroTime(value)) { + try { + dateValue = SqlUtils.toLocalDateTime(value); + } catch (Exception e) { + ps.setString(index, SqlUtils.convertToString(value)); + return; + } + } else if (StringUtils.isNotBlank(config.getZeroDate())) { + dateValue = SqlUtils.toLocalDateTime(config.getZeroDate()); + } else { + ps.setObject(index, value); + return; + } + if (dateValue == null) { + ps.setNull(index, Types.TIMESTAMP); + } else { + ps.setString(index, dataTimePattern.format(dateValue)); + } + return; + case TIME: + String timeValue = SqlUtils.toMySqlTime(value); + if (StringUtils.isBlank(timeValue)) { + ps.setNull(index, 12); + return; + } else { + ps.setString(index, timeValue); + return; + } + case YEAR: + LocalDateTime yearValue = null; + if (!SqlUtils.isZeroTime(value)) { + yearValue = SqlUtils.toLocalDateTime(value); + } else if (StringUtils.isNotBlank(config.getZeroDate())) { + yearValue = SqlUtils.toLocalDateTime(config.getZeroDate()); + } else { + ps.setInt(index, 0); + return; + } + if (yearValue == null) { + ps.setNull(index, 4); + } else { + ps.setInt(index, yearValue.getYear()); + } + return; + case CHAR: + case VARCHAR: + case TINYTEXT: + case TEXT: + case MEDIUMTEXT: + case LONGTEXT: + case ENUM: + case SET: + String strValue = value.toString(); + if (strValue == null) { + ps.setNull(index, Types.VARCHAR); + return; + } else { + ps.setString(index, strValue); + return; + } + case JSON: + String jsonValue = value.toString(); + if (jsonValue == null) { + ps.setNull(index, Types.VARCHAR); + } else { + ps.setString(index, jsonValue); + } + return; + case BIT: + if (value instanceof Boolean) { + byte[] arrayBoolean = new byte[1]; + arrayBoolean[0] = (byte) (Boolean.TRUE.equals(value) ? 1 : 0); + ps.setBytes(index, arrayBoolean); + return; + } else if (value instanceof Number) { + ps.setBytes(index, SqlUtils.numberToBinaryArray((Number) value)); + return; + } else if ((value instanceof byte[]) || value.toString().startsWith("0x") || value.toString().startsWith("0X")) { + byte[] arrayBoolean = SqlUtils.toBytes(value); + if (arrayBoolean == null || arrayBoolean.length == 0) { + ps.setNull(index, Types.BIT); + return; + } else { + ps.setBytes(index, arrayBoolean); + return; + } + } else { + ps.setBytes(index, SqlUtils.numberToBinaryArray(SqlUtils.toInt(value))); + return; + } + case BINARY: + case VARBINARY: + case TINYBLOB: + case BLOB: + case MEDIUMBLOB: + case LONGBLOB: + byte[] binaryValue = SqlUtils.toBytes(value); + if (binaryValue == null) { + ps.setNull(index, Types.BINARY); + return; + } else { + ps.setBytes(index, binaryValue); + return; + } + case GEOMETRY: + case GEOMETRY_COLLECTION: + case GEOM_COLLECTION: + case POINT: + case LINESTRING: + case POLYGON: + case MULTIPOINT: + case MULTILINESTRING: + case MULTIPOLYGON: + String geoValue = SqlUtils.toGeometry(value); + if (geoValue == null) { + ps.setNull(index, Types.VARCHAR); + return; + } + ps.setString(index, geoValue); + return; + default: + throw new UnsupportedOperationException("columnType '" + colType + "' Unsupported."); + } + } + } + + public String genTargetPkInSql(MySQLTableDef def, int pkGroupSize, String leftQuote, String rightQuote, String selectEleStr) { + List pkCols = def.getPrimaryKeys(); + if (pkCols == null || pkCols.isEmpty()) { + throw new IllegalArgumentException("unsupported pk is empty table check."); + } else if (pkCols.size() == 1) { + return genSinglePkInSql(def, pkGroupSize, leftQuote, rightQuote, selectEleStr); + } else { + return genMultiPkInSql(def, pkGroupSize, leftQuote, rightQuote, selectEleStr); + } + } + + public String genSinglePkInSql(MySQLTableDef def, int pkGroupSize, String leftQuote, String rightQuote, String selectEleStr) { + return MessageFormat.format(genFetchSqlFormat(leftQuote, rightQuote, selectEleStr), def.getSchemaName(), def.getTableName(), + leftQuote + def.getPrimaryKeys().get(0) + rightQuote, genSinglePkPlaceHolderStr(pkGroupSize)); + } + + public String genMultiPkInSql(MySQLTableDef def, int pkGroupSize, String leftQuote, String rightQuote, String selectEleStr) { + String fetchSqlFormat = genFetchSqlFormat(leftQuote, rightQuote, selectEleStr); + List pkCols = def.getPrimaryKeys(); + StringBuilder pksBuilder = new StringBuilder("("); + for (int i = 0; i < pkCols.size(); i++) { + if (i != 0) { + pksBuilder.append(","); + } + pksBuilder.append(leftQuote).append(pkCols.get(i)).append(rightQuote); + } + pksBuilder.append(")"); + return MessageFormat.format(fetchSqlFormat, def.getSchemaName(), def.getTableName(), pksBuilder.toString(), + genMultiPkPlaceHolderStr(pkGroupSize, pkCols.size())); + } + + public String genFetchSqlFormat(String leftQuote, String rightQuote, String selectEleStr) { + return "select " + selectEleStr + " from " + leftQuote + "{0}" + rightQuote + "." + leftQuote + "{1}" + rightQuote + " where {2} in ({3})"; + } + + public String genSinglePkPlaceHolderStr(int valueSize) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < valueSize; i++) { + if (i != 0) { + sb.append(","); + } + sb.append("?"); + } + return sb.toString(); + } + + public String genMultiPkPlaceHolderStr(int valueSize, int sizePerGroup) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < valueSize; i++) { + if (i != 0) { + sb.append(","); + } + sb.append("("); + for (int j = 0; j < sizePerGroup; j++) { + if (j != 0) { + sb.append(","); + } + sb.append("?"); + } + sb.append(")"); + } + return sb.toString(); + } + + + + private SendExceptionContext buildSendExceptionContext(ConnectRecord record, Throwable e) { + SendExceptionContext sendExceptionContext = new SendExceptionContext(); + sendExceptionContext.setMessageId(record.getRecordId()); + sendExceptionContext.setCause(e); + if (StringUtils.isNotEmpty(record.getExtension("topic"))) { + sendExceptionContext.setTopic(record.getExtension("topic")); + } + return sendExceptionContext; + } + + private SendResult convertToSendResult(ConnectRecord record) { + SendResult result = new SendResult(); + result.setMessageId(record.getRecordId()); + if (StringUtils.isNotEmpty(record.getExtension("topic"))) { + result.setTopic(record.getExtension("topic")); + } + return result; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalFullConsumer.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalFullConsumer.java new file mode 100644 index 0000000000..939d1101aa --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalFullConsumer.java @@ -0,0 +1,391 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink.connector; + +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkFullConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.Constants; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLColumnDef; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordOffset; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.SqlUtils; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +import com.alibaba.druid.pool.DruidPooledConnection; +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class CanalFullConsumer { + private BlockingQueue> queue; + private RdbTableMgr tableMgr; + private CanalSinkFullConfig config; + private final DateTimeFormatter dataTimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"); + + + public CanalFullConsumer(BlockingQueue> queue, RdbTableMgr tableMgr, CanalSinkFullConfig config) { + this.config = config; + this.queue = queue; + this.tableMgr = tableMgr; + } + + + public void start(AtomicBoolean flag) { + while (flag.get()) { + List sinkRecords = null; + try { + sinkRecords = queue.poll(2, TimeUnit.SECONDS); + if (sinkRecords == null || sinkRecords.isEmpty()) { + continue; + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + ConnectRecord record = sinkRecords.get(0); + Map dataMap = + JsonUtils.parseTypeReferenceObject((byte[]) record.getData(), new TypeReference>() { + }); + + List> rows = JsonUtils.parseObject(dataMap.get("data").toString(), List.class); + + if (rows == null || rows.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("[{}] got rows data is none", this.getClass()); + } + return; + } + CanalFullRecordOffset offset = JsonUtils.parseObject(dataMap.get("offset").toString(), CanalFullRecordOffset.class); + if (offset == null || offset.getPosition() == null) { + if (log.isDebugEnabled()) { + log.debug("[{}] got canal full offset is none", this.getClass()); + } + return; + } + + MySQLTableDef tableDefinition = (MySQLTableDef) tableMgr.getTable(offset.getPosition().getSchema(), offset.getPosition().getTableName()); + if (tableDefinition == null) { + log.warn("target schema [{}] table [{}] is not exists", offset.getPosition().getSchema(), offset.getPosition().getTableName()); + return; + } + List cols = new ArrayList<>(tableDefinition.getColumnDefinitions().values()); + String sql = generateInsertPrepareSql(offset.getPosition().getSchema(), offset.getPosition().getTableName(), + cols); + DruidPooledConnection connection = null; + PreparedStatement statement = null; + try { + connection = DatabaseConnection.sinkDataSource.getConnection(); + statement = + connection.prepareStatement(sql); + for (Map col : rows) { + setPrepareParams(statement, col, cols); + log.debug("insert sql {}", statement.toString()); + statement.addBatch(); + } + statement.executeBatch(); + connection.commit(); + log.info("execute batch insert sql size: {}", rows.size()); + record.getCallback().onSuccess(convertToSendResult(record)); + } catch (SQLException e) { + log.warn("full sink process schema [{}] table [{}] connector write fail", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), + e); + LockSupport.parkNanos(3000 * 1000L); + record.getCallback().onException(buildSendExceptionContext(record, e)); + } catch (Exception e) { + log.error("full sink process schema [{}] table [{}] catch unknown exception", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), e); + record.getCallback().onException(buildSendExceptionContext(record, e)); + try { + if (connection != null && !connection.isClosed()) { + connection.rollback(); + } + } catch (SQLException rollback) { + log.warn("full sink process schema [{}] table [{}] rollback fail", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), e); + } + } finally { + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + log.error("close prepare statement fail", e); + } + } + + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + log.error("close db connection fail", e); + } + } + } + } + } + + + private SendExceptionContext buildSendExceptionContext(ConnectRecord record, Throwable e) { + SendExceptionContext sendExceptionContext = new SendExceptionContext(); + sendExceptionContext.setMessageId(record.getRecordId()); + sendExceptionContext.setCause(e); + if (StringUtils.isNotEmpty(record.getExtension("topic"))) { + sendExceptionContext.setTopic(record.getExtension("topic")); + } + return sendExceptionContext; + } + + private SendResult convertToSendResult(ConnectRecord record) { + SendResult result = new SendResult(); + result.setMessageId(record.getRecordId()); + if (StringUtils.isNotEmpty(record.getExtension("topic"))) { + result.setTopic(record.getExtension("topic")); + } + return result; + } + + private void setPrepareParams(PreparedStatement preparedStatement, Map col, List columnDefs) throws Exception { + for (int i = 0; i < columnDefs.size(); i++) { + writeColumn(preparedStatement, i + 1, columnDefs.get(i), col.get(columnDefs.get(i).getName())); + } + } + + public void writeColumn(PreparedStatement ps, int index, MySQLColumnDef colType, Object value) throws Exception { + if (colType == null) { + String colVal = null; + if (value != null) { + colVal = value.toString(); + } + if (colVal == null) { + ps.setNull(index, Types.VARCHAR); + } else { + ps.setString(index, colVal); + } + } else if (value == null) { + ps.setNull(index, colType.getJdbcType().getVendorTypeNumber()); + } else { + switch (colType.getType()) { + case TINYINT: + case SMALLINT: + case MEDIUMINT: + case INT: + Long longValue = SqlUtils.toLong(value); + if (longValue == null) { + ps.setNull(index, 4); + return; + } else { + ps.setLong(index, longValue); + return; + } + case BIGINT: + case DECIMAL: + BigDecimal bigDecimalValue = SqlUtils.toBigDecimal(value); + if (bigDecimalValue == null) { + ps.setNull(index, 3); + return; + } else { + ps.setBigDecimal(index, bigDecimalValue); + return; + } + case FLOAT: + case DOUBLE: + Double doubleValue = SqlUtils.toDouble(value); + if (doubleValue == null) { + ps.setNull(index, 8); + } else { + ps.setDouble(index, doubleValue); + } + return; + case DATE: + case DATETIME: + case TIMESTAMP: + LocalDateTime dateValue = null; + if (!SqlUtils.isZeroTime(value)) { + try { + dateValue = SqlUtils.toLocalDateTime(value); + } catch (Exception e) { + ps.setString(index, SqlUtils.convertToString(value)); + return; + } + } else if (StringUtils.isNotBlank(config.getZeroDate())) { + dateValue = SqlUtils.toLocalDateTime(config.getZeroDate()); + } else { + ps.setObject(index, value); + return; + } + if (dateValue == null) { + ps.setNull(index, Types.TIMESTAMP); + } else { + ps.setString(index, dataTimePattern.format(dateValue)); + } + return; + case TIME: + String timeValue = SqlUtils.toMySqlTime(value); + if (StringUtils.isBlank(timeValue)) { + ps.setNull(index, 12); + return; + } else { + ps.setString(index, timeValue); + return; + } + case YEAR: + LocalDateTime yearValue = null; + if (!SqlUtils.isZeroTime(value)) { + yearValue = SqlUtils.toLocalDateTime(value); + } else if (StringUtils.isNotBlank(config.getZeroDate())) { + yearValue = SqlUtils.toLocalDateTime(config.getZeroDate()); + } else { + ps.setInt(index, 0); + return; + } + if (yearValue == null) { + ps.setNull(index, 4); + } else { + ps.setInt(index, yearValue.getYear()); + } + return; + case CHAR: + case VARCHAR: + case TINYTEXT: + case TEXT: + case MEDIUMTEXT: + case LONGTEXT: + case ENUM: + case SET: + String strValue = value.toString(); + if (strValue == null) { + ps.setNull(index, Types.VARCHAR); + return; + } else { + ps.setString(index, strValue); + return; + } + case JSON: + String jsonValue = value.toString(); + if (jsonValue == null) { + ps.setNull(index, Types.VARCHAR); + } else { + ps.setString(index, jsonValue); + } + return; + case BIT: + if (value instanceof Boolean) { + byte[] arrayBoolean = new byte[1]; + arrayBoolean[0] = (byte) (Boolean.TRUE.equals(value) ? 1 : 0); + ps.setBytes(index, arrayBoolean); + return; + } else if (value instanceof Number) { + ps.setBytes(index, SqlUtils.numberToBinaryArray((Number) value)); + return; + } else if ((value instanceof byte[]) || value.toString().startsWith("0x") || value.toString().startsWith("0X")) { + byte[] arrayBoolean = SqlUtils.toBytes(value); + if (arrayBoolean == null || arrayBoolean.length == 0) { + ps.setNull(index, Types.BIT); + return; + } else { + ps.setBytes(index, arrayBoolean); + return; + } + } else { + ps.setBytes(index, SqlUtils.numberToBinaryArray(SqlUtils.toInt(value))); + return; + } + case BINARY: + case VARBINARY: + case TINYBLOB: + case BLOB: + case MEDIUMBLOB: + case LONGBLOB: + byte[] binaryValue = SqlUtils.toBytes(value); + if (binaryValue == null) { + ps.setNull(index, Types.BINARY); + return; + } else { + ps.setBytes(index, binaryValue); + return; + } + case GEOMETRY: + case GEOMETRY_COLLECTION: + case GEOM_COLLECTION: + case POINT: + case LINESTRING: + case POLYGON: + case MULTIPOINT: + case MULTILINESTRING: + case MULTIPOLYGON: + String geoValue = SqlUtils.toGeometry(value); + if (geoValue == null) { + ps.setNull(index, Types.VARCHAR); + return; + } + ps.setString(index, geoValue); + return; + default: + throw new UnsupportedOperationException("columnType '" + colType + "' Unsupported."); + } + } + } + + private String generateInsertPrepareSql(String schema, String table, List cols) { + StringBuilder builder = new StringBuilder(); + builder.append("INSERT IGNORE INTO "); + builder.append(Constants.MySQLQuot); + builder.append(schema); + builder.append(Constants.MySQLQuot); + builder.append("."); + builder.append(Constants.MySQLQuot); + builder.append(table); + builder.append(Constants.MySQLQuot); + StringBuilder columns = new StringBuilder(); + StringBuilder values = new StringBuilder(); + for (MySQLColumnDef colInfo : cols) { + if (columns.length() > 0) { + columns.append(", "); + values.append(", "); + } + String wrapName = Constants.MySQLQuot + colInfo.getName() + Constants.MySQLQuot; + columns.append(wrapName); + values.append(colInfo.getType() == null ? "?" : colInfo.getType().genPrepareStatement4Insert()); + } + builder.append("(").append(columns).append(")"); + builder.append(" VALUES "); + builder.append("(").append(values).append(")"); + return builder.toString(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkCheckConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkCheckConnector.java new file mode 100644 index 0000000000..6819c936fd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkCheckConnector.java @@ -0,0 +1,151 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink.connector; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkFullConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSinkCheckConnector implements Sink, ConnectorCreateService { + + private CanalSinkFullConfig config; + private RdbTableMgr tableMgr; + private ThreadPoolExecutor executor; + private final BlockingQueue> queue = new LinkedBlockingQueue<>(10000); + private final AtomicBoolean flag = new AtomicBoolean(true); + + @Override + public void start() throws Exception { + tableMgr.start(); + } + + @Override + public void stop() throws Exception { + flag.set(false); + if (!executor.isShutdown()) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + log.warn("wait thread pool shutdown timeout, it will shutdown now"); + executor.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.info("shutdown thread pool fail"); + } + } + if (DatabaseConnection.sinkDataSource != null) { + DatabaseConnection.sinkDataSource.close(); + log.info("data source has been closed"); + } + } + + @Override + public Sink create() { + return new CanalSinkCheckConnector(); + } + + @Override + public Class configClass() { + return CanalSinkFullConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.config = (CanalSinkFullConfig) config; + init(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + CanalSinkConfig canalSinkConfig = (CanalSinkConfig) ((SinkConnectorContext) connectorContext).getSinkConfig(); + this.config = ConfigUtil.parse(canalSinkConfig.getSinkConfig(), CanalSinkFullConfig.class); + init(); + } + + private void init() { + if (config.getSinkConnectorConfig() == null) { + throw new EventMeshException(String.format("[%s] sink config is null", this.getClass())); + } + DatabaseConnection.sinkConfig = this.config.getSinkConnectorConfig(); + DatabaseConnection.initSinkConnection(); + DatabaseConnection.sinkDataSource.setDefaultAutoCommit(false); + + tableMgr = new RdbTableMgr(this.config.getSinkConnectorConfig(), DatabaseConnection.sinkDataSource); + executor = new ThreadPoolExecutor(config.getParallel(), config.getParallel(), 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new EventMeshThreadFactory("canal-sink-check")); + List consumers = new LinkedList<>(); + for (int i = 0; i < config.getParallel(); i++) { + CanalCheckConsumer canalCheckConsumer = new CanalCheckConsumer(queue, tableMgr, config); + consumers.add(canalCheckConsumer); + } + consumers.forEach(c -> executor.execute(() -> c.start(flag))); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return null; + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void put(List sinkRecords) { + if (sinkRecords == null || sinkRecords.isEmpty() || sinkRecords.get(0) == null) { + if (log.isDebugEnabled()) { + log.debug("[{}] got sink records are none", this.getClass()); + } + return; + } + try { + queue.put(sinkRecords); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkConnector.java new file mode 100644 index 0000000000..b03df2dfff --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkConnector.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkConfig; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSinkConnector implements Sink, ConnectorCreateService { + + private CanalSinkConfig sinkConfig; + + private Sink sink; + + @Override + public Class configClass() { + return CanalSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for canal source connector + this.sinkConfig = (CanalSinkConfig) config; + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for canal source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + if (sinkConnectorContext.getJobType().equals(JobType.FULL)) { + this.sink = new CanalSinkFullConnector(); + } else if (sinkConnectorContext.getJobType().equals(JobType.INCREASE)) { + this.sink = new CanalSinkIncrementConnector(); + } else if (sinkConnectorContext.getJobType().equals(JobType.CHECK)) { + this.sink = new CanalSinkCheckConnector(); + } else { + throw new RuntimeException("unsupported job type " + sinkConnectorContext.getJobType()); + } + this.sink.init(sinkConnectorContext); + } + + @Override + public void start() throws Exception { + this.sink.start(); + } + + @Override + public void commit(ConnectRecord record) { + this.sink.commit(record); + } + + @Override + public String name() { + return this.sink.name(); + } + + @Override + public void onException(ConnectRecord record) { + this.sink.onException(record); + } + + @Override + public void stop() throws Exception { + this.sink.stop(); + } + + @Override + public void put(List sinkRecords) { + this.sink.put(sinkRecords); + } + + @Override + public Sink create() { + return new CanalSinkConnector(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkFullConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkFullConnector.java new file mode 100644 index 0000000000..cb50dc5648 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkFullConnector.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink.connector; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkFullConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSinkFullConnector implements Sink, ConnectorCreateService { + + private CanalSinkFullConfig config; + private RdbTableMgr tableMgr; + private ThreadPoolExecutor executor; + private final BlockingQueue> queue = new LinkedBlockingQueue<>(10000); + private final AtomicBoolean flag = new AtomicBoolean(true); + + @Override + public void start() throws Exception { + tableMgr.start(); + } + + @Override + public void stop() throws Exception { + flag.set(false); + if (!executor.isShutdown()) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + log.warn("wait thread pool shutdown timeout, it will shutdown now"); + executor.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.info("shutdown thread pool fail"); + } + } + if (DatabaseConnection.sinkDataSource != null) { + DatabaseConnection.sinkDataSource.close(); + log.info("data source has been closed"); + } + } + + @Override + public Sink create() { + return new CanalSinkFullConnector(); + } + + @Override + public Class configClass() { + return CanalSinkFullConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.config = (CanalSinkFullConfig) config; + init(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + CanalSinkConfig canalSinkConfig = (CanalSinkConfig) sinkConnectorContext.getSinkConfig(); + this.config = ConfigUtil.parse(canalSinkConfig.getSinkConfig(), CanalSinkFullConfig.class); + init(); + } + + private void init() { + if (config.getSinkConnectorConfig() == null) { + throw new EventMeshException(String.format("[%s] sink config is null", this.getClass())); + } + DatabaseConnection.sinkConfig = this.config.getSinkConnectorConfig(); + DatabaseConnection.initSinkConnection(); + DatabaseConnection.sinkDataSource.setDefaultAutoCommit(false); + + tableMgr = new RdbTableMgr(this.config.getSinkConnectorConfig(), DatabaseConnection.sinkDataSource); + executor = new ThreadPoolExecutor(config.getParallel(), config.getParallel(), 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new EventMeshThreadFactory("canal-sink-full")); + List consumers = new LinkedList<>(); + for (int i = 0; i < config.getParallel(); i++) { + CanalFullConsumer canalFullConsumer = new CanalFullConsumer(queue, tableMgr, config); + consumers.add(canalFullConsumer); + } + consumers.forEach(c -> executor.execute(() -> c.start(flag))); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return null; + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void put(List sinkRecords) { + if (sinkRecords == null || sinkRecords.isEmpty() || sinkRecords.get(0) == null) { + if (log.isDebugEnabled()) { + log.debug("[{}] got sink records are none", this.getClass()); + } + return; + } + try { + queue.put(sinkRecords); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkIncrementConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkIncrementConnector.java new file mode 100644 index 0000000000..84373ae7a7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/sink/connector/CanalSinkIncrementConnector.java @@ -0,0 +1,865 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSinkIncrementConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.CanalConnectRecord; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.SqlUtils; +import org.apache.eventmesh.connector.canal.dialect.DbDialect; +import org.apache.eventmesh.connector.canal.dialect.MysqlDialect; +import org.apache.eventmesh.connector.canal.interceptor.SqlBuilderLoadInterceptor; +import org.apache.eventmesh.connector.canal.model.EventColumn; +import org.apache.eventmesh.connector.canal.model.EventType; +import org.apache.eventmesh.connector.canal.sink.DbLoadContext; +import org.apache.eventmesh.connector.canal.sink.DbLoadData; +import org.apache.eventmesh.connector.canal.sink.DbLoadData.TableLoadData; +import org.apache.eventmesh.connector.canal.sink.DbLoadMerger; +import org.apache.eventmesh.connector.canal.sink.GtidBatch; +import org.apache.eventmesh.connector.canal.sink.GtidBatchManager; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.SerializationUtils; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DeadlockLoserDataAccessException; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.jdbc.core.StatementCallback; +import org.springframework.jdbc.core.StatementCreatorUtils; +import org.springframework.jdbc.support.lob.DefaultLobHandler; +import org.springframework.jdbc.support.lob.LobCreator; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.util.CollectionUtils; + +import com.alibaba.otter.canal.common.utils.NamedThreadFactory; +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSinkIncrementConnector implements Sink, ConnectorCreateService { + + private CanalSinkIncrementConfig sinkConfig; + + private JdbcTemplate jdbcTemplate; + + private SqlBuilderLoadInterceptor interceptor; + + private DbDialect dbDialect; + + private ExecutorService executor; + + private ExecutorService gtidSingleExecutor; + + private int batchSize = 50; + + private boolean useBatch = true; + + private RdbTableMgr tableMgr; + + @Override + public Class configClass() { + return CanalSinkIncrementConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for canal source connector + this.sinkConfig = (CanalSinkIncrementConfig) config; + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for canal source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + CanalSinkConfig canalSinkConfig = (CanalSinkConfig) sinkConnectorContext.getSinkConfig(); + this.sinkConfig = ConfigUtil.parse(canalSinkConfig.getSinkConfig(), CanalSinkIncrementConfig.class); + this.batchSize = sinkConfig.getBatchSize(); + this.useBatch = sinkConfig.getUseBatch(); + DatabaseConnection.sinkConfig = this.sinkConfig.getSinkConnectorConfig(); + DatabaseConnection.initSinkConnection(); + jdbcTemplate = new JdbcTemplate(DatabaseConnection.sinkDataSource); + dbDialect = new MysqlDialect(jdbcTemplate, new DefaultLobHandler()); + interceptor = new SqlBuilderLoadInterceptor(); + interceptor.setDbDialect(dbDialect); + tableMgr = new RdbTableMgr(sinkConfig.getSinkConnectorConfig(), DatabaseConnection.sinkDataSource); + executor = new ThreadPoolExecutor(sinkConfig.getPoolSize(), + sinkConfig.getPoolSize(), + 0L, + TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(sinkConfig.getPoolSize() * 4), + new NamedThreadFactory("canalSink"), + new ThreadPoolExecutor.CallerRunsPolicy()); + gtidSingleExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "gtidSingleExecutor")); + } + + @Override + public void start() throws Exception { + tableMgr.start(); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + executor.shutdown(); + gtidSingleExecutor.shutdown(); + } + + @Override + public void put(List sinkRecords) { + DbLoadContext context = new DbLoadContext(); + for (ConnectRecord connectRecord : sinkRecords) { + List canalConnectRecordList = new ArrayList<>(); + + List canalConnectRecords = convertToCanalConnectRecord(connectRecord); + + // deep copy connectRecord data + for (CanalConnectRecord record : canalConnectRecords) { + canalConnectRecordList.add(SerializationUtils.clone(record)); + } + canalConnectRecordList = filterRecord(canalConnectRecordList); + if (isDdlDatas(canalConnectRecordList)) { + doDdl(context, canalConnectRecordList, connectRecord); + } else if (sinkConfig.isGTIDMode()) { + doLoadWithGtid(context, sinkConfig, connectRecord); + } else { + canalConnectRecordList = DbLoadMerger.merge(canalConnectRecordList); + + DbLoadData loadData = new DbLoadData(); + doBefore(canalConnectRecordList, loadData); + + doLoad(context, sinkConfig, loadData, connectRecord); + + } + + } + } + + @Override + public Sink create() { + return new CanalSinkIncrementConnector(); + } + + private boolean isDdlDatas(List canalConnectRecordList) { + boolean result = false; + for (CanalConnectRecord canalConnectRecord : canalConnectRecordList) { + result |= canalConnectRecord.getEventType().isDdl(); + if (result && !canalConnectRecord.getEventType().isDdl()) { + throw new RuntimeException("ddl/dml can't be in one batch, it's may be a bug , pls submit issues."); + } + } + return result; + } + + private List filterRecord(List canalConnectRecordList) { + return canalConnectRecordList.stream() + .filter(record -> tableMgr.getTable(record.getSchemaName(), record.getTableName()) != null) + .collect(Collectors.toList()); + } + + private void doDdl(DbLoadContext context, List canalConnectRecordList, ConnectRecord connectRecord) { + for (final CanalConnectRecord record : canalConnectRecordList) { + try { + Boolean result = jdbcTemplate.execute(new StatementCallback() { + + public Boolean doInStatement(Statement stmt) throws SQLException, DataAccessException { + boolean result = true; + if (StringUtils.isNotEmpty(record.getDdlSchemaName())) { + result &= stmt.execute("use `" + record.getDdlSchemaName() + "`"); + } + result &= stmt.execute(record.getSql()); + return result; + } + }); + if (Boolean.TRUE.equals(result)) { + context.getProcessedRecords().add(record); + } else { + context.getFailedRecords().add(record); + } + } catch (Throwable e) { + connectRecord.getCallback().onException(buildSendExceptionContext(connectRecord, e)); + throw new RuntimeException(e); + } + } + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + + private SendExceptionContext buildSendExceptionContext(ConnectRecord record, Throwable e) { + SendExceptionContext sendExceptionContext = new SendExceptionContext(); + sendExceptionContext.setMessageId(record.getRecordId()); + sendExceptionContext.setCause(e); + if (org.apache.commons.lang3.StringUtils.isNotEmpty(record.getExtension("topic"))) { + sendExceptionContext.setTopic(record.getExtension("topic")); + } + return sendExceptionContext; + } + + private SendResult convertToSendResult(ConnectRecord record) { + SendResult result = new SendResult(); + result.setMessageId(record.getRecordId()); + if (org.apache.commons.lang3.StringUtils.isNotEmpty(record.getExtension("topic"))) { + result.setTopic(record.getExtension("topic")); + } + return result; + } + + private void doBefore(List canalConnectRecordList, final DbLoadData loadData) { + for (final CanalConnectRecord record : canalConnectRecordList) { + boolean filter = interceptor.before(sinkConfig, record); + if (!filter) { + loadData.merge(record); + } + } + } + + private void doLoad(DbLoadContext context, CanalSinkIncrementConfig sinkConfig, DbLoadData loadData, ConnectRecord connectRecord) { + List> batchDatas = new ArrayList<>(); + for (TableLoadData tableData : loadData.getTables()) { + if (useBatch) { + batchDatas.addAll(split(tableData.getDeleteDatas())); + } else { + for (CanalConnectRecord data : tableData.getDeleteDatas()) { + batchDatas.add(Arrays.asList(data)); + } + } + } + + doTwoPhase(context, sinkConfig, batchDatas, true, connectRecord); + + batchDatas.clear(); + + for (TableLoadData tableData : loadData.getTables()) { + if (useBatch) { + batchDatas.addAll(split(tableData.getInsertDatas())); + batchDatas.addAll(split(tableData.getUpdateDatas())); + } else { + for (CanalConnectRecord data : tableData.getInsertDatas()) { + batchDatas.add(Arrays.asList(data)); + } + for (CanalConnectRecord data : tableData.getUpdateDatas()) { + batchDatas.add(Arrays.asList(data)); + } + } + } + + doTwoPhase(context, sinkConfig, batchDatas, true, connectRecord); + + batchDatas.clear(); + } + + private void doLoadWithGtid(DbLoadContext context, CanalSinkIncrementConfig sinkConfig, ConnectRecord connectRecord) { + int batchIndex = connectRecord.getExtension("batchIndex", Integer.class); + int totalBatches = connectRecord.getExtension("totalBatches", Integer.class); + List canalConnectRecordList = convertToCanalConnectRecord(connectRecord); + + String gtid = canalConnectRecordList.get(0).getCurrentGtid(); + GtidBatchManager.addBatch(gtid, batchIndex, totalBatches, canalConnectRecordList); + // check whether the batch is complete + if (GtidBatchManager.isComplete(gtid)) { + GtidBatch batch = GtidBatchManager.getGtidBatch(gtid); + List> totalRows = batch.getBatches(); + List filteredRows = new ArrayList<>(); + for (List canalConnectRecords : totalRows) { + canalConnectRecords = filterRecord(canalConnectRecords); + if (!CollectionUtils.isEmpty(canalConnectRecords)) { + for (final CanalConnectRecord record : canalConnectRecords) { + boolean filter = interceptor.before(sinkConfig, record); + filteredRows.add(record); + } + } + } + context.setGtid(gtid); + Future result = gtidSingleExecutor.submit(new DbLoadWorker(context, filteredRows, dbDialect, false, sinkConfig)); + Exception ex = null; + try { + ex = result.get(); + if (ex == null) { + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + } catch (Exception e) { + ex = e; + } + Boolean skipException = sinkConfig.getSkipException(); + if (skipException != null && skipException) { + if (ex != null) { + // do skip + log.warn("skip exception will ack data : {} , caused by {}", + filteredRows, + ExceptionUtils.getFullStackTrace(ex)); + GtidBatchManager.removeGtidBatch(gtid); + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + } else { + if (ex != null) { + log.error("sink connector will shutdown by " + ex.getMessage(), ExceptionUtils.getFullStackTrace(ex)); + connectRecord.getCallback().onException(buildSendExceptionContext(connectRecord, ex)); + gtidSingleExecutor.shutdown(); + System.exit(1); + } else { + GtidBatchManager.removeGtidBatch(gtid); + } + } + } else { + log.info("Batch received, waiting for other batches."); + // ack this record + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + } + + private List convertToCanalConnectRecord(ConnectRecord connectRecord) { + List canalConnectRecordList; + try { + canalConnectRecordList = + JsonUtils.parseTypeReferenceObject((byte[]) connectRecord.getData(), new TypeReference>() { + }); + } catch (Exception e) { + log.error("Failed to parse the canalConnectRecords.", e); + connectRecord.getCallback().onException(buildSendExceptionContext(connectRecord, e)); + throw new RuntimeException("Failed to parse the canalConnectRecords.", e); + } + return canalConnectRecordList; + } + + private List> split(List records) { + List> result = new ArrayList<>(); + if (records == null || records.isEmpty()) { + return result; + } else { + int[] bits = new int[records.size()]; + for (int i = 0; i < bits.length; i++) { + while (i < bits.length && bits[i] == 1) { + i++; + } + + if (i >= bits.length) { + break; + } + + List batch = new ArrayList<>(); + bits[i] = 1; + batch.add(records.get(i)); + for (int j = i + 1; j < bits.length && batch.size() < batchSize; j++) { + if (bits[j] == 0 && canBatch(records.get(i), records.get(j))) { + batch.add(records.get(j)); + bits[j] = 1; + } + } + result.add(batch); + } + + return result; + } + } + + private boolean canBatch(CanalConnectRecord source, CanalConnectRecord target) { + return StringUtils.equals(source.getSchemaName(), + target.getSchemaName()) + && StringUtils.equals(source.getTableName(), target.getTableName()) + && StringUtils.equals(source.getSql(), target.getSql()); + } + + private void doTwoPhase(DbLoadContext context, CanalSinkIncrementConfig sinkConfig, List> totalRows, boolean canBatch, + ConnectRecord connectRecord) { + List> results = new ArrayList<>(); + for (List rows : totalRows) { + if (CollectionUtils.isEmpty(rows)) { + continue; + } + results.add(executor.submit(new DbLoadWorker(context, rows, dbDialect, canBatch, sinkConfig))); + } + + boolean partFailed = false; + for (Future result : results) { + Exception ex = null; + try { + ex = result.get(); + if (ex == null) { + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + } catch (Exception e) { + ex = e; + } + + if (ex != null) { + log.warn("##load phase one failed!", ex); + partFailed = true; + } + } + + if (partFailed) { + List retryRecords = new ArrayList<>(); + for (List rows : totalRows) { + retryRecords.addAll(rows); + } + + context.getFailedRecords().clear(); + + Boolean skipException = sinkConfig.getSkipException(); + if (skipException != null && skipException) { + for (CanalConnectRecord retryRecord : retryRecords) { + DbLoadWorker worker = new DbLoadWorker(context, Arrays.asList(retryRecord), dbDialect, false, sinkConfig); + try { + Exception ex = worker.call(); + if (ex != null) { + // do skip + log.warn("skip exception for data : {} , caused by {}", + retryRecord, + ExceptionUtils.getFullStackTrace(ex)); + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + } catch (Exception ex) { + // do skip + log.warn("skip exception for data : {} , caused by {}", + retryRecord, + ExceptionUtils.getFullStackTrace(ex)); + connectRecord.getCallback().onSuccess(convertToSendResult(connectRecord)); + } + } + } else { + DbLoadWorker worker = new DbLoadWorker(context, retryRecords, dbDialect, false, sinkConfig); + try { + Exception ex = worker.call(); + if (ex != null) { + throw ex; + } + } catch (Exception ex) { + log.error("##load phase two failed!", ex); + log.error("sink connector will shutdown by " + ex.getMessage(), ex); + connectRecord.getCallback().onException(buildSendExceptionContext(connectRecord, ex)); + executor.shutdown(); + System.exit(1); + } + } + } + } + + enum ExecuteResult { + SUCCESS, ERROR, RETRY + } + + class DbLoadWorker implements Callable { + + private final DbLoadContext context; + private final DbDialect dbDialect; + private final List records; + private final boolean canBatch; + + private final CanalSinkIncrementConfig sinkConfig; + + private final List allFailedRecords = new ArrayList<>(); + private final List allProcessedRecords = new ArrayList<>(); + private final List processedRecords = new ArrayList<>(); + private final List failedRecords = new ArrayList<>(); + + public DbLoadWorker(DbLoadContext context, List records, DbDialect dbDialect, boolean canBatch, + CanalSinkIncrementConfig sinkConfig) { + this.context = context; + this.records = records; + this.canBatch = canBatch; + this.dbDialect = dbDialect; + this.sinkConfig = sinkConfig; + } + + public Exception call() throws Exception { + try { + return doCall(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private Exception doCall() { + RuntimeException error = null; + ExecuteResult exeResult = null; + + if (sinkConfig.isGTIDMode()) { + int retryCount = 0; + final List toExecuteRecords = new ArrayList<>(); + try { + if (!CollectionUtils.isEmpty(failedRecords)) { + // if failedRecords not empty, make it retry + toExecuteRecords.addAll(failedRecords); + } else { + toExecuteRecords.addAll(records); + // add to failed record first, maybe get lob or datasource error + failedRecords.addAll(toExecuteRecords); + } + JdbcTemplate template = dbDialect.getJdbcTemplate(); + String sourceGtid = context.getGtid(); + if (StringUtils.isNotEmpty(sourceGtid) && !sinkConfig.isMariaDB()) { + String setMySQLGtid = "SET @@session.gtid_next = '" + sourceGtid + "';"; + template.execute(setMySQLGtid); + } else if (StringUtils.isNotEmpty(sourceGtid) && sinkConfig.isMariaDB()) { + throw new RuntimeException("unsupport gtid mode for mariaDB"); + } else { + log.error("gtid is empty in gtid mode"); + throw new RuntimeException("gtid is empty in gtid mode"); + } + + final LobCreator lobCreator = dbDialect.getLobHandler().getLobCreator(); + int affect = (Integer) dbDialect.getTransactionTemplate().execute((TransactionCallback) status -> { + try { + failedRecords.clear(); + processedRecords.clear(); + int affect1 = 0; + for (CanalConnectRecord record : toExecuteRecords) { + int affects = template.update(record.getSql(), new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + doPreparedStatement(ps, dbDialect, lobCreator, record); + } + }); + affect1 = affect1 + affects; + processStat(record, affects, false); + } + return affect1; + } catch (Exception e) { + // rollback + status.setRollbackOnly(); + throw new RuntimeException("Failed to executed", e); + } finally { + lobCreator.close(); + } + }); + + // reset gtid + if (sinkConfig.isMariaDB()) { + throw new RuntimeException("unsupport gtid mode for mariaDB"); + } else { + String resetMySQLGtid = "SET @@session.gtid_next = 'AUTOMATIC';"; + dbDialect.getJdbcTemplate().execute(resetMySQLGtid); + } + + error = null; + exeResult = ExecuteResult.SUCCESS; + } catch (DeadlockLoserDataAccessException ex) { + error = new RuntimeException(ExceptionUtils.getFullStackTrace(ex)); + exeResult = ExecuteResult.RETRY; + } catch (Throwable ex) { + error = new RuntimeException(ExceptionUtils.getFullStackTrace(ex)); + exeResult = ExecuteResult.ERROR; + } + + if (ExecuteResult.SUCCESS == exeResult) { + allFailedRecords.addAll(failedRecords); + allProcessedRecords.addAll(processedRecords); + failedRecords.clear(); + processedRecords.clear(); + } else if (ExecuteResult.RETRY == exeResult) { + retryCount = retryCount + 1; + processedRecords.clear(); + failedRecords.clear(); + failedRecords.addAll(toExecuteRecords); + int retry = 3; + if (retryCount >= retry) { + processFailedDatas(toExecuteRecords.size()); + throw new RuntimeException(String.format("execute retry %s times failed", retryCount), error); + } else { + try { + int retryWait = 3000; + int wait = retryCount * retryWait; + wait = Math.max(wait, retryWait); + Thread.sleep(wait); + } catch (InterruptedException ex) { + Thread.interrupted(); + processFailedDatas(toExecuteRecords.size()); + throw new RuntimeException(ex); + } + } + } else { + processedRecords.clear(); + failedRecords.clear(); + failedRecords.addAll(toExecuteRecords); + processFailedDatas(toExecuteRecords.size()); + throw error; + } + } else { + int index = 0; + while (index < records.size()) { + final List toExecuteRecords = new ArrayList<>(); + if (useBatch && canBatch) { + int end = Math.min(index + batchSize, records.size()); + toExecuteRecords.addAll(records.subList(index, end)); + index = end; + } else { + toExecuteRecords.add(records.get(index)); + index = index + 1; + } + + int retryCount = 0; + while (true) { + try { + if (!CollectionUtils.isEmpty(failedRecords)) { + toExecuteRecords.clear(); + toExecuteRecords.addAll(failedRecords); + } else { + failedRecords.addAll(toExecuteRecords); + } + + final LobCreator lobCreator = dbDialect.getLobHandler().getLobCreator(); + if (useBatch && canBatch) { + JdbcTemplate template = dbDialect.getJdbcTemplate(); + final String sql = toExecuteRecords.get(0).getSql(); + + int[] affects = new int[toExecuteRecords.size()]; + + affects = (int[]) dbDialect.getTransactionTemplate().execute((TransactionCallback) status -> { + try { + failedRecords.clear(); + processedRecords.clear(); + int[] affects1 = template.batchUpdate(sql, new BatchPreparedStatementSetter() { + + public void setValues(PreparedStatement ps, int idx) throws SQLException { + doPreparedStatement(ps, dbDialect, lobCreator, toExecuteRecords.get(idx)); + } + + public int getBatchSize() { + return toExecuteRecords.size(); + } + }); + return affects1; + } catch (Exception e) { + // rollback + status.setRollbackOnly(); + throw new RuntimeException("Failed to execute batch ", e); + } finally { + lobCreator.close(); + } + }); + + for (int i = 0; i < toExecuteRecords.size(); i++) { + assert affects != null; + processStat(toExecuteRecords.get(i), affects[i], true); + } + } else { + final CanalConnectRecord record = toExecuteRecords.get(0); + JdbcTemplate template = dbDialect.getJdbcTemplate(); + int affect = 0; + affect = (Integer) dbDialect.getTransactionTemplate().execute((TransactionCallback) status -> { + try { + failedRecords.clear(); + processedRecords.clear(); + int affect1 = template.update(record.getSql(), new PreparedStatementSetter() { + + public void setValues(PreparedStatement ps) throws SQLException { + doPreparedStatement(ps, dbDialect, lobCreator, record); + } + }); + return affect1; + } catch (Exception e) { + // rollback + status.setRollbackOnly(); + throw new RuntimeException("Failed to executed", e); + } finally { + lobCreator.close(); + } + }); + processStat(record, affect, false); + } + + error = null; + exeResult = ExecuteResult.SUCCESS; + } catch (DeadlockLoserDataAccessException ex) { + error = new RuntimeException(ExceptionUtils.getFullStackTrace(ex)); + exeResult = ExecuteResult.RETRY; + } catch (Throwable ex) { + error = new RuntimeException(ExceptionUtils.getFullStackTrace(ex)); + exeResult = ExecuteResult.ERROR; + } + + if (ExecuteResult.SUCCESS == exeResult) { + allFailedRecords.addAll(failedRecords); + allProcessedRecords.addAll(processedRecords); + failedRecords.clear(); + processedRecords.clear(); + break; // do next eventData + } else if (ExecuteResult.RETRY == exeResult) { + retryCount = retryCount + 1; + processedRecords.clear(); + failedRecords.clear(); + failedRecords.addAll(toExecuteRecords); + int retry = 3; + if (retryCount >= retry) { + processFailedDatas(index); + throw new RuntimeException(String.format("execute retry %s times failed", retryCount), error); + } else { + try { + int retryWait = 3000; + int wait = retryCount * retryWait; + wait = Math.max(wait, retryWait); + Thread.sleep(wait); + } catch (InterruptedException ex) { + Thread.interrupted(); + processFailedDatas(index); + throw new RuntimeException(ex); + } + } + } else { + processedRecords.clear(); + failedRecords.clear(); + failedRecords.addAll(toExecuteRecords); + processFailedDatas(index); + throw error; + } + } + } + } + + context.getFailedRecords().addAll(allFailedRecords); + context.getProcessedRecords().addAll(allProcessedRecords); + return null; + } + + private void doPreparedStatement(PreparedStatement ps, DbDialect dbDialect, LobCreator lobCreator, + CanalConnectRecord record) throws SQLException { + EventType type = record.getEventType(); + List columns = new ArrayList(); + if (type.isInsert()) { + columns.addAll(record.getColumns()); + columns.addAll(record.getKeys()); + } else if (type.isDelete()) { + columns.addAll(record.getKeys()); + } else if (type.isUpdate()) { + boolean existOldKeys = !CollectionUtils.isEmpty(record.getOldKeys()); + columns.addAll(record.getUpdatedColumns()); + columns.addAll(record.getKeys()); + if (existOldKeys) { + columns.addAll(record.getOldKeys()); + } + } + + for (int i = 0; i < columns.size(); i++) { + int paramIndex = i + 1; + EventColumn column = columns.get(i); + int sqlType = column.getColumnType(); + + Object param = null; + if (dbDialect instanceof MysqlDialect + && (sqlType == Types.TIME || sqlType == Types.TIMESTAMP || sqlType == Types.DATE)) { + param = column.getColumnValue(); + } else { + param = SqlUtils.stringToSqlValue(column.getColumnValue(), + sqlType, + false, + dbDialect.isEmptyStringNulled()); + } + + try { + switch (sqlType) { + case Types.CLOB: + lobCreator.setClobAsString(ps, paramIndex, (String) param); + break; + + case Types.BLOB: + lobCreator.setBlobAsBytes(ps, paramIndex, (byte[]) param); + break; + case Types.TIME: + case Types.TIMESTAMP: + case Types.DATE: + if (dbDialect instanceof MysqlDialect) { + ps.setObject(paramIndex, param); + } else { + StatementCreatorUtils.setParameterValue(ps, paramIndex, sqlType, null, param); + } + break; + case Types.BIT: + if (dbDialect instanceof MysqlDialect) { + StatementCreatorUtils.setParameterValue(ps, paramIndex, Types.DECIMAL, null, param); + } else { + StatementCreatorUtils.setParameterValue(ps, paramIndex, sqlType, null, param); + } + break; + default: + StatementCreatorUtils.setParameterValue(ps, paramIndex, sqlType, null, param); + break; + } + } catch (SQLException ex) { + log.error("## SetParam error , [pairId={}, sqltype={}, value={}]", + record.getPairId(), sqlType, param); + throw ex; + } + } + } + + private void processStat(CanalConnectRecord record, int affect, boolean batch) { + if (batch && (affect < 1 && affect != Statement.SUCCESS_NO_INFO)) { + failedRecords.add(record); + } else if (!batch && affect < 1) { + failedRecords.add(record); + } else { + processedRecords.add(record); + // this.processStat(record, context); + } + } + + private void processFailedDatas(int index) { + allFailedRecords.addAll(failedRecords); + context.getFailedRecords().addAll(allFailedRecords); + for (; index < records.size(); index++) { + context.getFailedRecords().add(records.get(index)); + } + allProcessedRecords.addAll(processedRecords); + context.getProcessedRecords().addAll(allProcessedRecords); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/EntryParser.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/EntryParser.java new file mode 100644 index 0000000000..d7388c628b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/EntryParser.java @@ -0,0 +1,349 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source; + +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceIncrementConfig; +import org.apache.eventmesh.connector.canal.CanalConnectRecord; +import org.apache.eventmesh.connector.canal.model.EventColumn; +import org.apache.eventmesh.connector.canal.model.EventColumnIndexComparable; +import org.apache.eventmesh.connector.canal.model.EventType; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.util.CollectionUtils; + +import com.alibaba.otter.canal.protocol.CanalEntry; +import com.alibaba.otter.canal.protocol.CanalEntry.Column; +import com.alibaba.otter.canal.protocol.CanalEntry.Entry; +import com.alibaba.otter.canal.protocol.CanalEntry.RowChange; +import com.alibaba.otter.canal.protocol.CanalEntry.RowData; + +import lombok.extern.slf4j.Slf4j; + +/** + * data object parse + */ +@Slf4j +public class EntryParser { + + public static Map> parse(CanalSourceIncrementConfig sourceConfig, List datas, + RdbTableMgr tables) { + List recordList = new ArrayList<>(); + List transactionDataBuffer = new ArrayList<>(); + // need check weather the entry is loopback + boolean needSync; + Map> recordMap = new HashMap<>(); + try { + for (Entry entry : datas) { + switch (entry.getEntryType()) { + case ROWDATA: + RowChange rowChange = RowChange.parseFrom(entry.getStoreValue()); + // don't support gtid for mariadb + if (sourceConfig.getServerUUID() != null && sourceConfig.isGTIDMode() && !sourceConfig.isMariaDB()) { + if (checkGtidForEntry(entry, sourceConfig)) { + transactionDataBuffer.add(entry); + } + } else { + // if not gtid mode, need check weather the entry is loopback by specified column value + needSync = checkNeedSync(sourceConfig, rowChange); + if (needSync) { + log.debug("entry evenType {}|rowChange {}", rowChange.getEventType(), rowChange); + transactionDataBuffer.add(entry); + } + } + break; + case TRANSACTIONEND: + parseRecordListWithEntryBuffer(sourceConfig, recordList, transactionDataBuffer, tables); + if (!recordList.isEmpty()) { + List transactionEndList = new ArrayList<>(recordList); + recordMap.put(entry.getHeader().getLogfileOffset(), transactionEndList); + } + recordList.clear(); + transactionDataBuffer.clear(); + break; + default: + break; + } + } + + // add last data in transactionDataBuffer, in case no TRANSACTIONEND + parseRecordListWithEntryBuffer(sourceConfig, recordList, transactionDataBuffer, tables); + if (!recordList.isEmpty()) { + List transactionEndList = new ArrayList<>(recordList); + CanalConnectRecord lastCanalConnectRecord = transactionEndList.get(transactionEndList.size() - 1); + recordMap.put(lastCanalConnectRecord.getBinLogOffset(), transactionEndList); + } + recordList.clear(); + transactionDataBuffer.clear(); + + } catch (Exception e) { + throw new RuntimeException(e); + } + return recordMap; + } + + private static boolean checkGtidForEntry(Entry entry, CanalSourceIncrementConfig sourceConfig) { + String currentGtid = entry.getHeader().getPropsList().get(0).getValue(); + return currentGtid.contains(sourceConfig.getServerUUID()); + } + + private static void parseRecordListWithEntryBuffer(CanalSourceIncrementConfig sourceConfig, + List recordList, + List transactionDataBuffer, RdbTableMgr tables) { + for (Entry bufferEntry : transactionDataBuffer) { + List recordParsedList = internParse(sourceConfig, bufferEntry, tables); + if (CollectionUtils.isEmpty(recordParsedList)) { + continue; + } + long totalSize = bufferEntry.getHeader().getEventLength(); + long eachSize = totalSize / recordParsedList.size(); + for (CanalConnectRecord record : recordParsedList) { + if (record == null) { + continue; + } + record.setSize(eachSize); + recordList.add(record); + } + } + } + + private static boolean checkNeedSync(CanalSourceIncrementConfig sourceConfig, RowChange rowChange) { + Column markedColumn = null; + CanalEntry.EventType eventType = rowChange.getEventType(); + if (StringUtils.isEmpty(sourceConfig.getNeedSyncMarkTableColumnName())) { + return true; + } + if (eventType.equals(CanalEntry.EventType.DELETE)) { + markedColumn = getColumnIgnoreCase(rowChange.getRowDatas(0).getBeforeColumnsList(), + sourceConfig.getNeedSyncMarkTableColumnName()); + } else if (eventType.equals(CanalEntry.EventType.INSERT) || eventType.equals(CanalEntry.EventType.UPDATE)) { + markedColumn = getColumnIgnoreCase(rowChange.getRowDatas(0).getAfterColumnsList(), + sourceConfig.getNeedSyncMarkTableColumnName()); + } + if (markedColumn != null) { + return StringUtils.equalsIgnoreCase(markedColumn.getValue(), + sourceConfig.getNeedSyncMarkTableColumnValue()); + } + return false; + } + + private static Column getColumnIgnoreCase(List columns, String columName) { + for (Column column : columns) { + if (column.getName().equalsIgnoreCase(columName)) { + return column; + } + } + return null; + } + + private static List internParse(CanalSourceIncrementConfig sourceConfig, Entry entry, + RdbTableMgr tableMgr) { + String schemaName = entry.getHeader().getSchemaName(); + String tableName = entry.getHeader().getTableName(); + if (tableMgr.getTable(schemaName, tableName) == null) { + return null; + } + + RowChange rowChange = null; + try { + rowChange = RowChange.parseFrom(entry.getStoreValue()); + } catch (Exception e) { + throw new RuntimeException("parser of canal-event has an error , data:" + entry.toString(), e); + } + + if (rowChange == null) { + return null; + } + + EventType eventType = EventType.valueOf(rowChange.getEventType().name()); + + if (eventType.isQuery()) { + return null; + } + + if (eventType.isDdl()) { + log.warn("unsupported ddl event type: {}", eventType); + return null; + } + + List recordList = new ArrayList<>(); + for (RowData rowData : rowChange.getRowDatasList()) { + CanalConnectRecord record = internParse(sourceConfig, entry, rowChange, rowData); + recordList.add(record); + } + + return recordList; + } + + private static CanalConnectRecord internParse(CanalSourceIncrementConfig canalSourceConfig, Entry entry, + RowChange rowChange, RowData rowData) { + CanalConnectRecord canalConnectRecord = new CanalConnectRecord(); + canalConnectRecord.setTableName(entry.getHeader().getTableName()); + canalConnectRecord.setSchemaName(entry.getHeader().getSchemaName()); + canalConnectRecord.setEventType(EventType.valueOf(rowChange.getEventType().name())); + canalConnectRecord.setExecuteTime(entry.getHeader().getExecuteTime()); + canalConnectRecord.setJournalName(entry.getHeader().getLogfileName()); + canalConnectRecord.setBinLogOffset(entry.getHeader().getLogfileOffset()); + // if enabled gtid mode, gtid not null + if (canalSourceConfig.isGTIDMode()) { + if (canalSourceConfig.isMariaDB()) { + String currentGtid = entry.getHeader().getGtid(); + canalConnectRecord.setGtid(currentGtid); + canalConnectRecord.setCurrentGtid(currentGtid); + } else { + String currentGtid = entry.getHeader().getPropsList().get(0).getValue(); + String gtidRange = replaceGtidRange(entry.getHeader().getGtid(), currentGtid, canalSourceConfig.getServerUUID()); + canalConnectRecord.setGtid(gtidRange); + canalConnectRecord.setCurrentGtid(currentGtid); + } + } + + EventType eventType = canalConnectRecord.getEventType(); + + List beforeColumns = rowData.getBeforeColumnsList(); + List afterColumns = rowData.getAfterColumnsList(); + + boolean isRowMode = canalSourceConfig.getSyncMode().isRow(); + + Map keyColumns = new LinkedHashMap<>(); + Map oldKeyColumns = new LinkedHashMap<>(); + Map notKeyColumns = new LinkedHashMap<>(); + + if (eventType.isInsert()) { + for (Column column : afterColumns) { + if (column.getIsKey()) { + keyColumns.put(column.getName(), copyEventColumn(column, true)); + } else { + notKeyColumns.put(column.getName(), copyEventColumn(column, true)); + } + } + } else if (eventType.isDelete()) { + for (Column column : beforeColumns) { + if (column.getIsKey()) { + keyColumns.put(column.getName(), copyEventColumn(column, true)); + } else { + notKeyColumns.put(column.getName(), copyEventColumn(column, true)); + } + } + } else if (eventType.isUpdate()) { + for (Column column : beforeColumns) { + if (column.getIsKey()) { + oldKeyColumns.put(column.getName(), copyEventColumn(column, true)); + keyColumns.put(column.getName(), copyEventColumn(column, true)); + } else { + if (isRowMode && entry.getHeader().getSourceType() == CanalEntry.Type.ORACLE) { + notKeyColumns.put(column.getName(), copyEventColumn(column, true)); + } + } + } + for (Column column : afterColumns) { + if (column.getIsKey()) { + keyColumns.put(column.getName(), copyEventColumn(column, true)); + } else if (isRowMode || entry.getHeader().getSourceType() == CanalEntry.Type.ORACLE + || column.getUpdated()) { + + boolean isUpdate = true; + if (entry.getHeader().getSourceType() == CanalEntry.Type.MYSQL) { + isUpdate = column.getUpdated(); + } + + notKeyColumns.put(column.getName(), copyEventColumn(column, isUpdate)); + } + } + + if (entry.getHeader().getSourceType() == CanalEntry.Type.ORACLE) { + checkUpdateKeyColumns(oldKeyColumns, keyColumns); + } + } + + List keys = new ArrayList<>(keyColumns.values()); + List oldKeys = new ArrayList<>(oldKeyColumns.values()); + List columns = new ArrayList<>(notKeyColumns.values()); + + keys.sort(new EventColumnIndexComparable()); + oldKeys.sort(new EventColumnIndexComparable()); + columns.sort(new EventColumnIndexComparable()); + if (!keyColumns.isEmpty()) { + canalConnectRecord.setKeys(keys); + if (canalConnectRecord.getEventType().isUpdate() && !oldKeys.equals(keys)) { + canalConnectRecord.setOldKeys(oldKeys); + } + canalConnectRecord.setColumns(columns); + } else { + throw new RuntimeException("this row data has no pks , entry: " + entry + " and rowData: " + + rowData); + } + + return canalConnectRecord; + } + + public static String replaceGtidRange(String gtid, String currentGtid, String serverUUID) { + String[] gtidRangeArray = gtid.split(","); + for (int i = 0; i < gtidRangeArray.length; i++) { + String gtidRange = gtidRangeArray[i]; + if (gtidRange.startsWith(serverUUID)) { + gtidRangeArray[i] = gtidRange.replaceFirst("\\d+$", currentGtid.split(":")[1]); + } + } + return String.join(",", gtidRangeArray); + } + + private static void checkUpdateKeyColumns(Map oldKeyColumns, + Map keyColumns) { + if (oldKeyColumns.isEmpty()) { + return; + } + if (keyColumns.size() > oldKeyColumns.size()) { + return; + } + + if (keyColumns.isEmpty()) { + keyColumns.putAll(oldKeyColumns); + return; + } + + if (oldKeyColumns.size() != keyColumns.size()) { + for (String oldKey : oldKeyColumns.keySet()) { + if (keyColumns.get(oldKey) == null) { + keyColumns.put(oldKey, oldKeyColumns.get(oldKey)); + } + } + } + } + + private static EventColumn copyEventColumn(Column column, boolean isUpdate) { + EventColumn eventColumn = new EventColumn(); + eventColumn.setIndex(column.getIndex()); + eventColumn.setKey(column.getIsKey()); + eventColumn.setNull(column.getIsNull()); + eventColumn.setColumnName(column.getName()); + eventColumn.setColumnValue(column.getValue()); + eventColumn.setUpdate(isUpdate); + eventColumn.setColumnType(column.getSqlType()); + + return eventColumn; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalFullProducer.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalFullProducer.java new file mode 100644 index 0000000000..644b77247d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalFullProducer.java @@ -0,0 +1,443 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.connector; + +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalMySQLType; +import org.apache.eventmesh.common.config.connector.rdb.canal.JobRdbFullPosition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbColumnDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.Constants; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLColumnDef; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordOffset; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordPartition; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.SqlUtils; +import org.apache.eventmesh.connector.canal.source.position.TableFullPosition; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; + +import javax.sql.DataSource; + +import com.google.common.util.concurrent.RateLimiter; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class CanalFullProducer { + private BlockingQueue> queue; + private final DataSource dataSource; + private final MySQLTableDef tableDefinition; + private final TableFullPosition tableFullPosition; + private final JobRdbFullPosition startPosition; + private static final int LIMIT = 2048; + private final int flushSize; + private final AtomicReference choosePrimaryKey = new AtomicReference<>(null); + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter DATE_STAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private AtomicLong scanCount = new AtomicLong(0); + private final RateLimiter pageLimiter; + @Setter + private RateLimiter recordLimiter; + + + public CanalFullProducer(BlockingQueue> queue, DataSource dataSource, + MySQLTableDef tableDefinition, JobRdbFullPosition startPosition, int flushSize, int pagePerSecond) { + this.queue = queue; + this.dataSource = dataSource; + this.tableDefinition = tableDefinition; + this.startPosition = startPosition; + this.tableFullPosition = JsonUtils.parseObject(startPosition.getPrimaryKeyRecords(), TableFullPosition.class); + this.scanCount.set(startPosition.getHandledRecordCount()); + this.flushSize = flushSize; + this.pageLimiter = RateLimiter.create(pagePerSecond); + } + + public void choosePrimaryKey() { + for (RdbColumnDefinition col : tableDefinition.getColumnDefinitions().values()) { + if (tableFullPosition.getCurPrimaryKeyCols().get(col.getName()) != null) { + // random choose the first primary key from the table + choosePrimaryKey.set(col.getName()); + log.info("schema [{}] table [{}] choose primary key [{}]", tableDefinition.getSchemaName(), tableDefinition.getTableName(), + col.getName()); + return; + } + } + throw new EventMeshException("illegal: can't pick any primary key"); + } + + + public void start(AtomicBoolean flag) { + choosePrimaryKey(); + // used to page query + boolean isFirstSelect = true; + List> rows = new LinkedList<>(); + while (flag.get()) { + // acquire a permit before each database read + pageLimiter.acquire(); + + String scanSql = generateScanSql(isFirstSelect); + log.info("scan sql is [{}] , cur position [{}]", scanSql, JsonUtils.toJSONString(tableFullPosition.getCurPrimaryKeyCols())); + + try (Connection connection = dataSource.getConnection(); PreparedStatement statement = + connection.prepareStatement(scanSql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) { + statement.setFetchSize(Integer.MIN_VALUE); + setPrepareStatementValue(statement); + try (ResultSet resultSet = statement.executeQuery()) { + Map lastCol = null; + while (flag.get() && resultSet.next()) { + Map columnValues = new LinkedHashMap<>(); + for (Map.Entry col : + tableDefinition.getColumnDefinitions().entrySet()) { + columnValues.put(col.getKey(), readColumn(resultSet, col.getKey(), + col.getValue().getType())); + } + lastCol = columnValues; + rows.add(lastCol); + this.scanCount.incrementAndGet(); + if (rows.size() < flushSize) { + continue; + } + refreshPosition(lastCol); + // may be not reach + commitConnectRecord(rows, false, this.scanCount.get(), startPosition); + rows = new LinkedList<>(); + } + + if (lastCol == null || checkIsScanFinish(lastCol)) { + log.info("full scan db [{}] table [{}] finish", tableDefinition.getSchemaName(), + tableDefinition.getTableName()); + // commit the last record if rows.size() < flushSize + commitConnectRecord(rows, true, this.scanCount.get(), startPosition); + return; + } + refreshPosition(lastCol); + } catch (InterruptedException ignore) { + log.info("full scan db [{}] table [{}] interrupted", tableDefinition.getSchemaName(), + tableDefinition.getTableName()); + Thread.currentThread().interrupt(); + return; + } + } catch (SQLException e) { + log.error("full source process schema [{}] table [{}] catch SQLException fail", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), e); + LockSupport.parkNanos(3000 * 1000L); + } catch (Exception e) { + log.error("full source process schema [{}] table [{}] catch unknown exception", tableDefinition.getSchemaName(), + tableDefinition.getTableName(), e); + return; + } + if (isFirstSelect) { + isFirstSelect = false; + } + } + } + + private void commitConnectRecord(List> rows, boolean isFinished, long migratedCount, JobRdbFullPosition position) + throws InterruptedException { + if (rows == null || rows.isEmpty()) { + return; + } + JobRdbFullPosition jobRdbFullPosition = new JobRdbFullPosition(); + jobRdbFullPosition.setPrimaryKeyRecords(JsonUtils.toJSONString(tableFullPosition)); + jobRdbFullPosition.setTableName(tableDefinition.getTableName()); + jobRdbFullPosition.setSchema(tableDefinition.getSchemaName()); + jobRdbFullPosition.setFinished(isFinished); + jobRdbFullPosition.setHandledRecordCount(migratedCount); + jobRdbFullPosition.setMaxCount(position.getMaxCount()); + if (isFinished) { + jobRdbFullPosition.setPercent(new BigDecimal("100")); + } else { + double num = 100.0d * ((double) migratedCount) * 1.0d / (double) position.getMaxCount(); + String number = Double.toString(num); + BigDecimal percent = new BigDecimal(number).setScale(2, RoundingMode.HALF_UP); + jobRdbFullPosition.setPercent(percent); + } + CanalFullRecordOffset offset = new CanalFullRecordOffset(); + offset.setPosition(jobRdbFullPosition); + CanalFullRecordPartition partition = new CanalFullRecordPartition(); + Map dataMap = new HashMap<>(); + dataMap.put("data", JsonUtils.toJSONString(rows)); + dataMap.put("partition", JsonUtils.toJSONString(partition)); + dataMap.put("offset", JsonUtils.toJSONString(offset)); + ArrayList records = new ArrayList<>(); + records.add( + new ConnectRecord(partition, offset, System.currentTimeMillis(), JsonUtils.toJSONString(dataMap).getBytes(StandardCharsets.UTF_8))); + // global limiter, 100 records per second default + recordLimiter.acquire(); + queue.put(records); + } + + private boolean checkIsScanFinish(Map lastCol) { + Object lastPrimaryValue = lastCol.get(choosePrimaryKey.get()); + Object maxPrimaryValue = tableFullPosition.getMaxPrimaryKeyCols().get(choosePrimaryKey.get()); + if (lastPrimaryValue instanceof Number) { + BigDecimal last = new BigDecimal(String.valueOf(lastPrimaryValue)); + BigDecimal max = + new BigDecimal(String.valueOf(maxPrimaryValue)); + return last.compareTo(max) > 0; + } + if (lastPrimaryValue instanceof Comparable) { + return ((Comparable) lastPrimaryValue).compareTo(maxPrimaryValue) > 0; + } + return false; + } + + public Object readColumn(ResultSet rs, String colName, CanalMySQLType colType) throws Exception { + switch (colType) { + case TINYINT: + case SMALLINT: + case MEDIUMINT: + case INT: + Long valueLong = rs.getLong(colName); + if (rs.wasNull()) { + return null; + } + if (valueLong.compareTo((long) Integer.MAX_VALUE) > 0) { + return valueLong; + } + return valueLong.intValue(); + case BIGINT: + String v = rs.getString(colName); + if (v == null) { + return null; + } + BigDecimal valueBigInt = new BigDecimal(v); + if (valueBigInt.compareTo(BigDecimal.valueOf(Long.MAX_VALUE)) > 0) { + return valueBigInt; + } + return valueBigInt.longValue(); + case FLOAT: + case DOUBLE: + case DECIMAL: + return rs.getBigDecimal(colName); + case DATE: + return rs.getObject(colName, LocalDate.class); + case TIME: + return rs.getObject(colName, LocalTime.class); + case DATETIME: + case TIMESTAMP: + return rs.getObject(colName, LocalDateTime.class); + case YEAR: + int year = rs.getInt(colName); + if (rs.wasNull()) { + return null; + } + return year; + case CHAR: + case VARCHAR: + case TINYTEXT: + case TEXT: + case MEDIUMTEXT: + case LONGTEXT: + case ENUM: + case SET: + case JSON: + return rs.getString(colName); + case BIT: + case BINARY: + case VARBINARY: + case TINYBLOB: + case BLOB: + case MEDIUMBLOB: + case LONGBLOB: + return rs.getBytes(colName); + case GEOMETRY: + case GEOMETRY_COLLECTION: + case GEOM_COLLECTION: + case POINT: + case LINESTRING: + case POLYGON: + case MULTIPOINT: + case MULTILINESTRING: + case MULTIPOLYGON: + byte[] geo = rs.getBytes(colName); + if (geo == null) { + return null; + } + return SqlUtils.toGeometry(geo); + default: + return rs.getObject(colName); + } + } + + + private void refreshPosition(Map lastCol) { + Map nextPosition = new LinkedHashMap<>(); + for (Map.Entry entry : tableFullPosition.getCurPrimaryKeyCols().entrySet()) { + nextPosition.put(entry.getKey(), lastCol.get(entry.getKey())); + } + tableFullPosition.setCurPrimaryKeyCols(nextPosition); + } + + private void setPrepareStatementValue(PreparedStatement statement) throws SQLException { + String colName = choosePrimaryKey.get(); + if (colName == null) { + return; + } + RdbColumnDefinition columnDefinition = tableDefinition.getColumnDefinitions().get(colName); + Object value = tableFullPosition.getCurPrimaryKeyCols().get(colName); + String str; + switch (columnDefinition.getJdbcType()) { + case BIT: + case TINYINT: + case SMALLINT: + case INTEGER: + case BIGINT: + statement.setBigDecimal(1, new BigDecimal(String.valueOf(value))); + break; + case DECIMAL: + case FLOAT: + case DOUBLE: + case NUMERIC: + statement.setDouble(1, new BigDecimal(String.valueOf(value)).doubleValue()); + break; + case CHAR: + case VARCHAR: + case LONGNVARCHAR: + case NCHAR: + case NVARCHAR: + case LONGVARCHAR: + case CLOB: + case NCLOB: + statement.setString(1, String.valueOf(value)); + break; + case BLOB: + case VARBINARY: + case BINARY: + str = String.valueOf(value); + String hexStr = str; + if (str.startsWith("0x")) { + hexStr = str.substring(str.indexOf("0x")); + } + byte[] bytes = SqlUtils.hex2bytes(hexStr); + statement.setBytes(1, bytes); + break; + case DATE: + Instant d; + if (value instanceof Long) { + Long val = (Long) value; + d = Instant.ofEpochMilli(val); + str = d.atZone(ZoneId.systemDefault()).toLocalDateTime().format(DATE_FORMATTER); + } else if (value instanceof Integer) { + Integer val = (Integer) value; + d = Instant.ofEpochMilli((long) val); + str = d.atZone(ZoneId.systemDefault()).toLocalDateTime().format(DATE_FORMATTER); + } else if (value instanceof String) { + str = (String) value; + } else { + if (!(value instanceof LocalDate)) { + throw new IllegalArgumentException("unsupported date class type:" + value.getClass().getSimpleName()); + } + str = ((LocalDate) value).format(DATE_FORMATTER); + } + statement.setString(1, str); + break; + case TIMESTAMP: + if (value instanceof String) { + str = (String) value; + } else { + if (!(value instanceof LocalDateTime)) { + throw new IllegalArgumentException("unsupported timestamp class type:" + value.getClass().getSimpleName()); + } + str = ((LocalDateTime) value).format(DATE_STAMP_FORMATTER); + } + statement.setString(1, str); + break; + default: + throw new EventMeshException(String.format("not support the primary key type [%s]", value.getClass())); + } + } + + + private void generateQueryColumnsSql(StringBuilder builder, Collection rdbColDefs) { + if (rdbColDefs == null || rdbColDefs.isEmpty()) { + builder.append("*"); + return; + } + boolean first = true; + for (RdbColumnDefinition colDef : rdbColDefs) { + if (first) { + first = false; + } else { + builder.append(","); + } + builder.append(Constants.MySQLQuot); + builder.append(colDef.getName()); + builder.append(Constants.MySQLQuot); + } + } + + private String generateScanSql(boolean isFirst) { + StringBuilder builder = new StringBuilder(); + builder.append("select "); + generateQueryColumnsSql(builder, tableDefinition.getColumnDefinitions().values()); + builder.append(" from "); + builder.append(Constants.MySQLQuot); + builder.append(tableDefinition.getSchemaName()); + builder.append(Constants.MySQLQuot); + builder.append("."); + builder.append(Constants.MySQLQuot); + builder.append(tableDefinition.getTableName()); + builder.append(Constants.MySQLQuot); + buildWhereSql(builder, isFirst); + builder.append(" limit " + LIMIT); + return builder.toString(); + } + + private void buildWhereSql(StringBuilder builder, boolean isEquals) { + builder.append(" where ") + .append(Constants.MySQLQuot) + .append(choosePrimaryKey.get()) + .append(Constants.MySQLQuot); + if (isEquals) { + builder.append(" >= ? "); + } else { + builder.append(" > ? "); + } + builder.append(" order by ").append(Constants.MySQLQuot).append(choosePrimaryKey.get()).append(Constants.MySQLQuot) + .append(" asc "); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceCheckConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceCheckConnector.java new file mode 100644 index 0000000000..4d3e569dcd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceCheckConnector.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.connector; + +import org.apache.eventmesh.common.AbstractComponent; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceCheckConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.JobRdbFullPosition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.position.CanalCheckPositionMgr; +import org.apache.eventmesh.connector.canal.source.table.RdbSimpleTable; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.common.util.concurrent.RateLimiter; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSourceCheckConnector extends AbstractComponent implements Source, ConnectorCreateService { + + private CanalSourceCheckConfig config; + private CanalCheckPositionMgr positionMgr; + private RdbTableMgr tableMgr; + private ThreadPoolExecutor executor; + private final ScheduledExecutorService scheduledThreadPoolExecutor = Executors.newSingleThreadScheduledExecutor(); + private final BlockingQueue> queue = new LinkedBlockingQueue<>(10000); + private final AtomicBoolean flag = new AtomicBoolean(true); + private RateLimiter globalLimiter; + + @Override + protected void run() throws Exception { + scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> { + try { + this.tableMgr.start(); + } catch (Exception e) { + log.error("start tableMgr fail", e); + throw new RuntimeException(e); + } + try { + this.positionMgr.start(); + } catch (Exception e) { + throw new RuntimeException(e); + } + // if (positionMgr.isFinished()) { + // log.info("connector [{}] has finished the job", config.getSourceConnectorConfig().getConnectorName()); + // return; + // } + executor = new ThreadPoolExecutor(config.getParallel(), config.getParallel(), 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new EventMeshThreadFactory("canal-source-check")); + List producers = new LinkedList<>(); + if (config.getSourceConnectorConfig().getDatabases() != null) { + for (RdbDBDefinition db : config.getSourceConnectorConfig().getDatabases()) { + for (RdbTableDefinition table : db.getTables()) { + try { + log.info("it will create producer of db [{}] table [{}]", db.getSchemaName(), table.getTableName()); + RdbSimpleTable simpleTable = new RdbSimpleTable(db.getSchemaName(), table.getTableName()); + JobRdbFullPosition position = positionMgr.getPosition(simpleTable); + if (position == null) { + throw new EventMeshException(String.format("db [%s] table [%s] have none position info", + db.getSchemaName(), table.getTableName())); + } + RdbTableDefinition tableDefinition = tableMgr.getTable(simpleTable); + if (tableDefinition == null) { + throw new EventMeshException(String.format("db [%s] table [%s] have none table definition info", + db.getSchemaName(), table.getTableName())); + } + CanalFullProducer producer = + new CanalFullProducer(queue, DatabaseConnection.sourceDataSource, (MySQLTableDef) tableDefinition, + position, config.getFlushSize(), config.getPagePerSecond()); + producer.setRecordLimiter(globalLimiter); + producers.add(producer); + } catch (Exception e) { + log.error("create schema [{}] table [{}] producers fail", db.getSchemaName(), + table.getTableName(), e); + } + } + } + } + producers.forEach(p -> executor.execute(() -> p.start(flag))); + + }, 0, config.getExecutePeriod(), TimeUnit.SECONDS); + } + + @Override + protected void shutdown() throws Exception { + flag.set(false); + if (!executor.isShutdown()) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + log.warn("wait thread pool shutdown timeout, it will shutdown now"); + executor.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.info("shutdown thread pool fail"); + } + } + if (!scheduledThreadPoolExecutor.isShutdown()) { + scheduledThreadPoolExecutor.shutdown(); + try { + if (!scheduledThreadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS)) { + log.warn("wait scheduledThreadPoolExecutor shutdown timeout, it will shutdown now"); + scheduledThreadPoolExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.info("shutdown scheduledThreadPoolExecutor fail"); + } + } + if (DatabaseConnection.sourceDataSource != null) { + DatabaseConnection.sourceDataSource.close(); + log.info("data source has been closed"); + } + } + + @Override + public Source create() { + return new CanalSourceCheckConnector(); + } + + @Override + public Class configClass() { + return CanalSourceCheckConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.config = (CanalSourceCheckConfig) config; + init(); + } + + private void init() { + DatabaseConnection.sourceConfig = this.config.getSourceConnectorConfig(); + DatabaseConnection.initSourceConnection(); + this.tableMgr = new RdbTableMgr(config.getSourceConnectorConfig(), DatabaseConnection.sourceDataSource); + this.positionMgr = new CanalCheckPositionMgr(config, tableMgr); + this.globalLimiter = RateLimiter.create(config.getRecordPerSecond()); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + CanalSourceConfig canalSourceConfig = (CanalSourceConfig) sourceConnectorContext.getSourceConfig(); + this.config = ConfigUtil.parse(canalSourceConfig.getSourceConfig(), CanalSourceCheckConfig.class); + init(); + } + + @Override + public void commit(ConnectRecord record) { + // nothing + } + + @Override + public String name() { + return this.config.getSourceConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public List poll() { + while (flag.get()) { + try { + List records = queue.poll(5, TimeUnit.SECONDS); + if (records == null || records.isEmpty()) { + continue; + } + return records; + } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + log.info("[{}] thread interrupted", this.getClass()); + return null; + } + } + log.info("[{}] life flag is stop, so return null", this.getClass()); + return null; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceConnector.java new file mode 100644 index 0000000000..e24301ae07 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceConnector.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceConfig; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSourceConnector implements Source, ConnectorCreateService { + + private CanalSourceConfig sourceConfig; + + private Source source; + + @Override + public Class configClass() { + return CanalSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for canal source connector + this.sourceConfig = (CanalSourceConfig) config; + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + if (sourceConnectorContext.getJobType().equals(JobType.FULL)) { + this.source = new CanalSourceFullConnector(); + } else if (sourceConnectorContext.getJobType().equals(JobType.INCREASE)) { + this.source = new CanalSourceIncrementConnector(); + } else if (sourceConnectorContext.getJobType().equals(JobType.CHECK)) { + this.source = new CanalSourceCheckConnector(); + } else { + throw new RuntimeException("unsupported job type " + sourceConnectorContext.getJobType()); + } + this.source.init(sourceConnectorContext); + } + + + @Override + public void start() throws Exception { + this.source.start(); + } + + + @Override + public void commit(ConnectRecord record) { + this.source.commit(record); + } + + @Override + public String name() { + return this.source.name(); + } + + @Override + public void onException(ConnectRecord record) { + this.source.onException(record); + } + + @Override + public void stop() throws Exception { + this.source.stop(); + } + + @Override + public List poll() { + return this.source.poll(); + } + + @Override + public Source create() { + return new CanalSourceConnector(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceFullConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceFullConnector.java new file mode 100644 index 0000000000..df28342c39 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceFullConnector.java @@ -0,0 +1,187 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.connector; + +import org.apache.eventmesh.common.AbstractComponent; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceFullConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.JobRdbFullPosition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.position.CanalFullPositionMgr; +import org.apache.eventmesh.connector.canal.source.table.RdbSimpleTable; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.common.util.concurrent.RateLimiter; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSourceFullConnector extends AbstractComponent implements Source { + + private CanalSourceFullConfig config; + private CanalFullPositionMgr positionMgr; + private RdbTableMgr tableMgr; + private ThreadPoolExecutor executor; + private final BlockingQueue> queue = new LinkedBlockingQueue<>(10000); + private final AtomicBoolean flag = new AtomicBoolean(true); + private RateLimiter globalLimiter; + + @Override + protected void run() throws Exception { + this.tableMgr.start(); + this.positionMgr.start(); + if (positionMgr.isFinished()) { + log.info("connector [{}] has finished the job", config.getSourceConnectorConfig().getConnectorName()); + return; + } + executor = new ThreadPoolExecutor(config.getParallel(), config.getParallel(), 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new EventMeshThreadFactory("canal-source-full")); + List producers = new LinkedList<>(); + if (config.getSourceConnectorConfig().getDatabases() != null) { + for (RdbDBDefinition db : config.getSourceConnectorConfig().getDatabases()) { + for (RdbTableDefinition table : db.getTables()) { + try { + log.info("it will create producer of db [{}] table [{}]", db.getSchemaName(), table.getTableName()); + RdbSimpleTable simpleTable = new RdbSimpleTable(db.getSchemaName(), table.getTableName()); + JobRdbFullPosition position = positionMgr.getPosition(simpleTable); + if (position == null) { + throw new EventMeshException(String.format("db [%s] table [%s] have none position info", + db.getSchemaName(), table.getTableName())); + } + RdbTableDefinition tableDefinition = tableMgr.getTable(simpleTable); + if (tableDefinition == null) { + throw new EventMeshException(String.format("db [%s] table [%s] have none table definition info", + db.getSchemaName(), table.getTableName())); + } + CanalFullProducer producer = + new CanalFullProducer(queue, DatabaseConnection.sourceDataSource, (MySQLTableDef) tableDefinition, + position, config.getFlushSize(), config.getPagePerSecond()); + producer.setRecordLimiter(globalLimiter); + producers.add(producer); + } catch (Exception e) { + log.error("create schema [{}] table [{}] producers fail", db.getSchemaName(), + table.getTableName(), e); + } + } + } + } + producers.forEach(p -> executor.execute(() -> p.start(flag))); + } + + @Override + protected void shutdown() throws Exception { + flag.set(false); + if (!executor.isShutdown()) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + log.warn("wait thread pool shutdown timeout, it will shutdown now"); + executor.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.info("shutdown thread pool fail"); + } + } + if (DatabaseConnection.sourceDataSource != null) { + DatabaseConnection.sourceDataSource.close(); + log.info("data source has been closed"); + } + } + + @Override + public Class configClass() { + return CanalSourceFullConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.config = (CanalSourceFullConfig) config; + init(); + } + + private void init() { + DatabaseConnection.sourceConfig = this.config.getSourceConnectorConfig(); + DatabaseConnection.initSourceConnection(); + this.tableMgr = new RdbTableMgr(config.getSourceConnectorConfig(), DatabaseConnection.sourceDataSource); + this.positionMgr = new CanalFullPositionMgr(config, tableMgr); + this.globalLimiter = RateLimiter.create(config.getRecordPerSecond()); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + CanalSourceConfig canalSourceConfig = (CanalSourceConfig) sourceConnectorContext.getSourceConfig(); + this.config = ConfigUtil.parse(canalSourceConfig.getSourceConfig(), CanalSourceFullConfig.class); + init(); + } + + @Override + public void commit(ConnectRecord record) { + // nothing + } + + @Override + public String name() { + return this.config.getSourceConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public List poll() { + while (flag.get()) { + try { + List records = queue.poll(2, TimeUnit.SECONDS); + if (records == null || records.isEmpty()) { + continue; + } + return records; + } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + log.info("[{}] thread interrupted", this.getClass()); + return null; + } + } + log.info("[{}] life flag is stop, so return null", this.getClass()); + return null; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceIncrementConnector.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceIncrementConnector.java new file mode 100644 index 0000000000..c6e7603805 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/connector/CanalSourceIncrementConnector.java @@ -0,0 +1,464 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceIncrementConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.offset.canal.CanalRecordOffset; +import org.apache.eventmesh.common.remote.offset.canal.CanalRecordPartition; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.CanalConnectRecord; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.EntryParser; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.commons.lang3.StringUtils; + +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.otter.canal.instance.core.CanalInstance; +import com.alibaba.otter.canal.instance.core.CanalInstanceGenerator; +import com.alibaba.otter.canal.instance.manager.CanalInstanceWithManager; +import com.alibaba.otter.canal.instance.manager.model.Canal; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.ClusterMode; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.HAMode; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.IndexMode; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.MetaMode; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.RunMode; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.SourcingType; +import com.alibaba.otter.canal.instance.manager.model.CanalParameter.StorageMode; +import com.alibaba.otter.canal.parse.CanalEventParser; +import com.alibaba.otter.canal.parse.ha.CanalHAController; +import com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser; +import com.alibaba.otter.canal.protocol.CanalEntry.Entry; +import com.alibaba.otter.canal.protocol.ClientIdentity; +import com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalSourceIncrementConnector implements Source { + + private CanalSourceIncrementConfig sourceConfig; + + private CanalServerWithEmbedded canalServer; + + private ClientIdentity clientIdentity; + + private String tableFilter = null; + + private String fieldFilter = null; + + private volatile boolean running = false; + + private static final int maxEmptyTimes = 10; + + private RdbTableMgr tableMgr; + + private static final String SQL_SELECT_RDB_VERSION = "select version() as rdb_version"; + + private static final String SQL_SELECT_SERVER_UUID_IN_MARIADB = "SELECT @@global.server_id as server_uuid"; + + private static final String SQL_SHOW_SERVER_UUID_IN_MYSQL = "SELECT @@server_uuid as server_uuid"; + + @Override + public Class configClass() { + return CanalSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for canal source connector + this.sourceConfig = (CanalSourceIncrementConfig) config; + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + CanalSourceConfig canalSourceConfig = (CanalSourceConfig) sourceConnectorContext.getSourceConfig(); + this.sourceConfig = ConfigUtil.parse(canalSourceConfig.getSourceConfig(), CanalSourceIncrementConfig.class); + if (sourceConnectorContext.getRecordPositionList() != null) { + this.sourceConfig.setRecordPositions(sourceConnectorContext.getRecordPositionList()); + } + // filter: your_database\\.your_table; .*\\..* (all database & table) + tableFilter = buildTableFilters(sourceConfig); + + if (StringUtils.isNotEmpty(sourceConfig.getFieldFilter())) { + fieldFilter = sourceConfig.getFieldFilter(); + } + DatabaseConnection.sourceConfig = sourceConfig.getSourceConnectorConfig(); + DatabaseConnection.initSourceConnection(); + + DataSourceType dataSourceType = checkRDBDataSourceType(DatabaseConnection.sourceDataSource); + String serverUUID = queryServerUUID(DatabaseConnection.sourceDataSource, dataSourceType); + if (StringUtils.isNotEmpty(serverUUID)) { + log.info("init source increment connector, serverUUID: {}", serverUUID); + sourceConfig.setServerUUID(serverUUID); + } else { + log.warn("get source data source serverUUID empty please check"); + } + tableMgr = new RdbTableMgr(sourceConfig.getSourceConnectorConfig(), DatabaseConnection.sourceDataSource); + + canalServer = CanalServerWithEmbedded.instance(); + + canalServer.setCanalInstanceGenerator(new CanalInstanceGenerator() { + @Override + public CanalInstance generate(String destination) { + Canal canal = buildCanal(sourceConfig); + + CanalInstanceWithManager instance = new CanalInstanceWithManager(canal, tableFilter) { + + protected CanalHAController initHaController() { + return super.initHaController(); + } + + protected void startEventParserInternal(CanalEventParser parser, boolean isGroup) { + super.startEventParserInternal(parser, isGroup); + + if (eventParser instanceof MysqlEventParser) { + // set eventParser support type + ((MysqlEventParser) eventParser).setSupportBinlogFormats("ROW"); + ((MysqlEventParser) eventParser).setSupportBinlogImages("FULL"); + MysqlEventParser mysqlEventParser = (MysqlEventParser) eventParser; + mysqlEventParser.setParallel(false); + if (StringUtils.isNotEmpty(fieldFilter)) { + mysqlEventParser.setFieldFilter(fieldFilter); + } + + CanalHAController haController = mysqlEventParser.getHaController(); + if (!haController.isStart()) { + haController.start(); + } + } + } + }; + return instance; + } + }); + } + + private String queryServerUUID(DruidDataSource sourceDataSource, DataSourceType dataSourceType) { + String serverUUID = ""; + try { + String queryServerUUIDSql; + if (DataSourceType.MariaDB.equals(dataSourceType)) { + queryServerUUIDSql = SQL_SELECT_SERVER_UUID_IN_MARIADB; + } else { + queryServerUUIDSql = SQL_SHOW_SERVER_UUID_IN_MYSQL; + } + log.info("execute sql '{}' start.", queryServerUUIDSql); + try (PreparedStatement preparedStatement = sourceDataSource.getConnection().prepareStatement(queryServerUUIDSql)) { + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + log.info("execute sql '{}' result:{}", queryServerUUIDSql, resultSet); + serverUUID = resultSet.getString("server_uuid"); + log.info("execute sql '{}',query server_uuid result:{}", queryServerUUIDSql, serverUUID); + return serverUUID; + } + } + } catch (Exception e) { + log.warn("select server_uuid failed,data source:{}", sourceDataSource, e); + throw new RuntimeException("select server_uuid failed"); + } + return serverUUID; + } + + // check is mariadb or mysql + private DataSourceType checkRDBDataSourceType(DruidDataSource sourceDataSource) { + try { + log.info("execute sql '{}' start.", SQL_SELECT_RDB_VERSION); + try (PreparedStatement preparedStatement = sourceDataSource.getConnection().prepareStatement(SQL_SELECT_RDB_VERSION)) { + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + log.info("execute sql '{}' result:{}", SQL_SELECT_RDB_VERSION, resultSet); + String rdbVersion = resultSet.getString("rdb_version"); + if (StringUtils.isNotBlank(rdbVersion)) { + if (rdbVersion.toLowerCase().contains(DataSourceType.MariaDB.getName().toLowerCase())) { + return DataSourceType.MariaDB; + } + } + } + } + } catch (Exception e) { + log.warn("select rdb version failed,data source:{}", sourceDataSource, e); + throw new RuntimeException("select rdb version failed"); + } + return DataSourceType.MYSQL; + } + + private String buildTableFilters(CanalSourceIncrementConfig sourceConfig) { + StringBuilder tableFilterBuilder = new StringBuilder(); + Set dbDefinitions = sourceConfig.getSourceConnectorConfig().getDatabases(); + for (RdbDBDefinition dbDefinition : dbDefinitions) { + Set tableDefinitions = dbDefinition.getTables(); + for (RdbTableDefinition rdbTableDefinition : tableDefinitions) { + if (tableFilterBuilder.length() > 0) { + tableFilterBuilder.append(","); + } + String dbName = rdbTableDefinition.getSchemaName(); + String tableName = rdbTableDefinition.getTableName(); + tableFilterBuilder.append(dbName); + tableFilterBuilder.append("\\."); + tableFilterBuilder.append(tableName); + } + } + return tableFilterBuilder.toString(); + } + + private Canal buildCanal(CanalSourceIncrementConfig sourceConfig) { + long slaveId = 10000; + if (sourceConfig.getSlaveId() != null) { + slaveId = sourceConfig.getSlaveId(); + } + + Canal canal = new Canal(); + canal.setId(sourceConfig.getCanalInstanceId()); + canal.setName(sourceConfig.getDestination()); + canal.setDesc(sourceConfig.getDesc()); + + CanalParameter parameter = new CanalParameter(); + + parameter.setRunMode(RunMode.EMBEDDED); + parameter.setClusterMode(ClusterMode.STANDALONE); + parameter.setMetaMode(MetaMode.MEMORY); + parameter.setHaMode(HAMode.HEARTBEAT); + parameter.setIndexMode(IndexMode.MEMORY); + parameter.setStorageMode(StorageMode.MEMORY); + parameter.setMemoryStorageBufferSize(32 * 1024); + + parameter.setSourcingType(SourcingType.MYSQL); + parameter.setDbAddresses(Collections.singletonList(new InetSocketAddress(sourceConfig.getSourceConnectorConfig().getDbAddress(), + sourceConfig.getSourceConnectorConfig().getDbPort()))); + parameter.setDbUsername(sourceConfig.getSourceConnectorConfig().getUserName()); + parameter.setDbPassword(sourceConfig.getSourceConnectorConfig().getPassWord()); + + // set if enabled gtid mode + parameter.setGtidEnable(sourceConfig.isGTIDMode()); + + // check positions + // example: Arrays.asList("{\"journalName\":\"mysql-bin.000001\",\"position\":6163L,\"timestamp\":1322803601000L}", + // "{\"journalName\":\"mysql-bin.000001\",\"position\":6163L,\"timestamp\":1322803601000L}") + if (sourceConfig.getRecordPositions() != null && !sourceConfig.getRecordPositions().isEmpty()) { + List recordPositions = sourceConfig.getRecordPositions(); + List positions = new ArrayList<>(); + recordPositions.forEach(recordPosition -> { + Map recordPositionMap = new HashMap<>(); + CanalRecordPartition canalRecordPartition = (CanalRecordPartition) (recordPosition.getRecordPartition()); + CanalRecordOffset canalRecordOffset = (CanalRecordOffset) (recordPosition.getRecordOffset()); + recordPositionMap.put("journalName", canalRecordPartition.getJournalName()); + recordPositionMap.put("timestamp", canalRecordPartition.getTimeStamp()); + recordPositionMap.put("position", canalRecordOffset.getOffset()); + // for mariaDB not support gtid mode + if (sourceConfig.isGTIDMode() && !sourceConfig.isMariaDB()) { + String gtidRange = canalRecordOffset.getGtid(); + if (gtidRange != null) { + if (canalRecordOffset.getCurrentGtid() != null) { + gtidRange = EntryParser.replaceGtidRange(canalRecordOffset.getGtid(), canalRecordOffset.getCurrentGtid(), + sourceConfig.getServerUUID()); + } + recordPositionMap.put("gtid", gtidRange); + } + } + positions.add(JsonUtils.toJSONString(recordPositionMap)); + }); + parameter.setPositions(positions); + } + + parameter.setSlaveId(slaveId); + + parameter.setDefaultConnectionTimeoutInSeconds(30); + parameter.setConnectionCharset("UTF-8"); + parameter.setConnectionCharsetNumber((byte) 33); + parameter.setReceiveBufferSize(8 * 1024); + parameter.setSendBufferSize(8 * 1024); + + // heartbeat detect + parameter.setDetectingEnable(false); + + parameter.setDdlIsolation(sourceConfig.isDdlSync()); + parameter.setFilterTableError(sourceConfig.isFilterTableError()); + parameter.setMemoryStorageRawEntry(false); + + canal.setCanalParameter(parameter); + return canal; + } + + + @Override + public void start() throws Exception { + if (running) { + return; + } + tableMgr.start(); + canalServer.start(); + + canalServer.start(sourceConfig.getDestination()); + this.clientIdentity = new ClientIdentity(sourceConfig.getDestination(), sourceConfig.getClientId(), tableFilter); + canalServer.subscribe(clientIdentity); + + running = true; + } + + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getSourceConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + if (!running) { + return; + } + running = false; + canalServer.stop(sourceConfig.getDestination()); + canalServer.stop(); + } + + @Override + public List poll() { + int emptyTimes = 0; + com.alibaba.otter.canal.protocol.Message message = null; + if (sourceConfig.getBatchTimeout() < 0) { + while (running) { + message = canalServer.getWithoutAck(clientIdentity, sourceConfig.getBatchSize()); + if (message == null || message.getId() == -1L) { // empty + applyWait(emptyTimes++); + } else { + break; + } + } + } else { // perform with timeout + while (running) { + message = + canalServer.getWithoutAck(clientIdentity, sourceConfig.getBatchSize(), sourceConfig.getBatchTimeout(), TimeUnit.MILLISECONDS); + if (message == null || message.getId() == -1L) { // empty + continue; + } + break; + } + } + + List entries; + assert message != null; + if (message.isRaw()) { + entries = new ArrayList<>(message.getRawEntries().size()); + for (ByteString entry : message.getRawEntries()) { + try { + entries.add(Entry.parseFrom(entry)); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + } + } else { + entries = message.getEntries(); + } + + List result = new ArrayList<>(); + // key: Xid offset + Map> connectorRecordMap = EntryParser.parse(sourceConfig, entries, tableMgr); + + if (!connectorRecordMap.isEmpty()) { + Set>> entrySet = connectorRecordMap.entrySet(); + for (Map.Entry> entry : entrySet) { + List connectRecordList = entry.getValue(); + CanalConnectRecord lastRecord = entry.getValue().get(connectRecordList.size() - 1); + CanalRecordPartition canalRecordPartition = new CanalRecordPartition(); + canalRecordPartition.setServerUUID(sourceConfig.getServerUUID()); + canalRecordPartition.setJournalName(lastRecord.getJournalName()); + canalRecordPartition.setTimeStamp(lastRecord.getExecuteTime()); + // Xid offset with gtid + Long binLogOffset = entry.getKey(); + CanalRecordOffset canalRecordOffset = new CanalRecordOffset(); + canalRecordOffset.setOffset(binLogOffset); + if (StringUtils.isNotEmpty(lastRecord.getGtid()) && StringUtils.isNotEmpty(lastRecord.getCurrentGtid())) { + canalRecordOffset.setGtid(lastRecord.getGtid()); + canalRecordOffset.setCurrentGtid(lastRecord.getCurrentGtid()); + } + + // split record list + List> splitLists = new ArrayList<>(); + for (int i = 0; i < connectRecordList.size(); i += sourceConfig.getBatchSize()) { + int end = Math.min(i + sourceConfig.getBatchSize(), connectRecordList.size()); + List subList = connectRecordList.subList(i, end); + splitLists.add(subList); + } + + for (int i = 0; i < splitLists.size(); i++) { + ConnectRecord connectRecord = new ConnectRecord(canalRecordPartition, canalRecordOffset, System.currentTimeMillis()); + connectRecord.addExtension("messageId", String.valueOf(message.getId())); + connectRecord.addExtension("batchIndex", i); + connectRecord.addExtension("totalBatches", splitLists.size()); + connectRecord.setData(JsonUtils.toJSONString(splitLists.get(i)).getBytes(StandardCharsets.UTF_8)); + result.add(connectRecord); + } + } + log.debug("message {} has been processed", message); + } + log.debug("ack message, messageId {}", message.getId()); + canalServer.ack(clientIdentity, message.getId()); + + return result; + } + + // Handle the situation of no data and avoid empty loop death + private void applyWait(int emptyTimes) { + int newEmptyTimes = Math.min(emptyTimes, maxEmptyTimes); + if (emptyTimes <= 3) { + Thread.yield(); + } else { + LockSupport.parkNanos(1000 * 1000L * newEmptyTimes); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/CanalCheckPositionMgr.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/CanalCheckPositionMgr.java new file mode 100644 index 0000000000..149c62602c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/CanalCheckPositionMgr.java @@ -0,0 +1,250 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.position; + +import org.apache.eventmesh.common.AbstractComponent; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceCheckConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.JobRdbFullPosition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbColumnDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.Constants; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordOffset; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.table.RdbSimpleTable; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; + +import org.apache.commons.lang3.StringUtils; + +import java.sql.JDBCType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalCheckPositionMgr extends AbstractComponent { + + private final CanalSourceCheckConfig config; + private final Map positions = new LinkedHashMap<>(); + private final RdbTableMgr tableMgr; + + public CanalCheckPositionMgr(CanalSourceCheckConfig config, RdbTableMgr tableMgr) { + this.config = config; + this.tableMgr = tableMgr; + } + + @Override + protected void run() throws Exception { + if (config == null || config.getSourceConnectorConfig() == null || config.getSourceConnectorConfig().getDatabases() == null) { + log.info("config or database is null"); + return; + } + prepareRecordPosition(); + initPositions(); + } + + public void prepareRecordPosition() { + if (config.getStartPosition() != null && !config.getStartPosition().isEmpty()) { + for (RecordPosition record : config.getStartPosition()) { + CanalFullRecordOffset offset = (CanalFullRecordOffset) record.getRecordOffset(); + RdbSimpleTable table = new RdbSimpleTable(offset.getPosition().getSchema(), offset.getPosition().getTableName()); + positions.put(table, offset.getPosition()); + } + } + } + + public JobRdbFullPosition getPosition(RdbSimpleTable table) { + return positions.get(table); + } + + public boolean isFinished() { + for (JobRdbFullPosition position : positions.values()) { + if (!position.isFinished()) { + log.info("schema [{}] table [{}] is not finish", position.getSchema(), position.getTableName()); + return false; + } + } + return true; + } + + private void initPositions() { + for (RdbDBDefinition database : config.getSourceConnectorConfig().getDatabases()) { + for (RdbTableDefinition table : database.getTables()) { + try { + RdbSimpleTable simpleTable = new RdbSimpleTable(database.getSchemaName(), table.getTableName()); + RdbTableDefinition tableDefinition; + if ((tableDefinition = tableMgr.getTable(simpleTable)) == null) { + log.error("db [{}] table [{}] definition is null", database.getSchemaName(), table.getTableName()); + continue; + } + log.info("init position of data [{}] table [{}]", database.getSchemaName(), table.getTableName()); + + JobRdbFullPosition recordPosition = positions.get(simpleTable); + if (recordPosition == null || !recordPosition.isFinished()) { + positions.put(simpleTable, + fetchTableInfo(DatabaseConnection.sourceDataSource, (MySQLTableDef) tableDefinition, recordPosition)); + } + } catch (Exception e) { + log.error("process schema [{}] table [{}] position fail", database.getSchemaName(), table.getTableName(), e); + } + + } + } + } + + private JobRdbFullPosition fetchTableInfo(DataSource dataSource, MySQLTableDef tableDefinition, JobRdbFullPosition recordPosition) + throws SQLException { + TableFullPosition position = new TableFullPosition(); + Map preMinPrimaryKeys = new LinkedHashMap<>(); + Map preMaxPrimaryKeys = new LinkedHashMap<>(); + for (String pk : tableDefinition.getPrimaryKeys()) { + Object min = fetchMinPrimaryKey(dataSource, tableDefinition, preMinPrimaryKeys, pk); + Object max = fetchMaxPrimaryKey(dataSource, tableDefinition, preMaxPrimaryKeys, pk); + preMinPrimaryKeys.put(pk, min); + preMaxPrimaryKeys.put(pk, max); + position.getCurPrimaryKeyCols().put(pk, min); + position.getMinPrimaryKeyCols().put(pk, min); + position.getMaxPrimaryKeyCols().put(pk, max); + } + JobRdbFullPosition jobRdbFullPosition = new JobRdbFullPosition(); + if (recordPosition != null) { + if (StringUtils.isNotBlank(recordPosition.getPrimaryKeyRecords())) { + TableFullPosition record = JsonUtils.parseObject(recordPosition.getPrimaryKeyRecords(), TableFullPosition.class); + if (record != null && record.getCurPrimaryKeyCols() != null && !record.getCurPrimaryKeyCols().isEmpty()) { + position.setCurPrimaryKeyCols(record.getCurPrimaryKeyCols()); + } + } + jobRdbFullPosition.setPercent(recordPosition.getPercent()); + } + long rowCount = queryCurTableRowCount(dataSource, tableDefinition); + jobRdbFullPosition.setSchema(tableDefinition.getSchemaName()); + jobRdbFullPosition.setTableName(tableDefinition.getTableName()); + jobRdbFullPosition.setMaxCount(rowCount); + jobRdbFullPosition.setPrimaryKeyRecords(JsonUtils.toJSONString(position)); + return jobRdbFullPosition; + } + + + private long queryCurTableRowCount(DataSource datasource, MySQLTableDef tableDefinition) throws SQLException { + String sql = "select `AVG_ROW_LENGTH`,`DATA_LENGTH` from information_schema.TABLES where `TABLE_SCHEMA`='" + tableDefinition.getSchemaName() + + "' and `TABLE_NAME`='" + tableDefinition.getTableName() + "'"; + try (Statement statement = datasource.getConnection().createStatement(); ResultSet resultSet = statement.executeQuery(sql)) { + long result = 0L; + if (resultSet.next()) { + long avgRowLength = resultSet.getLong("AVG_ROW_LENGTH"); + long dataLength = resultSet.getLong("DATA_LENGTH"); + if (avgRowLength != 0L) { + result = dataLength / avgRowLength; + } + } + return result; + } + } + + private void appendPrePrimaryKey(Map preMap, StringBuilder sql) { + if (preMap != null && !preMap.isEmpty()) { + sql.append(" WHERE "); + boolean first = true; + for (Map.Entry entry : preMap.entrySet()) { + if (first) { + first = false; + } else { + sql.append(" AND "); + } + sql.append(Constants.MySQLQuot).append(entry.getKey()).append(Constants.MySQLQuot).append("=?"); + } + } + } + + private void setValue2Statement(PreparedStatement ps, Map preMap, MySQLTableDef tableDefinition) throws SQLException { + if (preMap != null && !preMap.isEmpty()) { + int index = 1; + for (Map.Entry entry : preMap.entrySet()) { + RdbColumnDefinition def = tableDefinition.getColumnDefinitions().get(entry.getKey()); + ps.setObject(index, entry.getValue(), def.getJdbcType().getVendorTypeNumber()); + ++index; + } + } + } + + private Object fetchMinPrimaryKey(DataSource dataSource, MySQLTableDef tableDefinition, Map prePrimary, String curPrimaryKeyCol) + throws SQLException { + StringBuilder builder = new StringBuilder(); + builder.append("SELECT MIN(").append(Constants.MySQLQuot).append(curPrimaryKeyCol).append(Constants.MySQLQuot) + .append(") min_primary_key FROM").append(Constants.MySQLQuot).append(tableDefinition.getSchemaName()).append(Constants.MySQLQuot) + .append(".").append(Constants.MySQLQuot).append(tableDefinition.getTableName()).append(Constants.MySQLQuot); + appendPrePrimaryKey(prePrimary, builder); + String sql = builder.toString(); + log.info("fetch min primary sql [{}]", sql); + try (PreparedStatement statement = dataSource.getConnection().prepareStatement(sql)) { + setValue2Statement(statement, prePrimary, tableDefinition); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + RdbColumnDefinition columnDefinition = tableDefinition.getColumnDefinitions().get(curPrimaryKeyCol); + if (columnDefinition.getJdbcType() == JDBCType.TIMESTAMP) { + return resultSet.getString("min_primary_key"); + } else { + return resultSet.getObject("min_primary_key"); + } + } + } + } + return null; + } + + private Object fetchMaxPrimaryKey(DataSource dataSource, MySQLTableDef tableDefinition, Map prePrimary, String curPrimaryKeyCol) + throws SQLException { + StringBuilder builder = new StringBuilder(); + builder.append("SELECT MAX(").append(Constants.MySQLQuot).append(curPrimaryKeyCol).append(Constants.MySQLQuot) + .append(") max_primary_key FROM").append(Constants.MySQLQuot).append(tableDefinition.getSchemaName()).append(Constants.MySQLQuot) + .append(".").append(Constants.MySQLQuot).append(tableDefinition.getTableName()).append(Constants.MySQLQuot); + appendPrePrimaryKey(prePrimary, builder); + String sql = builder.toString(); + log.info("fetch max primary sql [{}]", sql); + try (PreparedStatement statement = dataSource.getConnection().prepareStatement(sql)) { + setValue2Statement(statement, prePrimary, tableDefinition); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + RdbColumnDefinition columnDefinition = tableDefinition.getColumnDefinitions().get(curPrimaryKeyCol); + if (columnDefinition.getJdbcType() == JDBCType.TIMESTAMP) { + return resultSet.getString("max_primary_key"); + } else { + return resultSet.getObject("max_primary_key"); + } + } + } + } + return null; + } + + + @Override + protected void shutdown() throws Exception { + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/CanalFullPositionMgr.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/CanalFullPositionMgr.java new file mode 100644 index 0000000000..dad0ddbf3b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/CanalFullPositionMgr.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.position; + +import org.apache.eventmesh.common.AbstractComponent; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalSourceFullConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.JobRdbFullPosition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbColumnDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.Constants; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.offset.canal.CanalFullRecordOffset; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.canal.DatabaseConnection; +import org.apache.eventmesh.connector.canal.source.table.RdbSimpleTable; +import org.apache.eventmesh.connector.canal.source.table.RdbTableMgr; + +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.JDBCType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CanalFullPositionMgr extends AbstractComponent { + + private final CanalSourceFullConfig config; + private final Map positions = new LinkedHashMap<>(); + private final RdbTableMgr tableMgr; + + public CanalFullPositionMgr(CanalSourceFullConfig config, RdbTableMgr tableMgr) { + this.config = config; + this.tableMgr = tableMgr; + } + + @Override + protected void run() throws Exception { + if (config == null || config.getSourceConnectorConfig() == null || config.getSourceConnectorConfig().getDatabases() == null) { + log.info("config or database is null"); + return; + } + prepareRecordPosition(); + initPositions(); + } + + public void prepareRecordPosition() { + if (config.getStartPosition() != null && !config.getStartPosition().isEmpty()) { + for (RecordPosition record : config.getStartPosition()) { + CanalFullRecordOffset offset = (CanalFullRecordOffset) record.getRecordOffset(); + RdbSimpleTable table = new RdbSimpleTable(offset.getPosition().getSchema(), offset.getPosition().getTableName()); + positions.put(table, offset.getPosition()); + } + } + } + + public JobRdbFullPosition getPosition(RdbSimpleTable table) { + return positions.get(table); + } + + public boolean isFinished() { + for (JobRdbFullPosition position : positions.values()) { + if (!position.isFinished()) { + log.info("schema [{}] table [{}] is not finish", position.getSchema(), position.getTableName()); + return false; + } + } + return true; + } + + private void initPositions() { + for (RdbDBDefinition database : config.getSourceConnectorConfig().getDatabases()) { + for (RdbTableDefinition table : database.getTables()) { + try { + RdbSimpleTable simpleTable = new RdbSimpleTable(database.getSchemaName(), table.getTableName()); + RdbTableDefinition tableDefinition; + if ((tableDefinition = tableMgr.getTable(simpleTable)) == null) { + log.error("db [{}] table [{}] definition is null", database.getSchemaName(), table.getTableName()); + continue; + } + log.info("init position of data [{}] table [{}]", database.getSchemaName(), table.getTableName()); + + JobRdbFullPosition recordPosition = positions.get(simpleTable); + if (recordPosition == null || !recordPosition.isFinished()) { + positions.put(simpleTable, + fetchTableInfo(DatabaseConnection.sourceDataSource, (MySQLTableDef) tableDefinition, recordPosition)); + } + } catch (Exception e) { + log.error("process schema [{}] table [{}] position fail", database.getSchemaName(), table.getTableName(), e); + } + + } + } + } + + private JobRdbFullPosition fetchTableInfo(DataSource dataSource, MySQLTableDef tableDefinition, JobRdbFullPosition recordPosition) + throws SQLException { + TableFullPosition position = new TableFullPosition(); + Map preMinPrimaryKeys = new LinkedHashMap<>(); + Map preMaxPrimaryKeys = new LinkedHashMap<>(); + for (String pk : tableDefinition.getPrimaryKeys()) { + Object min = fetchMinPrimaryKey(dataSource, tableDefinition, preMinPrimaryKeys, pk); + Object max = fetchMaxPrimaryKey(dataSource, tableDefinition, preMaxPrimaryKeys, pk); + preMinPrimaryKeys.put(pk, min); + preMaxPrimaryKeys.put(pk, max); + position.getCurPrimaryKeyCols().put(pk, min); + position.getMinPrimaryKeyCols().put(pk, min); + position.getMaxPrimaryKeyCols().put(pk, max); + } + JobRdbFullPosition jobRdbFullPosition = new JobRdbFullPosition(); + if (recordPosition != null) { + if (StringUtils.isNotBlank(recordPosition.getPrimaryKeyRecords())) { + TableFullPosition record = JsonUtils.parseObject(recordPosition.getPrimaryKeyRecords(), TableFullPosition.class); + if (record != null && record.getCurPrimaryKeyCols() != null && !record.getCurPrimaryKeyCols().isEmpty()) { + position.setCurPrimaryKeyCols(record.getCurPrimaryKeyCols()); + } + } + jobRdbFullPosition.setPercent(recordPosition.getPercent()); + } + long rowCount = queryCurTableRowCount(dataSource, tableDefinition); + jobRdbFullPosition.setSchema(tableDefinition.getSchemaName()); + jobRdbFullPosition.setTableName(tableDefinition.getTableName()); + jobRdbFullPosition.setMaxCount(rowCount); + jobRdbFullPosition.setPrimaryKeyRecords(JsonUtils.toJSONString(position)); + return jobRdbFullPosition; + } + + + private long queryCurTableRowCount(DataSource datasource, MySQLTableDef tableDefinition) throws SQLException { + String sql = "select `AVG_ROW_LENGTH`,`DATA_LENGTH` from information_schema.TABLES where `TABLE_SCHEMA`='" + tableDefinition.getSchemaName() + + "' and `TABLE_NAME`='" + tableDefinition.getTableName() + "'"; + try (Connection conn = datasource.getConnection(); Statement statement = conn.createStatement(); + ResultSet resultSet = statement.executeQuery(sql)) { + long result = 0L; + if (resultSet.next()) { + long avgRowLength = resultSet.getLong("AVG_ROW_LENGTH"); + long dataLength = resultSet.getLong("DATA_LENGTH"); + if (avgRowLength != 0L) { + result = dataLength / avgRowLength; + } + } + return result; + } + } + + private void appendPrePrimaryKey(Map preMap, StringBuilder sql) { + if (preMap != null && !preMap.isEmpty()) { + sql.append(" WHERE "); + boolean first = true; + for (Map.Entry entry : preMap.entrySet()) { + if (first) { + first = false; + } else { + sql.append(" AND "); + } + sql.append(Constants.MySQLQuot).append(entry.getKey()).append(Constants.MySQLQuot).append("=?"); + } + } + } + + private void setValue2Statement(PreparedStatement ps, Map preMap, MySQLTableDef tableDefinition) throws SQLException { + if (preMap != null && !preMap.isEmpty()) { + int index = 1; + for (Map.Entry entry : preMap.entrySet()) { + RdbColumnDefinition def = tableDefinition.getColumnDefinitions().get(entry.getKey()); + ps.setObject(index, entry.getValue(), def.getJdbcType().getVendorTypeNumber()); + ++index; + } + } + } + + private Object fetchMinPrimaryKey(DataSource dataSource, MySQLTableDef tableDefinition, Map prePrimary, String curPrimaryKeyCol) + throws SQLException { + StringBuilder builder = new StringBuilder(); + builder.append("SELECT MIN(").append(Constants.MySQLQuot).append(curPrimaryKeyCol).append(Constants.MySQLQuot) + .append(") min_primary_key FROM").append(Constants.MySQLQuot).append(tableDefinition.getSchemaName()).append(Constants.MySQLQuot) + .append(".").append(Constants.MySQLQuot).append(tableDefinition.getTableName()).append(Constants.MySQLQuot); + appendPrePrimaryKey(prePrimary, builder); + String sql = builder.toString(); + log.info("fetch min primary sql [{}]", sql); + try (Connection conn = dataSource.getConnection(); PreparedStatement statement = conn.prepareStatement(sql)) { + setValue2Statement(statement, prePrimary, tableDefinition); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + RdbColumnDefinition columnDefinition = tableDefinition.getColumnDefinitions().get(curPrimaryKeyCol); + if (columnDefinition.getJdbcType() == JDBCType.TIMESTAMP) { + return resultSet.getString("min_primary_key"); + } else { + return resultSet.getObject("min_primary_key"); + } + } + } + } + return null; + } + + private Object fetchMaxPrimaryKey(DataSource dataSource, MySQLTableDef tableDefinition, Map prePrimary, String curPrimaryKeyCol) + throws SQLException { + StringBuilder builder = new StringBuilder(); + builder.append("SELECT MAX(").append(Constants.MySQLQuot).append(curPrimaryKeyCol).append(Constants.MySQLQuot) + .append(") max_primary_key FROM").append(Constants.MySQLQuot).append(tableDefinition.getSchemaName()).append(Constants.MySQLQuot) + .append(".").append(Constants.MySQLQuot).append(tableDefinition.getTableName()).append(Constants.MySQLQuot); + appendPrePrimaryKey(prePrimary, builder); + String sql = builder.toString(); + log.info("fetch max primary sql [{}]", sql); + try (Connection conn = dataSource.getConnection(); PreparedStatement statement = conn.prepareStatement(sql)) { + setValue2Statement(statement, prePrimary, tableDefinition); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + RdbColumnDefinition columnDefinition = tableDefinition.getColumnDefinitions().get(curPrimaryKeyCol); + if (columnDefinition.getJdbcType() == JDBCType.TIMESTAMP) { + return resultSet.getString("max_primary_key"); + } else { + return resultSet.getObject("max_primary_key"); + } + } + } + } + return null; + } + + + @Override + protected void shutdown() throws Exception { + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/TableFullPosition.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/TableFullPosition.java new file mode 100644 index 0000000000..b1a8024ec5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/position/TableFullPosition.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.position; + +import java.util.LinkedHashMap; +import java.util.Map; + +import lombok.Data; + +@Data +public class TableFullPosition { + private Map curPrimaryKeyCols = new LinkedHashMap<>(); + private Map minPrimaryKeyCols = new LinkedHashMap<>(); + private Map maxPrimaryKeyCols = new LinkedHashMap<>(); +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/table/RdbSimpleTable.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/table/RdbSimpleTable.java new file mode 100644 index 0000000000..5b9c35fff3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/table/RdbSimpleTable.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.table; + +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; + +import java.util.Objects; + +import lombok.Data; + +@Data +public class RdbSimpleTable extends RdbTableDefinition { + public RdbSimpleTable(String database, String schema, String tableName) { + this.schemaName = schema; + this.tableName = tableName; + this.database = database; + } + + public RdbSimpleTable(String schema, String tableName) { + this(null, schema, tableName); + } + + private final String database; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + RdbSimpleTable that = (RdbSimpleTable) o; + return Objects.equals(database, that.database); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), database); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/table/RdbTableMgr.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/table/RdbTableMgr.java new file mode 100644 index 0000000000..954b81ca70 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/source/table/RdbTableMgr.java @@ -0,0 +1,212 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.source.table; + +import org.apache.eventmesh.common.AbstractComponent; +import org.apache.eventmesh.common.config.connector.rdb.JdbcConfig; +import org.apache.eventmesh.common.config.connector.rdb.canal.CanalMySQLType; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbDBDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.RdbTableDefinition; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLColumnDef; +import org.apache.eventmesh.common.config.connector.rdb.canal.mysql.MySQLTableDef; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.canal.SqlUtils; + +import java.sql.Connection; +import java.sql.JDBCType; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import lombok.extern.slf4j.Slf4j; + +/** + * Description: + */ +@Slf4j + +public class RdbTableMgr extends AbstractComponent { + + private final JdbcConfig config; + private final Map tables = new HashMap<>(); + private final DataSource dataSource; + + public RdbTableMgr(JdbcConfig config, DataSource dataSource) { + this.config = config; + this.dataSource = dataSource; + } + + public RdbTableDefinition getTable(String schema, String tableName) { + return getTable(new RdbSimpleTable(schema, tableName)); + } + + public RdbTableDefinition getTable(RdbSimpleTable table) { + return tables.get(table); + } + + @Override + protected void run() { + if (config != null && config.getDatabases() != null) { + for (RdbDBDefinition db : config.getDatabases()) { + if (db.getTables() == null) { + log.warn("init db [{}] position, but it's tables are null", db.getSchemaName()); + continue; + } + for (RdbTableDefinition table : db.getTables()) { + try { + MySQLTableDef mysqlTable = new MySQLTableDef(); + mysqlTable.setSchemaName(db.getSchemaName()); + mysqlTable.setTableName(table.getTableName()); + List tables = Collections.singletonList(table.getTableName()); + Map> primaryKeys = queryTablePrimaryKey(db.getSchemaName(), tables); + Map> columns = queryColumns(db.getSchemaName(), tables); + if (primaryKeys == null || primaryKeys.isEmpty() || primaryKeys.get(table.getTableName()) == null) { + log.warn("init db [{}] table [{}] info, and primary keys are empty", db.getSchemaName(), table.getTableName()); + } else { + mysqlTable.setPrimaryKeys(primaryKeys.get(table.getTableName())); + } + if (columns == null || columns.isEmpty() || columns.get(table.getTableName()) == null) { + log.warn("init db [{}] table [{}] info, and columns are empty", db.getSchemaName(), table.getTableName()); + throw new EventMeshException("db [{}] table [{}] columns are empty"); + } else { + LinkedHashMap cols = new LinkedHashMap<>(); + columns.get(table.getTableName()).forEach(x -> cols.put(x.getName(), x)); + mysqlTable.setColumnDefinitions(cols); + } + + this.tables.put(new RdbSimpleTable(db.getSchemaName(), table.getTableName()), mysqlTable); + } catch (SQLException e) { + log.error("init rdb table schema [{}] table [{}] fail", db.getSchemaName(), table.getTableName(), e); + throw new EventMeshException(e); + } + } + + } + } + } + + private Map> queryTablePrimaryKey(String schema, List tables) throws SQLException { + Map> primaryKeys = new LinkedHashMap<>(); + String prepareTables = SqlUtils.genPrepareSqlOfInClause(tables.size()); + String sql = "select L.TABLE_NAME,L.COLUMN_NAME,R.CONSTRAINT_TYPE from " + + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE L left join INFORMATION_SCHEMA.TABLE_CONSTRAINTS R on L" + + ".TABLE_SCHEMA = R.TABLE_SCHEMA and L.TABLE_NAME = R.TABLE_NAME and L.CONSTRAINT_CATALOG = R" + + ".CONSTRAINT_CATALOG and L.CONSTRAINT_SCHEMA = R.CONSTRAINT_SCHEMA and L.CONSTRAINT_NAME = R" + + ".CONSTRAINT_NAME where L.TABLE_SCHEMA = ? and L.TABLE_NAME in " + prepareTables + " and R" + + ".CONSTRAINT_TYPE IN ('PRIMARY KEY') order by L.ORDINAL_POSITION asc"; + try (Connection conn = dataSource.getConnection(); + PreparedStatement statement = conn.prepareStatement(sql)) { + statement.setString(1, schema); + SqlUtils.setInClauseParameters(statement, 2, tables); + try (ResultSet rs = statement.executeQuery()) { + if (rs == null) { + return null; + } + while (rs.next()) { + String tableName = rs.getString("TABLE_NAME"); + String colName = rs.getString("COLUMN_NAME"); + primaryKeys.compute(tableName, (k, v) -> { + if (v == null) { + v = new LinkedList<>(); + } + v.add(colName); + return v; + }); + } + } + } + return primaryKeys; + } + + private Map> queryColumns(String schema, List tables) throws SQLException { + String prepareTables = SqlUtils.genPrepareSqlOfInClause(tables.size()); + String sql = "select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,IS_NULLABLE,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH," + + "CHARACTER_OCTET_LENGTH,NUMERIC_SCALE,NUMERIC_PRECISION,DATETIME_PRECISION,CHARACTER_SET_NAME," + + "COLLATION_NAME,COLUMN_TYPE,COLUMN_DEFAULT,COLUMN_COMMENT,ORDINAL_POSITION,EXTRA from " + + "INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME in " + prepareTables + " order by " + "ORDINAL_POSITION asc"; + Map> cols = new LinkedHashMap<>(); + Connection conn = null; + PreparedStatement statement = null; + ResultSet rs = null; + try { + conn = dataSource.getConnection(); + statement = conn.prepareStatement(sql); + statement.setString(1, schema); + SqlUtils.setInClauseParameters(statement, 2, tables); + rs = statement.executeQuery(); + if (rs == null) { + return null; + } + while (rs.next()) { + String dataType = rs.getString("DATA_TYPE"); + JDBCType jdbcType = SqlUtils.toJDBCType(dataType); + MySQLColumnDef col = new MySQLColumnDef(); + col.setJdbcType(jdbcType); + col.setType(CanalMySQLType.valueOfCode(dataType)); + String colName = rs.getString("COLUMN_NAME"); + col.setName(colName); + String tableName = rs.getString("TABLE_NAME"); + cols.compute(tableName, (k, v) -> { + if (v == null) { + v = new LinkedList<>(); + } + v.add(col); + return v; + }); + } + } catch (SQLException e) { + log.error("init rdb table schema [{}] tables fail", schema, e); + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + log.error("close result set fail", e); + } + } + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + log.error("close prepare statement fail", e); + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + log.error("close db connection fail", e); + } + } + } + return cols; + } + + @Override + protected void shutdown() throws Exception { + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/AbstractSqlTemplate.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/AbstractSqlTemplate.java new file mode 100644 index 0000000000..10c647c8f1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/AbstractSqlTemplate.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.template; + +/** + * implement SQL CRUD with standard SQL + */ +public abstract class AbstractSqlTemplate implements SqlTemplate { + + private static final String DOT = "."; + + public String getSelectSql(String schemaName, String tableName, String[] pkNames, String[] columnNames) { + StringBuilder sql = new StringBuilder("select "); + int size = columnNames.length; + for (int i = 0; i < size; i++) { + sql.append(appendEscape(columnNames[i])).append((i + 1 < size) ? " , " : ""); + } + + sql.append(" from ").append(getFullName(schemaName, tableName)).append(" where ( "); + appendColumnEquals(sql, pkNames, "and"); + sql.append(" ) "); + return sql.toString().intern(); + } + + public String getUpdateSql(String schemaName, String tableName, String[] pkNames, String[] columnNames, boolean updatePks, String shardColumn) { + StringBuilder sql = new StringBuilder("update " + getFullName(schemaName, tableName) + " set "); + appendExcludeSingleShardColumnEquals(sql, columnNames, ",", updatePks, shardColumn); + sql.append(" where ("); + appendColumnEquals(sql, pkNames, "and"); + sql.append(")"); + return sql.toString().intern(); + } + + public String getInsertSql(String schemaName, String tableName, String[] pkNames, String[] columnNames) { + StringBuilder sql = new StringBuilder("insert into " + getFullName(schemaName, tableName) + "("); + String[] allColumns = new String[pkNames.length + columnNames.length]; + System.arraycopy(columnNames, 0, allColumns, 0, columnNames.length); + System.arraycopy(pkNames, 0, allColumns, columnNames.length, pkNames.length); + + int size = allColumns.length; + for (int i = 0; i < size; i++) { + sql.append(appendEscape(allColumns[i])).append((i + 1 < size) ? "," : ""); + } + + sql.append(") values ("); + appendColumnQuestions(sql, allColumns); + sql.append(")"); + return sql.toString().intern(); + } + + public String getDeleteSql(String schemaName, String tableName, String[] pkNames) { + StringBuilder sql = new StringBuilder("delete from " + getFullName(schemaName, tableName) + " where "); + appendColumnEquals(sql, pkNames, "and"); + return sql.toString().intern(); + } + + protected String getFullName(String schemaName, String tableName) { + StringBuilder sb = new StringBuilder(); + if (schemaName != null) { + sb.append(appendEscape(schemaName)).append(DOT); + } + sb.append(appendEscape(tableName)); + return sb.toString().intern(); + } + + // ================ helper method ============ + + protected String appendEscape(String columnName) { + return columnName; + } + + protected void appendColumnQuestions(StringBuilder sql, String[] columns) { + int size = columns.length; + for (int i = 0; i < size; i++) { + sql.append("?").append((i + 1 < size) ? " , " : ""); + } + } + + protected void appendColumnEquals(StringBuilder sql, String[] columns, String separator) { + int size = columns.length; + for (int i = 0; i < size; i++) { + sql.append(" ").append(appendEscape(columns[i])).append(" = ").append("? "); + if (i != size - 1) { + sql.append(separator); + } + } + } + + protected void appendExcludeSingleShardColumnEquals(StringBuilder sql, String[] columns, String separator, boolean updatePks, + String excludeShardColumn) { + int size = columns.length; + for (int i = 0; i < size; i++) { + if (!updatePks && columns[i].equals(excludeShardColumn)) { + continue; + } + sql.append(" ").append(appendEscape(columns[i])).append(" = ").append("? "); + if (i != size - 1) { + sql.append(separator); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/MysqlSqlTemplate.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/MysqlSqlTemplate.java new file mode 100644 index 0000000000..37b45c746f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/MysqlSqlTemplate.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.template; + +public class MysqlSqlTemplate extends AbstractSqlTemplate { + + private static final String ESCAPE = "`"; + + public String getMergeSql(String schemaName, String tableName, String[] pkNames, String[] columnNames, + String[] viewColumnNames, boolean includePks, String shardColumn) { + StringBuilder sql = new StringBuilder("insert into " + getFullName(schemaName, tableName) + "("); + int size = columnNames.length; + for (int i = 0; i < size; i++) { + sql.append(appendEscape(columnNames[i])).append(" , "); + } + size = pkNames.length; + for (int i = 0; i < size; i++) { + sql.append(appendEscape(pkNames[i])).append((i + 1 < size) ? " , " : ""); + } + + sql.append(") values ("); + size = columnNames.length; + for (int i = 0; i < size; i++) { + sql.append("?").append(" , "); + } + size = pkNames.length; + for (int i = 0; i < size; i++) { + sql.append("?").append((i + 1 < size) ? " , " : ""); + } + sql.append(")"); + sql.append(" on duplicate key update "); + + size = columnNames.length; + for (int i = 0; i < size; i++) { + if (!includePks && columnNames[i].equals(shardColumn)) { + continue; + } + + sql.append(appendEscape(columnNames[i])) + .append("=values(") + .append(appendEscape(columnNames[i])) + .append(")"); + if (includePks) { + sql.append(" , "); + } else { + sql.append((i + 1 < size) ? " , " : ""); + } + } + + if (includePks) { + size = pkNames.length; + for (int i = 0; i < size; i++) { + sql.append(appendEscape(pkNames[i])).append("=values(").append(appendEscape(pkNames[i])).append(")"); + sql.append((i + 1 < size) ? " , " : ""); + } + } + + return sql.toString().intern(); + } + + protected String appendEscape(String columnName) { + return ESCAPE + columnName + ESCAPE; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/SqlTemplate.java b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/SqlTemplate.java new file mode 100644 index 0000000000..5b92cac2eb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/java/org/apache/eventmesh/connector/canal/template/SqlTemplate.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.canal.template; + +/** + * SqlTemplate + */ +public interface SqlTemplate { + + public String getSelectSql(String schemaName, String tableName, String[] pkNames, String[] columnNames); + + public String getUpdateSql(String schemaName, String tableName, String[] pkNames, String[] columnNames, boolean updatePks, String shardColumn); + + public String getDeleteSql(String schemaName, String tableName, String[] pkNames); + + public String getInsertSql(String schemaName, String tableName, String[] pkNames, String[] columnNames); + + public String getMergeSql(String schemaName, String tableName, String[] pkNames, String[] columnNames, + String[] viewColumnNames, boolean updatePks, String shardColumn); +} diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService new file mode 100644 index 0000000000..f55b34d852 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService @@ -0,0 +1,19 @@ +# +# 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. +# + +MySQL-Source=org.apache.eventmesh.connector.canal.source.connector.CanalSourceConnector +MySQL-Sink=org.apache.eventmesh.connector.canal.sink.connector.CanalSinkConnector diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..210361dc28 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSink + appId: 5031 + userName: rocketmqSinkUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSink + nameServer: 127.0.0.1:9876 + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/source-config.yml new file mode 100644 index 0000000000..7a7880b877 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/main/resources/source-config.yml @@ -0,0 +1,40 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: rocketmqSourceUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSource + nameserver: 127.0.0.1:9876 + topic: TopicTest + commitOffsetIntervalMs: 5000 +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with topic + dataId: TopicTest, + #same with group + group: rocketmqSource + } diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-canal/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..210361dc28 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/test/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSink + appId: 5031 + userName: rocketmqSinkUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSink + nameServer: 127.0.0.1:9876 + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-canal/src/test/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-canal/src/test/resources/source-config.yml new file mode 100644 index 0000000000..7a7880b877 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-canal/src/test/resources/source-config.yml @@ -0,0 +1,40 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: rocketmqSourceUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSource + nameserver: 127.0.0.1:9876 + topic: TopicTest + commitOffsetIntervalMs: 5000 +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with topic + dataId: TopicTest, + #same with group + group: rocketmqSource + } diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/build.gradle b/eventmesh-connectors/eventmesh-connector-chatgpt/build.gradle new file mode 100644 index 0000000000..95b80d02e8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/build.gradle @@ -0,0 +1,28 @@ +/* + * 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. + */ + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + implementation 'com.theokanning.openai-gpt3-java:service:0.18.2' + implementation 'io.cloudevents:cloudevents-http-vertx:3.0.0' + implementation 'io.vertx:vertx-web:4.5.8' + + testImplementation "org.apache.httpcomponents:httpclient" + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/gradle.properties b/eventmesh-connectors/eventmesh-connector-chatgpt/gradle.properties new file mode 100644 index 0000000000..715bad3de4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=chatgpt \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/config/ChatGPTServerConfig.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/config/ChatGPTServerConfig.java new file mode 100644 index 0000000000..a8d026067e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/config/ChatGPTServerConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ChatGPTServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/server/ChatGPTConnectServer.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/server/ChatGPTConnectServer.java new file mode 100644 index 0000000000..ca104fe562 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/server/ChatGPTConnectServer.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.server; + +import org.apache.eventmesh.connector.chatgpt.config.ChatGPTServerConfig; +import org.apache.eventmesh.connector.chatgpt.source.connector.ChatGPTSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class ChatGPTConnectServer { + + public static void main(String[] args) throws Exception { + ChatGPTServerConfig serverConfig = ConfigUtil.parse(ChatGPTServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application chatGPTSourceApp = new Application(); + chatGPTSourceApp.run(ChatGPTSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + // TODO support sink connector + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/ChatGPTSourceConfig.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/ChatGPTSourceConfig.java new file mode 100644 index 0000000000..21ddd84dc6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/ChatGPTSourceConfig.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.config; + +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ChatGPTSourceConfig extends SourceConfig { + + public ChatGPTSourceConnectorConfig connectorConfig; + + public OpenaiProxyConfig openaiProxyConfig; + + public OpenaiConfig openaiConfig; + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/ChatGPTSourceConnectorConfig.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/ChatGPTSourceConnectorConfig.java new file mode 100644 index 0000000000..316fb5f241 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/ChatGPTSourceConnectorConfig.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.config; + +import lombok.Data; + +@Data +public class ChatGPTSourceConnectorConfig { + + private String connectorName = "chatgptSource"; + + private String path = "/chatgpt"; + + private int port = 3756; + + private int idleTimeout; + + private boolean proxyEnable = false; + + private String parsePromptFileName = "prompt"; + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/OpenaiConfig.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/OpenaiConfig.java new file mode 100644 index 0000000000..51858a709a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/OpenaiConfig.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.config; + + +import java.util.List; +import java.util.Map; + +import lombok.Data; + +@Data +public class OpenaiConfig { + + private String token; + private String model = "gpt-3.5-turbo"; + private long timeout; + private Double temperature; + private Integer maxTokens; + private Boolean logprob; + private Double topLogprobs; + private Map logitBias; + private Double frequencyPenalty; + private Double presencePenalty; + private String user = "eventMesh"; + private List stop; + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/OpenaiProxyConfig.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/OpenaiProxyConfig.java new file mode 100644 index 0000000000..14dd69f350 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/config/OpenaiProxyConfig.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.config; + +import lombok.Data; + +@Data +public class OpenaiProxyConfig { + + private String host; + + private int port; + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/connector/ChatGPTSourceConnector.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/connector/ChatGPTSourceConnector.java new file mode 100644 index 0000000000..1b6955feb2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/connector/ChatGPTSourceConnector.java @@ -0,0 +1,267 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.connector; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.chatgpt.source.config.ChatGPTSourceConfig; +import org.apache.eventmesh.connector.chatgpt.source.dto.ChatGPTRequestDTO; +import org.apache.eventmesh.connector.chatgpt.source.enums.ChatGPTRequestType; +import org.apache.eventmesh.connector.chatgpt.source.handlers.ChatHandler; +import org.apache.eventmesh.connector.chatgpt.source.handlers.ParseHandler; +import org.apache.eventmesh.connector.chatgpt.source.managers.OpenaiManager; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ChatGPTSourceConnector implements Source { + + private ChatGPTSourceConfig sourceConfig; + private BlockingQueue queue; + private HttpServer server; + private final ExecutorService chatgptSourceExecutorService = + ThreadPoolFactory.createThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, Runtime.getRuntime().availableProcessors() * 2, + "ChatGPTSourceThread"); + + private OpenaiManager openaiManager; + private String parsePromptTemplateStr; + private ChatHandler chatHandler; + private ParseHandler parseHandler; + private static final int DEFAULT_TIMEOUT = 0; + + private static final String APPLICATION_JSON = "application/json"; + private static final String TEXT_PLAIN = "text/plain"; + + private int maxBatchSize; + private long maxPollWaitTime; + + + @Override + public Class configClass() { + return ChatGPTSourceConfig.class; + } + + @Override + public void init(Config config) { + this.sourceConfig = (ChatGPTSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (ChatGPTSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + public void initParsePrompt() { + String parsePromptFileName = sourceConfig.getConnectorConfig().getParsePromptFileName(); + URL resource = Thread.currentThread().getContextClassLoader().getResource(parsePromptFileName); + if (resource == null) { + log.warn("cannot find prompt file {} in resources", parsePromptFileName); + return; + } + String filePath = resource.getPath(); + try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { + StringBuilder builder = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + if (!line.startsWith("#") && StringUtils.isNotBlank(line)) { + builder.append(line).append("\n"); + } + } + this.parsePromptTemplateStr = builder.toString(); + } catch (IOException e) { + throw new IllegalStateException("Unable to read file", e); + } + } + + + @SuppressWarnings("checkstyle:WhitespaceAround") + private void doInit() { + initParsePrompt(); + this.openaiManager = new OpenaiManager(sourceConfig); + this.chatHandler = new ChatHandler(this.openaiManager); + if (StringUtils.isNotEmpty(parsePromptTemplateStr)) { + this.parseHandler = new ParseHandler(openaiManager, parsePromptTemplateStr); + } + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + final Vertx vertx = Vertx.vertx(); + final Router router = Router.router(vertx); + router.route().path(this.sourceConfig.connectorConfig.getPath()).method(HttpMethod.POST).handler(BodyHandler.create()).handler(ctx -> { + try { + RequestBody body = ctx.body(); + ChatGPTRequestDTO bodyObject = body.asPojo(ChatGPTRequestDTO.class); + validateRequestDTO(bodyObject); + handleRequest(bodyObject, ctx); + } catch (Exception e) { + handleError(e, ctx); + } + }); + if (sourceConfig.connectorConfig.getIdleTimeout() < 0) { + log.warn("idleTimeout must be >= 0, your config value is {}, idleTimeout will be reset {}", sourceConfig.connectorConfig.getIdleTimeout(), + DEFAULT_TIMEOUT); + sourceConfig.connectorConfig.setIdleTimeout(DEFAULT_TIMEOUT); + } + this.server = vertx.createHttpServer(new HttpServerOptions().setPort(this.sourceConfig.connectorConfig.getPort()) + .setIdleTimeout(this.sourceConfig.connectorConfig.getIdleTimeout())).requestHandler(router); + } + + + private void validateRequestDTO(ChatGPTRequestDTO bodyObject) { + if (StringUtils.isBlank(bodyObject.getText())) { + throw new IllegalArgumentException("Attributes 'text' cannot be null"); + } + } + + private void handleRequest(ChatGPTRequestDTO bodyObject, RoutingContext ctx) { + chatgptSourceExecutorService.execute(() -> { + try { + ChatGPTRequestType chatgptRequestType = ChatGPTRequestType.valueOf(bodyObject.getRequestType()); + CloudEvent cloudEvent = invokeHandler(chatgptRequestType, bodyObject); + queue.add(cloudEvent); + log.info("[ChatGPTSourceConnector] Succeed to convert payload into CloudEvent."); + ctx.response().setStatusCode(HttpResponseStatus.OK.code()).end(); + } catch (IllegalArgumentException e) { + log.error("[ChatGPTSourceConnector] the request type is illegal: {}", e.getMessage(), e); + ctx.response().setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) + .setStatusMessage(String.format("request type '%s' is not supported", bodyObject.getRequestType())).end(); + } catch (Exception e) { + log.error("[ChatGPTSourceConnector] Error processing request: {}", e.getMessage(), e); + ctx.response().setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()).end(); + } + }); + } + + private CloudEvent invokeHandler(ChatGPTRequestType chatgptRequestType, ChatGPTRequestDTO bodyObject) { + switch (chatgptRequestType) { + case CHAT: + if (StringUtils.isBlank(bodyObject.getDataContentType())) { + bodyObject.setDataContentType(TEXT_PLAIN); + } + return chatHandler.invoke(bodyObject); + case PARSE: + if (StringUtils.isBlank(parsePromptTemplateStr)) { + throw new IllegalStateException( + "the request type of PARSE must be configured with the correct parsePromptFileName in source-config.yml"); + } + if (StringUtils.isBlank(bodyObject.getFields())) { + throw new IllegalStateException("Attributes 'fields' cannot be null in PARSE"); + } + if (StringUtils.isBlank(bodyObject.getDataContentType())) { + bodyObject.setDataContentType(APPLICATION_JSON); + } + return parseHandler.invoke(bodyObject); + default: + throw new IllegalStateException("the request type is illegal"); + } + } + + private void handleError(Exception e, RoutingContext ctx) { + log.error("[ChatGPTSourceConnector] Malformed request.", e); + ctx.response().setStatusCode(HttpResponseStatus.BAD_REQUEST.code()).end(); + } + + @Override + public void start() { + Throwable t = this.server.listen().cause(); + if (t != null) { + throw new EventMeshException("failed to start Vertx server", t); + } + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + Throwable t = this.server.close().cause(); + if (t != null) { + throw new EventMeshException("failed to stop Vertx server", t); + } + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int i = 0; i < maxBatchSize; i++) { + try { + CloudEvent event = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (event == null) { + break; + } + connectRecords.add(CloudEventUtil.convertEventToRecord(event)); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + break; + } + } + return connectRecords; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/dto/ChatGPTRequestDTO.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/dto/ChatGPTRequestDTO.java new file mode 100644 index 0000000000..a203a24e5a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/dto/ChatGPTRequestDTO.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.dto; + +import org.apache.eventmesh.connector.chatgpt.source.enums.ChatGPTRequestType; + +import java.time.ZonedDateTime; +import java.util.UUID; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ChatGPTRequestDTO { + + private String requestType = ChatGPTRequestType.CHAT.name(); + + private String source = "/"; + + private String subject = "chatGPT"; + + @JsonProperty("datacontenttype") + private String dataContentType; + + private String type = "cloudevents"; + + private String text; + + private String fields; + + @JsonInclude + private String id = UUID.randomUUID().toString(); + + @JsonInclude + private String time = ZonedDateTime.now().toOffsetDateTime().toString(); + + public String getFields() { + return fields.replace(";", "\n"); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/enums/ChatGPTRequestType.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/enums/ChatGPTRequestType.java new file mode 100644 index 0000000000..9930525651 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/enums/ChatGPTRequestType.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.enums; + + +public enum ChatGPTRequestType { + + CHAT, PARSE; + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/handlers/ChatHandler.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/handlers/ChatHandler.java new file mode 100644 index 0000000000..6d79a0559f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/handlers/ChatHandler.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.handlers; + + +import org.apache.eventmesh.connector.chatgpt.source.dto.ChatGPTRequestDTO; +import org.apache.eventmesh.connector.chatgpt.source.managers.OpenaiManager; + +import java.net.URI; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.theokanning.openai.completion.chat.ChatCompletionRequest; +import com.theokanning.openai.completion.chat.ChatMessage; +import com.theokanning.openai.completion.chat.ChatMessageRole; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ChatHandler { + + private final OpenaiManager openaiManager; + + public ChatHandler(OpenaiManager openaiManager) { + this.openaiManager = openaiManager; + } + + public CloudEvent invoke(ChatGPTRequestDTO event) { + return genGptConnectRecord(event); + } + + private CloudEvent genGptConnectRecord(ChatGPTRequestDTO event) { + List chatMessages = new ArrayList<>(); + chatMessages.add(new ChatMessage(ChatMessageRole.USER.value(), event.getText())); + ChatCompletionRequest req = openaiManager.newChatCompletionRequest(chatMessages); + String chatResult = openaiManager.getResult(req); + + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create(event.getSource())) + .withType(event.getType()) + .withTime(ZonedDateTime.now().toOffsetDateTime()) + .withData(chatResult.getBytes()) + .withSubject(event.getSubject()) + .withDataContentType(event.getDataContentType()) + .build(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/handlers/ParseHandler.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/handlers/ParseHandler.java new file mode 100644 index 0000000000..aad3d384cf --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/handlers/ParseHandler.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.handlers; + + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.chatgpt.source.dto.ChatGPTRequestDTO; +import org.apache.eventmesh.connector.chatgpt.source.managers.OpenaiManager; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringSubstitutor; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.cloudevents.CloudEvent; +import io.cloudevents.jackson.JsonFormat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.theokanning.openai.completion.chat.ChatCompletionRequest; +import com.theokanning.openai.completion.chat.ChatMessage; +import com.theokanning.openai.completion.chat.ChatMessageRole; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ParseHandler { + + private final OpenaiManager openaiManager; + + private final String promptTemplate; + + private static final JsonFormat jsonFormat = new JsonFormat(false, true); + + + public ParseHandler(OpenaiManager openaiManager, String promptTemplate) { + this.openaiManager = openaiManager; + this.promptTemplate = promptTemplate; + } + + @SuppressWarnings("checkstyle:WhitespaceAfter") + public CloudEvent invoke(ChatGPTRequestDTO event) { + Map map = convertToMap(event); + + StringSubstitutor substitute = new StringSubstitutor(map); + String finalPrompt = substitute.replace(promptTemplate); + List chatMessages = new ArrayList<>(); + chatMessages.add(new ChatMessage(ChatMessageRole.USER.value(), finalPrompt)); + ChatCompletionRequest req = openaiManager.newChatCompletionRequest(chatMessages); + String chatResult = openaiManager.getResult(req); + chatResult = StringUtils.removeFirst(chatResult, "```json"); + chatResult = StringUtils.removeEnd(chatResult, "```"); + CloudEvent cloudEvent; + try { + cloudEvent = jsonFormat.deserialize(chatResult.getBytes(Constants.DEFAULT_CHARSET)); + } catch (Exception e) { + throw new IllegalStateException("cloudEvent parse fail, please check your parse prompt file content", e); + } + return cloudEvent; + } + + public Map convertToMap(Object obj) { + Map map = new HashMap<>(); + Class clazz = obj.getClass(); + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (field.isSynthetic()) { + continue; + } + if (Map.class.isAssignableFrom(field.getType()) || List.class.isAssignableFrom(field.getType())) { + continue; + } + try { + String key = field.getName(); + if (field.isAnnotationPresent(JsonProperty.class)) { + JsonProperty annotation = field.getAnnotation(JsonProperty.class); + key = annotation.value(); + } + Method getter = getGetter(field, clazz); + map.put(key, String.valueOf(getter.invoke(obj))); + } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + throw new IllegalStateException("convert to Map is fail", e); + } + } + + return map; + } + + public Method getGetter(Field field, Class clazz) throws NoSuchMethodException { + boolean isBooleanField = boolean.class.isAssignableFrom(field.getType()) || Boolean.class.isAssignableFrom(field.getType()); + String handledFieldName = upperFirst(field.getName()); + String methodName; + if (isBooleanField) { + methodName = "is" + handledFieldName; + } else { + methodName = "get" + handledFieldName; + } + return clazz.getDeclaredMethod(methodName); + } + + public String upperFirst(String str) { + if (null == str) { + return null; + } + if (!str.isEmpty()) { + char firstChar = str.charAt(0); + if (Character.isLowerCase(firstChar)) { + return Character.toUpperCase(firstChar) + StringUtils.substring(str, 1); + } + } + return str; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/managers/OpenaiManager.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/managers/OpenaiManager.java new file mode 100644 index 0000000000..fda5216bbf --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/java/org/apache/eventmesh/connector/chatgpt/source/managers/OpenaiManager.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.managers; + +import static com.theokanning.openai.service.OpenAiService.defaultClient; +import static com.theokanning.openai.service.OpenAiService.defaultObjectMapper; +import static com.theokanning.openai.service.OpenAiService.defaultRetrofit; + +import org.apache.eventmesh.common.utils.AssertUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.chatgpt.source.config.ChatGPTSourceConfig; +import org.apache.eventmesh.connector.chatgpt.source.config.OpenaiConfig; +import org.apache.eventmesh.connector.chatgpt.source.config.OpenaiProxyConfig; + +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.time.Duration; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.theokanning.openai.client.OpenAiApi; +import com.theokanning.openai.completion.chat.ChatCompletionRequest; +import com.theokanning.openai.completion.chat.ChatCompletionRequest.ChatCompletionRequestBuilder; +import com.theokanning.openai.completion.chat.ChatMessage; +import com.theokanning.openai.service.OpenAiService; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; + + +@Slf4j +public class OpenaiManager { + + @Getter + private OpenAiService openAiService; + + private String chatCompletionRequestTemplateStr; + + private static final int DEFAULT_TIMEOUT = 0; + + public OpenaiManager(ChatGPTSourceConfig sourceConfig) { + initOpenAi(sourceConfig); + } + + public String getResult(ChatCompletionRequest req) { + StringBuilder gptData = new StringBuilder(); + try { + openAiService.createChatCompletion(req).getChoices() + .forEach(chatCompletionChoice -> gptData.append(chatCompletionChoice.getMessage().getContent())); + } catch (Exception e) { + log.error("Failed to generate GPT connection record: {}", e.getMessage()); + } + return gptData.toString(); + } + + public ChatCompletionRequest newChatCompletionRequest(List chatMessages) { + ChatCompletionRequest request = JsonUtils.parseObject(chatCompletionRequestTemplateStr, ChatCompletionRequest.class); + request.setMessages(chatMessages); + return request; + } + + private void initOpenAi(ChatGPTSourceConfig sourceConfig) { + OpenaiConfig openaiConfig = sourceConfig.getOpenaiConfig(); + if (openaiConfig.getTimeout() < 0) { + log.warn("openaiTimeout must be >= 0, your config value is {}, openaiTimeout will be reset {}", openaiConfig.getTimeout(), + DEFAULT_TIMEOUT); + openaiConfig.setTimeout(DEFAULT_TIMEOUT); + } + boolean proxyEnable = sourceConfig.connectorConfig.isProxyEnable(); + if (proxyEnable) { + OpenaiProxyConfig chatgptProxyConfig = sourceConfig.openaiProxyConfig; + if (chatgptProxyConfig.getHost() == null) { + throw new IllegalStateException("chatgpt proxy config 'host' cannot be null"); + } + ObjectMapper mapper = defaultObjectMapper(); + Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(chatgptProxyConfig.getHost(), chatgptProxyConfig.getPort())); + OkHttpClient client = + defaultClient(openaiConfig.getToken(), Duration.ofSeconds(openaiConfig.getTimeout())).newBuilder().proxy(proxy).build(); + Retrofit retrofit = defaultRetrofit(client, mapper); + OpenAiApi api = retrofit.create(OpenAiApi.class); + this.openAiService = new OpenAiService(api); + } else { + this.openAiService = new OpenAiService(openaiConfig.getToken(), Duration.ofSeconds(openaiConfig.getTimeout())); + } + ChatCompletionRequestBuilder builder = ChatCompletionRequest.builder().model(openaiConfig.getModel()); + AssertUtils.notNull(openaiConfig.getModel(), "model cannot be null"); + builder = builder.model(openaiConfig.getModel()); + if (openaiConfig.getUser() != null) { + builder = builder.user(openaiConfig.getUser()); + } + if (openaiConfig.getPresencePenalty() != null) { + builder = builder.presencePenalty(openaiConfig.getPresencePenalty()); + } + if (openaiConfig.getFrequencyPenalty() != null) { + builder = builder.frequencyPenalty(openaiConfig.getFrequencyPenalty()); + } + if (openaiConfig.getMaxTokens() != null) { + builder = builder.maxTokens(openaiConfig.getMaxTokens()); + } + if (openaiConfig.getTemperature() != null) { + builder = builder.temperature(openaiConfig.getTemperature()); + } + if (openaiConfig.getLogitBias() != null && !openaiConfig.getLogitBias().isEmpty()) { + builder = builder.logitBias(openaiConfig.getLogitBias()); + } + if (openaiConfig.getStop() != null && !openaiConfig.getStop().isEmpty()) { + builder = builder.stop(openaiConfig.getStop()); + } + this.chatCompletionRequestTemplateStr = JsonUtils.toJSONString(builder.build()); + } + + +} diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/prompt b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/prompt new file mode 100644 index 0000000000..e10ecc331d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/prompt @@ -0,0 +1,44 @@ +# +# 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. +# + +You are an AI assistant named CloudEventsConverter. avoid escape characters . +Your task is to construct a JSON object in CloudEvents format. Based on the field name and field description in the 'data' field of the CloudEvents formatted JSON object, convert the input text provided by the user into the content of the 'data' field, which must comply with the specifications of the content of the 'datacontenttype' field. +The role is : + - If the 'datacontenttype' field content is 'application/json', then the' data 'field content should be a JSON object, + - else If the 'datacontenttype' field content is not 'application/json' and is 'application/xml', then the' data 'field content should be a string in XML format and the outermost of XML format is , inside is the XML generated by you based on field info; + - else the 'datacontenttype' field content is not 'application/json' and 'application/xml', then the' data 'field content is string of the 'text' field content; +Except for the content of the data field, all other values should be set to and cannot be modified. Finally, return to me the JSON object in CloudEvents format that you constructed + +The following text is the field name and field description in the 'data' field of the CloudEvents-formatted JSON object, extract the following information: + +${fields} + + +text: ${text} + +The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```": +```json +{ + "specversion": string, Set to "1.0" + "type": string, Set to ${type} + "source": string, Set to ${source} + "subject": string, Set to ${subject} + "id": string, Set to ${id} + "time": string, Set to ${time} + "datacontenttype": string, Set to ${datacontenttype} + "data": object or string +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/server-config.yml new file mode 100644 index 0000000000..0cd7b5b5ab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/source-config.yml new file mode 100644 index 0000000000..b194e99ecb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/main/resources/source-config.yml @@ -0,0 +1,51 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: chatgptSource + appId: 5032 + userName: chatgptSourceUser + passWord: chatgptPassWord +connectorConfig: + connectorName: chatgptSource + path: /chatgpt + port: 3756 + idleTimeout: 0 + proxyEnable: false + parsePromptFileName: prompt + +# https://platform.openai.com/docs/api-reference/chat/create +openaiConfig: + token: + model: gpt-3.5-turbo + timeout: 0 + temperature: 1 + maxTokens: + frequencyPenalty: 0 + presencePenalty: 0 + user: eventMesh + stop: [] + logitBias: {} + +openaiProxyConfig: + host: 127.0.0.1 + port: 7890 + diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/java/org/apache/eventmesh/connector/chatgpt/source/connector/ChatGPTSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/java/org/apache/eventmesh/connector/chatgpt/source/connector/ChatGPTSourceConnectorTest.java new file mode 100644 index 0000000000..8347fdcbb1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/java/org/apache/eventmesh/connector/chatgpt/source/connector/ChatGPTSourceConnectorTest.java @@ -0,0 +1,166 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.chatgpt.source.connector; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.chatgpt.source.config.ChatGPTSourceConfig; +import org.apache.eventmesh.connector.chatgpt.source.config.ChatGPTSourceConnectorConfig; +import org.apache.eventmesh.connector.chatgpt.source.config.OpenaiConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import java.util.List; + +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +class ChatGPTSourceConnectorTest { + + private static final Logger LOGGER = LoggerFactory.getLogger("ChatGPTSourceConnectorTest"); + + private ChatGPTSourceConnector connector; + private ChatGPTSourceConnectorConfig config; + private CloseableHttpClient httpClient; + private String uri; + private final String expectedMessage = "Hello, can you tell me a story."; + + private final String expectedParseMessage = "User 13356288979 from Tianjin store placed an order with order number 11221122"; + + + public boolean checkOpenAi() throws Exception { + ChatGPTSourceConfig sourceConfig = (ChatGPTSourceConfig) ConfigUtil.parse(connector.configClass()); + OpenaiConfig openaiConfig = sourceConfig.getOpenaiConfig(); + if (StringUtils.isBlank(openaiConfig.getToken())) { + return false; + } + return true; + } + + @BeforeEach + void setUp() throws Exception { + connector = new ChatGPTSourceConnector(); + if (!checkOpenAi()) { + LOGGER.error("please set openai token in the config"); + return; + } + ChatGPTSourceConfig sourceConfig = (ChatGPTSourceConfig) ConfigUtil.parse(connector.configClass()); + config = sourceConfig.getConnectorConfig(); + connector.init(sourceConfig); + connector.start(); + + uri = new URIBuilder().setScheme("http").setHost("127.0.0.1").setPort(config.getPort()).setPath(config.getPath()).build().toString(); + + httpClient = HttpClients.createDefault(); + } + + @Test + void testPoll() throws Exception { + ChatGPTSourceConfig sourceConfig = (ChatGPTSourceConfig) ConfigUtil.parse(connector.configClass()); + OpenaiConfig openaiConfig = sourceConfig.getOpenaiConfig(); + if (StringUtils.isBlank(openaiConfig.getToken())) { + LOGGER.error("please set openai token in the config"); + return; + } + + final int batchSize = 10; + + for (int i = 0; i < batchSize; i++) { + HttpResponse resp = mockStructuredChatRequest(); + Assertions.assertEquals(resp.getStatusLine().getStatusCode(), HttpStatus.SC_OK); + } + + List res = connector.poll(); + Assertions.assertEquals(batchSize, res.size()); + + for (int i = 0; i < batchSize; i++) { + HttpResponse resp = mockStructuredParseRequest(); + Assertions.assertEquals(resp.getStatusLine().getStatusCode(), HttpStatus.SC_OK); + } + + List res1 = connector.poll(); + Assertions.assertEquals(batchSize, res1.size()); + } + + + HttpResponse mockStructuredChatRequest() throws Exception { + TestEvent event = new TestEvent(); + event.type = "com.example.someevent"; + event.source = "/mycontext"; + event.subject = "test"; + event.datacontenttype = "text/plain"; + event.text = expectedMessage; + event.requestType = "CHAT"; + HttpPost httpPost = new HttpPost(uri); + httpPost.setEntity(new StringEntity(JsonUtils.toJSONString(event))); + + return httpClient.execute(httpPost); + } + + + HttpResponse mockStructuredParseRequest() throws Exception { + TestEvent event = new TestEvent(); + event.type = "com.example.someevent"; + event.source = "/mycontext"; + event.subject = "test"; + event.datacontenttype = "application/json"; + event.text = expectedParseMessage; + event.requestType = "PARSE"; + event.fields = "orderNo:this is order number;address:this is a address;phone:this is phone number"; + HttpPost httpPost = new HttpPost(uri); + httpPost.setEntity(new StringEntity(JsonUtils.toJSONString(event))); + return httpClient.execute(httpPost); + } + + @AfterEach + void tearDown() throws Exception { + if (!checkOpenAi()) { + return; + } + if (connector != null) { + connector.stop(); + } + if (httpClient != null) { + httpClient.close(); + } + } + + class TestEvent { + + public String requestType; + public String type; + public String source; + public String subject; + public String datacontenttype; + public String text; + public String fields; + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/resources/server-config.yml new file mode 100644 index 0000000000..0cd7b5b5ab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false diff --git a/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/resources/source-config.yml new file mode 100644 index 0000000000..47f25edbb2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-chatgpt/src/test/resources/source-config.yml @@ -0,0 +1,52 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: chatgptSource + appId: 5032 + userName: chatgptSourceUser + passWord: chatgptPassWord +connectorConfig: + connectorName: chatgptSource + path: /chatgpt + port: 3756 + idleTimeout: 0 + proxyEnable: true + parsePromptFileName: prompt + +# https://platform.openai.com/docs/api-reference/chat/create +openaiConfig: + token: + model: gpt-3.5-turbo + timeout: 0 + temperature: 1 + maxTokens: + frequencyPenalty: 0 + presencePenalty: 0 + user: eventMesh + stop: [] + logitBias: { + + } + +openaiProxyConfig: + host: 127.0.0.1 + port: 7890 diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/build.gradle b/eventmesh-connectors/eventmesh-connector-dingtalk/build.gradle new file mode 100644 index 0000000000..dfe1a40e95 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/build.gradle @@ -0,0 +1,36 @@ +/* + * 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. + */ + +configurations { + implementation.exclude group: 'ch.qos.logback', module: 'logback-classic' + implementation.exclude group: 'log4j', module: 'log4j' + testImplementation.exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j' +} + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation "com.aliyun:dingtalk:2.1.27" + implementation 'com.google.guava:guava' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/gradle.properties b/eventmesh-connectors/eventmesh-connector-dingtalk/gradle.properties new file mode 100644 index 0000000000..be63fc4f95 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=dingtalk \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/common/constants/ConnectRecordExtensionKeys.java b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/common/constants/ConnectRecordExtensionKeys.java new file mode 100644 index 0000000000..bb6292134b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/common/constants/ConnectRecordExtensionKeys.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.dingtalk.common.constants; + +/** + * Constants of record extension key. + */ +public interface ConnectRecordExtensionKeys { + + String DINGTALK_TEMPLATE_TYPE = "dingtalktemplatetype"; + + String DINGTALK_MARKDOWN_MESSAGE_TITLE = "dingtalkmarkdownmessagetitle"; +} diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/config/DingDingConnectServerConfig.java b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/config/DingDingConnectServerConfig.java new file mode 100644 index 0000000000..d9657bc23b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/config/DingDingConnectServerConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.dingtalk.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class DingDingConnectServerConfig extends Config { + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/config/DingDingMessageTemplateType.java b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/config/DingDingMessageTemplateType.java new file mode 100644 index 0000000000..5c26066869 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/config/DingDingMessageTemplateType.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.dingtalk.config; + +import java.util.Arrays; + +public enum DingDingMessageTemplateType { + + PLAIN_TEXT("text", "sampleText"), + MARKDOWN("markdown", "sampleMarkdown"); + + private final String templateType; + + private final String templateKey; + + DingDingMessageTemplateType(String templateType, String templateKey) { + this.templateType = templateType; + this.templateKey = templateKey; + } + + public String getTemplateType() { + return templateType; + } + + public String getTemplateKey() { + return templateKey; + } + + public static DingDingMessageTemplateType of(String templateType) { + return Arrays.stream(values()) + .filter(v -> v.getTemplateType().equals(templateType)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("TemplateType: " + templateType + " not found.")); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/server/DingDingConnectServer.java b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/server/DingDingConnectServer.java new file mode 100644 index 0000000000..a7ea6fad0b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/server/DingDingConnectServer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.dingtalk.server; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.dingtalk.config.DingDingConnectServerConfig; +import org.apache.eventmesh.connector.dingtalk.sink.connector.DingDingSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class DingDingConnectServer { + + public static void main(String[] args) throws Exception { + + DingDingConnectServerConfig dingDingConnectServerConfig = ConfigUtil.parse(DingDingConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (dingDingConnectServerConfig.isSinkEnable()) { + Application application = new Application(); + application.run(DingDingSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/sink/connector/DingDingSinkConnector.java b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/sink/connector/DingDingSinkConnector.java new file mode 100644 index 0000000000..8c5a1e6611 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/java/org/apache/eventmesh/connector/dingtalk/sink/connector/DingDingSinkConnector.java @@ -0,0 +1,198 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.dingtalk.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.dingtalk.DingDingSinkConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.dingtalk.common.constants.ConnectRecordExtensionKeys; +import org.apache.eventmesh.connector.dingtalk.config.DingDingMessageTemplateType; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest; +import com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendHeaders; +import com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendRequest; +import com.aliyun.tea.TeaException; +import com.aliyun.teautil.Common; +import com.aliyun.teautil.models.RuntimeOptions; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DingDingSinkConnector implements Sink { + + public static final Cache AUTH_CACHE = CacheBuilder.newBuilder() + .initialCapacity(12) + .maximumSize(10) + .concurrencyLevel(5) + .expireAfterWrite(20, TimeUnit.MINUTES) + .build(); + + public static final String ACCESS_TOKEN_CACHE_KEY = "access_token"; + + private DingDingSinkConfig sinkConfig; + + private com.aliyun.dingtalkrobot_1_0.Client sendMessageClient; + + private com.aliyun.dingtalkoauth2_1_0.Client authClient; + + private volatile boolean isRunning = false; + + @Override + public Class configClass() { + return DingDingSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for dingding sink connector + this.sinkConfig = (DingDingSinkConfig) config; + sendMessageClient = createSendMessageClient(); + authClient = createOAuthClient(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for dingding source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (DingDingSinkConfig) sinkConnectorContext.getSinkConfig(); + sendMessageClient = createSendMessageClient(); + authClient = createOAuthClient(); + } + + @Override + public void start() { + isRunning = true; + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + + @SneakyThrows + @Override + public void put(List sinkRecords) { + for (ConnectRecord record : sinkRecords) { + try { + if (Objects.isNull(record.getData())) { + log.warn("ConnectRecord data is null, ignore."); + continue; + } + String accessToken = getAccessToken(); + OrgGroupSendHeaders orgGroupSendHeaders = + new OrgGroupSendHeaders(); + orgGroupSendHeaders.xAcsDingtalkAccessToken = accessToken; + + String templateTypeKey = record.getExtension(ConnectRecordExtensionKeys.DINGTALK_TEMPLATE_TYPE); + if (templateTypeKey == null || "null".equals(templateTypeKey)) { + templateTypeKey = DingDingMessageTemplateType.PLAIN_TEXT.getTemplateType(); + } + DingDingMessageTemplateType templateType = DingDingMessageTemplateType.of(templateTypeKey); + + Map contentMap = new HashMap<>(); + if (DingDingMessageTemplateType.PLAIN_TEXT == templateType) { + contentMap.put("content", new String((byte[]) record.getData())); + } else if (DingDingMessageTemplateType.MARKDOWN == templateType) { + String title = Optional.ofNullable(record.getExtension(ConnectRecordExtensionKeys.DINGTALK_MARKDOWN_MESSAGE_TITLE)) + .orElse("EventMesh-Message"); + contentMap.put("title", title); + contentMap.put("text", new String((byte[]) record.getData())); + } + + OrgGroupSendRequest orgGroupSendRequest = + new OrgGroupSendRequest() + .setMsgParam(JsonUtils.toJSONString(contentMap)) + .setMsgKey(templateType.getTemplateKey()) + .setOpenConversationId(sinkConfig.getSinkConnectorConfig().getOpenConversationId()) + .setRobotCode(sinkConfig.getSinkConnectorConfig().getRobotCode()) + .setCoolAppCode(sinkConfig.getSinkConnectorConfig().getCoolAppCode()); + + try { + sendMessageClient.orgGroupSendWithOptions(orgGroupSendRequest, orgGroupSendHeaders, new RuntimeOptions()); + } catch (TeaException e) { + if (!Common.empty(e.code) && !Common.empty(e.message)) { + String errorMessage = e.getMessage(); + if ("invalidParameter.token.invalid".equals(errorMessage)) { + AUTH_CACHE.invalidate(ACCESS_TOKEN_CACHE_KEY); + } + } + } + } catch (Exception e) { + log.error("Failed to sink message to DingDing.", e); + } + } + } + + @SneakyThrows + private String getAccessToken() { + return AUTH_CACHE.get(ACCESS_TOKEN_CACHE_KEY, () -> { + GetAccessTokenRequest getAccessTokenRequest = + new GetAccessTokenRequest() + .setAppKey(sinkConfig.getSinkConnectorConfig().getAppKey()) + .setAppSecret(sinkConfig.getSinkConnectorConfig().getAppSecret()); + return authClient.getAccessToken(getAccessTokenRequest).getBody().getAccessToken(); + }); + } + + public static com.aliyun.dingtalkrobot_1_0.Client createSendMessageClient() throws Exception { + com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); + config.protocol = "https"; + config.regionId = "central"; + return new com.aliyun.dingtalkrobot_1_0.Client(config); + } + + public static com.aliyun.dingtalkoauth2_1_0.Client createOAuthClient() throws Exception { + com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); + config.protocol = "https"; + config.regionId = "central"; + return new com.aliyun.dingtalkoauth2_1_0.Client(config); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..551013beb6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/main/resources/sink-config.yml @@ -0,0 +1,32 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-DINGTALK + idc: FT + env: PRD + group: dingTalkSink + appId: 5034 + userName: dingTalkSinkUser + passWord: dingTalkPassWord +sinkConnectorConfig: + connectorName: dingTalkSink + appKey: dingTalkAppKey + appSecret: dingTalkAppSecret + openConversationId: dingTalkOpenConversationId + robotCode: dingTalkRobotCode diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/java/org/apache/eventmesh/connector/dingtalk/sink/connector/DingDingSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/java/org/apache/eventmesh/connector/dingtalk/sink/connector/DingDingSinkConnectorTest.java new file mode 100644 index 0000000000..736137629d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/java/org/apache/eventmesh/connector/dingtalk/sink/connector/DingDingSinkConnectorTest.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.dingtalk.sink.connector; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.apache.eventmesh.common.config.connector.dingtalk.DingDingSinkConfig; +import org.apache.eventmesh.connector.dingtalk.common.constants.ConnectRecordExtensionKeys; +import org.apache.eventmesh.connector.dingtalk.config.DingDingMessageTemplateType; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +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 org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse; +import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponseBody; + +@ExtendWith(MockitoExtension.class) +public class DingDingSinkConnectorTest { + + @Spy + private DingDingSinkConnector connector; + + @Mock + private com.aliyun.dingtalkrobot_1_0.Client sendMessageClient; + + @Mock + private com.aliyun.dingtalkoauth2_1_0.Client authClient; + + @BeforeEach + public void setUp() throws Exception { + Mockito.doReturn(null).when(sendMessageClient) + .orgGroupSendWithOptions(Mockito.any(), Mockito.any(), Mockito.any()); + GetAccessTokenResponse response = new GetAccessTokenResponse(); + GetAccessTokenResponseBody body = new GetAccessTokenResponseBody(); + body.setAccessToken("testAccessToken"); + response.setBody(body); + Mockito.doReturn(response).when(authClient).getAccessToken(Mockito.any()); + + DingDingSinkConfig sinkConfig = (DingDingSinkConfig) ConfigUtil.parse(connector.configClass()); + connector.init(sinkConfig); + Field sendMessageClientField = ReflectionSupport.findFields(connector.getClass(), + (f) -> f.getName().equals("sendMessageClient"), + HierarchyTraversalMode.BOTTOM_UP).get(0); + Field authClientField = ReflectionSupport.findFields(connector.getClass(), + (f) -> f.getName().equals("authClient"), + HierarchyTraversalMode.BOTTOM_UP).get(0); + sendMessageClientField.setAccessible(true); + authClientField.setAccessible(true); + sendMessageClientField.set(connector, sendMessageClient); + authClientField.set(connector, authClient); + connector.start(); + } + + @Test + public void testSendMessageToDingDing() throws Exception { + final int times = 3; + List records = new ArrayList<>(); + for (int i = 0; i < times; i++) { + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "Hello, EventMesh!".getBytes(StandardCharsets.UTF_8)); + connectRecord.addExtension(ConnectRecordExtensionKeys.DINGTALK_TEMPLATE_TYPE, + DingDingMessageTemplateType.PLAIN_TEXT.getTemplateType()); + records.add(connectRecord); + } + connector.put(records); + verify(sendMessageClient, times(times)).orgGroupSendWithOptions(any(), any(), any()); + // verify for access token cache. + verify(authClient, times(1)).getAccessToken(any()); + } + + @AfterEach + public void tearDown() { + DingDingSinkConnector.AUTH_CACHE.invalidate(DingDingSinkConnector.ACCESS_TOKEN_CACHE_KEY); + connector.stop(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..53f4a24da6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-dingtalk/src/test/resources/sink-config.yml @@ -0,0 +1,32 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-DINGDING + idc: FT + env: PRD + group: dingDingSink + appId: 5034 + userName: dingDingSinkUser + passWord: dingDingPassWord +sinkConnectorConfig: + connectorName: dingDingSink + appKey: dingDingAppKey + appSecret: dingDingAppSecret + openConversationId: dingDingOpenConversationId + robotCode: dingDingRobotCode \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-file/build.gradle b/eventmesh-connectors/eventmesh-connector-file/build.gradle new file mode 100644 index 0000000000..ea441248b8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/build.gradle @@ -0,0 +1,25 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.mockito:mockito-junit-jupiter' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-file/gradle.properties b/eventmesh-connectors/eventmesh-connector-file/gradle.properties new file mode 100644 index 0000000000..1820ec46fa --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=file \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/config/FileServerConfig.java b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/config/FileServerConfig.java new file mode 100644 index 0000000000..ad25b8a410 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/config/FileServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.file.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class FileServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/server/FileConnectServer.java b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/server/FileConnectServer.java new file mode 100644 index 0000000000..ac52432701 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/server/FileConnectServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.file.server; + +import org.apache.eventmesh.connector.file.config.FileServerConfig; +import org.apache.eventmesh.connector.file.sink.connector.FileSinkConnector; +import org.apache.eventmesh.connector.file.source.connector.FileSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FileConnectServer { + + public static void main(String[] args) throws Exception { + + FileServerConfig serverConfig = ConfigUtil.parse(FileServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application fileSourceApp = new Application(); + fileSourceApp.run(FileSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application fileSinkApp = new Application(); + fileSinkApp.run(FileSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/sink/connector/FileSinkConnector.java b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/sink/connector/FileSinkConnector.java new file mode 100644 index 0000000000..fabae0d43a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/sink/connector/FileSinkConnector.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.file.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.file.FileSinkConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicInteger; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FileSinkConnector implements Sink { + + private static final AtomicInteger fileSize = new AtomicInteger(0); + + private String filePath; + + private String fileName; + + private int flushSize; + + private boolean hourlyFlushEnabled; + + private FileSinkConfig sinkConfig; + + private PrintStream outputStream; + + @Override + public Class configClass() { + return FileSinkConfig.class; + } + + @Override + public void init(Config config) { + // init config for hdfs source connector + this.sinkConfig = (FileSinkConfig) config; + this.filePath = buildFilePath(); + this.fileName = buildFileName(); + this.flushSize = sinkConfig.getFlushSize(); + this.hourlyFlushEnabled = sinkConfig.isHourlyFlushEnabled(); + } + + @Override + public void init(ConnectorContext connectorContext) { + // init config for hdfs source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (FileSinkConfig) sinkConnectorContext.getSinkConfig(); + this.fileName = buildFileName(); + this.filePath = buildFilePath(); + this.flushSize = sinkConfig.getFlushSize(); + this.hourlyFlushEnabled = sinkConfig.isHourlyFlushEnabled(); + } + + @Override + public void start() throws Exception { + if (fileName == null || fileName.length() == 0 || filePath == null || filePath.length() == 0) { + this.outputStream = System.out; + } else { + this.outputStream = + new PrintStream(Files.newOutputStream(Paths.get(filePath + fileName), StandardOpenOption.CREATE, StandardOpenOption.APPEND), + false, StandardCharsets.UTF_8.name()); + } + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + outputStream.flush(); + outputStream.close(); + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + // the file data exceed the flushSize create the new file or + // hourlyFlushEnabled && time on the hour + if (fileSize.get() >= flushSize || (hourlyFlushEnabled && LocalDateTime.now().getHour() == 0)) { + log.info("flush the file and open"); + outputStream.flush(); + outputStream.close(); + try { + fileSize.set(0); + this.outputStream = openWithNewFile(); + } catch (IOException e) { + log.error("create file under path {} error", filePath); + throw new RuntimeException(e); + } + } + outputStream.println(new String((byte[]) connectRecord.getData(), StandardCharsets.UTF_8)); + fileSize.addAndGet(1); + } + } + + private String buildFilePath() { + Calendar calendar = Calendar.getInstance(Locale.CHINA); + int year = calendar.get(Calendar.YEAR); + int month = calendar.get(Calendar.MONTH) + 1; + int day = calendar.get(Calendar.DATE); + String filePath = sinkConfig.getConnectorConfig().getTopic() + + File.separator + year + File.separator + month + File.separator + day + File.separator; + File path = new File(filePath); + if (!path.exists()) { + if (!path.mkdirs()) { + log.error("make file dir {} error", filePath); + } + } + return filePath; + } + + private String buildFileName() { + Calendar calendar = Calendar.getInstance(Locale.CHINA); + long currentTime = calendar.getTime().getTime(); + return sinkConfig.getConnectorConfig().getTopic() + "-" + calendar.get(Calendar.HOUR_OF_DAY) + "-" + currentTime; + } + + private PrintStream openWithNewFile() throws IOException { + this.filePath = buildFilePath(); + this.fileName = buildFileName(); + if (fileName.length() == 0 || filePath == null || filePath.length() == 0) { + return System.out; + } + return new PrintStream(Files.newOutputStream(Paths.get(filePath + fileName), + StandardOpenOption.CREATE, StandardOpenOption.APPEND), + false, StandardCharsets.UTF_8.name()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/source/connector/FileSourceConnector.java b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/source/connector/FileSourceConnector.java new file mode 100644 index 0000000000..68b1a50989 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/java/org/apache/eventmesh/connector/file/source/connector/FileSourceConnector.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.file.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.file.FileSourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.file.FileRecordPartition; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FileSourceConnector implements Source { + private static final int BUFFER_SIZE = 8192; + private FileSourceConfig sourceConfig; + private String filePath; + private String fileName; + private BufferedReader bufferedReader; + + @Override + public Class configClass() { + return FileSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for hdfs source connector + this.sourceConfig = (FileSourceConfig) config; + this.filePath = ((FileSourceConfig) config).getConnectorConfig().getFilePath(); + this.fileName = getFileName(filePath); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (FileSourceConfig) sourceConnectorContext.getSourceConfig(); + } + + @Override + public void start() throws Exception { + if (filePath == null || filePath.isEmpty()) { + this.bufferedReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); + } else { + Path path = Paths.get(filePath); + this.bufferedReader = new BufferedReader(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8), BUFFER_SIZE); + } + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + try { + if (bufferedReader != null) { + bufferedReader.close(); + } + } catch (Exception e) { + log.error("Error closing resources: {}", e.getMessage()); + } + } + + @Override + public List poll() { + List connectRecords = new ArrayList<>(); + RecordPartition recordPartition = convertToRecordPartition(fileName); + try { + int bytesRead; + char[] buffer = new char[BUFFER_SIZE]; + while ((bytesRead = bufferedReader.read(buffer)) != -1) { + String line = new String(buffer, 0, bytesRead); + long timeStamp = System.currentTimeMillis(); + ConnectRecord connectRecord = new ConnectRecord(recordPartition, null, timeStamp, line); + connectRecords.add(connectRecord); + } + } catch (IOException e) { + log.error("Error reading data from the file: {}", e.getMessage()); + } + return connectRecords; + } + + public static RecordPartition convertToRecordPartition(String fileName) { + FileRecordPartition fileRecordPartition = new FileRecordPartition(); + fileRecordPartition.setFileName(fileName); + return fileRecordPartition; + } + + private static String getFileName(String filePath) throws NullPointerException { + File file = new File(filePath); + return file.getName(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-file/src/main/resources/server-config.yml new file mode 100644 index 0000000000..d9416e1ed2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: false +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-file/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..03789687ed --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/resources/sink-config.yml @@ -0,0 +1,29 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: fileSink + appId: 5031 + userName: fileSinkUser + passWord: filePassWord +connectorConfig: + connectorName: fileSink + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-file/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-file/src/main/resources/source-config.yml new file mode 100644 index 0000000000..9dd5dc0e56 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/main/resources/source-config.yml @@ -0,0 +1,29 @@ +# +# 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. +# +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: fileSource + appId: 5032 + userName: fileSourceUser + passWord: filePassWord +connectorConfig: + connectorName: fileSource + filePath: userFilePath + diff --git a/eventmesh-connectors/eventmesh-connector-file/src/test/java/org/apache/eventmesh/connector/file/sink/connector/FileSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-file/src/test/java/org/apache/eventmesh/connector/file/sink/connector/FileSinkConnectorTest.java new file mode 100644 index 0000000000..281d31f043 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/test/java/org/apache/eventmesh/connector/file/sink/connector/FileSinkConnectorTest.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.file.sink.connector; + + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.common.config.connector.file.FileSinkConfig; +import org.apache.eventmesh.common.config.connector.file.SinkConnectorConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + + +public class FileSinkConnectorTest { + + private FileSinkConnector fileSinkConnector; + + @Mock + private FileSinkConfig fileSinkConfig; + + @Test + void testFileSinkConnector() throws Exception { + + fileSinkConfig = mock(FileSinkConfig.class); + SinkConnectorConfig connectorConfig = mock(SinkConnectorConfig.class); + when(fileSinkConfig.getConnectorConfig()).thenReturn(connectorConfig); + when(connectorConfig.getTopic()).thenReturn("test-topic"); + when(fileSinkConfig.getFlushSize()).thenReturn(10); + when(fileSinkConfig.isHourlyFlushEnabled()).thenReturn(false); + + fileSinkConnector = new FileSinkConnector(); + fileSinkConnector.init(fileSinkConfig); + fileSinkConnector.start(); + + String content = "line1\nline2\nline3"; + ConnectRecord record = new ConnectRecord(null, null, System.currentTimeMillis(), content.getBytes(StandardCharsets.UTF_8)); + List connectRecords = Collections.singletonList(record); + fileSinkConnector.put(connectRecords); + fileSinkConnector.stop(); + + Calendar calendar = Calendar.getInstance(Locale.CHINA); + int year = calendar.get(Calendar.YEAR); + int month = calendar.get(Calendar.MONTH) + 1; + int day = calendar.get(Calendar.DATE); + Path topicPath = Paths.get("test-topic", + String.valueOf(year), + String.valueOf(month), + String.valueOf(day)); + Assertions.assertTrue(Files.exists(topicPath), "Directory for topic should exist"); + + Path outputPath = Files.list(topicPath) + .filter(path -> path.toString().contains("test-topic")) + .findFirst() + .orElseThrow(() -> new RuntimeException("No output file found with 'test-topic' in the name")); + + List lines = Files.readAllLines(outputPath, StandardCharsets.UTF_8); + String actualContent = String.join("\n", lines); + Assertions.assertEquals(content, actualContent); + + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-file/src/test/java/org/apache/eventmesh/connector/file/source/connector/FileSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-file/src/test/java/org/apache/eventmesh/connector/file/source/connector/FileSourceConnectorTest.java new file mode 100644 index 0000000000..5c36a95d5d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-file/src/test/java/org/apache/eventmesh/connector/file/source/connector/FileSourceConnectorTest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.file.source.connector; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.common.config.connector.file.FileSourceConfig; +import org.apache.eventmesh.common.config.connector.file.SourceConnectorConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +class FileSourceConnectorTest { + + private FileSourceConnector fileSourceConnector; + @Mock + private FileSourceConfig fileSourceConfig; + + @Test + void testFileSourceConnector() throws Exception { + String directoryPath = "d/g/"; + Path directory = Paths.get(directoryPath); + Files.createDirectories(directory); + Path newFilePath = directory.resolve("foo.txt"); + Files.createFile(newFilePath); + fileSourceConfig = mock(FileSourceConfig.class); + SourceConnectorConfig connectorConfig = mock(SourceConnectorConfig.class); + when(fileSourceConfig.getConnectorConfig()).thenReturn(connectorConfig); + when(fileSourceConfig.getConnectorConfig().getFilePath()).thenReturn("d/g/foo.txt"); + String filePath = fileSourceConfig.getConnectorConfig().getFilePath(); + Path mockPath = Paths.get(filePath); + String content = "line1\nline2\nline3"; + byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8); + Files.write(mockPath, contentBytes); + fileSourceConnector = new FileSourceConnector(); + fileSourceConnector.init(fileSourceConfig); + fileSourceConnector.start(); + List connectRecords = fileSourceConnector.poll(); + fileSourceConnector.stop(); + Files.delete(newFilePath); + Assertions.assertEquals(content, connectRecords.get(0).getData().toString()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/build.gradle b/eventmesh-connectors/eventmesh-connector-http/build.gradle new file mode 100644 index 0000000000..48c7aecd06 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + + implementation 'io.cloudevents:cloudevents-http-vertx:3.0.0' + implementation 'io.vertx:vertx-web:4.5.8' + implementation 'io.vertx:vertx-web-client:4.5.9' + implementation 'dev.failsafe:failsafe:3.3.2' + + + testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.4' + testImplementation 'org.apache.httpcomponents.client5:httpclient5-fluent:5.4' + testImplementation 'org.mock-server:mockserver-netty:5.15.0' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-http/gradle.properties b/eventmesh-connectors/eventmesh-connector-http/gradle.properties new file mode 100644 index 0000000000..cc0e7324ca --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=http \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/common/SynchronizedCircularFifoQueue.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/common/SynchronizedCircularFifoQueue.java new file mode 100644 index 0000000000..0564e58734 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/common/SynchronizedCircularFifoQueue.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.common; + +import org.apache.commons.collections4.queue.CircularFifoQueue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + + +/** + * SynchronizedCircularFifoQueue is a synchronized version of CircularFifoQueue. + */ +public class SynchronizedCircularFifoQueue extends CircularFifoQueue { + + /** + *

Default constructor. capacity = 32

+ */ + public SynchronizedCircularFifoQueue() { + super(); + } + + public SynchronizedCircularFifoQueue(Collection coll) { + super(coll); + } + + public SynchronizedCircularFifoQueue(int size) { + super(size); + } + + @Override + public synchronized boolean add(E element) { + return super.add(element); + } + + @Override + public synchronized void clear() { + super.clear(); + } + + @Override + public synchronized E element() { + return super.element(); + } + + @Override + public synchronized E get(int index) { + return super.get(index); + } + + @Override + public synchronized boolean isAtFullCapacity() { + return super.isAtFullCapacity(); + } + + @Override + public synchronized boolean isEmpty() { + return super.isEmpty(); + } + + @Override + public synchronized boolean isFull() { + return super.isFull(); + } + + @Override + public synchronized int maxSize() { + return super.maxSize(); + } + + @Override + public synchronized boolean offer(E element) { + return super.offer(element); + } + + @Override + public synchronized E peek() { + return super.peek(); + } + + @Override + public synchronized E poll() { + return super.poll(); + } + + @Override + public synchronized E remove() { + return super.remove(); + } + + @Override + public synchronized int size() { + return super.size(); + } + + /** + *

Fetch a range of elements from the queue.

+ * + * @param start start index + * @param end end index + * @param removed whether to remove the elements from the queue + * @return list of elements + */ + public synchronized List fetchRange(int start, int end, boolean removed) { + + if (start < 0 || start > end) { + throw new IllegalArgumentException("Invalid range"); + } + end = Math.min(end, this.size()); + + Iterator iterator = this.iterator(); + List items = new ArrayList<>(end - start); + + int count = 0; + while (iterator.hasNext() && count < end) { + E item = iterator.next(); + if (item != null && count >= start) { + // Add the element to the list + items.add(item); + if (removed) { + // Remove the element from the queue + iterator.remove(); + } + } + count++; + } + return items; + + } + + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/config/HttpServerConfig.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/config/HttpServerConfig.java new file mode 100644 index 0000000000..8517b869fd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/config/HttpServerConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HttpServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/server/HttpConnectServer.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/server/HttpConnectServer.java new file mode 100644 index 0000000000..dbe0838bc8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/server/HttpConnectServer.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.server; + +import org.apache.eventmesh.connector.http.config.HttpServerConfig; +import org.apache.eventmesh.connector.http.sink.HttpSinkConnector; +import org.apache.eventmesh.connector.http.source.HttpSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class HttpConnectServer { + + public static void main(String[] args) throws Exception { + HttpServerConfig serverConfig = ConfigUtil.parse(HttpServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application httpSourceApp = new Application(); + httpSourceApp.run(HttpSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application httpSinkApp = new Application(); + httpSinkApp.run(HttpSinkConnector.class); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/HttpSinkConnector.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/HttpSinkConnector.java new file mode 100644 index 0000000000..8e808ccc93 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/HttpSinkConnector.java @@ -0,0 +1,175 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.http.HttpSinkConfig; +import org.apache.eventmesh.common.config.connector.http.SinkConnectorConfig; +import org.apache.eventmesh.connector.http.sink.handler.HttpSinkHandler; +import org.apache.eventmesh.connector.http.sink.handler.impl.CommonHttpSinkHandler; +import org.apache.eventmesh.connector.http.sink.handler.impl.HttpSinkHandlerRetryWrapper; +import org.apache.eventmesh.connector.http.sink.handler.impl.WebhookHttpSinkHandler; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpSinkConnector implements Sink, ConnectorCreateService { + + private HttpSinkConfig httpSinkConfig; + + @Getter + private HttpSinkHandler sinkHandler; + + private ThreadPoolExecutor executor; + + private final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(10000); + + private final AtomicBoolean isStart = new AtomicBoolean(true); + + @Override + public Class configClass() { + return HttpSinkConfig.class; + } + + @Override + public Sink create() { + return new HttpSinkConnector(); + } + + @Override + public void init(Config config) throws Exception { + this.httpSinkConfig = (HttpSinkConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.httpSinkConfig = (HttpSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + @SneakyThrows + private void doInit() { + // Fill default values if absent + SinkConnectorConfig.populateFieldsWithDefaults(this.httpSinkConfig.connectorConfig); + // Create different handlers for different configurations + HttpSinkHandler nonRetryHandler; + if (this.httpSinkConfig.connectorConfig.getWebhookConfig().isActivate()) { + nonRetryHandler = new WebhookHttpSinkHandler(this.httpSinkConfig.connectorConfig); + } else { + nonRetryHandler = new CommonHttpSinkHandler(this.httpSinkConfig.connectorConfig); + } + + int maxRetries = this.httpSinkConfig.connectorConfig.getRetryConfig().getMaxRetries(); + if (maxRetries == 0) { + // Use the original sink handler + this.sinkHandler = nonRetryHandler; + } else if (maxRetries > 0) { + // Wrap the sink handler with a retry handler + this.sinkHandler = new HttpSinkHandlerRetryWrapper(this.httpSinkConfig.connectorConfig, nonRetryHandler); + } else { + throw new IllegalArgumentException("Max retries must be greater than or equal to 0."); + } + boolean isParallelized = this.httpSinkConfig.connectorConfig.isParallelized(); + int parallelism = isParallelized ? this.httpSinkConfig.connectorConfig.getParallelism() : 1; + executor = new ThreadPoolExecutor(parallelism, parallelism, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new EventMeshThreadFactory("http-sink-handler")); + } + + @Override + public void start() throws Exception { + this.sinkHandler.start(); + for (int i = 0; i < this.httpSinkConfig.connectorConfig.getParallelism(); i++) { + executor.execute(() -> { + while (isStart.get()) { + ConnectRecord connectRecord = null; + try { + connectRecord = queue.poll(2, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + if (connectRecord != null) { + sinkHandler.handle(connectRecord); + } + } + }); + } + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.httpSinkConfig.connectorConfig.getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + isStart.set(false); + while (!queue.isEmpty()) { + ConnectRecord record = queue.poll(); + this.sinkHandler.handle(record); + } + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + this.sinkHandler.stop(); + log.info("All tasks completed, start shut down http sink connector"); + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord sinkRecord : sinkRecords) { + try { + if (Objects.isNull(sinkRecord)) { + log.warn("ConnectRecord data is null, ignore."); + continue; + } + queue.put(sinkRecord); + } catch (Exception e) { + log.error("Failed to sink message via HTTP. ", e); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpAttemptEvent.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpAttemptEvent.java new file mode 100644 index 0000000000..8163852f8f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpAttemptEvent.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.data; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Single HTTP attempt event + */ +public class HttpAttemptEvent { + + public static final String PREFIX = "http-attempt-event-"; + + private final int maxAttempts; + + private final AtomicInteger attempts; + + private Throwable lastException; + + + public HttpAttemptEvent(int maxAttempts) { + this.maxAttempts = maxAttempts; + this.attempts = new AtomicInteger(0); + } + + /** + * Increment the attempts + */ + public void incrementAttempts() { + attempts.incrementAndGet(); + } + + /** + * Update the event, incrementing the attempts and setting the last exception + * + * @param exception the exception to update, can be null + */ + public void updateEvent(Throwable exception) { + // increment the attempts + incrementAttempts(); + + // update the last exception + lastException = exception; + } + + /** + * Check if the attempts are less than the maximum attempts + * + * @return true if the attempts are less than the maximum attempts, false otherwise + */ + public boolean canAttempt() { + return attempts.get() < maxAttempts; + } + + public boolean isComplete() { + if (attempts.get() == 0) { + // No start yet + return false; + } + + // If no attempt can be made or the last exception is null, the event completed + return !canAttempt() || lastException == null; + } + + + public int getMaxAttempts() { + return maxAttempts; + } + + public int getAttempts() { + return attempts.get(); + } + + public Throwable getLastException() { + return lastException; + } + + /** + * Get the limited exception message with the default limit of 256 + * + * @return the limited exception message + */ + public String getLimitedExceptionMessage() { + return getLimitedExceptionMessage(256); + } + + /** + * Get the limited exception message with the specified limit + * + * @param maxLimit the maximum limit of the exception message + * @return the limited exception message + */ + public String getLimitedExceptionMessage(int maxLimit) { + if (lastException == null) { + return ""; + } + String message = lastException.getMessage(); + if (message == null) { + return ""; + } + if (message.length() > maxLimit) { + return message.substring(0, maxLimit); + } + return message; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpConnectRecord.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpConnectRecord.java new file mode 100644 index 0000000000..9c8b1ce673 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpConnectRecord.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.data; + +import org.apache.eventmesh.common.remote.offset.http.HttpRecordOffset; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.KeyValue; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import lombok.Builder; +import lombok.Getter; + +/** + * a special ConnectRecord for HttpSinkConnector + */ +@Getter +@Builder +public class HttpConnectRecord implements Serializable { + + private static final long serialVersionUID = 5271462532332251473L; + + /** + * The unique identifier for the HttpConnectRecord + */ + private final String httpRecordId = UUID.randomUUID().toString(); + + /** + * The time when the HttpConnectRecord was created + */ + private LocalDateTime createTime; + + /** + * The type of the HttpConnectRecord + */ + private String type; + + /** + * The event id of the HttpConnectRecord + */ + private String eventId; + + private Object data; + + private KeyValue extensions; + + @Override + public String toString() { + return "HttpConnectRecord{" + + "createTime=" + createTime + + ", httpRecordId='" + httpRecordId + + ", type='" + type + + ", eventId='" + eventId + + ", data=" + data + + ", extensions=" + extensions + + '}'; + } + + /** + * Convert ConnectRecord to HttpConnectRecord + * + * @param record the ConnectRecord to convert + * @return the converted HttpConnectRecord + */ + public static HttpConnectRecord convertConnectRecord(ConnectRecord record, String type) { + Map offsetMap = new HashMap<>(); + if (record != null && record.getPosition() != null && record.getPosition().getRecordOffset() != null) { + if (HttpRecordOffset.class.equals(record.getPosition().getRecordOffsetClazz())) { + offsetMap = ((HttpRecordOffset) record.getPosition().getRecordOffset()).getOffsetMap(); + } + } + String offset = "0"; + if (!offsetMap.isEmpty()) { + offset = offsetMap.values().iterator().next().toString(); + } + if (record.getData() instanceof byte[]) { + String data = Base64.getEncoder().encodeToString((byte[]) record.getData()); + record.addExtension("isBase64", true); + return HttpConnectRecord.builder() + .type(type) + .createTime(LocalDateTime.now()) + .eventId(type + "-" + offset) + .data(data) + .extensions(record.getExtensions()) + .build(); + } else { + record.addExtension("isBase64", false); + return HttpConnectRecord.builder() + .type(type) + .createTime(LocalDateTime.now()) + .eventId(type + "-" + offset) + .data(record.getData()) + .extensions(record.getExtensions()) + .build(); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportMetadata.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportMetadata.java new file mode 100644 index 0000000000..111ee6b3e9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportMetadata.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +import lombok.Builder; +import lombok.Data; + +/** + * Metadata for an HTTP export operation. + */ +@Data +@Builder +public class HttpExportMetadata implements Serializable { + + private static final long serialVersionUID = 1121010466793041920L; + + private String url; + + private int code; + + private String message; + + private LocalDateTime receivedTime; + + private String recordId; + + private String retriedBy; + + private int retryNum; +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportRecord.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportRecord.java new file mode 100644 index 0000000000..c6bdb02884 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportRecord.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.data; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Represents an HTTP export record containing metadata and data to be exported. + */ +@Data +@AllArgsConstructor +public class HttpExportRecord implements Serializable { + + private static final long serialVersionUID = 6010283911452947157L; + + private HttpExportMetadata metadata; + + private Object data; +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportRecordPage.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportRecordPage.java new file mode 100644 index 0000000000..81e582c33a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/HttpExportRecordPage.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.data; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Represents a page of HTTP export records. + */ +@Data +@AllArgsConstructor +public class HttpExportRecordPage implements Serializable { + + private static final long serialVersionUID = 1143791658357035990L; + + private int pageNum; + + private int pageSize; + + private List pageItems; + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/MultiHttpRequestContext.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/MultiHttpRequestContext.java new file mode 100644 index 0000000000..66f5d0e7ec --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/data/MultiHttpRequestContext.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.data; + +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * Multi HTTP request context + */ +public class MultiHttpRequestContext { + + public static final String NAME = "multi-http-request-context"; + + /** + * The remaining requests to be processed. + */ + private final AtomicInteger remainingRequests; + + /** + * The last failed event. + * If retries occur but still fail, it will be logged, and only the last one will be retained. + */ + private HttpAttemptEvent lastFailedEvent; + + public MultiHttpRequestContext(int remainingEvents) { + this.remainingRequests = new AtomicInteger(remainingEvents); + } + + /** + * Decrement the remaining requests by 1. + */ + public void decrementRemainingRequests() { + remainingRequests.decrementAndGet(); + } + + /** + * Check if all requests have been processed. + * + * @return true if all requests have been processed, false otherwise. + */ + public boolean isAllRequestsProcessed() { + return remainingRequests.get() == 0; + } + + public int getRemainingRequests() { + return remainingRequests.get(); + } + + public HttpAttemptEvent getLastFailedEvent() { + return lastFailedEvent; + } + + public void setLastFailedEvent(HttpAttemptEvent lastFailedEvent) { + this.lastFailedEvent = lastFailedEvent; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/AbstractHttpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/AbstractHttpSinkHandler.java new file mode 100644 index 0000000000..d38e9d30d8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/AbstractHttpSinkHandler.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.handler; + +import org.apache.eventmesh.common.config.connector.http.SinkConnectorConfig; +import org.apache.eventmesh.connector.http.sink.data.HttpAttemptEvent; +import org.apache.eventmesh.connector.http.sink.data.HttpConnectRecord; +import org.apache.eventmesh.connector.http.sink.data.MultiHttpRequestContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import lombok.Getter; + +/** + * AbstractHttpSinkHandler is an abstract class that provides a base implementation for HttpSinkHandler. + */ +public abstract class AbstractHttpSinkHandler implements HttpSinkHandler { + + @Getter + private final SinkConnectorConfig sinkConnectorConfig; + + @Getter + private final List urls; + + private final HttpDeliveryStrategy deliveryStrategy; + + private int roundRobinIndex = 0; + + protected AbstractHttpSinkHandler(SinkConnectorConfig sinkConnectorConfig) { + this.sinkConnectorConfig = sinkConnectorConfig; + this.deliveryStrategy = HttpDeliveryStrategy.valueOf(sinkConnectorConfig.getDeliveryStrategy()); + // Initialize URLs + String[] urlStrings = sinkConnectorConfig.getUrls(); + this.urls = Arrays.stream(urlStrings) + .map(URI::create) + .collect(Collectors.toList()); + } + + /** + * Processes a ConnectRecord by sending it over HTTP or HTTPS. This method should be called for each ConnectRecord that needs to be processed. + * + * @param record the ConnectRecord to process + */ + @Override + public void handle(ConnectRecord record) { + // build attributes + Map attributes = new ConcurrentHashMap<>(); + + switch (deliveryStrategy) { + case ROUND_ROBIN: + attributes.put(MultiHttpRequestContext.NAME, new MultiHttpRequestContext(1)); + URI url = urls.get(roundRobinIndex); + roundRobinIndex = (roundRobinIndex + 1) % urls.size(); + sendRecordToUrl(record, attributes, url); + break; + case BROADCAST: + attributes.put(MultiHttpRequestContext.NAME, new MultiHttpRequestContext(urls.size())); + // send the record to all URLs + urls.forEach(url0 -> sendRecordToUrl(record, attributes, url0)); + break; + default: + throw new IllegalArgumentException("Unknown delivery strategy: " + deliveryStrategy); + } + } + + private void sendRecordToUrl(ConnectRecord record, Map attributes, URI url) { + // convert ConnectRecord to HttpConnectRecord + String type = String.format("%s.%s.%s", + this.sinkConnectorConfig.getConnectorName(), url.getScheme(), + this.sinkConnectorConfig.getWebhookConfig().isActivate() ? "webhook" : "common"); + HttpConnectRecord httpConnectRecord = HttpConnectRecord.convertConnectRecord(record, type); + + // add AttemptEvent to the attributes + HttpAttemptEvent attemptEvent = new HttpAttemptEvent(this.sinkConnectorConfig.getRetryConfig().getMaxRetries() + 1); + attributes.put(HttpAttemptEvent.PREFIX + httpConnectRecord.getHttpRecordId(), attemptEvent); + + // deliver the record + deliver(url, httpConnectRecord, attributes, record); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/HttpDeliveryStrategy.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/HttpDeliveryStrategy.java new file mode 100644 index 0000000000..2e770eb120 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/HttpDeliveryStrategy.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.handler; + +public enum HttpDeliveryStrategy { + ROUND_ROBIN, + BROADCAST +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/HttpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/HttpSinkHandler.java new file mode 100644 index 0000000000..d5a27940e5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/HttpSinkHandler.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.handler; + +import org.apache.eventmesh.connector.http.sink.data.HttpConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.util.Map; + +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.client.HttpResponse; + +/** + * Interface for handling ConnectRecords via HTTP or HTTPS. Classes implementing this interface are responsible for processing ConnectRecords by + * sending them over HTTP or HTTPS, with additional support for handling multiple requests and asynchronous processing. + * + *

Any class that needs to process ConnectRecords via HTTP or HTTPS should implement this interface. + * Implementing classes must provide implementations for the {@link #start()}, {@link #handle(ConnectRecord)}, + * {@link #deliver(URI, HttpConnectRecord, Map, ConnectRecord)}, and {@link #stop()} methods.

+ * + *

Implementing classes should ensure thread safety and handle HTTP/HTTPS communication efficiently. + * The {@link #start()} method initializes any necessary resources for HTTP/HTTPS communication. The {@link #handle(ConnectRecord)} method processes a + * ConnectRecord by sending it over HTTP or HTTPS. The {@link #deliver(URI, HttpConnectRecord, Map, ConnectRecord)} method processes HttpConnectRecord + * on specified URL while returning its own processing logic {@link #stop()} method releases any resources used for HTTP/HTTPS communication.

+ * + *

It's recommended to handle exceptions gracefully within the {@link #deliver(URI, HttpConnectRecord, Map, ConnectRecord)} method + * to prevent message loss or processing interruptions.

+ */ +public interface HttpSinkHandler { + + /** + * Initializes the HTTP/HTTPS handler. This method should be called before using the handler. + */ + void start(); + + /** + * Processes a ConnectRecord by sending it over HTTP or HTTPS. This method should be called for each ConnectRecord that needs to be processed. + * + * @param record the ConnectRecord to process + */ + void handle(ConnectRecord record); + + + /** + * Processes HttpConnectRecord on specified URL while returning its own processing logic + * + * @param url URI to which the HttpConnectRecord should be sent + * @param httpConnectRecord HttpConnectRecord to process + * @param attributes additional attributes to be used in processing + * @return processing chain + */ + Future> deliver(URI url, HttpConnectRecord httpConnectRecord, Map attributes, ConnectRecord connectRecord); + + /** + * Cleans up and releases resources used by the HTTP/HTTPS handler. This method should be called when the handler is no longer needed. + */ + void stop(); +} + diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/CommonHttpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/CommonHttpSinkHandler.java new file mode 100644 index 0000000000..0b57cc06ef --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/CommonHttpSinkHandler.java @@ -0,0 +1,270 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.handler.impl; + +import org.apache.eventmesh.common.config.connector.http.SinkConnectorConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.http.sink.data.HttpAttemptEvent; +import org.apache.eventmesh.connector.http.sink.data.HttpConnectRecord; +import org.apache.eventmesh.connector.http.sink.data.MultiHttpRequestContext; +import org.apache.eventmesh.connector.http.sink.handler.AbstractHttpSinkHandler; +import org.apache.eventmesh.connector.http.util.HttpUtils; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.time.ZoneId; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import io.netty.handler.codec.http.HttpHeaderNames; +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * Common HTTP/HTTPS Sink Handler implementation to handle ConnectRecords by sending them over HTTP or HTTPS to configured URLs. + * + *

This handler initializes a WebClient for making HTTP requests based on the provided SinkConnectorConfig. + * It handles processing ConnectRecords by converting them to HttpConnectRecord and sending them asynchronously to each configured URL using the + * WebClient.

+ * + *

The handler uses Vert.x's WebClient to perform HTTP/HTTPS requests. It initializes the WebClient in the {@link #start()} + * method and closes it in the {@link #stop()} method to manage resources efficiently.

+ * + *

Each ConnectRecord is processed and sent to all configured URLs concurrently using asynchronous HTTP requests.

+ */ +@Slf4j +@Getter +public class CommonHttpSinkHandler extends AbstractHttpSinkHandler { + + private WebClient webClient; + + + public CommonHttpSinkHandler(SinkConnectorConfig sinkConnectorConfig) { + super(sinkConnectorConfig); + } + + /** + * Initializes the WebClient for making HTTP requests based on the provided SinkConnectorConfig. + */ + @Override + public void start() { + // Create WebClient + doInitWebClient(); + } + + /** + * Initializes the WebClient with the provided configuration options. + */ + private void doInitWebClient() { + SinkConnectorConfig sinkConnectorConfig = getSinkConnectorConfig(); + final Vertx vertx = Vertx.vertx(); + WebClientOptions options = new WebClientOptions() + .setKeepAlive(sinkConnectorConfig.isKeepAlive()) + .setKeepAliveTimeout(sinkConnectorConfig.getKeepAliveTimeout() / 1000) + .setIdleTimeout(sinkConnectorConfig.getIdleTimeout()) + .setIdleTimeoutUnit(TimeUnit.MILLISECONDS) + .setConnectTimeout(sinkConnectorConfig.getConnectionTimeout()) + .setMaxPoolSize(sinkConnectorConfig.getMaxConnectionPoolSize()) + .setPipelining(sinkConnectorConfig.isParallelized()); + this.webClient = WebClient.create(vertx, options); + } + + /** + * Processes HttpConnectRecord on specified URL while returning its own processing logic. This method sends the HttpConnectRecord to the specified + * URL using the WebClient. + * + * @param url URI to which the HttpConnectRecord should be sent + * @param httpConnectRecord HttpConnectRecord to process + * @param attributes additional attributes to be used in processing + * @return processing chain + */ + @Override + public Future> deliver(URI url, HttpConnectRecord httpConnectRecord, Map attributes, + ConnectRecord connectRecord) { + // create headers + Map extensionMap = new HashMap<>(); + Set extensionKeySet = httpConnectRecord.getExtensions().keySet(); + for (String extensionKey : extensionKeySet) { + Object v = httpConnectRecord.getExtensions().getObject(extensionKey); + extensionMap.put(extensionKey, v); + } + + MultiMap headers = HttpHeaders.headers() + .set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8") + .set(HttpHeaderNames.ACCEPT, "application/json; charset=utf-8") + .set("extension", JsonUtils.toJSONString(extensionMap)); + // get timestamp and offset + Long timestamp = httpConnectRecord.getCreateTime() + .atZone(ZoneId.systemDefault()) + .toInstant() + .toEpochMilli(); + + // send the request + return this.webClient.post(url.getPath()) + .host(url.getHost()) + .port(url.getPort() == -1 ? (Objects.equals(url.getScheme(), "https") ? 443 : 80) : url.getPort()) + .putHeaders(headers) + .ssl(Objects.equals(url.getScheme(), "https")) + .sendJson(httpConnectRecord.getData()) + .onSuccess(res -> { + log.info("Request sent successfully. Record: timestamp={}", timestamp); + + Exception e = null; + + // log the response + if (HttpUtils.is2xxSuccessful(res.statusCode())) { + if (log.isDebugEnabled()) { + log.debug("Received successful response: statusCode={}. Record: timestamp={}, responseBody={}", + res.statusCode(), timestamp, res.bodyAsString()); + } else { + log.info("Received successful response: statusCode={}. Record: timestamp={}", res.statusCode(), timestamp); + } + } else { + if (log.isDebugEnabled()) { + log.warn("Received non-2xx response: statusCode={}. Record: timestamp={}, responseBody={}", + res.statusCode(), timestamp, res.bodyAsString()); + } else { + log.warn("Received non-2xx response: statusCode={}. Record: timestamp={}", res.statusCode(), timestamp); + } + + e = new RuntimeException("Unexpected HTTP response code: " + res.statusCode()); + } + + // try callback + tryCallback(httpConnectRecord, e, attributes, connectRecord); + }).onFailure(err -> { + log.error("Request failed to send. Record: timestamp={}", timestamp, err); + + // try callback + tryCallback(httpConnectRecord, err, attributes, connectRecord); + }); + } + + /** + * Tries to call the callback based on the result of the request. + * + * @param httpConnectRecord the HttpConnectRecord to use + * @param e the exception thrown during the request, may be null + * @param attributes additional attributes to be used in processing + */ + private void tryCallback(HttpConnectRecord httpConnectRecord, Throwable e, Map attributes, ConnectRecord record) { + // get and update the attempt event + HttpAttemptEvent attemptEvent = (HttpAttemptEvent) attributes.get(HttpAttemptEvent.PREFIX + httpConnectRecord.getHttpRecordId()); + attemptEvent.updateEvent(e); + + // get and update the multiHttpRequestContext + MultiHttpRequestContext multiHttpRequestContext = getAndUpdateMultiHttpRequestContext(attributes, attemptEvent); + + if (multiHttpRequestContext.isAllRequestsProcessed()) { + // do callback + if (record.getCallback() == null) { + if (log.isDebugEnabled()) { + log.warn("ConnectRecord callback is null. Ignoring callback. {}", record); + } else { + log.warn("ConnectRecord callback is null. Ignoring callback."); + } + return; + } + + // get the last failed event + HttpAttemptEvent lastFailedEvent = multiHttpRequestContext.getLastFailedEvent(); + if (lastFailedEvent == null) { + // success + record.getCallback().onSuccess(convertToSendResult(record)); + } else { + // failure + record.getCallback().onException(buildSendExceptionContext(record, lastFailedEvent.getLastException())); + } + } else { + log.warn("still have requests to process, size {}|attempt num {}", + multiHttpRequestContext.getRemainingRequests(), attemptEvent.getAttempts()); + } + } + + + /** + * Gets and updates the multi http request context based on the provided attributes and HttpConnectRecord. + * + * @param attributes the attributes to use + * @param attemptEvent the HttpAttemptEvent to use + * @return the updated multi http request context + */ + private MultiHttpRequestContext getAndUpdateMultiHttpRequestContext(Map attributes, HttpAttemptEvent attemptEvent) { + // get the multi http request context + MultiHttpRequestContext multiHttpRequestContext = (MultiHttpRequestContext) attributes.get(MultiHttpRequestContext.NAME); + + // Check if the current attempted event has completed + if (attemptEvent.isComplete()) { + // decrement the counter + multiHttpRequestContext.decrementRemainingRequests(); + + if (attemptEvent.getLastException() != null) { + // if all attempts are exhausted, set the last failed event + multiHttpRequestContext.setLastFailedEvent(attemptEvent); + } + } + + return multiHttpRequestContext; + } + + private SendResult convertToSendResult(ConnectRecord record) { + SendResult result = new SendResult(); + result.setMessageId(record.getRecordId()); + if (org.apache.commons.lang3.StringUtils.isNotEmpty(record.getExtension("topic"))) { + result.setTopic(record.getExtension("topic")); + } + return result; + } + + private SendExceptionContext buildSendExceptionContext(ConnectRecord record, Throwable e) { + SendExceptionContext sendExceptionContext = new SendExceptionContext(); + sendExceptionContext.setMessageId(record.getRecordId()); + sendExceptionContext.setCause(e); + if (org.apache.commons.lang3.StringUtils.isNotEmpty(record.getExtension("topic"))) { + sendExceptionContext.setTopic(record.getExtension("topic")); + } + return sendExceptionContext; + } + + + /** + * Cleans up and releases resources used by the HTTP/HTTPS handler. + */ + @Override + public void stop() { + if (this.webClient != null) { + this.webClient.close(); + } else { + log.warn("WebClient is null, ignore."); + } + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/HttpSinkHandlerRetryWrapper.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/HttpSinkHandlerRetryWrapper.java new file mode 100644 index 0000000000..050839451a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/HttpSinkHandlerRetryWrapper.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.handler.impl; + +import org.apache.eventmesh.common.config.connector.http.HttpRetryConfig; +import org.apache.eventmesh.common.config.connector.http.SinkConnectorConfig; +import org.apache.eventmesh.connector.http.sink.data.HttpConnectRecord; +import org.apache.eventmesh.connector.http.sink.handler.AbstractHttpSinkHandler; +import org.apache.eventmesh.connector.http.sink.handler.HttpSinkHandler; +import org.apache.eventmesh.connector.http.util.HttpUtils; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.ConnectException; +import java.net.URI; +import java.time.Duration; +import java.util.Map; + +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.client.HttpResponse; + +import lombok.extern.slf4j.Slf4j; + +import dev.failsafe.Failsafe; +import dev.failsafe.RetryPolicy; + + +/** + * HttpSinkHandlerRetryWrapper is a wrapper class for the HttpSinkHandler that provides retry functionality for failed HTTP requests. + */ +@Slf4j +public class HttpSinkHandlerRetryWrapper extends AbstractHttpSinkHandler { + + private final HttpRetryConfig httpRetryConfig; + + private final HttpSinkHandler sinkHandler; + + private final RetryPolicy> retryPolicy; + + public HttpSinkHandlerRetryWrapper(SinkConnectorConfig sinkConnectorConfig, HttpSinkHandler sinkHandler) { + super(sinkConnectorConfig); + this.sinkHandler = sinkHandler; + this.httpRetryConfig = getSinkConnectorConfig().getRetryConfig(); + this.retryPolicy = buildRetryPolicy(); + } + + private RetryPolicy> buildRetryPolicy() { + return RetryPolicy.>builder() + .handleIf(e -> e instanceof ConnectException) + .handleResultIf(response -> httpRetryConfig.isRetryOnNonSuccess() && !HttpUtils.is2xxSuccessful(response.statusCode())) + .withMaxRetries(httpRetryConfig.getMaxRetries()) + .withDelay(Duration.ofMillis(httpRetryConfig.getInterval())) + .onRetry(event -> { + if (log.isDebugEnabled()) { + log.warn("Failed to deliver message after {} attempts. Retrying in {} ms. Error: {}", + event.getAttemptCount(), httpRetryConfig.getInterval(), event.getLastException()); + } else { + log.warn("Failed to deliver message after {} attempts. Retrying in {} ms.", + event.getAttemptCount(), httpRetryConfig.getInterval()); + } + }).onFailure(event -> { + if (log.isDebugEnabled()) { + log.error("Failed to deliver message after {} attempts. Error: {}", + event.getAttemptCount(), event.getException()); + } else { + log.error("Failed to deliver message after {} attempts.", + event.getAttemptCount()); + } + }).build(); + } + + /** + * Initializes the WebClient for making HTTP requests based on the provided SinkConnectorConfig. + */ + @Override + public void start() { + sinkHandler.start(); + } + + + /** + * Processes HttpConnectRecord on specified URL while returning its own processing logic This method provides the retry power to process the + * HttpConnectRecord + * + * @param url URI to which the HttpConnectRecord should be sent + * @param httpConnectRecord HttpConnectRecord to process + * @param attributes additional attributes to pass to the processing chain + * @return processing chain + */ + @Override + public Future> deliver(URI url, HttpConnectRecord httpConnectRecord, Map attributes, + ConnectRecord connectRecord) { + Failsafe.with(retryPolicy) + .getStageAsync(() -> sinkHandler.deliver(url, httpConnectRecord, attributes, connectRecord).toCompletionStage()); + return null; + } + + + /** + * Cleans up and releases resources used by the HTTP/HTTPS handler. + */ + @Override + public void stop() { + sinkHandler.stop(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/WebhookHttpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/WebhookHttpSinkHandler.java new file mode 100644 index 0000000000..0751918ee7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/sink/handler/impl/WebhookHttpSinkHandler.java @@ -0,0 +1,317 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink.handler.impl; + +import org.apache.eventmesh.common.config.connector.http.HttpWebhookConfig; +import org.apache.eventmesh.common.config.connector.http.SinkConnectorConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.http.common.SynchronizedCircularFifoQueue; +import org.apache.eventmesh.connector.http.sink.data.HttpAttemptEvent; +import org.apache.eventmesh.connector.http.sink.data.HttpConnectRecord; +import org.apache.eventmesh.connector.http.sink.data.HttpExportMetadata; +import org.apache.eventmesh.connector.http.sink.data.HttpExportRecord; +import org.apache.eventmesh.connector.http.sink.data.HttpExportRecordPage; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.StringUtils; + +import java.net.URI; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.handler.LoggerHandler; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONWriter; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * Extends CommonHttpSinkHandler to provide additional functionality for handling webhook features, including sending requests to callback servers, + * allowing longer response wait times, storing responses returned from callback servers, and exposing received data through an HTTP service. + */ +@Slf4j +public class WebhookHttpSinkHandler extends CommonHttpSinkHandler { + + // the configuration for webhook + private final HttpWebhookConfig webhookConfig; + + // the server for exporting the received data + private HttpServer exportServer; + + // store the received data, when webhook is enabled + private final SynchronizedCircularFifoQueue receivedDataQueue; + + private volatile boolean exportStarted = false; + + private volatile boolean exportDestroyed = false; + + public boolean isExportStarted() { + return exportStarted; + } + + public boolean isExportDestroyed() { + return exportDestroyed; + } + + public WebhookHttpSinkHandler(SinkConnectorConfig sinkConnectorConfig) { + super(sinkConnectorConfig); + + this.webhookConfig = sinkConnectorConfig.getWebhookConfig(); + int maxQueueSize = this.webhookConfig.getMaxStorageSize(); + this.receivedDataQueue = new SynchronizedCircularFifoQueue<>(maxQueueSize); + // init the export server + doInitExportServer(); + } + + + /** + * Initialize the server for exporting the received data + */ + private void doInitExportServer() { + final Vertx vertx = Vertx.vertx(); + final Router router = Router.router(vertx); + // add logger handler + router.route().handler(LoggerHandler.create()); + // add export handler + router.route() + .path(this.webhookConfig.getExportPath()) + .method(HttpMethod.GET) + .produces("application/json") + .handler(ctx -> { + // Validate the request parameters + MultiMap params = ctx.request().params(); + String pageNumStr = params.get(ParamEnum.PAGE_NUM.getValue()); + String pageSizeStr = params.get(ParamEnum.PAGE_SIZE.getValue()); + String type = params.get(ParamEnum.TYPE.getValue()); + + // 1. type must be "poll" or "peek" or null + // 2. if type is "peek", pageNum must be greater than 0 + // 3. pageSize must be greater than 0 + if ((type != null && !Objects.equals(type, TypeEnum.PEEK.getValue()) && !Objects.equals(type, TypeEnum.POLL.getValue())) + || (Objects.equals(type, TypeEnum.PEEK.getValue()) && (StringUtils.isBlank(pageNumStr) || Integer.parseInt(pageNumStr) < 1)) + || (StringUtils.isBlank(pageSizeStr) || Integer.parseInt(pageSizeStr) < 1)) { + + // Return 400 Bad Request if the request parameters are invalid + ctx.response() + .putHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8") + .setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) + .end(); + log.info("Invalid request parameters. pageNum: {}, pageSize: {}, type: {}", pageNumStr, pageSizeStr, type); + return; + } + + // Parse the request parameters + if (type == null) { + type = TypeEnum.PEEK.getValue(); + } + int pageNum = StringUtils.isBlank(pageNumStr) ? 1 : Integer.parseInt(pageNumStr); + int pageSize = Integer.parseInt(pageSizeStr); + + if (receivedDataQueue.isEmpty()) { + ctx.response() + .putHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8") + .setStatusCode(HttpResponseStatus.NO_CONTENT.code()) + .end(); + log.info("No callback data to export."); + return; + } + + // Get the received data + List exportRecords; + if (Objects.equals(type, TypeEnum.POLL.getValue())) { + // If the type is poll, only the first page of data is exported and removed + exportRecords = receivedDataQueue.fetchRange(0, pageSize, true); + } else { + // If the type is peek, the specified page of data is exported without removing + int startIndex = (pageNum - 1) * pageSize; + int endIndex = startIndex + pageSize; + exportRecords = receivedDataQueue.fetchRange(startIndex, endIndex, false); + } + + // Create HttpExportRecordPage + HttpExportRecordPage page = new HttpExportRecordPage(pageNum, exportRecords.size(), exportRecords); + + // export the received data + ctx.response() + .putHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8") + .setStatusCode(HttpResponseStatus.OK.code()) + .send(JSON.toJSONString(page, JSONWriter.Feature.WriteMapNullValue)); + if (log.isDebugEnabled()) { + log.debug("Succeed to export callback data. Data: {}", page); + } else { + log.info("Succeed to export callback data."); + } + }); + // create the export server + this.exportServer = vertx.createHttpServer(new HttpServerOptions() + .setPort(this.webhookConfig.getPort()) + .setIdleTimeout(this.webhookConfig.getServerIdleTimeout()) + .setIdleTimeoutUnit(TimeUnit.MILLISECONDS)).requestHandler(router); + } + + /** + * Starts the HTTP/HTTPS handler by creating a WebClient with configured options and starting the export server. + */ + @Override + public void start() { + // start the webclient + super.start(); + // start the export server + this.exportServer.listen(res -> { + if (res.succeeded()) { + this.exportStarted = true; + log.info("WebhookHttpExportServer started on port: {}", this.webhookConfig.getPort()); + } else { + log.error("WebhookHttpExportServer failed to start on port: {}", this.webhookConfig.getPort()); + throw new EventMeshException("Failed to start Vertx server. ", res.cause()); + } + }); + } + + + /** + * Processes HttpConnectRecord on specified URL while returning its own processing logic This method sends the HttpConnectRecord to the specified + * URL by super class method and stores the received data. + * + * @param url URI to which the HttpConnectRecord should be sent + * @param httpConnectRecord HttpConnectRecord to process + * @param attributes additional attributes to be used in processing + * @return processing chain + */ + @Override + public Future> deliver(URI url, HttpConnectRecord httpConnectRecord, Map attributes, + ConnectRecord connectRecord) { + // send the request + Future> responseFuture = super.deliver(url, httpConnectRecord, attributes, connectRecord); + // store the received data + return responseFuture.onComplete(arr -> { + // get HttpAttemptEvent + HttpAttemptEvent attemptEvent = (HttpAttemptEvent) attributes.get(HttpAttemptEvent.PREFIX + httpConnectRecord.getHttpRecordId()); + + // get the response + HttpResponse response = arr.succeeded() ? arr.result() : null; + + // create ExportMetadata + HttpExportMetadata httpExportMetadata = buildHttpExportMetadata(url, response, httpConnectRecord, attemptEvent); + + // create ExportRecord + HttpExportRecord exportRecord = new HttpExportRecord(httpExportMetadata, arr.succeeded() ? arr.result().bodyAsString() : null); + // add the data to the queue + receivedDataQueue.offer(exportRecord); + }); + } + + /** + * Builds the HttpExportMetadata object based on the response, HttpConnectRecord, and HttpRetryEvent. + * + * @param url the URI to which the HttpConnectRecord was sent + * @param response the response received from the URI + * @param httpConnectRecord the HttpConnectRecord that was sent + * @param attemptEvent the HttpAttemptEvent that was used to send the HttpConnectRecord + * @return the HttpExportMetadata object + */ + private HttpExportMetadata buildHttpExportMetadata(URI url, HttpResponse response, HttpConnectRecord httpConnectRecord, + HttpAttemptEvent attemptEvent) { + + String msg = null; + // order of precedence: lastException > response > null + if (attemptEvent.getLastException() != null) { + msg = attemptEvent.getLimitedExceptionMessage(); + } else if (response != null) { + msg = response.statusMessage(); + } + + return HttpExportMetadata.builder() + .url(url.toString()) + .code(response != null ? response.statusCode() : -1) + .message(msg) + .receivedTime(LocalDateTime.now()) + .recordId(httpConnectRecord.getHttpRecordId()) + .retryNum(attemptEvent.getAttempts() - 1) + .build(); + } + + + /** + * Cleans up and releases resources used by the HTTP/HTTPS handler. + */ + @Override + public void stop() { + // stop the webclient + super.stop(); + // stop the export server + if (this.exportServer != null) { + this.exportServer.close(res -> { + if (res.succeeded()) { + this.exportDestroyed = true; + log.info("WebhookHttpExportServer stopped on port: {}", this.webhookConfig.getPort()); + } else { + log.error("WebhookHttpExportServer failed to stop on port: {}", this.webhookConfig.getPort()); + throw new EventMeshException("Failed to stop Vertx server. ", res.cause()); + } + }); + } else { + log.warn("Callback server is null, ignore."); + } + } + + + @Getter + public enum ParamEnum { + PAGE_NUM("pageNum"), + PAGE_SIZE("pageSize"), + TYPE("type"); + + private final String value; + + ParamEnum(String value) { + this.value = value; + } + + } + + + @Getter + public enum TypeEnum { + POLL("poll"), + PEEK("peek"); + + private final String value; + + TypeEnum(String value) { + this.value = value; + } + + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/HttpSourceConnector.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/HttpSourceConnector.java new file mode 100644 index 0000000000..5aa8c63dd9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/HttpSourceConnector.java @@ -0,0 +1,219 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.http.HttpSourceConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.http.source.data.CommonResponse; +import org.apache.eventmesh.connector.http.source.protocol.Protocol; +import org.apache.eventmesh.connector.http.source.protocol.ProtocolFactory; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.LoggerHandler; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpSourceConnector implements Source, ConnectorCreateService { + + private HttpSourceConfig sourceConfig; + + private BlockingQueue queue; + + private int batchSize; + + private Route route; + + private Protocol protocol; + + private HttpServer server; + + @Getter + private volatile boolean started = false; + + @Getter + private volatile boolean destroyed = false; + + + @Override + public Class configClass() { + return HttpSourceConfig.class; + } + + @Override + public Source create() { + return new HttpSourceConnector(); + } + + @Override + public void init(Config config) { + this.sourceConfig = (HttpSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (HttpSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + // init queue + int maxQueueSize = this.sourceConfig.getConnectorConfig().getMaxStorageSize(); + this.queue = new LinkedBlockingQueue<>(maxQueueSize); + + // init batch size + this.batchSize = this.sourceConfig.getConnectorConfig().getBatchSize(); + + // init protocol + String protocolName = this.sourceConfig.getConnectorConfig().getProtocol(); + this.protocol = ProtocolFactory.getInstance(this.sourceConfig.connectorConfig, protocolName); + + final Vertx vertx = Vertx.vertx(); + final Router router = Router.router(vertx); + route = router.route() + .path(this.sourceConfig.connectorConfig.getPath()) + .handler(LoggerHandler.create()); + + // set protocol handler + this.protocol.setHandler(route, queue); + + // create server + this.server = vertx.createHttpServer(new HttpServerOptions() + .setPort(this.sourceConfig.connectorConfig.getPort()) + .setMaxFormAttributeSize(this.sourceConfig.connectorConfig.getMaxFormAttributeSize()) + .setIdleTimeout(this.sourceConfig.connectorConfig.getIdleTimeout()) + .setIdleTimeoutUnit(TimeUnit.MILLISECONDS)).requestHandler(router); + } + + @Override + public void start() { + this.server.listen(res -> { + if (res.succeeded()) { + this.started = true; + log.info("HttpSourceConnector started on port: {}", this.sourceConfig.getConnectorConfig().getPort()); + } else { + log.error("HttpSourceConnector failed to start on port: {}", this.sourceConfig.getConnectorConfig().getPort()); + throw new EventMeshException("failed to start Vertx server", res.cause()); + } + }); + } + + @Override + public void commit(ConnectRecord record) { + if (sourceConfig.getConnectorConfig().isDataConsistencyEnabled()) { + log.debug("HttpSourceConnector commit record: {}", record.getRecordId()); + RoutingContext routingContext = (RoutingContext) record.getExtensionObj("routingContext"); + if (routingContext != null) { + routingContext.response() + .putHeader("content-type", "application/json") + .setStatusCode(HttpResponseStatus.OK.code()) + .end(CommonResponse.success().toJsonStr()); + } else { + log.error("Failed to commit the record, routingContext is null, recordId: {}", record.getRecordId()); + } + } + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + if (this.route != null) { + this.route.failureHandler(ctx -> { + log.error("Failed to handle the request, recordId {}. ", record.getRecordId(), ctx.failure()); + // Return Bad Response + ctx.response() + .setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()) + .end("{\"status\":\"failed\",\"recordId\":\"" + record.getRecordId() + "\"}"); + }); + } + } + + @Override + public void stop() { + if (this.server != null) { + this.server.close(res -> { + if (res.succeeded()) { + this.destroyed = true; + log.info("HttpSourceConnector stopped on port: {}", this.sourceConfig.getConnectorConfig().getPort()); + } else { + log.error("HttpSourceConnector failed to stop on port: {}", this.sourceConfig.getConnectorConfig().getPort()); + throw new EventMeshException("failed to stop Vertx server", res.cause()); + } + } + ); + } else { + log.warn("HttpSourceConnector server is null, ignore."); + } + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long maxPollWaitTime = 5000; + long remainingTime = maxPollWaitTime; + + // poll from queue + List connectRecords = new ArrayList<>(batchSize); + for (int i = 0; i < batchSize; i++) { + try { + Object obj = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (obj == null) { + break; + } + // convert to ConnectRecord + ConnectRecord connectRecord = protocol.convertToConnectRecord(obj); + connectRecords.add(connectRecord); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (Exception e) { + log.error("Failed to poll from queue.", e); + throw new RuntimeException(e); + } + + } + return connectRecords; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/data/CommonResponse.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/data/CommonResponse.java new file mode 100644 index 0000000000..870f2afbe5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/data/CommonResponse.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONWriter.Feature; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Webhook response. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CommonResponse implements Serializable { + + private static final long serialVersionUID = 8616938575207104455L; + + private String msg; + + private LocalDateTime handleTime; + + /** + * Convert to json string. + * + * @return json string + */ + public String toJsonStr() { + return JSON.toJSONString(this, Feature.WriteMapNullValue); + } + + + /** + * Create a success response. + * + * @return response + */ + public static CommonResponse success() { + return base("success"); + } + + + /** + * Create a base response. + * + * @param msg message + * @return response + */ + public static CommonResponse base(String msg) { + return new CommonResponse(msg, LocalDateTime.now()); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/data/WebhookRequest.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/data/WebhookRequest.java new file mode 100644 index 0000000000..9e1dcb7b4c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/data/WebhookRequest.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.data; + +import java.io.Serializable; +import java.util.Map; + +import io.vertx.ext.web.RoutingContext; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Webhook Protocol Request. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WebhookRequest implements Serializable { + + private static final long serialVersionUID = -483500600756490500L; + + private String protocolName; + + private String url; + + private Map headers; + + private Object payload; + + private RoutingContext routingContext; + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/Protocol.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/Protocol.java new file mode 100644 index 0000000000..c5a22139e0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/Protocol.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.protocol; + +import org.apache.eventmesh.common.config.connector.http.SourceConnectorConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.concurrent.BlockingQueue; + +import io.vertx.ext.web.Route; + + +/** + * Protocol Interface. + * All protocols should implement this interface. + */ +public interface Protocol { + + + /** + * Initialize the protocol. + * + * @param sourceConnectorConfig source connector config + */ + void initialize(SourceConnectorConfig sourceConnectorConfig); + + + /** + * Handle the protocol message. + * + * @param route route + * @param queue queue info + */ + void setHandler(Route route, BlockingQueue queue); + + + /** + * Convert the message to ConnectRecord. + * + * @param message message + * @return ConnectRecord + */ + ConnectRecord convertToConnectRecord(Object message); +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/ProtocolFactory.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/ProtocolFactory.java new file mode 100644 index 0000000000..6e6100e88b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/ProtocolFactory.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.protocol; + +import org.apache.eventmesh.common.config.connector.http.SourceConnectorConfig; +import org.apache.eventmesh.connector.http.source.protocol.impl.CloudEventProtocol; +import org.apache.eventmesh.connector.http.source.protocol.impl.CommonProtocol; +import org.apache.eventmesh.connector.http.source.protocol.impl.GitHubProtocol; + +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Protocol factory. This class is responsible for storing and creating instances of {@link Protocol} classes. + */ +public class ProtocolFactory { + + // protocol name -> protocol class + private static final ConcurrentHashMap> protocols = new ConcurrentHashMap<>(); + + static { + // register all protocols + registerProtocol(CloudEventProtocol.PROTOCOL_NAME, CloudEventProtocol.class); + registerProtocol(GitHubProtocol.PROTOCOL_NAME, GitHubProtocol.class); + registerProtocol(CommonProtocol.PROTOCOL_NAME, CommonProtocol.class); + } + + + /** + * Register a protocol + * + * @param name name of the protocol + * @param clazz class of the protocol + */ + public static void registerProtocol(String name, Class clazz) { + if (Protocol.class.isAssignableFrom(clazz)) { + // put the class into the map(case insensitive) + protocols.put(name.toLowerCase(), clazz); + } else { + throw new IllegalArgumentException("Class " + clazz.getName() + " does not implement Protocol interface"); + } + } + + /** + * Get an instance of a protocol, if it is not already created, create a new instance + * + * @param name name of the protocol + * @return instance of the protocol + */ + public static Protocol getInstance(SourceConnectorConfig sourceConnectorConfig, String name) { + // get the class by name(case insensitive) + Class clazz = Optional.ofNullable(protocols.get(name.toLowerCase())) + .orElseThrow(() -> new IllegalArgumentException("Protocol " + name + " is not registered")); + try { + // create a new instance + Protocol protocol = (Protocol) clazz.newInstance(); + // initialize the protocol + protocol.initialize(sourceConnectorConfig); + return protocol; + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException("Failed to instantiate protocol " + name, e); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/WebhookConstants.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/WebhookConstants.java new file mode 100644 index 0000000000..b31637427b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/WebhookConstants.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.protocol; + +public class WebhookConstants { + + /** + * -------------------------------------- About GitHub -------------------------------------- + */ + + // A globally unique identifier (GUID) to identify the delivery. + public static final String GITHUB_DELIVERY = "X-GitHub-Delivery"; + + // This header is sent if the webhook is configured with a secret. + // We recommend that you use the more secure X-Hub-Signature-256 instead + public static final String GITHUB_SIGNATURE = "X-Hub-Signature"; + + // This header is sent if the webhook is configured with a secret + public static final String GITHUB_SIGNATURE_256 = "X-Hub-Signature-256"; + + public static final String GITHUB_HASH_265_PREFIX = "sha256="; + + // The name of the event that triggered the delivery. + public static final String GITHUB_EVENT = "X-GitHub-Event"; + + // The unique identifier of the webhook. + public static final String GITHUB_HOOK_ID = "X-GitHub-Hook-ID"; + + // The unique identifier of the resource where the webhook was created. + public static final String GITHUB_HOOK_INSTALLATION_TARGET_ID = "X-GitHub-Hook-Installation-Target-ID"; + + // The type of resource where the webhook was created. + public static final String GITHUB_HOOK_INSTALLATION_TARGET_TYPE = "X-GitHub-Hook-Installation-Target-Type"; + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/CloudEventProtocol.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/CloudEventProtocol.java new file mode 100644 index 0000000000..10158f6eba --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/CloudEventProtocol.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.protocol.impl; + +import org.apache.eventmesh.common.config.connector.http.SourceConnectorConfig; +import org.apache.eventmesh.connector.http.source.data.CommonResponse; +import org.apache.eventmesh.connector.http.source.protocol.Protocol; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.concurrent.BlockingQueue; + +import io.cloudevents.CloudEvent; +import io.cloudevents.http.vertx.VertxMessageFactory; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.web.Route; + +import lombok.extern.slf4j.Slf4j; + +/** + * CloudEvent Protocol. + */ +@Slf4j +public class CloudEventProtocol implements Protocol { + + // Protocol name + public static final String PROTOCOL_NAME = "CloudEvent"; + + + /** + * Initialize the protocol. + * + * @param sourceConnectorConfig source connector config + */ + @Override + public void initialize(SourceConnectorConfig sourceConnectorConfig) { + + } + + + /** + * Handle the protocol message for CloudEvent. + * + * @param route route + * @param queue queue info + */ + @Override + public void setHandler(Route route, BlockingQueue queue) { + route.method(HttpMethod.POST) + .handler(ctx -> VertxMessageFactory.createReader(ctx.request()) + .map(reader -> { + CloudEvent event = reader.toEvent(); + if (event.getSubject() == null) { + throw new IllegalStateException("attribute 'subject' cannot be null"); + } + if (event.getDataContentType() == null) { + throw new IllegalStateException("attribute 'datacontenttype' cannot be null"); + } + if (event.getData() == null) { + throw new IllegalStateException("attribute 'data' cannot be null"); + } + return event; + }) + .onSuccess(event -> { + // Add the event to the queue, thread-safe + if (!queue.offer(event)) { + throw new IllegalStateException("Failed to store the request."); + } + log.info("[HttpSourceConnector] Succeed to convert payload into CloudEvent. StatusCode={}", HttpResponseStatus.OK.code()); + ctx.response() + .setStatusCode(HttpResponseStatus.OK.code()) + .end(CommonResponse.success().toJsonStr()); + }) + .onFailure(t -> { + log.error("[HttpSourceConnector] Malformed request. StatusCode={}", HttpResponseStatus.BAD_REQUEST.code(), t); + ctx.response() + .setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) + .end(CommonResponse.base(t.getMessage()).toJsonStr()); + })); + } + + /** + * Convert the message to ConnectRecord. + * + * @param message message + * @return ConnectRecord + */ + @Override + public ConnectRecord convertToConnectRecord(Object message) { + return CloudEventUtil.convertEventToRecord((CloudEvent) message); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/CommonProtocol.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/CommonProtocol.java new file mode 100644 index 0000000000..e831dc9723 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/CommonProtocol.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.protocol.impl; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.connector.http.SourceConnectorConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.http.source.data.CommonResponse; +import org.apache.eventmesh.connector.http.source.data.WebhookRequest; +import org.apache.eventmesh.connector.http.source.protocol.Protocol; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.Base64; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.stream.Collectors; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.handler.BodyHandler; + +import lombok.extern.slf4j.Slf4j; + +/** + * Common Protocol. This class represents the common webhook protocol. The processing method of this class does not perform any other operations + * except storing the request and returning a general response. + */ +@Slf4j +public class CommonProtocol implements Protocol { + + public static final String PROTOCOL_NAME = "Common"; + + private SourceConnectorConfig sourceConnectorConfig; + + /** + * Initialize the protocol + * + * @param sourceConnectorConfig source connector config + */ + @Override + public void initialize(SourceConnectorConfig sourceConnectorConfig) { + this.sourceConnectorConfig = sourceConnectorConfig; + } + + /** + * Set the handler for the route + * + * @param route route + * @param queue queue info + */ + @Override + public void setHandler(Route route, BlockingQueue queue) { + route.method(HttpMethod.POST) + .handler(BodyHandler.create()) + .handler(ctx -> { + // Get the payload + Object payload = ctx.body().asString(Constants.DEFAULT_CHARSET.toString()); + payload = JsonUtils.parseObject(payload.toString(), String.class); + + // Create and store the webhook request + Map headerMap = ctx.request().headers().entries().stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + WebhookRequest webhookRequest = new WebhookRequest(PROTOCOL_NAME, ctx.request().absoluteURI(), headerMap, payload, ctx); + if (!queue.offer(webhookRequest)) { + throw new IllegalStateException("Failed to store the request."); + } + + if (!sourceConnectorConfig.isDataConsistencyEnabled()) { + // Return 200 OK + ctx.response() + .setStatusCode(HttpResponseStatus.OK.code()) + .end(CommonResponse.success().toJsonStr()); + } + + }) + .failureHandler(ctx -> { + log.error("Failed to handle the request. ", ctx.failure()); + + // Return Bad Response + ctx.response() + .setStatusCode(ctx.statusCode()) + .end(CommonResponse.base(ctx.failure().getMessage()).toJsonStr()); + }); + + } + + /** + * Convert the message to a connect record + * + * @param message message + * @return connect record + */ + @Override + public ConnectRecord convertToConnectRecord(Object message) { + WebhookRequest request = (WebhookRequest) message; + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), request.getPayload()); + connectRecord.addExtension("source", request.getProtocolName()); + connectRecord.addExtension("url", request.getUrl()); + request.getHeaders().forEach((k, v) -> { + if (k.equalsIgnoreCase("extension")) { + JsonObject extension = new JsonObject(v); + extension.forEach(e -> connectRecord.addExtension(e.getKey(), e.getValue())); + } + }); + // check recordUniqueId + if (!connectRecord.getExtensions().containsKey("recordUniqueId")) { + connectRecord.addExtension("recordUniqueId", connectRecord.getRecordId()); + } + + // check data + if (connectRecord.getExtensionObj("isBase64") != null) { + if (Boolean.parseBoolean(connectRecord.getExtensionObj("isBase64").toString())) { + byte[] data = Base64.getDecoder().decode(connectRecord.getData().toString()); + connectRecord.setData(data); + } + } + if (request.getRoutingContext() != null) { + connectRecord.addExtension("routingContext", request.getRoutingContext()); + } + return connectRecord; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/GitHubProtocol.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/GitHubProtocol.java new file mode 100644 index 0000000000..e1edbd0faf --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/source/protocol/impl/GitHubProtocol.java @@ -0,0 +1,227 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source.protocol.impl; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.connector.http.SourceConnectorConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.http.source.data.CommonResponse; +import org.apache.eventmesh.connector.http.source.data.WebhookRequest; +import org.apache.eventmesh.connector.http.source.protocol.Protocol; +import org.apache.eventmesh.connector.http.source.protocol.WebhookConstants; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.stream.Collectors; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.handler.BodyHandler; + +import com.alibaba.fastjson2.JSONObject; + +import lombok.extern.slf4j.Slf4j; + + +/** + * GitHub Protocol. This class represents the GitHub webhook protocol. + */ +@Slf4j +public class GitHubProtocol implements Protocol { + + // Protocol name + public static final String PROTOCOL_NAME = "GitHub"; + + private static final String H_MAC_SHA_265 = "HmacSHA256"; + + private static final String SECRET_KEY = "secret"; + + private String contentType = "application/json"; + + private String secret; + + + /** + * Initialize the protocol. + * + * @param sourceConnectorConfig source connector config + */ + @Override + public void initialize(SourceConnectorConfig sourceConnectorConfig) { + // Initialize the protocol + Map extraConfig = sourceConnectorConfig.getExtraConfig(); + // set the secret, if it is not set, throw an exception + this.secret = extraConfig.get(SECRET_KEY); + if (StringUtils.isBlank(this.secret)) { + throw new EventMeshException("The secret is required for GitHub protocol."); + } + // if the content-type is not set, use the default value + this.contentType = extraConfig.getOrDefault("contentType", contentType); + } + + /** + * Handle the protocol message for GitHub. + * + * @param route route + * @param queue queue info + */ + @Override + public void setHandler(Route route, BlockingQueue queue) { + route.method(HttpMethod.POST) + .handler(BodyHandler.create()) + .handler(ctx -> { + // Get the payload and headers + String payloadStr = ctx.body().asString(Constants.DEFAULT_CHARSET.toString()); + MultiMap headers = ctx.request().headers(); + + // validate the content type + if (!StringUtils.contains(headers.get("Content-Type"), contentType)) { + String errorMsg = String.format("content-type is invalid, please check the content-type. received content-type: %s", + headers.get("Content-Type")); + // Return Bad Request + ctx.fail(HttpResponseStatus.BAD_REQUEST.code(), new EventMeshException(errorMsg)); + return; + } + + // validate the signature + String signature = headers.get(WebhookConstants.GITHUB_SIGNATURE_256); + if (BooleanUtils.isFalse(validateSignature(signature, payloadStr, secret))) { + String errorMsg = String.format("signature is invalid, please check the secret. received signature: %s", signature); + // Return Bad Request + ctx.fail(HttpResponseStatus.BAD_REQUEST.code(), new EventMeshException(errorMsg)); + return; + } + + // if the content type is form data, convert it to json string + if (StringUtils.contains(contentType, "application/x-www-form-urlencoded") + || StringUtils.contains(contentType, "multipart/form-data")) { + /* + Convert form data to json string. There are the following benefits: + 1. Raw form data is not decoded, so it is not easy to process directly. + 2. Converted to reduce storage space by more than 20 percent. Experimental result: 10329 bytes -> 7893 bytes. + */ + JSONObject payloadObj = new JSONObject(); + ctx.request().formAttributes().forEach(entry -> payloadObj.put(entry.getKey(), entry.getValue())); + payloadStr = payloadObj.toJSONString(); + } + + // Create and store the webhook request + Map headerMap = headers.entries().stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + WebhookRequest webhookRequest = new WebhookRequest(PROTOCOL_NAME, ctx.request().absoluteURI(), headerMap, payloadStr, ctx); + + if (!queue.offer(webhookRequest)) { + throw new IllegalStateException("Failed to store the request."); + } + + // Return 200 OK + ctx.response() + .setStatusCode(HttpResponseStatus.OK.code()) + .end(CommonResponse.success().toJsonStr()); + }) + .failureHandler(ctx -> { + log.error("Failed to handle the request from github. ", ctx.failure()); + + // Return Bad Response + ctx.response() + .setStatusCode(ctx.statusCode()) + .end(CommonResponse.base(ctx.failure().getMessage()).toJsonStr()); + }); + } + + + /** + * Validate the signature. + * + * @param signature signature + * @param payload payload + * @param secret secret + * @return boolean + */ + public boolean validateSignature(String signature, String payload, String secret) { + String hash = WebhookConstants.GITHUB_HASH_265_PREFIX; + try { + Mac sha = Mac.getInstance(H_MAC_SHA_265); + SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(Constants.DEFAULT_CHARSET), H_MAC_SHA_265); + sha.init(secretKey); + byte[] bytes = sha.doFinal(payload.getBytes(Constants.DEFAULT_CHARSET)); + hash += byteArrayToHexString(bytes); + } catch (Exception e) { + throw new EventMeshException("Error occurred while validating the signature.", e); + } + + return hash.equals(signature); + } + + + /** + * Convert the byte array to hex string. + * + * @param bytes bytes + * @return String + */ + private String byteArrayToHexString(byte[] bytes) { + if (bytes == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(0xFF & b); + if (hex.length() == 1) { + // If the length is 1, append 0 + sb.append('0'); + } + sb.append(hex); + } + + return sb.toString(); + } + + + /** + * Convert the message to ConnectRecord. + * + * @param message message + * @return ConnectRecord + */ + @Override + public ConnectRecord convertToConnectRecord(Object message) { + WebhookRequest request = (WebhookRequest) message; + Map headers = request.getHeaders(); + + // Create the ConnectRecord + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), request.getPayload()); + connectRecord.addExtension("id", headers.get(WebhookConstants.GITHUB_DELIVERY)); + connectRecord.addExtension("topic", headers.get(WebhookConstants.GITHUB_EVENT)); + connectRecord.addExtension("source", headers.get(request.getProtocolName())); + connectRecord.addExtension("type", headers.get(WebhookConstants.GITHUB_HOOK_INSTALLATION_TARGET_TYPE)); + return connectRecord; + } + + +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/util/HttpUtils.java b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/util/HttpUtils.java new file mode 100644 index 0000000000..79f9fd120d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/java/org/apache/eventmesh/connector/http/util/HttpUtils.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.util; + +public class HttpUtils { + + /** + * Checks if the status code represents a successful response (2xx). + * + * @param statusCode the HTTP status code to check + * @return true if the status code is 2xx, false otherwise + */ + public static boolean is2xxSuccessful(int statusCode) { + int seriesCode = statusCode / 100; + return seriesCode == 2; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService new file mode 100644 index 0000000000..d62ff11992 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService @@ -0,0 +1,20 @@ +# +# 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. +# + + +HTTP-Source=org.apache.eventmesh.connector.http.source.HttpSourceConnector +HTTP-Sink=org.apache.eventmesh.connector.http.sink.HttpSinkConnector diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..5103525456 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/sink-config.yml @@ -0,0 +1,45 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: httpSink + appId: 5032 + userName: httpSinkUser + passWord: httpPassWord +connectorConfig: + connectorName: httpSink + urls: + - http://127.0.0.1:8987/test + keepAlive: true + keepAliveTimeout: 60000 + idleTimeout: 5000 # timeunit: ms, recommended scope: common(5s - 10s), webhook(15s - 60s) + connectionTimeout: 5000 # timeunit: ms, recommended scope: 5 - 10s + maxConnectionPoolSize: 5 + retryConfig: + maxRetries: 2 + interval: 1000 + retryOnNonSuccess: false + webhookConfig: + activate: false + exportPath: /export + port: 8988 + serverIdleTimeout: 5000 + maxStorageSize: 5000 diff --git a/eventmesh-connectors/eventmesh-connector-http/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/source-config.yml new file mode 100644 index 0000000000..0a73e627b0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/main/resources/source-config.yml @@ -0,0 +1,36 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: httpSource + appId: 5032 + userName: httpSourceUser + passWord: httpPassWord +connectorConfig: + connectorName: httpSource + path: /test + port: 3755 + idleTimeout: 5000 # timeunit: ms + maxFormAttributeSize: 1048576 # timeunit: byte, default: 1048576(1MB). This applies only when handling form data submissions. + protocol: CloudEvent # Case insensitive, default: CloudEvent, options: CloudEvent, GitHub, Common + extraConfig: # extra config for different protocol, e.g. GitHub secret + secret: xxxxxxx # GitHub secret + contentType: application/json # GitHub content type \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-http/src/test/java/org/apache/eventmesh/connector/http/sink/HttpSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-http/src/test/java/org/apache/eventmesh/connector/http/sink/HttpSinkConnectorTest.java new file mode 100644 index 0000000000..be2b52e737 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/test/java/org/apache/eventmesh/connector/http/sink/HttpSinkConnectorTest.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.sink; + + +import static org.mockserver.model.HttpRequest.request; + +import org.apache.eventmesh.common.config.connector.http.HttpSinkConfig; +import org.apache.eventmesh.common.config.connector.http.HttpWebhookConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.net.URIBuilder; + +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +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.mockserver.integration.ClientAndServer; +import org.mockserver.model.HttpResponse; +import org.mockserver.model.MediaType; + + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; + + +public class HttpSinkConnectorTest { + + private HttpSinkConnector sinkConnector; + + private HttpSinkConfig sinkConfig; + + private URL url; + + private ClientAndServer mockServer; + + private static final AtomicInteger counter = new AtomicInteger(0); + + @BeforeEach + void before() throws Exception { + // init sinkConnector + sinkConnector = new HttpSinkConnector(); + sinkConfig = (HttpSinkConfig) ConfigUtil.parse(sinkConnector.configClass()); + sinkConnector.init(this.sinkConfig); + sinkConnector.start(); + + url = new URL(sinkConfig.connectorConfig.getUrls()[0]); + // start mockServer + mockServer = ClientAndServer.startClientAndServer(url.getPort()); + mockServer.reset() + .when( + request() + .withMethod("POST") + .withPath(url.getPath()) + ) + .respond( + httpRequest -> { + // Increase the number of requests received + counter.incrementAndGet(); + return HttpResponse.response() + .withContentType(MediaType.APPLICATION_JSON) + .withStatusCode(HttpStatus.SC_OK) + .withBody(new JSONObject() + .fluentPut("code", 0) + .fluentPut("message", "success") + .toJSONString() + ); // .withDelay(TimeUnit.SECONDS, 10); + } + ); + + } + + @AfterEach + void after() throws Exception { + this.sinkConnector.stop(); + this.mockServer.close(); + } + + @Test + void testPut() throws Exception { + // Create a list of ConnectRecord + final int size = 10; + List connectRecords = new ArrayList<>(); + for (int i = 0; i < size; i++) { + ConnectRecord record = createConnectRecord(); + connectRecords.add(record); + } + // Put ConnectRecord + sinkConnector.put(connectRecords); + + // wait for receiving request + final int times = 5000; // 5 seconds + long start = System.currentTimeMillis(); + while (counter.get() < size) { + if (System.currentTimeMillis() - start > times) { + // timeout + Assertions.fail("The number of requests received=" + counter.get() + " is less than the number of ConnectRecord=" + size); + } else { + Thread.sleep(100); + } + } + + // verify response + HttpWebhookConfig webhookConfig = sinkConfig.connectorConfig.getWebhookConfig(); + + URI exportUrl = new URIBuilder() + .setScheme("http") + .setHost(url.getHost()) + .setPort(webhookConfig.getPort()) + .setPath(webhookConfig.getExportPath()) + .addParameter("pageNum", "1") + .addParameter("pageSize", "10") + .addParameter("type", "poll") + .build(); + + Request.get(exportUrl) + .execute() + .handleResponse(response -> { + // check response code + Assertions.assertEquals(HttpStatus.SC_OK, response.getCode()); + // check response body + JSONObject jsonObject = JSON.parseObject(response.getEntity().getContent()); + JSONArray pageItems = jsonObject.getJSONArray("pageItems"); + + Assertions.assertNotNull(pageItems); + Assertions.assertEquals(size, pageItems.size()); + for (int i = 0; i < size; i++) { + JSONObject pageItem = pageItems.getJSONObject(i); + Assertions.assertNotNull(pageItem); + } + return null; + }); + } + + private ConnectRecord createConnectRecord() { + long timestamp = System.currentTimeMillis(); + return new ConnectRecord(null, null, timestamp, UUID.randomUUID().toString()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-http/src/test/java/org/apache/eventmesh/connector/http/source/HttpSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-http/src/test/java/org/apache/eventmesh/connector/http/source/HttpSourceConnectorTest.java new file mode 100644 index 0000000000..0dbac47653 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/test/java/org/apache/eventmesh/connector/http/source/HttpSourceConnectorTest.java @@ -0,0 +1,179 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.http.source; + + +import org.apache.eventmesh.common.config.connector.http.HttpSourceConfig; +import org.apache.eventmesh.common.config.connector.http.SourceConnectorConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.entity.StringEntity; + +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + + +class HttpSourceConnectorTest { + + private static HttpSourceConnector connector; + private static String url; + private static final String expectedMessage = "testHttpMessage"; + private static final int batchSize = 10; + + + @BeforeAll + static void setUpAll() throws Exception { + connector = new HttpSourceConnector(); + final HttpSourceConfig sourceConfig = (HttpSourceConfig) ConfigUtil.parse(connector.configClass()); + final SourceConnectorConfig config = sourceConfig.getConnectorConfig(); + // initialize and start the connector + connector.init(sourceConfig); + connector.start(); + + // wait for the connector to start + long timeout = 5000; // 5 seconds + long start = System.currentTimeMillis(); + while (!connector.isStarted()) { + if (System.currentTimeMillis() - start > timeout) { + // timeout + Assertions.fail("Failed to start the connector"); + } else { + Thread.sleep(100); + } + } + + url = new URL("http", "127.0.0.1", config.getPort(), config.getPath()).toString(); + } + + @AfterAll + static void tearDownAll() throws IOException { + connector.stop(); + } + + + @Test + void testPollForBinaryRequest() { + for (int i = 0; i < batchSize; i++) { + try { + // Set the request body + StringEntity entity = new StringEntity(expectedMessage, ContentType.TEXT_PLAIN); + + Request.post(url) + .addHeader("Content-Type", "text/plain") + .addHeader("ce-id", String.valueOf(UUID.randomUUID())) + .addHeader("ce-specversion", "1.0") + .addHeader("ce-type", "com.example.someevent") + .addHeader("ce-source", "/mycontext") + .addHeader("ce-subject", "test") + .body(entity) + .execute() + .handleResponse(res -> { + Assertions.assertEquals(HttpStatus.SC_OK, res.getCode()); + return null; + }); + } catch (IOException e) { + Assertions.fail("Failed to send request", e); + } + } + List res = connector.poll(); + Assertions.assertEquals(batchSize, res.size()); + for (ConnectRecord r : res) { + Assertions.assertEquals(expectedMessage, new String((byte[]) r.getData())); + } + } + + @Test + void testPollForStructuredRequest() { + for (int i = 0; i < batchSize; i++) { + try { + // Create a CloudEvent + TestEvent event = new TestEvent(); + event.id = String.valueOf(UUID.randomUUID()); + event.specversion = "1.0"; + event.type = "com.example.someevent"; + event.source = "/mycontext"; + event.subject = "test"; + event.datacontenttype = "text/plain"; + event.data = expectedMessage; + + // Set the request body + StringEntity entity = new StringEntity(Objects.requireNonNull(JsonUtils.toJSONString(event)), ContentType.APPLICATION_JSON); + + // Send the request and return the response + Request.post(url) + .addHeader("Content-Type", "application/cloudevents+json") + .body(entity) + .execute() + .handleResponse(res -> { + Assertions.assertEquals(HttpStatus.SC_OK, res.getCode()); + return null; + }); + } catch (IOException e) { + Assertions.fail("Failed to send request", e); + } + } + List res = connector.poll(); + Assertions.assertEquals(batchSize, res.size()); + for (ConnectRecord r : res) { + Assertions.assertEquals(expectedMessage, new String((byte[]) r.getData())); + } + } + + + @Test + void testPollForInvalidRequest() { + // Send a bad request. + try { + Request.post(url) + .addHeader("Content-Type", "text/plain") + .execute() + .handleResponse(res -> { + // Check the response code + Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, res.getCode()); + return null; + }); + } catch (IOException e) { + Assertions.fail("Failed to send request", e); + } + } + + class TestEvent { + + public String specversion; + public String type; + public String source; + public String subject; + public String datacontenttype; + public String id; + + public String data; + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-http/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-http/src/test/resources/server-config.yml new file mode 100644 index 0000000000..0cd7b5b5ab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/test/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false diff --git a/eventmesh-connectors/eventmesh-connector-http/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-http/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..3ea4238790 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/test/resources/sink-config.yml @@ -0,0 +1,45 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: httpSink + appId: 5032 + userName: httpSinkUser + passWord: httpPassWord +connectorConfig: + connectorName: httpSink + urls: + - http://127.0.0.1:8987/test + keepAlive: true + keepAliveTimeout: 60000 + idleTimeout: 15000 # timeunit: ms, recommended scope: common(5s - 10s), webhook(15s - 60s) + connectionTimeout: 5000 # timeunit: ms, recommended scope: 5 - 10s + maxConnectionPoolSize: 10 + retryConfig: + maxRetries: 2 + interval: 1000 + retryOnNonSuccess: true + webhookConfig: + activate: true + exportPath: /export + port: 8988 + serverIdleTimeout: 5000 + maxStorageSize: 5000 \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-http/src/test/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-http/src/test/resources/source-config.yml new file mode 100644 index 0000000000..336bb2cb5e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-http/src/test/resources/source-config.yml @@ -0,0 +1,36 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: httpSource + appId: 5032 + userName: httpSourceUser + passWord: httpmqPassWord +connectorConfig: + connectorName: httpSource + path: /test + port: 3755 + idleTimeout: 5000 # timeunit: ms + maxFormAttributeSize: 1048576 # timeunit: byte, default: 1048576(1MB). This applies only when handling form data submissions. + protocol: CloudEvent # Case insensitive, default: CloudEvent, options: CloudEvent, GitHub, Common + extraConfig: # extra config for different protocol, e.g. GitHub secret + secret: xxxxxxx # GitHub secret + contentType: application/json # GitHub content type \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/build.gradle b/eventmesh-connectors/eventmesh-connector-jdbc/build.gradle new file mode 100644 index 0000000000..b70bf6d357 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/build.gradle @@ -0,0 +1,53 @@ +/* + * 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. + */ + +plugins { + id 'antlr' +} + +repositories { + mavenCentral() +} + +generateGrammarSource { + maxHeapSize = '64m' + arguments += ['-package', 'org.apache.eventmesh.connector.jdbc.antlr4.autogeneration', '-visitor'] + outputDirectory = file('src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/autogeneration') +} + +packageSources { + dependsOn generateGrammarSource +} + +dependencies { + antlr("org.antlr:antlr4:4.13.1") + implementation 'org.antlr:antlr4-runtime:4.13.1' + implementation 'com.alibaba:druid:1.2.23' + compileOnly 'org.hibernate:hibernate-core:5.6.15.Final' + implementation project(":eventmesh-common") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-spi") + implementation 'com.zendesk:mysql-binlog-connector-java:0.30.1' + compileOnly 'com.mysql:mysql-connector-j' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.assertj:assertj-core" + + testImplementation "org.mockito:mockito-core" +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/gradle.properties b/eventmesh-connectors/eventmesh-connector-jdbc/gradle.properties new file mode 100644 index 0000000000..e230cab2e4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=jdbc \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/antlr/MySqlLexer.g4 b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/antlr/MySqlLexer.g4 new file mode 100644 index 0000000000..6ecef13c3e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/antlr/MySqlLexer.g4 @@ -0,0 +1,1356 @@ +/* + * 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. + */ + + +lexer grammar MySqlLexer; + +options { caseInsensitive = true; } + +channels { MYSQLCOMMENT, ERRORCHANNEL } + +// SKIP + +SPACE: [ \t\r\n]+ -> channel(HIDDEN); +SPEC_MYSQL_COMMENT: '/*!' .+? '*/' -> channel(MYSQLCOMMENT); +COMMENT_INPUT: '/*' .*? '*/' -> channel(HIDDEN); +LINE_COMMENT: ( + ('--' [ \t]* | '#') ~[\r\n]* ('\r'? '\n' | EOF) + | '--' ('\r'? '\n' | EOF) + ) -> channel(HIDDEN); + + +// Keywords +// Common Keywords + +ADD: 'ADD'; +ALL: 'ALL'; +ALTER: 'ALTER'; +ALWAYS: 'ALWAYS'; +ANALYZE: 'ANALYZE'; +AND: 'AND'; +ARRAY: 'ARRAY'; +AS: 'AS'; +ASC: 'ASC'; +ATTRIBUTE: 'ATTRIBUTE'; +BEFORE: 'BEFORE'; +BETWEEN: 'BETWEEN'; +BOTH: 'BOTH'; +BUCKETS: 'BUCKETS'; +BY: 'BY'; +CALL: 'CALL'; +CASCADE: 'CASCADE'; +CASE: 'CASE'; +CAST: 'CAST'; +CHANGE: 'CHANGE'; +CHARACTER: 'CHARACTER'; +CHECK: 'CHECK'; +COLLATE: 'COLLATE'; +COLUMN: 'COLUMN'; +CONDITION: 'CONDITION'; +CONSTRAINT: 'CONSTRAINT'; +CONTINUE: 'CONTINUE'; +CONVERT: 'CONVERT'; +CREATE: 'CREATE'; +CROSS: 'CROSS'; +CURRENT: 'CURRENT'; +CURRENT_ROLE: 'CURRENT_ROLE'; +CURRENT_USER: 'CURRENT_USER'; +CURSOR: 'CURSOR'; +DATABASE: 'DATABASE'; +DATABASES: 'DATABASES'; +DECLARE: 'DECLARE'; +DEFAULT: 'DEFAULT'; +DELAYED: 'DELAYED'; +DELETE: 'DELETE'; +DESC: 'DESC'; +DESCRIBE: 'DESCRIBE'; +DETERMINISTIC: 'DETERMINISTIC'; +DIAGNOSTICS: 'DIAGNOSTICS'; +DISTINCT: 'DISTINCT'; +DISTINCTROW: 'DISTINCTROW'; +DROP: 'DROP'; +EACH: 'EACH'; +ELSE: 'ELSE'; +ELSEIF: 'ELSEIF'; +EMPTY: 'EMPTY'; +ENCLOSED: 'ENCLOSED'; +ENFORCED: 'ENFORCED'; +ESCAPED: 'ESCAPED'; +EXCEPT: 'EXCEPT'; +EXISTS: 'EXISTS'; +EXIT: 'EXIT'; +EXPLAIN: 'EXPLAIN'; +FALSE: 'FALSE'; +FETCH: 'FETCH'; +FOR: 'FOR'; +FORCE: 'FORCE'; +FOREIGN: 'FOREIGN'; +FROM: 'FROM'; +FULLTEXT: 'FULLTEXT'; +GENERATED: 'GENERATED'; +GET: 'GET'; +GRANT: 'GRANT'; +GROUP: 'GROUP'; +HAVING: 'HAVING'; +HIGH_PRIORITY: 'HIGH_PRIORITY'; +HISTOGRAM: 'HISTOGRAM'; +IF: 'IF'; +IGNORE: 'IGNORE'; +IGNORED: 'IGNORED'; +IN: 'IN'; +INDEX: 'INDEX'; +INFILE: 'INFILE'; +INNER: 'INNER'; +INOUT: 'INOUT'; +INSERT: 'INSERT'; +INTERVAL: 'INTERVAL'; +INTO: 'INTO'; +IS: 'IS'; +ITERATE: 'ITERATE'; +JOIN: 'JOIN'; +KEY: 'KEY'; +KEYS: 'KEYS'; +KILL: 'KILL'; +LATERAL: 'LATERAL'; +LEADING: 'LEADING'; +LEAVE: 'LEAVE'; +LEFT: 'LEFT'; +LIKE: 'LIKE'; +LIMIT: 'LIMIT'; +LINEAR: 'LINEAR'; +LINES: 'LINES'; +LOAD: 'LOAD'; +LOCK: 'LOCK'; +LOCKED: 'LOCKED'; +LOOP: 'LOOP'; +LOW_PRIORITY: 'LOW_PRIORITY'; +MASTER_BIND: 'MASTER_BIND'; +MASTER_SSL_VERIFY_SERVER_CERT: 'MASTER_SSL_VERIFY_SERVER_CERT'; +MATCH: 'MATCH'; +MAXVALUE: 'MAXVALUE'; +MINVALUE: 'MINVALUE'; +MODIFIES: 'MODIFIES'; +NATURAL: 'NATURAL'; +NOT: 'NOT'; +NO_WRITE_TO_BINLOG: 'NO_WRITE_TO_BINLOG'; +NULL_LITERAL: 'NULL'; +NUMBER: 'NUMBER'; +ON: 'ON'; +OPTIMIZE: 'OPTIMIZE'; +OPTION: 'OPTION'; +OPTIONAL: 'OPTIONAL'; +OPTIONALLY: 'OPTIONALLY'; +OR: 'OR'; +ORDER: 'ORDER'; +OUT: 'OUT'; +OUTER: 'OUTER'; +OUTFILE: 'OUTFILE'; +OVER: 'OVER'; +PARTITION: 'PARTITION'; +PRIMARY: 'PRIMARY'; +PROCEDURE: 'PROCEDURE'; +PURGE: 'PURGE'; +RANGE: 'RANGE'; +READ: 'READ'; +READS: 'READS'; +REFERENCES: 'REFERENCES'; +REGEXP: 'REGEXP'; +RELEASE: 'RELEASE'; +RENAME: 'RENAME'; +REPEAT: 'REPEAT'; +REPLACE: 'REPLACE'; +REQUIRE: 'REQUIRE'; +RESIGNAL: 'RESIGNAL'; +RESTRICT: 'RESTRICT'; +RETAIN: 'RETAIN'; +RETURN: 'RETURN'; +REVOKE: 'REVOKE'; +RIGHT: 'RIGHT'; +RLIKE: 'RLIKE'; +SCHEMA: 'SCHEMA'; +SCHEMAS: 'SCHEMAS'; +SELECT: 'SELECT'; +SET: 'SET'; +SEPARATOR: 'SEPARATOR'; +SHOW: 'SHOW'; +SIGNAL: 'SIGNAL'; +SKIP_: 'SKIP'; +SKIP_QUERY_REWRITE: 'SKIP_QUERY_REWRITE'; +SPATIAL: 'SPATIAL'; +SQL: 'SQL'; +SQLEXCEPTION: 'SQLEXCEPTION'; +SQLSTATE: 'SQLSTATE'; +SQLWARNING: 'SQLWARNING'; +SQL_BIG_RESULT: 'SQL_BIG_RESULT'; +SQL_CALC_FOUND_ROWS: 'SQL_CALC_FOUND_ROWS'; +SQL_SMALL_RESULT: 'SQL_SMALL_RESULT'; +SSL: 'SSL'; +STACKED: 'STACKED'; +STARTING: 'STARTING'; +STATEMENT: 'STATEMENT'; +STRAIGHT_JOIN: 'STRAIGHT_JOIN'; +TABLE: 'TABLE'; +TERMINATED: 'TERMINATED'; +THEN: 'THEN'; +TO: 'TO'; +TRAILING: 'TRAILING'; +TRIGGER: 'TRIGGER'; +TRUE: 'TRUE'; +UNDO: 'UNDO'; +UNION: 'UNION'; +UNIQUE: 'UNIQUE'; +UNLOCK: 'UNLOCK'; +UNSIGNED: 'UNSIGNED'; +UPDATE: 'UPDATE'; +USAGE: 'USAGE'; +USE: 'USE'; +USING: 'USING'; +VALUES: 'VALUES'; +WHEN: 'WHEN'; +WHERE: 'WHERE'; +WHILE: 'WHILE'; +WITH: 'WITH'; +WRITE: 'WRITE'; +XOR: 'XOR'; +ZEROFILL: 'ZEROFILL'; + +// DATA TYPE Keywords + +TINYINT: 'TINYINT'; +SMALLINT: 'SMALLINT'; +MEDIUMINT: 'MEDIUMINT'; +MIDDLEINT: 'MIDDLEINT'; +INT: 'INT'; +INT1: 'INT1'; +INT2: 'INT2'; +INT3: 'INT3'; +INT4: 'INT4'; +INT8: 'INT8'; +INTEGER: 'INTEGER'; +BIGINT: 'BIGINT'; +REAL: 'REAL'; +DOUBLE: 'DOUBLE'; +PRECISION: 'PRECISION'; +FLOAT: 'FLOAT'; +FLOAT4: 'FLOAT4'; +FLOAT8: 'FLOAT8'; +DECIMAL: 'DECIMAL'; +DEC: 'DEC'; +NUMERIC: 'NUMERIC'; +DATE: 'DATE'; +TIME: 'TIME'; +TIMESTAMP: 'TIMESTAMP'; +DATETIME: 'DATETIME'; +YEAR: 'YEAR'; +CHAR: 'CHAR'; +VARCHAR: 'VARCHAR'; +NVARCHAR: 'NVARCHAR'; +NATIONAL: 'NATIONAL'; +BINARY: 'BINARY'; +VARBINARY: 'VARBINARY'; +TINYBLOB: 'TINYBLOB'; +BLOB: 'BLOB'; +MEDIUMBLOB: 'MEDIUMBLOB'; +LONG: 'LONG'; +LONGBLOB: 'LONGBLOB'; +TINYTEXT: 'TINYTEXT'; +TEXT: 'TEXT'; +MEDIUMTEXT: 'MEDIUMTEXT'; +LONGTEXT: 'LONGTEXT'; +ENUM: 'ENUM'; +VARYING: 'VARYING'; +SERIAL: 'SERIAL'; + + +// Interval type Keywords + +YEAR_MONTH: 'YEAR_MONTH'; +DAY_HOUR: 'DAY_HOUR'; +DAY_MINUTE: 'DAY_MINUTE'; +DAY_SECOND: 'DAY_SECOND'; +HOUR_MINUTE: 'HOUR_MINUTE'; +HOUR_SECOND: 'HOUR_SECOND'; +MINUTE_SECOND: 'MINUTE_SECOND'; +SECOND_MICROSECOND: 'SECOND_MICROSECOND'; +MINUTE_MICROSECOND: 'MINUTE_MICROSECOND'; +HOUR_MICROSECOND: 'HOUR_MICROSECOND'; +DAY_MICROSECOND: 'DAY_MICROSECOND'; + +// JSON keywords +JSON_ARRAY: 'JSON_ARRAY'; +JSON_ARRAYAGG: 'JSON_ARRAYAGG'; +JSON_ARRAY_APPEND: 'JSON_ARRAY_APPEND'; +JSON_ARRAY_INSERT: 'JSON_ARRAY_INSERT'; +JSON_CONTAINS: 'JSON_CONTAINS'; +JSON_CONTAINS_PATH: 'JSON_CONTAINS_PATH'; +JSON_DEPTH: 'JSON_DEPTH'; +JSON_EXTRACT: 'JSON_EXTRACT'; +JSON_INSERT: 'JSON_INSERT'; +JSON_KEYS: 'JSON_KEYS'; +JSON_LENGTH: 'JSON_LENGTH'; +JSON_MERGE: 'JSON_MERGE'; +JSON_MERGE_PATCH: 'JSON_MERGE_PATCH'; +JSON_MERGE_PRESERVE: 'JSON_MERGE_PRESERVE'; +JSON_OBJECT: 'JSON_OBJECT'; +JSON_OBJECTAGG: 'JSON_OBJECTAGG'; +JSON_OVERLAPS: 'JSON_OVERLAPS'; +JSON_PRETTY: 'JSON_PRETTY'; +JSON_QUOTE: 'JSON_QUOTE'; +JSON_REMOVE: 'JSON_REMOVE'; +JSON_REPLACE: 'JSON_REPLACE'; +JSON_SCHEMA_VALID: 'JSON_SCHEMA_VALID'; +JSON_SCHEMA_VALIDATION_REPORT: 'JSON_SCHEMA_VALIDATION_REPORT'; +JSON_SEARCH: 'JSON_SEARCH'; +JSON_SET: 'JSON_SET'; +JSON_STORAGE_FREE: 'JSON_STORAGE_FREE'; +JSON_STORAGE_SIZE: 'JSON_STORAGE_SIZE'; +JSON_TABLE: 'JSON_TABLE'; +JSON_TYPE: 'JSON_TYPE'; +JSON_UNQUOTE: 'JSON_UNQUOTE'; +JSON_VALID: 'JSON_VALID'; +JSON_VALUE: 'JSON_VALUE'; +NESTED: 'NESTED'; +ORDINALITY: 'ORDINALITY'; +PATH: 'PATH'; + +// Group function Keywords + +AVG: 'AVG'; +BIT_AND: 'BIT_AND'; +BIT_OR: 'BIT_OR'; +BIT_XOR: 'BIT_XOR'; +COUNT: 'COUNT'; +CUME_DIST: 'CUME_DIST'; +DENSE_RANK: 'DENSE_RANK'; +FIRST_VALUE: 'FIRST_VALUE'; +GROUP_CONCAT: 'GROUP_CONCAT'; +LAG: 'LAG'; +LAST_VALUE: 'LAST_VALUE'; +LEAD: 'LEAD'; +MAX: 'MAX'; +MIN: 'MIN'; +NTILE: 'NTILE'; +NTH_VALUE: 'NTH_VALUE'; +PERCENT_RANK: 'PERCENT_RANK'; +RANK: 'RANK'; +ROW_NUMBER: 'ROW_NUMBER'; +STD: 'STD'; +STDDEV: 'STDDEV'; +STDDEV_POP: 'STDDEV_POP'; +STDDEV_SAMP: 'STDDEV_SAMP'; +SUM: 'SUM'; +VAR_POP: 'VAR_POP'; +VAR_SAMP: 'VAR_SAMP'; +VARIANCE: 'VARIANCE'; + +// Common function Keywords + +CURRENT_DATE: 'CURRENT_DATE'; +CURRENT_TIME: 'CURRENT_TIME'; +CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'; +LOCALTIME: 'LOCALTIME'; +CURDATE: 'CURDATE'; +CURTIME: 'CURTIME'; +DATE_ADD: 'DATE_ADD'; +DATE_SUB: 'DATE_SUB'; +EXTRACT: 'EXTRACT'; +LOCALTIMESTAMP: 'LOCALTIMESTAMP'; +NOW: 'NOW'; +POSITION: 'POSITION'; +SUBSTR: 'SUBSTR'; +SUBSTRING: 'SUBSTRING'; +SYSDATE: 'SYSDATE'; +TRIM: 'TRIM'; +UTC_DATE: 'UTC_DATE'; +UTC_TIME: 'UTC_TIME'; +UTC_TIMESTAMP: 'UTC_TIMESTAMP'; + +// Keywords, but can be ID +// Common Keywords, but can be ID + +ACCOUNT: 'ACCOUNT'; +ACTION: 'ACTION'; +AFTER: 'AFTER'; +AGGREGATE: 'AGGREGATE'; +ALGORITHM: 'ALGORITHM'; +ANY: 'ANY'; +AT: 'AT'; +AUTHORS: 'AUTHORS'; +AUTOCOMMIT: 'AUTOCOMMIT'; +AUTOEXTEND_SIZE: 'AUTOEXTEND_SIZE'; +AUTO_INCREMENT: 'AUTO_INCREMENT'; +AVG_ROW_LENGTH: 'AVG_ROW_LENGTH'; +BEGIN: 'BEGIN'; +BINLOG: 'BINLOG'; +BIT: 'BIT'; +BLOCK: 'BLOCK'; +BOOL: 'BOOL'; +BOOLEAN: 'BOOLEAN'; +BTREE: 'BTREE'; +CACHE: 'CACHE'; +CASCADED: 'CASCADED'; +CHAIN: 'CHAIN'; +CHANGED: 'CHANGED'; +CHANNEL: 'CHANNEL'; +CHECKSUM: 'CHECKSUM'; +PAGE_CHECKSUM: 'PAGE_CHECKSUM'; +CIPHER: 'CIPHER'; +CLASS_ORIGIN: 'CLASS_ORIGIN'; +CLIENT: 'CLIENT'; +CLOSE: 'CLOSE'; +CLUSTERING: 'CLUSTERING'; +COALESCE: 'COALESCE'; +CODE: 'CODE'; +COLUMNS: 'COLUMNS'; +COLUMN_FORMAT: 'COLUMN_FORMAT'; +COLUMN_NAME: 'COLUMN_NAME'; +COMMENT: 'COMMENT'; +COMMIT: 'COMMIT'; +COMPACT: 'COMPACT'; +COMPLETION: 'COMPLETION'; +COMPRESSED: 'COMPRESSED'; +COMPRESSION: 'COMPRESSION' | QUOTE_SYMB? 'COMPRESSION' QUOTE_SYMB?; +CONCURRENT: 'CONCURRENT'; +CONNECT: 'CONNECT'; +CONNECTION: 'CONNECTION'; +CONSISTENT: 'CONSISTENT'; +CONSTRAINT_CATALOG: 'CONSTRAINT_CATALOG'; +CONSTRAINT_SCHEMA: 'CONSTRAINT_SCHEMA'; +CONSTRAINT_NAME: 'CONSTRAINT_NAME'; +CONTAINS: 'CONTAINS'; +CONTEXT: 'CONTEXT'; +CONTRIBUTORS: 'CONTRIBUTORS'; +COPY: 'COPY'; +CPU: 'CPU'; +CYCLE: 'CYCLE'; +CURSOR_NAME: 'CURSOR_NAME'; +DATA: 'DATA'; +DATAFILE: 'DATAFILE'; +DEALLOCATE: 'DEALLOCATE'; +DEFAULT_AUTH: 'DEFAULT_AUTH'; +DEFINER: 'DEFINER'; +DELAY_KEY_WRITE: 'DELAY_KEY_WRITE'; +DES_KEY_FILE: 'DES_KEY_FILE'; +DIRECTORY: 'DIRECTORY'; +DISABLE: 'DISABLE'; +DISCARD: 'DISCARD'; +DISK: 'DISK'; +DO: 'DO'; +DUMPFILE: 'DUMPFILE'; +DUPLICATE: 'DUPLICATE'; +DYNAMIC: 'DYNAMIC'; +ENABLE: 'ENABLE'; +ENCRYPTED: 'ENCRYPTED'; +ENCRYPTION: 'ENCRYPTION'; +ENCRYPTION_KEY_ID: 'ENCRYPTION_KEY_ID'; +END: 'END'; +ENDS: 'ENDS'; +ENGINE: 'ENGINE'; +ENGINES: 'ENGINES'; +ERROR: 'ERROR'; +ERRORS: 'ERRORS'; +ESCAPE: 'ESCAPE'; +EVEN: 'EVEN'; +EVENT: 'EVENT'; +EVENTS: 'EVENTS'; +EVERY: 'EVERY'; +EXCHANGE: 'EXCHANGE'; +EXCLUSIVE: 'EXCLUSIVE'; +EXPIRE: 'EXPIRE'; +EXPORT: 'EXPORT'; +EXTENDED: 'EXTENDED'; +EXTENT_SIZE: 'EXTENT_SIZE'; +FAILED_LOGIN_ATTEMPTS: 'FAILED_LOGIN_ATTEMPTS'; +FAST: 'FAST'; +FAULTS: 'FAULTS'; +FIELDS: 'FIELDS'; +FILE_BLOCK_SIZE: 'FILE_BLOCK_SIZE'; +FILTER: 'FILTER'; +FIRST: 'FIRST'; +FIXED: 'FIXED'; +FLUSH: 'FLUSH'; +FOLLOWING: 'FOLLOWING'; +FOLLOWS: 'FOLLOWS'; +FOUND: 'FOUND'; +FULL: 'FULL'; +FUNCTION: 'FUNCTION'; +GENERAL: 'GENERAL'; +GLOBAL: 'GLOBAL'; +GRANTS: 'GRANTS'; +GROUP_REPLICATION: 'GROUP_REPLICATION'; +HANDLER: 'HANDLER'; +HASH: 'HASH'; +HELP: 'HELP'; +HISTORY: 'HISTORY'; +HOST: 'HOST'; +HOSTS: 'HOSTS'; +IDENTIFIED: 'IDENTIFIED'; +IGNORE_SERVER_IDS: 'IGNORE_SERVER_IDS'; +IMPORT: 'IMPORT'; +INCREMENT: 'INCREMENT'; +INDEXES: 'INDEXES'; +INITIAL_SIZE: 'INITIAL_SIZE'; +INPLACE: 'INPLACE'; +INSERT_METHOD: 'INSERT_METHOD'; +INSTALL: 'INSTALL'; +INSTANCE: 'INSTANCE'; +INSTANT: 'INSTANT'; +INVISIBLE: 'INVISIBLE'; +INVOKER: 'INVOKER'; +IO: 'IO'; +IO_THREAD: 'IO_THREAD'; +IPC: 'IPC'; +ISOLATION: 'ISOLATION'; +ISSUER: 'ISSUER'; +JSON: 'JSON'; +KEY_BLOCK_SIZE: 'KEY_BLOCK_SIZE'; +LANGUAGE: 'LANGUAGE'; +LAST: 'LAST'; +LEAVES: 'LEAVES'; +LESS: 'LESS'; +LEVEL: 'LEVEL'; +LIST: 'LIST'; +LOCAL: 'LOCAL'; +LOGFILE: 'LOGFILE'; +LOGS: 'LOGS'; +MASTER: 'MASTER'; +MASTER_AUTO_POSITION: 'MASTER_AUTO_POSITION'; +MASTER_CONNECT_RETRY: 'MASTER_CONNECT_RETRY'; +MASTER_DELAY: 'MASTER_DELAY'; +MASTER_HEARTBEAT_PERIOD: 'MASTER_HEARTBEAT_PERIOD'; +MASTER_HOST: 'MASTER_HOST'; +MASTER_LOG_FILE: 'MASTER_LOG_FILE'; +MASTER_LOG_POS: 'MASTER_LOG_POS'; +MASTER_PASSWORD: 'MASTER_PASSWORD'; +MASTER_PORT: 'MASTER_PORT'; +MASTER_RETRY_COUNT: 'MASTER_RETRY_COUNT'; +MASTER_SSL: 'MASTER_SSL'; +MASTER_SSL_CA: 'MASTER_SSL_CA'; +MASTER_SSL_CAPATH: 'MASTER_SSL_CAPATH'; +MASTER_SSL_CERT: 'MASTER_SSL_CERT'; +MASTER_SSL_CIPHER: 'MASTER_SSL_CIPHER'; +MASTER_SSL_CRL: 'MASTER_SSL_CRL'; +MASTER_SSL_CRLPATH: 'MASTER_SSL_CRLPATH'; +MASTER_SSL_KEY: 'MASTER_SSL_KEY'; +MASTER_TLS_VERSION: 'MASTER_TLS_VERSION'; +MASTER_USER: 'MASTER_USER'; +MAX_CONNECTIONS_PER_HOUR: 'MAX_CONNECTIONS_PER_HOUR'; +MAX_QUERIES_PER_HOUR: 'MAX_QUERIES_PER_HOUR'; +MAX_ROWS: 'MAX_ROWS'; +MAX_SIZE: 'MAX_SIZE'; +MAX_UPDATES_PER_HOUR: 'MAX_UPDATES_PER_HOUR'; +MAX_USER_CONNECTIONS: 'MAX_USER_CONNECTIONS'; +MEDIUM: 'MEDIUM'; +MEMBER: 'MEMBER'; +MERGE: 'MERGE'; +MESSAGE_TEXT: 'MESSAGE_TEXT'; +MID: 'MID'; +MIGRATE: 'MIGRATE'; +MIN_ROWS: 'MIN_ROWS'; +MODE: 'MODE'; +MODIFY: 'MODIFY'; +MUTEX: 'MUTEX'; +MYSQL: 'MYSQL'; +MYSQL_ERRNO: 'MYSQL_ERRNO'; +NAME: 'NAME'; +NAMES: 'NAMES'; +NCHAR: 'NCHAR'; +NEVER: 'NEVER'; +NEXT: 'NEXT'; +NO: 'NO'; +NOCACHE: 'NOCACHE'; +NOCOPY: 'NOCOPY'; +NOCYCLE: 'NOCYCLE'; +NOMAXVALUE: 'NOMAXVALUE'; +NOMINVALUE: 'NOMINVALUE'; +NOWAIT: 'NOWAIT'; +NODEGROUP: 'NODEGROUP'; +NONE: 'NONE'; +ODBC: 'ODBC'; +OFFLINE: 'OFFLINE'; +OFFSET: 'OFFSET'; +OF: 'OF'; +OJ: 'OJ'; +OLD_PASSWORD: 'OLD_PASSWORD'; +ONE: 'ONE'; +ONLINE: 'ONLINE'; +ONLY: 'ONLY'; +OPEN: 'OPEN'; +OPTIMIZER_COSTS: 'OPTIMIZER_COSTS'; +OPTIONS: 'OPTIONS'; +OWNER: 'OWNER'; +PACK_KEYS: 'PACK_KEYS'; +PAGE: 'PAGE'; +PAGE_COMPRESSED: 'PAGE_COMPRESSED'; +PAGE_COMPRESSION_LEVEL: 'PAGE_COMPRESSION_LEVEL'; +PARSER: 'PARSER'; +PARTIAL: 'PARTIAL'; +PARTITIONING: 'PARTITIONING'; +PARTITIONS: 'PARTITIONS'; +PASSWORD: 'PASSWORD'; +PASSWORD_LOCK_TIME: 'PASSWORD_LOCK_TIME'; +PHASE: 'PHASE'; +PLUGIN: 'PLUGIN'; +PLUGIN_DIR: 'PLUGIN_DIR'; +PLUGINS: 'PLUGINS'; +PORT: 'PORT'; +PRECEDES: 'PRECEDES'; +PRECEDING: 'PRECEDING'; +PREPARE: 'PREPARE'; +PRESERVE: 'PRESERVE'; +PREV: 'PREV'; +PROCESSLIST: 'PROCESSLIST'; +PROFILE: 'PROFILE'; +PROFILES: 'PROFILES'; +PROXY: 'PROXY'; +QUERY: 'QUERY'; +QUICK: 'QUICK'; +REBUILD: 'REBUILD'; +RECOVER: 'RECOVER'; +RECURSIVE: 'RECURSIVE'; +REDO_BUFFER_SIZE: 'REDO_BUFFER_SIZE'; +REDUNDANT: 'REDUNDANT'; +RELAY: 'RELAY'; +RELAY_LOG_FILE: 'RELAY_LOG_FILE'; +RELAY_LOG_POS: 'RELAY_LOG_POS'; +RELAYLOG: 'RELAYLOG'; +REMOVE: 'REMOVE'; +REORGANIZE: 'REORGANIZE'; +REPAIR: 'REPAIR'; +REPLICATE_DO_DB: 'REPLICATE_DO_DB'; +REPLICATE_DO_TABLE: 'REPLICATE_DO_TABLE'; +REPLICATE_IGNORE_DB: 'REPLICATE_IGNORE_DB'; +REPLICATE_IGNORE_TABLE: 'REPLICATE_IGNORE_TABLE'; +REPLICATE_REWRITE_DB: 'REPLICATE_REWRITE_DB'; +REPLICATE_WILD_DO_TABLE: 'REPLICATE_WILD_DO_TABLE'; +REPLICATE_WILD_IGNORE_TABLE: 'REPLICATE_WILD_IGNORE_TABLE'; +REPLICATION: 'REPLICATION'; +RESET: 'RESET'; +RESTART: 'RESTART'; +RESUME: 'RESUME'; +RETURNED_SQLSTATE: 'RETURNED_SQLSTATE'; +RETURNING: 'RETURNING'; +RETURNS: 'RETURNS'; +REUSE: 'REUSE'; +ROLE: 'ROLE'; +ROLLBACK: 'ROLLBACK'; +ROLLUP: 'ROLLUP'; +ROTATE: 'ROTATE'; +ROW: 'ROW'; +ROWS: 'ROWS'; +ROW_FORMAT: 'ROW_FORMAT'; +RTREE: 'RTREE'; +SAVEPOINT: 'SAVEPOINT'; +SCHEDULE: 'SCHEDULE'; +SECURITY: 'SECURITY'; +SEQUENCE: 'SEQUENCE'; +SERVER: 'SERVER'; +SESSION: 'SESSION'; +SHARE: 'SHARE'; +SHARED: 'SHARED'; +SIGNED: 'SIGNED'; +SIMPLE: 'SIMPLE'; +SLAVE: 'SLAVE'; +SLOW: 'SLOW'; +SNAPSHOT: 'SNAPSHOT'; +SOCKET: 'SOCKET'; +SOME: 'SOME'; +SONAME: 'SONAME'; +SOUNDS: 'SOUNDS'; +SOURCE: 'SOURCE'; +SQL_AFTER_GTIDS: 'SQL_AFTER_GTIDS'; +SQL_AFTER_MTS_GAPS: 'SQL_AFTER_MTS_GAPS'; +SQL_BEFORE_GTIDS: 'SQL_BEFORE_GTIDS'; +SQL_BUFFER_RESULT: 'SQL_BUFFER_RESULT'; +SQL_CACHE: 'SQL_CACHE'; +SQL_NO_CACHE: 'SQL_NO_CACHE'; +SQL_THREAD: 'SQL_THREAD'; +START: 'START'; +STARTS: 'STARTS'; +STATS_AUTO_RECALC: 'STATS_AUTO_RECALC'; +STATS_PERSISTENT: 'STATS_PERSISTENT'; +STATS_SAMPLE_PAGES: 'STATS_SAMPLE_PAGES'; +STATUS: 'STATUS'; +STOP: 'STOP'; +STORAGE: 'STORAGE'; +STORED: 'STORED'; +STRING: 'STRING'; +SUBCLASS_ORIGIN: 'SUBCLASS_ORIGIN'; +SUBJECT: 'SUBJECT'; +SUBPARTITION: 'SUBPARTITION'; +SUBPARTITIONS: 'SUBPARTITIONS'; +SUSPEND: 'SUSPEND'; +SWAPS: 'SWAPS'; +SWITCHES: 'SWITCHES'; +TABLE_NAME: 'TABLE_NAME'; +TABLESPACE: 'TABLESPACE'; +TABLE_TYPE: 'TABLE_TYPE'; +TEMPORARY: 'TEMPORARY'; +TEMPTABLE: 'TEMPTABLE'; +THAN: 'THAN'; +TRADITIONAL: 'TRADITIONAL'; +TRANSACTION: 'TRANSACTION'; +TRANSACTIONAL: 'TRANSACTIONAL'; +TRIGGERS: 'TRIGGERS'; +TRUNCATE: 'TRUNCATE'; +UNBOUNDED: 'UNBOUNDED'; +UNDEFINED: 'UNDEFINED'; +UNDOFILE: 'UNDOFILE'; +UNDO_BUFFER_SIZE: 'UNDO_BUFFER_SIZE'; +UNINSTALL: 'UNINSTALL'; +UNKNOWN: 'UNKNOWN'; +UNTIL: 'UNTIL'; +UPGRADE: 'UPGRADE'; +USER: 'USER'; +USE_FRM: 'USE_FRM'; +USER_RESOURCES: 'USER_RESOURCES'; +VALIDATION: 'VALIDATION'; +VALUE: 'VALUE'; +VARIABLES: 'VARIABLES'; +VIEW: 'VIEW'; +VIRTUAL: 'VIRTUAL'; +VISIBLE: 'VISIBLE'; +WAIT: 'WAIT'; +WARNINGS: 'WARNINGS'; +WINDOW: 'WINDOW'; +WITHOUT: 'WITHOUT'; +WORK: 'WORK'; +WRAPPER: 'WRAPPER'; +X509: 'X509'; +XA: 'XA'; +XML: 'XML'; +YES: 'YES'; + +// Date format Keywords + +EUR: 'EUR'; +USA: 'USA'; +JIS: 'JIS'; +ISO: 'ISO'; +INTERNAL: 'INTERNAL'; + + +// Interval type Keywords + +QUARTER: 'QUARTER'; +MONTH: 'MONTH'; +DAY: 'DAY'; +HOUR: 'HOUR'; +MINUTE: 'MINUTE'; +WEEK: 'WEEK'; +SECOND: 'SECOND'; +MICROSECOND: 'MICROSECOND'; + + +// PRIVILEGES + +ADMIN: 'ADMIN'; +APPLICATION_PASSWORD_ADMIN: 'APPLICATION_PASSWORD_ADMIN'; +AUDIT_ABORT_EXEMPT: 'AUDIT_ABORT_EXEMPT'; +AUDIT_ADMIN: 'AUDIT_ADMIN'; +AUTHENTICATION_POLICY_ADMIN: 'AUTHENTICATION_POLICY_ADMIN'; +BACKUP_ADMIN: 'BACKUP_ADMIN'; +BINLOG_ADMIN: 'BINLOG_ADMIN'; +BINLOG_ENCRYPTION_ADMIN: 'BINLOG_ENCRYPTION_ADMIN'; +CLONE_ADMIN: 'CLONE_ADMIN'; +CONNECTION_ADMIN: 'CONNECTION_ADMIN'; +ENCRYPTION_KEY_ADMIN: 'ENCRYPTION_KEY_ADMIN'; +EXECUTE: 'EXECUTE'; +FILE: 'FILE'; +FIREWALL_ADMIN: 'FIREWALL_ADMIN'; +FIREWALL_EXEMPT: 'FIREWALL_EXEMPT'; +FIREWALL_USER: 'FIREWALL_USER'; +FLUSH_OPTIMIZER_COSTS: 'FLUSH_OPTIMIZER_COSTS'; +FLUSH_STATUS: 'FLUSH_STATUS'; +FLUSH_TABLES: 'FLUSH_TABLES'; +FLUSH_USER_RESOURCES: 'FLUSH_USER_RESOURCES'; +GROUP_REPLICATION_ADMIN: 'GROUP_REPLICATION_ADMIN'; +INNODB_REDO_LOG_ARCHIVE: 'INNODB_REDO_LOG_ARCHIVE'; +INNODB_REDO_LOG_ENABLE: 'INNODB_REDO_LOG_ENABLE'; +INVOKE: 'INVOKE'; +LAMBDA: 'LAMBDA'; +NDB_STORED_USER: 'NDB_STORED_USER'; +PASSWORDLESS_USER_ADMIN: 'PASSWORDLESS_USER_ADMIN'; +PERSIST_RO_VARIABLES_ADMIN: 'PERSIST_RO_VARIABLES_ADMIN'; +PRIVILEGES: 'PRIVILEGES'; +PROCESS: 'PROCESS'; +RELOAD: 'RELOAD'; +REPLICATION_APPLIER: 'REPLICATION_APPLIER'; +REPLICATION_SLAVE_ADMIN: 'REPLICATION_SLAVE_ADMIN'; +RESOURCE_GROUP_ADMIN: 'RESOURCE_GROUP_ADMIN'; +RESOURCE_GROUP_USER: 'RESOURCE_GROUP_USER'; +ROLE_ADMIN: 'ROLE_ADMIN'; +ROUTINE: 'ROUTINE'; +S3: 'S3'; +SERVICE_CONNECTION_ADMIN: 'SERVICE_CONNECTION_ADMIN'; +SESSION_VARIABLES_ADMIN: QUOTE_SYMB? 'SESSION_VARIABLES_ADMIN' QUOTE_SYMB?; +SET_USER_ID: 'SET_USER_ID'; +SHOW_ROUTINE: 'SHOW_ROUTINE'; +SHUTDOWN: 'SHUTDOWN'; +SUPER: 'SUPER'; +SYSTEM_VARIABLES_ADMIN: 'SYSTEM_VARIABLES_ADMIN'; +TABLES: 'TABLES'; +TABLE_ENCRYPTION_ADMIN: 'TABLE_ENCRYPTION_ADMIN'; +VERSION_TOKEN_ADMIN: 'VERSION_TOKEN_ADMIN'; +XA_RECOVER_ADMIN: 'XA_RECOVER_ADMIN'; + + +// Charsets + +ARMSCII8: 'ARMSCII8'; +ASCII: 'ASCII'; +BIG5: 'BIG5'; +CP1250: 'CP1250'; +CP1251: 'CP1251'; +CP1256: 'CP1256'; +CP1257: 'CP1257'; +CP850: 'CP850'; +CP852: 'CP852'; +CP866: 'CP866'; +CP932: 'CP932'; +DEC8: 'DEC8'; +EUCJPMS: 'EUCJPMS'; +EUCKR: 'EUCKR'; +GB18030: 'GB18030'; +GB2312: 'GB2312'; +GBK: 'GBK'; +GEOSTD8: 'GEOSTD8'; +GREEK: 'GREEK'; +HEBREW: 'HEBREW'; +HP8: 'HP8'; +KEYBCS2: 'KEYBCS2'; +KOI8R: 'KOI8R'; +KOI8U: 'KOI8U'; +LATIN1: 'LATIN1'; +LATIN2: 'LATIN2'; +LATIN5: 'LATIN5'; +LATIN7: 'LATIN7'; +MACCE: 'MACCE'; +MACROMAN: 'MACROMAN'; +SJIS: 'SJIS'; +SWE7: 'SWE7'; +TIS620: 'TIS620'; +UCS2: 'UCS2'; +UJIS: 'UJIS'; +UTF16: 'UTF16'; +UTF16LE: 'UTF16LE'; +UTF32: 'UTF32'; +UTF8: 'UTF8'; +UTF8MB3: 'UTF8MB3'; +UTF8MB4: 'UTF8MB4'; + + +// DB Engines + +ARCHIVE: 'ARCHIVE'; +BLACKHOLE: 'BLACKHOLE'; +CSV: 'CSV'; +FEDERATED: 'FEDERATED'; +INNODB: 'INNODB'; +MEMORY: 'MEMORY'; +MRG_MYISAM: 'MRG_MYISAM'; +MYISAM: 'MYISAM'; +NDB: 'NDB'; +NDBCLUSTER: 'NDBCLUSTER'; +PERFORMANCE_SCHEMA: 'PERFORMANCE_SCHEMA'; +TOKUDB: 'TOKUDB'; + + +// Transaction Levels + +REPEATABLE: 'REPEATABLE'; +COMMITTED: 'COMMITTED'; +UNCOMMITTED: 'UNCOMMITTED'; +SERIALIZABLE: 'SERIALIZABLE'; + + +// Spatial data types + +GEOMETRYCOLLECTION: 'GEOMETRYCOLLECTION'; +GEOMCOLLECTION: 'GEOMCOLLECTION'; +GEOMETRY: 'GEOMETRY'; +LINESTRING: 'LINESTRING'; +MULTILINESTRING: 'MULTILINESTRING'; +MULTIPOINT: 'MULTIPOINT'; +MULTIPOLYGON: 'MULTIPOLYGON'; +POINT: 'POINT'; +POLYGON: 'POLYGON'; + + +// Common function names + +ABS: 'ABS'; +ACOS: 'ACOS'; +ADDDATE: 'ADDDATE'; +ADDTIME: 'ADDTIME'; +AES_DECRYPT: 'AES_DECRYPT'; +AES_ENCRYPT: 'AES_ENCRYPT'; +AREA: 'AREA'; +ASBINARY: 'ASBINARY'; +ASIN: 'ASIN'; +ASTEXT: 'ASTEXT'; +ASWKB: 'ASWKB'; +ASWKT: 'ASWKT'; +ASYMMETRIC_DECRYPT: 'ASYMMETRIC_DECRYPT'; +ASYMMETRIC_DERIVE: 'ASYMMETRIC_DERIVE'; +ASYMMETRIC_ENCRYPT: 'ASYMMETRIC_ENCRYPT'; +ASYMMETRIC_SIGN: 'ASYMMETRIC_SIGN'; +ASYMMETRIC_VERIFY: 'ASYMMETRIC_VERIFY'; +ATAN: 'ATAN'; +ATAN2: 'ATAN2'; +BENCHMARK: 'BENCHMARK'; +BIN: 'BIN'; +BIT_COUNT: 'BIT_COUNT'; +BIT_LENGTH: 'BIT_LENGTH'; +BUFFER: 'BUFFER'; +CATALOG_NAME: 'CATALOG_NAME'; +CEIL: 'CEIL'; +CEILING: 'CEILING'; +CENTROID: 'CENTROID'; +CHARACTER_LENGTH: 'CHARACTER_LENGTH'; +CHARSET: 'CHARSET'; +CHAR_LENGTH: 'CHAR_LENGTH'; +COERCIBILITY: 'COERCIBILITY'; +COLLATION: 'COLLATION'; +COMPRESS: 'COMPRESS'; +CONCAT: 'CONCAT'; +CONCAT_WS: 'CONCAT_WS'; +CONNECTION_ID: 'CONNECTION_ID'; +CONV: 'CONV'; +CONVERT_TZ: 'CONVERT_TZ'; +COS: 'COS'; +COT: 'COT'; +CRC32: 'CRC32'; +CREATE_ASYMMETRIC_PRIV_KEY: 'CREATE_ASYMMETRIC_PRIV_KEY'; +CREATE_ASYMMETRIC_PUB_KEY: 'CREATE_ASYMMETRIC_PUB_KEY'; +CREATE_DH_PARAMETERS: 'CREATE_DH_PARAMETERS'; +CREATE_DIGEST: 'CREATE_DIGEST'; +CROSSES: 'CROSSES'; +DATEDIFF: 'DATEDIFF'; +DATE_FORMAT: 'DATE_FORMAT'; +DAYNAME: 'DAYNAME'; +DAYOFMONTH: 'DAYOFMONTH'; +DAYOFWEEK: 'DAYOFWEEK'; +DAYOFYEAR: 'DAYOFYEAR'; +DECODE: 'DECODE'; +DEGREES: 'DEGREES'; +DES_DECRYPT: 'DES_DECRYPT'; +DES_ENCRYPT: 'DES_ENCRYPT'; +DIMENSION: 'DIMENSION'; +DISJOINT: 'DISJOINT'; +ELT: 'ELT'; +ENCODE: 'ENCODE'; +ENCRYPT: 'ENCRYPT'; +ENDPOINT: 'ENDPOINT'; +ENGINE_ATTRIBUTE: 'ENGINE_ATTRIBUTE'; +ENVELOPE: 'ENVELOPE'; +EQUALS: 'EQUALS'; +EXP: 'EXP'; +EXPORT_SET: 'EXPORT_SET'; +EXTERIORRING: 'EXTERIORRING'; +EXTRACTVALUE: 'EXTRACTVALUE'; +FIELD: 'FIELD'; +FIND_IN_SET: 'FIND_IN_SET'; +FLOOR: 'FLOOR'; +FORMAT: 'FORMAT'; +FOUND_ROWS: 'FOUND_ROWS'; +FROM_BASE64: 'FROM_BASE64'; +FROM_DAYS: 'FROM_DAYS'; +FROM_UNIXTIME: 'FROM_UNIXTIME'; +GEOMCOLLFROMTEXT: 'GEOMCOLLFROMTEXT'; +GEOMCOLLFROMWKB: 'GEOMCOLLFROMWKB'; +GEOMETRYCOLLECTIONFROMTEXT: 'GEOMETRYCOLLECTIONFROMTEXT'; +GEOMETRYCOLLECTIONFROMWKB: 'GEOMETRYCOLLECTIONFROMWKB'; +GEOMETRYFROMTEXT: 'GEOMETRYFROMTEXT'; +GEOMETRYFROMWKB: 'GEOMETRYFROMWKB'; +GEOMETRYN: 'GEOMETRYN'; +GEOMETRYTYPE: 'GEOMETRYTYPE'; +GEOMFROMTEXT: 'GEOMFROMTEXT'; +GEOMFROMWKB: 'GEOMFROMWKB'; +GET_FORMAT: 'GET_FORMAT'; +GET_LOCK: 'GET_LOCK'; +GLENGTH: 'GLENGTH'; +GREATEST: 'GREATEST'; +GTID_SUBSET: 'GTID_SUBSET'; +GTID_SUBTRACT: 'GTID_SUBTRACT'; +HEX: 'HEX'; +IFNULL: 'IFNULL'; +INET6_ATON: 'INET6_ATON'; +INET6_NTOA: 'INET6_NTOA'; +INET_ATON: 'INET_ATON'; +INET_NTOA: 'INET_NTOA'; +INSTR: 'INSTR'; +INTERIORRINGN: 'INTERIORRINGN'; +INTERSECTS: 'INTERSECTS'; +ISCLOSED: 'ISCLOSED'; +ISEMPTY: 'ISEMPTY'; +ISNULL: 'ISNULL'; +ISSIMPLE: 'ISSIMPLE'; +IS_FREE_LOCK: 'IS_FREE_LOCK'; +IS_IPV4: 'IS_IPV4'; +IS_IPV4_COMPAT: 'IS_IPV4_COMPAT'; +IS_IPV4_MAPPED: 'IS_IPV4_MAPPED'; +IS_IPV6: 'IS_IPV6'; +IS_USED_LOCK: 'IS_USED_LOCK'; +LAST_INSERT_ID: 'LAST_INSERT_ID'; +LCASE: 'LCASE'; +LEAST: 'LEAST'; +LENGTH: 'LENGTH'; +LINEFROMTEXT: 'LINEFROMTEXT'; +LINEFROMWKB: 'LINEFROMWKB'; +LINESTRINGFROMTEXT: 'LINESTRINGFROMTEXT'; +LINESTRINGFROMWKB: 'LINESTRINGFROMWKB'; +LN: 'LN'; +LOAD_FILE: 'LOAD_FILE'; +LOCATE: 'LOCATE'; +LOG: 'LOG'; +LOG10: 'LOG10'; +LOG2: 'LOG2'; +LOWER: 'LOWER'; +LPAD: 'LPAD'; +LTRIM: 'LTRIM'; +MAKEDATE: 'MAKEDATE'; +MAKETIME: 'MAKETIME'; +MAKE_SET: 'MAKE_SET'; +MASTER_POS_WAIT: 'MASTER_POS_WAIT'; +MBRCONTAINS: 'MBRCONTAINS'; +MBRDISJOINT: 'MBRDISJOINT'; +MBREQUAL: 'MBREQUAL'; +MBRINTERSECTS: 'MBRINTERSECTS'; +MBROVERLAPS: 'MBROVERLAPS'; +MBRTOUCHES: 'MBRTOUCHES'; +MBRWITHIN: 'MBRWITHIN'; +MD5: 'MD5'; +MLINEFROMTEXT: 'MLINEFROMTEXT'; +MLINEFROMWKB: 'MLINEFROMWKB'; +MONTHNAME: 'MONTHNAME'; +MPOINTFROMTEXT: 'MPOINTFROMTEXT'; +MPOINTFROMWKB: 'MPOINTFROMWKB'; +MPOLYFROMTEXT: 'MPOLYFROMTEXT'; +MPOLYFROMWKB: 'MPOLYFROMWKB'; +MULTILINESTRINGFROMTEXT: 'MULTILINESTRINGFROMTEXT'; +MULTILINESTRINGFROMWKB: 'MULTILINESTRINGFROMWKB'; +MULTIPOINTFROMTEXT: 'MULTIPOINTFROMTEXT'; +MULTIPOINTFROMWKB: 'MULTIPOINTFROMWKB'; +MULTIPOLYGONFROMTEXT: 'MULTIPOLYGONFROMTEXT'; +MULTIPOLYGONFROMWKB: 'MULTIPOLYGONFROMWKB'; +NAME_CONST: 'NAME_CONST'; +NULLIF: 'NULLIF'; +NUMGEOMETRIES: 'NUMGEOMETRIES'; +NUMINTERIORRINGS: 'NUMINTERIORRINGS'; +NUMPOINTS: 'NUMPOINTS'; +OCT: 'OCT'; +OCTET_LENGTH: 'OCTET_LENGTH'; +ORD: 'ORD'; +OVERLAPS: 'OVERLAPS'; +PERIOD_ADD: 'PERIOD_ADD'; +PERIOD_DIFF: 'PERIOD_DIFF'; +PI: 'PI'; +POINTFROMTEXT: 'POINTFROMTEXT'; +POINTFROMWKB: 'POINTFROMWKB'; +POINTN: 'POINTN'; +POLYFROMTEXT: 'POLYFROMTEXT'; +POLYFROMWKB: 'POLYFROMWKB'; +POLYGONFROMTEXT: 'POLYGONFROMTEXT'; +POLYGONFROMWKB: 'POLYGONFROMWKB'; +POW: 'POW'; +POWER: 'POWER'; +QUOTE: 'QUOTE'; +RADIANS: 'RADIANS'; +RAND: 'RAND'; +RANDOM_BYTES: 'RANDOM_BYTES'; +RELEASE_LOCK: 'RELEASE_LOCK'; +REVERSE: 'REVERSE'; +ROUND: 'ROUND'; +ROW_COUNT: 'ROW_COUNT'; +RPAD: 'RPAD'; +RTRIM: 'RTRIM'; +SEC_TO_TIME: 'SEC_TO_TIME'; +SECONDARY_ENGINE_ATTRIBUTE: 'SECONDARY_ENGINE_ATTRIBUTE'; +SESSION_USER: 'SESSION_USER'; +SHA: 'SHA'; +SHA1: 'SHA1'; +SHA2: 'SHA2'; +SCHEMA_NAME: 'SCHEMA_NAME'; +SIGN: 'SIGN'; +SIN: 'SIN'; +SLEEP: 'SLEEP'; +SOUNDEX: 'SOUNDEX'; +SQL_THREAD_WAIT_AFTER_GTIDS: 'SQL_THREAD_WAIT_AFTER_GTIDS'; +SQRT: 'SQRT'; +SRID: 'SRID'; +STARTPOINT: 'STARTPOINT'; +STRCMP: 'STRCMP'; +STR_TO_DATE: 'STR_TO_DATE'; +ST_AREA: 'ST_AREA'; +ST_ASBINARY: 'ST_ASBINARY'; +ST_ASTEXT: 'ST_ASTEXT'; +ST_ASWKB: 'ST_ASWKB'; +ST_ASWKT: 'ST_ASWKT'; +ST_BUFFER: 'ST_BUFFER'; +ST_CENTROID: 'ST_CENTROID'; +ST_CONTAINS: 'ST_CONTAINS'; +ST_CROSSES: 'ST_CROSSES'; +ST_DIFFERENCE: 'ST_DIFFERENCE'; +ST_DIMENSION: 'ST_DIMENSION'; +ST_DISJOINT: 'ST_DISJOINT'; +ST_DISTANCE: 'ST_DISTANCE'; +ST_ENDPOINT: 'ST_ENDPOINT'; +ST_ENVELOPE: 'ST_ENVELOPE'; +ST_EQUALS: 'ST_EQUALS'; +ST_EXTERIORRING: 'ST_EXTERIORRING'; +ST_GEOMCOLLFROMTEXT: 'ST_GEOMCOLLFROMTEXT'; +ST_GEOMCOLLFROMTXT: 'ST_GEOMCOLLFROMTXT'; +ST_GEOMCOLLFROMWKB: 'ST_GEOMCOLLFROMWKB'; +ST_GEOMETRYCOLLECTIONFROMTEXT: 'ST_GEOMETRYCOLLECTIONFROMTEXT'; +ST_GEOMETRYCOLLECTIONFROMWKB: 'ST_GEOMETRYCOLLECTIONFROMWKB'; +ST_GEOMETRYFROMTEXT: 'ST_GEOMETRYFROMTEXT'; +ST_GEOMETRYFROMWKB: 'ST_GEOMETRYFROMWKB'; +ST_GEOMETRYN: 'ST_GEOMETRYN'; +ST_GEOMETRYTYPE: 'ST_GEOMETRYTYPE'; +ST_GEOMFROMTEXT: 'ST_GEOMFROMTEXT'; +ST_GEOMFROMWKB: 'ST_GEOMFROMWKB'; +ST_INTERIORRINGN: 'ST_INTERIORRINGN'; +ST_INTERSECTION: 'ST_INTERSECTION'; +ST_INTERSECTS: 'ST_INTERSECTS'; +ST_ISCLOSED: 'ST_ISCLOSED'; +ST_ISEMPTY: 'ST_ISEMPTY'; +ST_ISSIMPLE: 'ST_ISSIMPLE'; +ST_LINEFROMTEXT: 'ST_LINEFROMTEXT'; +ST_LINEFROMWKB: 'ST_LINEFROMWKB'; +ST_LINESTRINGFROMTEXT: 'ST_LINESTRINGFROMTEXT'; +ST_LINESTRINGFROMWKB: 'ST_LINESTRINGFROMWKB'; +ST_NUMGEOMETRIES: 'ST_NUMGEOMETRIES'; +ST_NUMINTERIORRING: 'ST_NUMINTERIORRING'; +ST_NUMINTERIORRINGS: 'ST_NUMINTERIORRINGS'; +ST_NUMPOINTS: 'ST_NUMPOINTS'; +ST_OVERLAPS: 'ST_OVERLAPS'; +ST_POINTFROMTEXT: 'ST_POINTFROMTEXT'; +ST_POINTFROMWKB: 'ST_POINTFROMWKB'; +ST_POINTN: 'ST_POINTN'; +ST_POLYFROMTEXT: 'ST_POLYFROMTEXT'; +ST_POLYFROMWKB: 'ST_POLYFROMWKB'; +ST_POLYGONFROMTEXT: 'ST_POLYGONFROMTEXT'; +ST_POLYGONFROMWKB: 'ST_POLYGONFROMWKB'; +ST_SRID: 'ST_SRID'; +ST_STARTPOINT: 'ST_STARTPOINT'; +ST_SYMDIFFERENCE: 'ST_SYMDIFFERENCE'; +ST_TOUCHES: 'ST_TOUCHES'; +ST_UNION: 'ST_UNION'; +ST_WITHIN: 'ST_WITHIN'; +ST_X: 'ST_X'; +ST_Y: 'ST_Y'; +SUBDATE: 'SUBDATE'; +SUBSTRING_INDEX: 'SUBSTRING_INDEX'; +SUBTIME: 'SUBTIME'; +SYSTEM_USER: 'SYSTEM_USER'; +TAN: 'TAN'; +TIMEDIFF: 'TIMEDIFF'; +TIMESTAMPADD: 'TIMESTAMPADD'; +TIMESTAMPDIFF: 'TIMESTAMPDIFF'; +TIME_FORMAT: 'TIME_FORMAT'; +TIME_TO_SEC: 'TIME_TO_SEC'; +TOUCHES: 'TOUCHES'; +TO_BASE64: 'TO_BASE64'; +TO_DAYS: 'TO_DAYS'; +TO_SECONDS: 'TO_SECONDS'; +TP_CONNECTION_ADMIN: 'TP_CONNECTION_ADMIN'; +UCASE: 'UCASE'; +UNCOMPRESS: 'UNCOMPRESS'; +UNCOMPRESSED_LENGTH: 'UNCOMPRESSED_LENGTH'; +UNHEX: 'UNHEX'; +UNIX_TIMESTAMP: 'UNIX_TIMESTAMP'; +UPDATEXML: 'UPDATEXML'; +UPPER: 'UPPER'; +UUID: 'UUID'; +UUID_SHORT: 'UUID_SHORT'; +VALIDATE_PASSWORD_STRENGTH: 'VALIDATE_PASSWORD_STRENGTH'; +VERSION: 'VERSION'; +WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS: 'WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS'; +WEEKDAY: 'WEEKDAY'; +WEEKOFYEAR: 'WEEKOFYEAR'; +WEIGHT_STRING: 'WEIGHT_STRING'; +WITHIN: 'WITHIN'; +YEARWEEK: 'YEARWEEK'; +Y_FUNCTION: 'Y'; +X_FUNCTION: 'X'; + + + + +// Operators +// Operators. Assigns + +VAR_ASSIGN: ':='; +PLUS_ASSIGN: '+='; +MINUS_ASSIGN: '-='; +MULT_ASSIGN: '*='; +DIV_ASSIGN: '/='; +MOD_ASSIGN: '%='; +AND_ASSIGN: '&='; +XOR_ASSIGN: '^='; +OR_ASSIGN: '|='; + + +// Operators. Arithmetics + +STAR: '*'; +DIVIDE: '/'; +MODULE: '%'; +PLUS: '+'; +MINUS: '-'; +DIV: 'DIV'; +MOD: 'MOD'; + + +// Operators. Comparation + +EQUAL_SYMBOL: '='; +GREATER_SYMBOL: '>'; +LESS_SYMBOL: '<'; +EXCLAMATION_SYMBOL: '!'; + + +// Operators. Bit + +BIT_NOT_OP: '~'; +BIT_OR_OP: '|'; +BIT_AND_OP: '&'; +BIT_XOR_OP: '^'; + + +// Constructors symbols + +DOT: '.'; +LR_BRACKET: '('; +RR_BRACKET: ')'; +COMMA: ','; +SEMI: ';'; +AT_SIGN: '@'; +ZERO_DECIMAL: '0'; +ONE_DECIMAL: '1'; +TWO_DECIMAL: '2'; +SINGLE_QUOTE_SYMB: '\''; +DOUBLE_QUOTE_SYMB: '"'; +REVERSE_QUOTE_SYMB: '`'; +COLON_SYMB: ':'; + +fragment QUOTE_SYMB + : SINGLE_QUOTE_SYMB | DOUBLE_QUOTE_SYMB | REVERSE_QUOTE_SYMB + ; + + + +// Charsets + +CHARSET_REVERSE_QOUTE_STRING: '`' CHARSET_NAME '`'; + + + +// File's sizes + + +FILESIZE_LITERAL: DEC_DIGIT+ ('K'|'M'|'G'|'T'); + + + +// Literal Primitives + + +START_NATIONAL_STRING_LITERAL: 'N' SQUOTA_STRING; +STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; +DECIMAL_LITERAL: DEC_DIGIT+; +HEXADECIMAL_LITERAL: 'X' '\'' (HEX_DIGIT HEX_DIGIT)+ '\'' + | '0X' HEX_DIGIT+; + +REAL_LITERAL: (DEC_DIGIT+)? '.' DEC_DIGIT+ + | DEC_DIGIT+ '.' EXPONENT_NUM_PART + | (DEC_DIGIT+)? '.' (DEC_DIGIT+ EXPONENT_NUM_PART) + | DEC_DIGIT+ EXPONENT_NUM_PART; +NULL_SPEC_LITERAL: '\\' 'N'; +BIT_STRING: BIT_STRING_L; +STRING_CHARSET_NAME: '_' CHARSET_NAME; + + + + +// Hack for dotID +// Prevent recognize string: .123somelatin AS ((.123), FLOAT_LITERAL), ((somelatin), ID) +// it must recoginze: .123somelatin AS ((.), DOT), (123somelatin, ID) + +DOT_ID: '.' ID_LITERAL; + + + +// Identifiers + +ID: ID_LITERAL; +// DOUBLE_QUOTE_ID: '"' ~'"'+ '"'; +REVERSE_QUOTE_ID: '`' ~'`'+ '`'; +STRING_USER_NAME: ( + SQUOTA_STRING | DQUOTA_STRING + | BQUOTA_STRING | ID_LITERAL + ) '@' + ( + SQUOTA_STRING | DQUOTA_STRING + | BQUOTA_STRING | ID_LITERAL + | IP_ADDRESS + ); +IP_ADDRESS: ( + [0-9]+ '.' [0-9.]+ + | [0-9A-F:]+ ':' [0-9A-F:]+ + ); +LOCAL_ID: '@' + ( + [A-Z0-9._$]+ + | SQUOTA_STRING + | DQUOTA_STRING + | BQUOTA_STRING + ); +GLOBAL_ID: '@' '@' + ( + [A-Z0-9._$]+ + | BQUOTA_STRING + ); + + +// Fragments for Literal primitives + +fragment CHARSET_NAME: ARMSCII8 | ASCII | BIG5 | BINARY | CP1250 + | CP1251 | CP1256 | CP1257 | CP850 + | CP852 | CP866 | CP932 | DEC8 | EUCJPMS + | EUCKR | GB2312 | GBK | GEOSTD8 | GREEK + | HEBREW | HP8 | KEYBCS2 | KOI8R | KOI8U + | LATIN1 | LATIN2 | LATIN5 | LATIN7 + | MACCE | MACROMAN | SJIS | SWE7 | TIS620 + | UCS2 | UJIS | UTF16 | UTF16LE | UTF32 + | UTF8 | UTF8MB3 | UTF8MB4; + +fragment EXPONENT_NUM_PART: 'E' [-+]? DEC_DIGIT+; +fragment ID_LITERAL: [A-Z_$0-9\u0080-\uFFFF]*?[A-Z_$\u0080-\uFFFF]+?[A-Z_$0-9\u0080-\uFFFF]*; +fragment DQUOTA_STRING: '"' ( '\\'. | '""' | ~('"'| '\\') )* '"'; +fragment SQUOTA_STRING: '\'' ('\\'. | '\'\'' | ~('\'' | '\\'))* '\''; +fragment BQUOTA_STRING: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`'; +fragment HEX_DIGIT: [0-9A-F]; +fragment DEC_DIGIT: [0-9]; +fragment BIT_STRING_L: 'B' '\'' [01]+ '\''; + + + +// Last tokens must generate Errors + +ERROR_RECONGNIGION: . -> channel(ERRORCHANNEL); diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/antlr/MySqlParser.g4 b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/antlr/MySqlParser.g4 new file mode 100644 index 0000000000..53bae6ae0f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/antlr/MySqlParser.g4 @@ -0,0 +1,2837 @@ +/* + * 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. + */ + + +parser grammar MySqlParser; + +options { tokenVocab=MySqlLexer; } + + +// Top Level Description + +root + : sqlStatements? (MINUS MINUS)? EOF + ; + +sqlStatements + : (sqlStatement (MINUS MINUS)? SEMI? | emptyStatement_)* + (sqlStatement ((MINUS MINUS)? SEMI)? | emptyStatement_) + ; + +sqlStatement + : ddlStatement | dmlStatement | transactionStatement + | replicationStatement | preparedStatement + | administrationStatement | utilityStatement + ; + +emptyStatement_ + : SEMI + ; + +ddlStatement + : createDatabase | createEvent | createIndex + | createLogfileGroup | createProcedure | createFunction + | createServer | createTable | createTablespaceInnodb + | createTablespaceNdb | createTrigger | createView | createRole + | alterDatabase | alterEvent | alterFunction + | alterInstance | alterLogfileGroup | alterProcedure + | alterServer | alterTable | alterTablespace | alterView + | dropDatabase | dropEvent | dropIndex + | dropLogfileGroup | dropProcedure | dropFunction + | dropServer | dropTable | dropTablespace + | dropTrigger | dropView | dropRole | setRole + | renameTable | truncateTable + ; + +dmlStatement + : selectStatement | insertStatement | updateStatement + | deleteStatement | replaceStatement | callStatement + | loadDataStatement | loadXmlStatement | doStatement + | handlerStatement | valuesStatement | withStatement + ; + +transactionStatement + : startTransaction + | beginWork | commitWork | rollbackWork + | savepointStatement | rollbackStatement + | releaseStatement | lockTables | unlockTables + ; + +replicationStatement + : changeMaster | changeReplicationFilter | purgeBinaryLogs + | resetMaster | resetSlave | startSlave | stopSlave + | startGroupReplication | stopGroupReplication + | xaStartTransaction | xaEndTransaction | xaPrepareStatement + | xaCommitWork | xaRollbackWork | xaRecoverWork + ; + +preparedStatement + : prepareStatement | executeStatement | deallocatePrepare + ; + +// remark: NOT INCLUDED IN sqlStatement, but include in body +// of routine's statements +compoundStatement + : blockStatement + | caseStatement | ifStatement | leaveStatement + | loopStatement | repeatStatement | whileStatement + | iterateStatement | returnStatement | cursorStatement + ; + +administrationStatement + : alterUser | createUser | dropUser | grantStatement + | grantProxy | renameUser | revokeStatement + | revokeProxy | analyzeTable | checkTable + | checksumTable | optimizeTable | repairTable + | createUdfunction | installPlugin | uninstallPlugin + | setStatement | showStatement | binlogStatement + | cacheIndexStatement | flushStatement | killStatement + | loadIndexIntoCache | resetStatement + | shutdownStatement + ; + +utilityStatement + : simpleDescribeStatement | fullDescribeStatement + | helpStatement | useStatement | signalStatement + | resignalStatement | diagnosticsStatement + ; + + +// Data Definition Language + +// Create statements + +createDatabase + : CREATE dbFormat=(DATABASE | SCHEMA) + ifNotExists? uid createDatabaseOption* + ; + +createEvent + : CREATE ownerStatement? EVENT ifNotExists? fullId + ON SCHEDULE scheduleExpression + (ON COMPLETION NOT? PRESERVE)? enableType? + (COMMENT STRING_LITERAL)? + DO routineBody + ; + +createIndex + : CREATE + intimeAction=(ONLINE | OFFLINE)? + indexCategory=(UNIQUE | FULLTEXT | SPATIAL)? INDEX + uid indexType? + ON tableName indexColumnNames + indexOption* + ( + ALGORITHM EQUAL_SYMBOL? algType=(DEFAULT | INPLACE | COPY) + | LOCK EQUAL_SYMBOL? lockType=(DEFAULT | NONE | SHARED | EXCLUSIVE) + )* + ; + +createLogfileGroup + : CREATE LOGFILE GROUP uid + ADD UNDOFILE undoFile=STRING_LITERAL + (INITIAL_SIZE '='? initSize=fileSizeLiteral)? + (UNDO_BUFFER_SIZE '='? undoSize=fileSizeLiteral)? + (REDO_BUFFER_SIZE '='? redoSize=fileSizeLiteral)? + (NODEGROUP '='? uid)? + WAIT? + (COMMENT '='? comment=STRING_LITERAL)? + ENGINE '='? engineName + ; + +createProcedure + : CREATE ownerStatement? + PROCEDURE fullId + '(' procedureParameter? (',' procedureParameter)* ')' + routineOption* + routineBody + ; + +createFunction + : CREATE ownerStatement? AGGREGATE? + FUNCTION ifNotExists? fullId + '(' functionParameter? (',' functionParameter)* ')' + RETURNS dataType + routineOption* + (routineBody | returnStatement) + ; + +createRole + : CREATE ROLE ifNotExists? roleName (',' roleName)* + ; + +createServer + : CREATE SERVER uid + FOREIGN DATA WRAPPER wrapperName=(MYSQL | STRING_LITERAL) + OPTIONS '(' serverOption (',' serverOption)* ')' + ; + +createTable + : CREATE TEMPORARY? TABLE ifNotExists? + tableName + ( + LIKE tableName + | '(' LIKE parenthesisTable=tableName ')' + ) #copyCreateTable + | CREATE TEMPORARY? TABLE ifNotExists? + tableName createDefinitions? + ( tableOption (','? tableOption)* )? + partitionDefinitions? keyViolate=(IGNORE | REPLACE)? + AS? selectStatement #queryCreateTable + | CREATE TEMPORARY? TABLE ifNotExists? + tableName createDefinitions + ( tableOption (','? tableOption)* )? + partitionDefinitions? #columnCreateTable + ; + +createTablespaceInnodb + : CREATE TABLESPACE uid + ADD DATAFILE datafile=STRING_LITERAL + (FILE_BLOCK_SIZE '=' fileBlockSize=fileSizeLiteral)? + (ENGINE '='? engineName)? + ; + +createTablespaceNdb + : CREATE TABLESPACE uid + ADD DATAFILE datafile=STRING_LITERAL + USE LOGFILE GROUP uid + (EXTENT_SIZE '='? extentSize=fileSizeLiteral)? + (INITIAL_SIZE '='? initialSize=fileSizeLiteral)? + (AUTOEXTEND_SIZE '='? autoextendSize=fileSizeLiteral)? + (MAX_SIZE '='? maxSize=fileSizeLiteral)? + (NODEGROUP '='? uid)? + WAIT? + (COMMENT '='? comment=STRING_LITERAL)? + ENGINE '='? engineName + ; + +createTrigger + : CREATE ownerStatement? + TRIGGER thisTrigger=fullId + triggerTime=(BEFORE | AFTER) + triggerEvent=(INSERT | UPDATE | DELETE) + ON tableName FOR EACH ROW + (triggerPlace=(FOLLOWS | PRECEDES) otherTrigger=fullId)? + routineBody + ; + +withClause + : WITH RECURSIVE? commonTableExpressions + ; + +commonTableExpressions + : cteName ('(' cteColumnName (',' cteColumnName)* ')')? AS '(' dmlStatement ')' + (',' commonTableExpressions)? + ; + +cteName + : uid + ; + +cteColumnName + : uid + ; + +createView + : CREATE orReplace? + ( + ALGORITHM '=' algType=(UNDEFINED | MERGE | TEMPTABLE) + )? + ownerStatement? + (SQL SECURITY secContext=(DEFINER | INVOKER))? + VIEW fullId ('(' uidList ')')? AS + ( + '(' withClause? selectStatement ')' + | + withClause? selectStatement (WITH checkOption=(CASCADED | LOCAL)? CHECK OPTION)? + ) + ; + + +// details + +createDatabaseOption + : DEFAULT? charSet '='? (charsetName | DEFAULT) + | DEFAULT? COLLATE '='? collationName + | DEFAULT? ENCRYPTION '='? STRING_LITERAL + | READ ONLY '='? (DEFAULT | ZERO_DECIMAL | ONE_DECIMAL) + ; + +charSet + : CHARACTER SET + | CHARSET + | CHAR SET + ; + +ownerStatement + : DEFINER '=' (userName | CURRENT_USER ( '(' ')')?) + ; + +scheduleExpression + : AT timestampValue intervalExpr* #preciseSchedule + | EVERY (decimalLiteral | expression) intervalType + ( + STARTS startTimestamp=timestampValue + (startIntervals+=intervalExpr)* + )? + ( + ENDS endTimestamp=timestampValue + (endIntervals+=intervalExpr)* + )? #intervalSchedule + ; + +timestampValue + : CURRENT_TIMESTAMP + | stringLiteral + | decimalLiteral + | expression + ; + +intervalExpr + : '+' INTERVAL (decimalLiteral | expression) intervalType + ; + +intervalType + : intervalTypeBase + | YEAR | YEAR_MONTH | DAY_HOUR | DAY_MINUTE + | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND + | SECOND_MICROSECOND | MINUTE_MICROSECOND + | HOUR_MICROSECOND | DAY_MICROSECOND + ; + +enableType + : ENABLE | DISABLE | DISABLE ON SLAVE + ; + +indexType + : USING (BTREE | HASH) + ; + +indexOption + : KEY_BLOCK_SIZE EQUAL_SYMBOL? fileSizeLiteral + | indexType + | WITH PARSER uid + | COMMENT STRING_LITERAL + | (VISIBLE | INVISIBLE) + | ENGINE_ATTRIBUTE EQUAL_SYMBOL? STRING_LITERAL + | SECONDARY_ENGINE_ATTRIBUTE EQUAL_SYMBOL? STRING_LITERAL + ; + +procedureParameter + : direction=(IN | OUT | INOUT)? uid dataType + ; + +functionParameter + : uid dataType + ; + +routineOption + : COMMENT STRING_LITERAL #routineComment + | LANGUAGE SQL #routineLanguage + | NOT? DETERMINISTIC #routineBehavior + | ( + CONTAINS SQL | NO SQL | READS SQL DATA + | MODIFIES SQL DATA + ) #routineData + | SQL SECURITY context=(DEFINER | INVOKER) #routineSecurity + ; + +serverOption + : HOST STRING_LITERAL + | DATABASE STRING_LITERAL + | USER STRING_LITERAL + | PASSWORD STRING_LITERAL + | SOCKET STRING_LITERAL + | OWNER STRING_LITERAL + | PORT decimalLiteral + ; + +createDefinitions + : '(' createDefinition (',' createDefinition)* ')' + ; + +createDefinition + : fullColumnName columnDefinition #columnDeclaration + | tableConstraint NOT? ENFORCED? #constraintDeclaration + | indexColumnDefinition #indexDeclaration + ; + +columnDefinition + : dataType columnConstraint* NOT? ENFORCED? + ; + +columnConstraint + : nullNotnull #nullColumnConstraint + | DEFAULT defaultValue #defaultColumnConstraint + | VISIBLE #visibilityColumnConstraint + | INVISIBLE #invisibilityColumnConstraint + | (AUTO_INCREMENT | ON UPDATE currentTimestamp) #autoIncrementColumnConstraint + | PRIMARY? KEY #primaryKeyColumnConstraint + | UNIQUE KEY? #uniqueKeyColumnConstraint + | COMMENT STRING_LITERAL #commentColumnConstraint + | COLUMN_FORMAT colformat=(FIXED | DYNAMIC | DEFAULT) #formatColumnConstraint + | STORAGE storageval=(DISK | MEMORY | DEFAULT) #storageColumnConstraint + | referenceDefinition #referenceColumnConstraint + | COLLATE collationName #collateColumnConstraint + | (GENERATED ALWAYS)? AS '(' expression ')' (VIRTUAL | STORED)? #generatedColumnConstraint + | SERIAL DEFAULT VALUE #serialDefaultColumnConstraint + | (CONSTRAINT name=uid?)? + CHECK '(' expression ')' #checkColumnConstraint + ; + +tableConstraint + : (CONSTRAINT name=uid?)? + PRIMARY KEY index=uid? indexType? + indexColumnNames indexOption* #primaryKeyTableConstraint + | (CONSTRAINT name=uid?)? + UNIQUE indexFormat=(INDEX | KEY)? index=uid? + indexType? indexColumnNames indexOption* #uniqueKeyTableConstraint + | (CONSTRAINT name=uid?)? + FOREIGN KEY index=uid? indexColumnNames + referenceDefinition #foreignKeyTableConstraint + | (CONSTRAINT name=uid?)? + CHECK '(' expression ')' #checkTableConstraint + ; + +referenceDefinition + : REFERENCES tableName indexColumnNames? + (MATCH matchType=(FULL | PARTIAL | SIMPLE))? + referenceAction? + ; + +referenceAction + : ON DELETE onDelete=referenceControlType + ( + ON UPDATE onUpdate=referenceControlType + )? + | ON UPDATE onUpdate=referenceControlType + ( + ON DELETE onDelete=referenceControlType + )? + ; + +referenceControlType + : RESTRICT | CASCADE | SET NULL_LITERAL | NO ACTION | SET DEFAULT + ; + +indexColumnDefinition + : indexFormat=(INDEX | KEY) uid? indexType? + indexColumnNames indexOption* #simpleIndexDeclaration + | (FULLTEXT | SPATIAL) + indexFormat=(INDEX | KEY)? uid? + indexColumnNames indexOption* #specialIndexDeclaration + ; + +tableOption + : ENGINE '='? engineName? #tableOptionEngine + | ENGINE_ATTRIBUTE '='? STRING_LITERAL #tableOptionEngineAttribute + | AUTOEXTEND_SIZE '='? decimalLiteral #tableOptionAutoextendSize + | AUTO_INCREMENT '='? decimalLiteral #tableOptionAutoIncrement + | AVG_ROW_LENGTH '='? decimalLiteral #tableOptionAverage + | DEFAULT? charSet '='? (charsetName|DEFAULT) #tableOptionCharset + | (CHECKSUM | PAGE_CHECKSUM) '='? boolValue=('0' | '1') #tableOptionChecksum + | DEFAULT? COLLATE '='? collationName #tableOptionCollate + | COMMENT '='? STRING_LITERAL #tableOptionComment + | COMPRESSION '='? (STRING_LITERAL | ID) #tableOptionCompression + | CONNECTION '='? STRING_LITERAL #tableOptionConnection + | (DATA | INDEX) DIRECTORY '='? STRING_LITERAL #tableOptionDataDirectory + | DELAY_KEY_WRITE '='? boolValue=('0' | '1') #tableOptionDelay + | ENCRYPTION '='? STRING_LITERAL #tableOptionEncryption + | (PAGE_COMPRESSED | STRING_LITERAL) '='? ('0' | '1') #tableOptionPageCompressed + | (PAGE_COMPRESSION_LEVEL | STRING_LITERAL) '='? decimalLiteral #tableOptionPageCompressionLevel + | ENCRYPTION_KEY_ID '='? decimalLiteral #tableOptionEncryptionKeyId + | INDEX DIRECTORY '='? STRING_LITERAL #tableOptionIndexDirectory + | INSERT_METHOD '='? insertMethod=(NO | FIRST | LAST) #tableOptionInsertMethod + | KEY_BLOCK_SIZE '='? fileSizeLiteral #tableOptionKeyBlockSize + | MAX_ROWS '='? decimalLiteral #tableOptionMaxRows + | MIN_ROWS '='? decimalLiteral #tableOptionMinRows + | PACK_KEYS '='? extBoolValue=('0' | '1' | DEFAULT) #tableOptionPackKeys + | PASSWORD '='? STRING_LITERAL #tableOptionPassword + | ROW_FORMAT '='? + rowFormat=( + DEFAULT | DYNAMIC | FIXED | COMPRESSED + | REDUNDANT | COMPACT | ID + ) #tableOptionRowFormat + | START TRANSACTION #tableOptionStartTransaction + | SECONDARY_ENGINE_ATTRIBUTE '='? STRING_LITERAL #tableOptionSecondaryEngineAttribute + | STATS_AUTO_RECALC '='? extBoolValue=(DEFAULT | '0' | '1') #tableOptionRecalculation + | STATS_PERSISTENT '='? extBoolValue=(DEFAULT | '0' | '1') #tableOptionPersistent + | STATS_SAMPLE_PAGES '='? (DEFAULT | decimalLiteral) #tableOptionSamplePage + | TABLESPACE uid tablespaceStorage? #tableOptionTablespace + | TABLE_TYPE '=' tableType #tableOptionTableType + | tablespaceStorage #tableOptionTablespace + | TRANSACTIONAL '='? ('0' | '1') #tableOptionTransactional + | UNION '='? '(' tables ')' #tableOptionUnion + ; + +tableType + : MYSQL | ODBC + ; + +tablespaceStorage + : STORAGE (DISK | MEMORY | DEFAULT) + ; + +partitionDefinitions + : PARTITION BY partitionFunctionDefinition + (PARTITIONS count=decimalLiteral)? + ( + SUBPARTITION BY subpartitionFunctionDefinition + (SUBPARTITIONS subCount=decimalLiteral)? + )? + ('(' partitionDefinition (',' partitionDefinition)* ')')? + ; + +partitionFunctionDefinition + : LINEAR? HASH '(' expression ')' #partitionFunctionHash + | LINEAR? KEY (ALGORITHM '=' algType=('1' | '2'))? + '(' uidList? ')' #partitionFunctionKey // Optional uidList for MySQL only + | RANGE ( '(' expression ')' | COLUMNS '(' uidList ')' ) #partitionFunctionRange + | LIST ( '(' expression ')' | COLUMNS '(' uidList ')' ) #partitionFunctionList + ; + +subpartitionFunctionDefinition + : LINEAR? HASH '(' expression ')' #subPartitionFunctionHash + | LINEAR? KEY (ALGORITHM '=' algType=('1' | '2'))? + '(' uidList ')' #subPartitionFunctionKey + ; + +partitionDefinition + : PARTITION uid VALUES LESS THAN + '(' + partitionDefinerAtom (',' partitionDefinerAtom)* + ')' + partitionOption* + ( '(' subpartitionDefinition (',' subpartitionDefinition)* ')' )? #partitionComparison + | PARTITION uid VALUES LESS THAN + partitionDefinerAtom partitionOption* + ( '(' subpartitionDefinition (',' subpartitionDefinition)* ')' )? #partitionComparison + | PARTITION uid VALUES IN + '(' + partitionDefinerAtom (',' partitionDefinerAtom)* + ')' + partitionOption* + ( '(' subpartitionDefinition (',' subpartitionDefinition)* ')' )? #partitionListAtom + | PARTITION uid VALUES IN + '(' + partitionDefinerVector (',' partitionDefinerVector)* + ')' + partitionOption* + ( '(' subpartitionDefinition (',' subpartitionDefinition)* ')' )? #partitionListVector + | PARTITION uid partitionOption* + ( '(' subpartitionDefinition (',' subpartitionDefinition)* ')' )? #partitionSimple + ; + +partitionDefinerAtom + : constant | expression | MAXVALUE + ; + +partitionDefinerVector + : '(' partitionDefinerAtom (',' partitionDefinerAtom)+ ')' + ; + +subpartitionDefinition + : SUBPARTITION uid partitionOption* + ; + +partitionOption + : DEFAULT? STORAGE? ENGINE '='? engineName #partitionOptionEngine + | COMMENT '='? comment=STRING_LITERAL #partitionOptionComment + | DATA DIRECTORY '='? dataDirectory=STRING_LITERAL #partitionOptionDataDirectory + | INDEX DIRECTORY '='? indexDirectory=STRING_LITERAL #partitionOptionIndexDirectory + | MAX_ROWS '='? maxRows=decimalLiteral #partitionOptionMaxRows + | MIN_ROWS '='? minRows=decimalLiteral #partitionOptionMinRows + | TABLESPACE '='? tablespace=uid #partitionOptionTablespace + | NODEGROUP '='? nodegroup=uid #partitionOptionNodeGroup + ; + +// Alter statements + +alterDatabase + : ALTER dbFormat=(DATABASE | SCHEMA) uid? + createDatabaseOption+ #alterSimpleDatabase + | ALTER dbFormat=(DATABASE | SCHEMA) uid + UPGRADE DATA DIRECTORY NAME #alterUpgradeName + ; + +alterEvent + : ALTER ownerStatement? + EVENT fullId + (ON SCHEDULE scheduleExpression)? + (ON COMPLETION NOT? PRESERVE)? + (RENAME TO fullId)? enableType? + (COMMENT STRING_LITERAL)? + (DO routineBody)? + ; + +alterFunction + : ALTER FUNCTION fullId routineOption* + ; + +alterInstance + : ALTER INSTANCE ROTATE INNODB MASTER KEY + ; + +alterLogfileGroup + : ALTER LOGFILE GROUP uid + ADD UNDOFILE STRING_LITERAL + (INITIAL_SIZE '='? fileSizeLiteral)? + WAIT? ENGINE '='? engineName + ; + +alterProcedure + : ALTER PROCEDURE fullId routineOption* + ; + +alterServer + : ALTER SERVER uid OPTIONS + '(' serverOption (',' serverOption)* ')' + ; + +alterTable + : ALTER intimeAction=(ONLINE | OFFLINE)? + IGNORE? TABLE tableName waitNowaitClause? + (alterSpecification (',' alterSpecification)*)? + partitionDefinitions? + ; + +alterTablespace + : ALTER TABLESPACE uid + objectAction=(ADD | DROP) DATAFILE STRING_LITERAL + (INITIAL_SIZE '=' fileSizeLiteral)? + WAIT? + ENGINE '='? engineName + ; + +alterView + : ALTER + ( + ALGORITHM '=' algType=(UNDEFINED | MERGE | TEMPTABLE) + )? + ownerStatement? + (SQL SECURITY secContext=(DEFINER | INVOKER))? + VIEW fullId ('(' uidList ')')? AS selectStatement + (WITH checkOpt=(CASCADED | LOCAL)? CHECK OPTION)? + ; + +// details + +alterSpecification + : tableOption (','? tableOption)* #alterByTableOption + | ADD COLUMN? uid columnDefinition (FIRST | AFTER uid)? #alterByAddColumn + | ADD COLUMN? + '(' + uid columnDefinition ( ',' uid columnDefinition)* + ')' #alterByAddColumns + | ADD indexFormat=(INDEX | KEY) uid? indexType? + indexColumnNames indexOption* #alterByAddIndex + | ADD (CONSTRAINT name=uid?)? PRIMARY KEY index=uid? + indexType? indexColumnNames indexOption* #alterByAddPrimaryKey + | ADD (CONSTRAINT name=uid?)? UNIQUE + indexFormat=(INDEX | KEY)? indexName=uid? + indexType? indexColumnNames indexOption* #alterByAddUniqueKey + | ADD keyType=(FULLTEXT | SPATIAL) + indexFormat=(INDEX | KEY)? uid? + indexColumnNames indexOption* #alterByAddSpecialIndex + | ADD (CONSTRAINT name=uid?)? FOREIGN KEY + indexName=uid? indexColumnNames referenceDefinition #alterByAddForeignKey + | ADD (CONSTRAINT name=uid?)? CHECK ( uid | stringLiteral | '(' expression ')' ) + NOT? ENFORCED? #alterByAddCheckTableConstraint + | ALTER (CONSTRAINT name=uid?)? CHECK ( uid | stringLiteral | '(' expression ')' ) + NOT? ENFORCED? #alterByAlterCheckTableConstraint + | ADD (CONSTRAINT name=uid?)? CHECK '(' expression ')' #alterByAddCheckTableConstraint + | ALGORITHM '='? algType=(DEFAULT | INSTANT | INPLACE | COPY) #alterBySetAlgorithm + | ALTER COLUMN? uid + (SET DEFAULT defaultValue | DROP DEFAULT) #alterByChangeDefault + | CHANGE COLUMN? oldColumn=uid + newColumn=uid columnDefinition + (FIRST | AFTER afterColumn=uid)? #alterByChangeColumn + | RENAME COLUMN oldColumn=uid TO newColumn=uid #alterByRenameColumn + | LOCK '='? lockType=(DEFAULT | NONE | SHARED | EXCLUSIVE) #alterByLock + | MODIFY COLUMN? + uid columnDefinition (FIRST | AFTER uid)? #alterByModifyColumn + | DROP COLUMN? uid RESTRICT? #alterByDropColumn + | DROP (CONSTRAINT | CHECK) uid #alterByDropConstraintCheck + | DROP PRIMARY KEY #alterByDropPrimaryKey + | DROP indexFormat=(INDEX | KEY) uid #alterByDropIndex + | RENAME indexFormat=(INDEX | KEY) uid TO uid #alterByRenameIndex + | ALTER COLUMN? uid ( + SET DEFAULT ( stringLiteral | '(' expression ')' ) + | SET (VISIBLE | INVISIBLE) + | DROP DEFAULT) #alterByAlterColumnDefault + | ALTER INDEX uid (VISIBLE | INVISIBLE) #alterByAlterIndexVisibility + | DROP FOREIGN KEY uid #alterByDropForeignKey + | DISABLE KEYS #alterByDisableKeys + | ENABLE KEYS #alterByEnableKeys + | RENAME renameFormat=(TO | AS)? (uid | fullId) #alterByRename + | ORDER BY uidList #alterByOrder + | CONVERT TO (CHARSET | CHARACTER SET) charsetName + (COLLATE collationName)? #alterByConvertCharset + | DEFAULT? CHARACTER SET '=' charsetName + (COLLATE '=' collationName)? #alterByDefaultCharset + | DISCARD TABLESPACE #alterByDiscardTablespace + | IMPORT TABLESPACE #alterByImportTablespace + | FORCE #alterByForce + | validationFormat=(WITHOUT | WITH) VALIDATION #alterByValidate + | ADD PARTITION + '(' + partitionDefinition (',' partitionDefinition)* + ')' #alterByAddPartition + | DROP PARTITION uidList #alterByDropPartition + | DISCARD PARTITION (uidList | ALL) TABLESPACE #alterByDiscardPartition + | IMPORT PARTITION (uidList | ALL) TABLESPACE #alterByImportPartition + | TRUNCATE PARTITION (uidList | ALL) #alterByTruncatePartition + | COALESCE PARTITION decimalLiteral #alterByCoalescePartition + | REORGANIZE PARTITION uidList + INTO '(' + partitionDefinition (',' partitionDefinition)* + ')' #alterByReorganizePartition + | EXCHANGE PARTITION uid WITH TABLE tableName + (validationFormat=(WITH | WITHOUT) VALIDATION)? #alterByExchangePartition + | ANALYZE PARTITION (uidList | ALL) #alterByAnalyzePartition + | CHECK PARTITION (uidList | ALL) #alterByCheckPartition + | OPTIMIZE PARTITION (uidList | ALL) #alterByOptimizePartition + | REBUILD PARTITION (uidList | ALL) #alterByRebuildPartition + | REPAIR PARTITION (uidList | ALL) #alterByRepairPartition + | REMOVE PARTITIONING #alterByRemovePartitioning + | UPGRADE PARTITIONING #alterByUpgradePartitioning + | ADD COLUMN? + '(' createDefinition (',' createDefinition)* ')' #alterByAddDefinitions + ; + + +// Drop statements + +dropDatabase + : DROP dbFormat=(DATABASE | SCHEMA) ifExists? uid + ; + +dropEvent + : DROP EVENT ifExists? fullId + ; + +dropIndex + : DROP INDEX intimeAction=(ONLINE | OFFLINE)? + uid ON tableName + ( + ALGORITHM '='? algType=(DEFAULT | INPLACE | COPY) + | LOCK '='? + lockType=(DEFAULT | NONE | SHARED | EXCLUSIVE) + )* + ; + +dropLogfileGroup + : DROP LOGFILE GROUP uid ENGINE '=' engineName + ; + +dropProcedure + : DROP PROCEDURE ifExists? fullId + ; + +dropFunction + : DROP FUNCTION ifExists? fullId + ; + +dropServer + : DROP SERVER ifExists? uid + ; + +dropTable + : DROP TEMPORARY? TABLE ifExists? + tables dropType=(RESTRICT | CASCADE)? + ; + +dropTablespace + : DROP TABLESPACE uid (ENGINE '='? engineName)? + ; + +dropTrigger + : DROP TRIGGER ifExists? fullId + ; + +dropView + : DROP VIEW ifExists? + fullId (',' fullId)* dropType=(RESTRICT | CASCADE)? + ; + +dropRole + : DROP ROLE ifExists? roleName (',' roleName)* + ; + +setRole + : SET DEFAULT ROLE (NONE | ALL | roleName (',' roleName)*) + TO (userName | uid) (',' (userName | uid))* + | SET ROLE roleOption + ; + +// Other DDL statements + +renameTable + : RENAME TABLE + renameTableClause (',' renameTableClause)* + ; + +renameTableClause + : tableName TO tableName + ; + +truncateTable + : TRUNCATE TABLE? tableName + ; + + +// Data Manipulation Language + +// Primary DML Statements + + +callStatement + : CALL fullId + ( + '(' (constants | expressions)? ')' + )? + ; + +deleteStatement + : singleDeleteStatement | multipleDeleteStatement + ; + +doStatement + : DO expressions + ; + +handlerStatement + : handlerOpenStatement + | handlerReadIndexStatement + | handlerReadStatement + | handlerCloseStatement + ; + +insertStatement + : INSERT + priority=(LOW_PRIORITY | DELAYED | HIGH_PRIORITY)? + IGNORE? INTO? tableName + (PARTITION '(' partitions=uidList? ')' )? + ( + ('(' columns=fullColumnNameList ')')? insertStatementValue (AS? uid)? + | SET + setFirst=updatedElement + (',' setElements+=updatedElement)* + ) + ( + ON DUPLICATE KEY UPDATE + duplicatedFirst=updatedElement + (',' duplicatedElements+=updatedElement)* + )? + ; + +loadDataStatement + : LOAD DATA + priority=(LOW_PRIORITY | CONCURRENT)? + LOCAL? INFILE filename=STRING_LITERAL + violation=(REPLACE | IGNORE)? + INTO TABLE tableName + (PARTITION '(' uidList ')' )? + (CHARACTER SET charset=charsetName)? + ( + fieldsFormat=(FIELDS | COLUMNS) + selectFieldsInto+ + )? + ( + LINES + selectLinesInto+ + )? + ( + IGNORE decimalLiteral linesFormat=(LINES | ROWS) + )? + ( '(' assignmentField (',' assignmentField)* ')' )? + (SET updatedElement (',' updatedElement)*)? + ; + +loadXmlStatement + : LOAD XML + priority=(LOW_PRIORITY | CONCURRENT)? + LOCAL? INFILE filename=STRING_LITERAL + violation=(REPLACE | IGNORE)? + INTO TABLE tableName + (CHARACTER SET charset=charsetName)? + (ROWS IDENTIFIED BY '<' tag=STRING_LITERAL '>')? + ( IGNORE decimalLiteral linesFormat=(LINES | ROWS) )? + ( '(' assignmentField (',' assignmentField)* ')' )? + (SET updatedElement (',' updatedElement)*)? + ; + +replaceStatement + : REPLACE priority=(LOW_PRIORITY | DELAYED)? + INTO? tableName + (PARTITION '(' partitions=uidList ')' )? + ( + ('(' columns=uidList ')')? insertStatementValue + | SET + setFirst=updatedElement + (',' setElements+=updatedElement)* + ) + ; + +selectStatement + : querySpecification lockClause? #simpleSelect + | queryExpression lockClause? #parenthesisSelect + | querySpecificationNointo unionStatement+ + ( + UNION unionType=(ALL | DISTINCT)? + (querySpecification | queryExpression) + )? + orderByClause? limitClause? lockClause? #unionSelect + | queryExpressionNointo unionParenthesis+ + ( + UNION unionType=(ALL | DISTINCT)? + queryExpression + )? + orderByClause? limitClause? lockClause? #unionParenthesisSelect + | querySpecificationNointo (',' lateralStatement)+ #withLateralStatement + ; + +updateStatement + : singleUpdateStatement | multipleUpdateStatement + ; + +// https://dev.mysql.com/doc/refman/8.0/en/values.html +valuesStatement + : VALUES + '(' expressionsWithDefaults? ')' + (',' '(' expressionsWithDefaults? ')')* + ; + +// details + +insertStatementValue + : selectStatement + | insertFormat=(VALUES | VALUE) + '(' expressionsWithDefaults? ')' + (',' '(' expressionsWithDefaults? ')')* + ; + +updatedElement + : fullColumnName '=' (expression | DEFAULT) + ; + +assignmentField + : uid | LOCAL_ID + ; + +lockClause + : FOR UPDATE | LOCK IN SHARE MODE + ; + +// Detailed DML Statements + +singleDeleteStatement + : DELETE priority=LOW_PRIORITY? QUICK? IGNORE? + FROM tableName (AS? uid)? + (PARTITION '(' uidList ')' )? + (WHERE expression)? + orderByClause? (LIMIT limitClauseAtom)? + ; + +multipleDeleteStatement + : DELETE priority=LOW_PRIORITY? QUICK? IGNORE? + ( + tableName ('.' '*')? ( ',' tableName ('.' '*')? )* + FROM tableSources + | FROM + tableName ('.' '*')? ( ',' tableName ('.' '*')? )* + USING tableSources + ) + (WHERE expression)? + ; + +handlerOpenStatement + : HANDLER tableName OPEN (AS? uid)? + ; + +handlerReadIndexStatement + : HANDLER tableName READ index=uid + ( + comparisonOperator '(' constants ')' + | moveOrder=(FIRST | NEXT | PREV | LAST) + ) + (WHERE expression)? (LIMIT limitClauseAtom)? + ; + +handlerReadStatement + : HANDLER tableName READ moveOrder=(FIRST | NEXT) + (WHERE expression)? (LIMIT limitClauseAtom)? + ; + +handlerCloseStatement + : HANDLER tableName CLOSE + ; + +singleUpdateStatement + : UPDATE priority=LOW_PRIORITY? IGNORE? tableName (AS? uid)? + SET updatedElement (',' updatedElement)* + (WHERE expression)? orderByClause? limitClause? + ; + +multipleUpdateStatement + : UPDATE priority=LOW_PRIORITY? IGNORE? tableSources + SET updatedElement (',' updatedElement)* + (WHERE expression)? + ; + +// details + +orderByClause + : ORDER BY orderByExpression (',' orderByExpression)* + ; + +orderByExpression + : expression order=(ASC | DESC)? + ; + +tableSources + : tableSource (',' tableSource)* + ; + +tableSource + : tableSourceItem joinPart* #tableSourceBase + | '(' tableSourceItem joinPart* ')' #tableSourceNested + | jsonTable #tableJson + ; + +tableSourceItem + : tableName + (PARTITION '(' uidList ')' )? (AS? alias=uid)? + (indexHint (',' indexHint)* )? #atomTableItem + | ( + selectStatement + | '(' parenthesisSubquery=selectStatement ')' + ) + AS? alias=uid #subqueryTableItem + | '(' tableSources ')' #tableSourcesItem + ; + +indexHint + : indexHintAction=(USE | IGNORE | FORCE) + keyFormat=(INDEX|KEY) ( FOR indexHintType)? + '(' uidList ')' + ; + +indexHintType + : JOIN | ORDER BY | GROUP BY + ; + +joinPart + : (INNER | CROSS)? JOIN LATERAL? tableSourceItem + ( + ON expression + | USING '(' uidList ')' + )? #innerJoin + | STRAIGHT_JOIN tableSourceItem (ON expression)? #straightJoin + | (LEFT | RIGHT) OUTER? JOIN LATERAL? tableSourceItem + ( + ON expression + | USING '(' uidList ')' + ) #outerJoin + | NATURAL ((LEFT | RIGHT) OUTER?)? JOIN tableSourceItem #naturalJoin + ; + +// Select Statement's Details + +queryExpression + : '(' querySpecification ')' + | '(' queryExpression ')' + ; + +queryExpressionNointo + : '(' querySpecificationNointo ')' + | '(' queryExpressionNointo ')' + ; + +querySpecification + : SELECT selectSpec* selectElements selectIntoExpression? + fromClause groupByClause? havingClause? windowClause? orderByClause? limitClause? + | SELECT selectSpec* selectElements + fromClause groupByClause? havingClause? windowClause? orderByClause? limitClause? selectIntoExpression? + ; + +querySpecificationNointo + : SELECT selectSpec* selectElements + fromClause groupByClause? havingClause? windowClause? orderByClause? limitClause? + ; + +unionParenthesis + : UNION unionType=(ALL | DISTINCT)? queryExpressionNointo + ; + +unionStatement + : UNION unionType=(ALL | DISTINCT)? + (querySpecificationNointo | queryExpressionNointo) + ; + +lateralStatement + : LATERAL (querySpecificationNointo | + queryExpressionNointo | + ('(' (querySpecificationNointo | queryExpressionNointo) ')' (AS? uid)?) + ) + ; + +// JSON + +// https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html +jsonTable + : JSON_TABLE '(' + STRING_LITERAL ',' + STRING_LITERAL + COLUMNS '(' jsonColumnList ')' + ')' (AS? uid)? + ; + +jsonColumnList + : jsonColumn (',' jsonColumn)* + ; + +jsonColumn + : fullColumnName ( FOR ORDINALITY + | dataType ( PATH STRING_LITERAL jsonOnEmpty? jsonOnError? + | EXISTS PATH STRING_LITERAL ) ) + | NESTED PATH? STRING_LITERAL COLUMNS '(' jsonColumnList ')' + ; + +jsonOnEmpty + : (NULL_LITERAL | ERROR | DEFAULT defaultValue) ON EMPTY + ; + +jsonOnError + : (NULL_LITERAL | ERROR | DEFAULT defaultValue) ON ERROR + ; + +// details + +selectSpec + : (ALL | DISTINCT | DISTINCTROW) + | HIGH_PRIORITY | STRAIGHT_JOIN | SQL_SMALL_RESULT + | SQL_BIG_RESULT | SQL_BUFFER_RESULT + | (SQL_CACHE | SQL_NO_CACHE) + | SQL_CALC_FOUND_ROWS + ; + +selectElements + : (star='*' | selectElement ) (',' selectElement)* + ; + +selectElement + : fullId '.' '*' #selectStarElement + | fullColumnName (AS? uid)? #selectColumnElement + | functionCall (AS? uid)? #selectFunctionElement + | (LOCAL_ID VAR_ASSIGN)? expression (AS? uid)? #selectExpressionElement + ; + +selectIntoExpression + : INTO assignmentField (',' assignmentField )* #selectIntoVariables + | INTO DUMPFILE STRING_LITERAL #selectIntoDumpFile + | ( + INTO OUTFILE filename=STRING_LITERAL + (CHARACTER SET charset=charsetName)? + ( + fieldsFormat=(FIELDS | COLUMNS) + selectFieldsInto+ + )? + ( + LINES selectLinesInto+ + )? + ) #selectIntoTextFile + ; + +selectFieldsInto + : TERMINATED BY terminationField=STRING_LITERAL + | OPTIONALLY? ENCLOSED BY enclosion=STRING_LITERAL + | ESCAPED BY escaping=STRING_LITERAL + ; + +selectLinesInto + : STARTING BY starting=STRING_LITERAL + | TERMINATED BY terminationLine=STRING_LITERAL + ; + +fromClause + : (FROM tableSources)? + (WHERE whereExpr=expression)? + ; + +groupByClause + : GROUP BY + groupByItem (',' groupByItem)* + (WITH ROLLUP)? + ; + +havingClause + : HAVING havingExpr=expression + ; + +windowClause + : WINDOW windowName AS '(' windowSpec ')' (',' windowName AS '(' windowSpec ')')* + ; + +groupByItem + : expression order=(ASC | DESC)? + ; + +limitClause + : LIMIT + ( + (offset=limitClauseAtom ',')? limit=limitClauseAtom + | limit=limitClauseAtom OFFSET offset=limitClauseAtom + ) + ; + +limitClauseAtom + : decimalLiteral | mysqlVariable | simpleId + ; + + +// Transaction's Statements + +startTransaction + : START TRANSACTION (transactionMode (',' transactionMode)* )? + ; + +beginWork + : BEGIN WORK? + ; + +commitWork + : COMMIT WORK? + (AND nochain=NO? CHAIN)? + (norelease=NO? RELEASE)? + ; + +rollbackWork + : ROLLBACK WORK? + (AND nochain=NO? CHAIN)? + (norelease=NO? RELEASE)? + ; + +savepointStatement + : SAVEPOINT uid + ; + +rollbackStatement + : ROLLBACK WORK? TO SAVEPOINT? uid + ; + +releaseStatement + : RELEASE SAVEPOINT uid + ; + +lockTables + : LOCK (TABLE | TABLES) lockTableElement (',' lockTableElement)* waitNowaitClause? + ; + +unlockTables + : UNLOCK TABLES + ; + + +// details + +setAutocommitStatement + : SET AUTOCOMMIT '=' autocommitValue=('0' | '1') + ; + +setTransactionStatement + : SET transactionContext=(GLOBAL | SESSION)? TRANSACTION + transactionOption (',' transactionOption)* + ; + +transactionMode + : WITH CONSISTENT SNAPSHOT + | READ WRITE + | READ ONLY + ; + +lockTableElement + : tableName (AS? uid)? lockAction + ; + +lockAction + : READ LOCAL? | LOW_PRIORITY? WRITE + ; + +transactionOption + : ISOLATION LEVEL transactionLevel + | READ WRITE + | READ ONLY + ; + +transactionLevel + : REPEATABLE READ + | READ COMMITTED + | READ UNCOMMITTED + | SERIALIZABLE + ; + + +// Replication's Statements + +// Base Replication + +changeMaster + : CHANGE MASTER TO + masterOption (',' masterOption)* channelOption? + ; + +changeReplicationFilter + : CHANGE REPLICATION FILTER + replicationFilter (',' replicationFilter)* + ; + +purgeBinaryLogs + : PURGE purgeFormat=(BINARY | MASTER) LOGS + ( + TO fileName=STRING_LITERAL + | BEFORE timeValue=STRING_LITERAL + ) + ; + +resetMaster + : RESET MASTER + ; + +resetSlave + : RESET SLAVE ALL? channelOption? + ; + +startSlave + : START SLAVE (threadType (',' threadType)*)? + (UNTIL untilOption)? + connectionOption* channelOption? + ; + +stopSlave + : STOP SLAVE (threadType (',' threadType)*)? + ; + +startGroupReplication + : START GROUP_REPLICATION + ; + +stopGroupReplication + : STOP GROUP_REPLICATION + ; + +// details + +masterOption + : stringMasterOption '=' STRING_LITERAL #masterStringOption + | decimalMasterOption '=' decimalLiteral #masterDecimalOption + | boolMasterOption '=' boolVal=('0' | '1') #masterBoolOption + | MASTER_HEARTBEAT_PERIOD '=' REAL_LITERAL #masterRealOption + | IGNORE_SERVER_IDS '=' '(' (uid (',' uid)*)? ')' #masterUidListOption + ; + +stringMasterOption + : MASTER_BIND | MASTER_HOST | MASTER_USER | MASTER_PASSWORD + | MASTER_LOG_FILE | RELAY_LOG_FILE | MASTER_SSL_CA + | MASTER_SSL_CAPATH | MASTER_SSL_CERT | MASTER_SSL_CRL + | MASTER_SSL_CRLPATH | MASTER_SSL_KEY | MASTER_SSL_CIPHER + | MASTER_TLS_VERSION + ; +decimalMasterOption + : MASTER_PORT | MASTER_CONNECT_RETRY | MASTER_RETRY_COUNT + | MASTER_DELAY | MASTER_LOG_POS | RELAY_LOG_POS + ; + +boolMasterOption + : MASTER_AUTO_POSITION | MASTER_SSL + | MASTER_SSL_VERIFY_SERVER_CERT + ; + +channelOption + : FOR CHANNEL STRING_LITERAL + ; + +replicationFilter + : REPLICATE_DO_DB '=' '(' uidList ')' #doDbReplication + | REPLICATE_IGNORE_DB '=' '(' uidList ')' #ignoreDbReplication + | REPLICATE_DO_TABLE '=' '(' tables ')' #doTableReplication + | REPLICATE_IGNORE_TABLE '=' '(' tables ')' #ignoreTableReplication + | REPLICATE_WILD_DO_TABLE '=' '(' simpleStrings ')' #wildDoTableReplication + | REPLICATE_WILD_IGNORE_TABLE + '=' '(' simpleStrings ')' #wildIgnoreTableReplication + | REPLICATE_REWRITE_DB '=' + '(' tablePair (',' tablePair)* ')' #rewriteDbReplication + ; + +tablePair + : '(' firstTable=tableName ',' secondTable=tableName ')' + ; + +threadType + : IO_THREAD | SQL_THREAD + ; + +untilOption + : gtids=(SQL_BEFORE_GTIDS | SQL_AFTER_GTIDS) + '=' gtuidSet #gtidsUntilOption + | MASTER_LOG_FILE '=' STRING_LITERAL + ',' MASTER_LOG_POS '=' decimalLiteral #masterLogUntilOption + | RELAY_LOG_FILE '=' STRING_LITERAL + ',' RELAY_LOG_POS '=' decimalLiteral #relayLogUntilOption + | SQL_AFTER_MTS_GAPS #sqlGapsUntilOption + ; + +connectionOption + : USER '=' conOptUser=STRING_LITERAL #userConnectionOption + | PASSWORD '=' conOptPassword=STRING_LITERAL #passwordConnectionOption + | DEFAULT_AUTH '=' conOptDefAuth=STRING_LITERAL #defaultAuthConnectionOption + | PLUGIN_DIR '=' conOptPluginDir=STRING_LITERAL #pluginDirConnectionOption + ; + +gtuidSet + : uuidSet (',' uuidSet)* + | STRING_LITERAL + ; + + +// XA Transactions + +xaStartTransaction + : XA xaStart=(START | BEGIN) xid xaAction=(JOIN | RESUME)? + ; + +xaEndTransaction + : XA END xid (SUSPEND (FOR MIGRATE)?)? + ; + +xaPrepareStatement + : XA PREPARE xid + ; + +xaCommitWork + : XA COMMIT xid (ONE PHASE)? + ; + +xaRollbackWork + : XA ROLLBACK xid + ; + +xaRecoverWork + : XA RECOVER (CONVERT xid)? + ; + + +// Prepared Statements + +prepareStatement + : PREPARE uid FROM + (query=STRING_LITERAL | variable=LOCAL_ID) + ; + +executeStatement + : EXECUTE uid (USING userVariables)? + ; + +deallocatePrepare + : dropFormat=(DEALLOCATE | DROP) PREPARE uid + ; + + +// Compound Statements + +routineBody + : blockStatement | sqlStatement + ; + +// details + +blockStatement + : (uid ':')? BEGIN + (declareVariable SEMI)* + (declareCondition SEMI)* + (declareCursor SEMI)* + (declareHandler SEMI)* + procedureSqlStatement* + END uid? + ; + +caseStatement + : CASE (uid | expression)? caseAlternative+ + (ELSE procedureSqlStatement+)? + END CASE + ; + +ifStatement + : IF expression + THEN thenStatements+=procedureSqlStatement+ + elifAlternative* + (ELSE elseStatements+=procedureSqlStatement+ )? + END IF + ; + +iterateStatement + : ITERATE uid + ; + +leaveStatement + : LEAVE uid + ; + +loopStatement + : (uid ':')? + LOOP procedureSqlStatement+ + END LOOP uid? + ; + +repeatStatement + : (uid ':')? + REPEAT procedureSqlStatement+ + UNTIL expression + END REPEAT uid? + ; + +returnStatement + : RETURN expression + ; + +whileStatement + : (uid ':')? + WHILE expression + DO procedureSqlStatement+ + END WHILE uid? + ; + +cursorStatement + : CLOSE uid #CloseCursor + | FETCH (NEXT? FROM)? uid INTO uidList #FetchCursor + | OPEN uid #OpenCursor + ; + +// details + +declareVariable + : DECLARE uidList dataType (DEFAULT expression)? + ; + +declareCondition + : DECLARE uid CONDITION FOR + ( decimalLiteral | SQLSTATE VALUE? STRING_LITERAL) + ; + +declareCursor + : DECLARE uid CURSOR FOR selectStatement + ; + +declareHandler + : DECLARE handlerAction=(CONTINUE | EXIT | UNDO) + HANDLER FOR + handlerConditionValue (',' handlerConditionValue)* + routineBody + ; + +handlerConditionValue + : decimalLiteral #handlerConditionCode + | SQLSTATE VALUE? STRING_LITERAL #handlerConditionState + | uid #handlerConditionName + | SQLWARNING #handlerConditionWarning + | NOT FOUND #handlerConditionNotfound + | SQLEXCEPTION #handlerConditionException + ; + +procedureSqlStatement + : (compoundStatement | sqlStatement) SEMI + ; + +caseAlternative + : WHEN (constant | expression) + THEN procedureSqlStatement+ + ; + +elifAlternative + : ELSEIF expression + THEN procedureSqlStatement+ + ; + +// Administration Statements + +// Account management statements + +alterUser + : ALTER USER + userSpecification (',' userSpecification)* #alterUserMysqlV56 + | ALTER USER ifExists? + userAuthOption (',' userAuthOption)* + ( + REQUIRE + (tlsNone=NONE | tlsOption (AND? tlsOption)* ) + )? + (WITH userResourceOption+)? + (userPasswordOption | userLockOption)* + (COMMENT STRING_LITERAL | ATTRIBUTE STRING_LITERAL)? #alterUserMysqlV80 + | ALTER USER ifExists? + (userName | uid) DEFAULT ROLE roleOption #alterUserMysqlV80 + ; + +createUser + : CREATE USER userAuthOption (',' userAuthOption)* #createUserMysqlV56 + | CREATE USER ifNotExists? + userAuthOption (',' userAuthOption)* + (DEFAULT ROLE roleOption)? + ( + REQUIRE + (tlsNone=NONE | tlsOption (AND? tlsOption)* ) + )? + (WITH userResourceOption+)? + (userPasswordOption | userLockOption)* + (COMMENT STRING_LITERAL | ATTRIBUTE STRING_LITERAL)? #createUserMysqlV80 + ; + +dropUser + : DROP USER ifExists? userName (',' userName)* + ; + +grantStatement + : GRANT privelegeClause (',' privelegeClause)* + ON + privilegeObject=(TABLE | FUNCTION | PROCEDURE)? + privilegeLevel + TO userAuthOption (',' userAuthOption)* + ( + REQUIRE + (tlsNone=NONE | tlsOption (AND? tlsOption)* ) + )? + (WITH (GRANT OPTION | userResourceOption)* )? + (AS userName WITH ROLE roleOption)? + | GRANT (userName | uid) (',' (userName | uid))* + TO (userName | uid) (',' (userName | uid))* + (WITH ADMIN OPTION)? + ; + +roleOption + : DEFAULT + | NONE + | ALL (EXCEPT userName (',' userName)*)? + | userName (',' userName)* + ; + +grantProxy + : GRANT PROXY ON fromFirst=userName + TO toFirst=userName (',' toOther+=userName)* + (WITH GRANT OPTION)? + ; + +renameUser + : RENAME USER + renameUserClause (',' renameUserClause)* + ; + +revokeStatement + : REVOKE privelegeClause (',' privelegeClause)* + ON + privilegeObject=(TABLE | FUNCTION | PROCEDURE)? + privilegeLevel + FROM userName (',' userName)* #detailRevoke + | REVOKE ALL PRIVILEGES? ',' GRANT OPTION + FROM userName (',' userName)* #shortRevoke + | REVOKE (userName | uid) (',' (userName | uid))* + FROM (userName | uid) (',' (userName | uid))* #roleRevoke + ; + +revokeProxy + : REVOKE PROXY ON onUser=userName + FROM fromFirst=userName (',' fromOther+=userName)* + ; + +setPasswordStatement + : SET PASSWORD (FOR userName)? + '=' ( passwordFunctionClause | STRING_LITERAL) + ; + +// details + +userSpecification + : userName userPasswordOption + ; + +userAuthOption + : userName IDENTIFIED BY PASSWORD hashed=STRING_LITERAL #hashAuthOption + | userName + IDENTIFIED BY STRING_LITERAL (RETAIN CURRENT PASSWORD)? #stringAuthOption + | userName + IDENTIFIED WITH + authenticationRule #moduleAuthOption + | userName #simpleAuthOption + ; + +authenticationRule + : authPlugin + ((BY | USING | AS) STRING_LITERAL)? #module + | authPlugin + USING passwordFunctionClause #passwordModuleOption + ; + +tlsOption + : SSL + | X509 + | CIPHER STRING_LITERAL + | ISSUER STRING_LITERAL + | SUBJECT STRING_LITERAL + ; + +userResourceOption + : MAX_QUERIES_PER_HOUR decimalLiteral + | MAX_UPDATES_PER_HOUR decimalLiteral + | MAX_CONNECTIONS_PER_HOUR decimalLiteral + | MAX_USER_CONNECTIONS decimalLiteral + ; + +userPasswordOption + : PASSWORD EXPIRE + (expireType=DEFAULT + | expireType=NEVER + | expireType=INTERVAL decimalLiteral DAY + )? + | PASSWORD HISTORY (DEFAULT | decimalLiteral) + | PASSWORD REUSE INTERVAL (DEFAULT | decimalLiteral DAY) + | PASSWORD REQUIRE CURRENT (OPTIONAL | DEFAULT)? + | FAILED_LOGIN_ATTEMPTS decimalLiteral + | PASSWORD_LOCK_TIME (decimalLiteral | UNBOUNDED) + ; + +userLockOption + : ACCOUNT lockType=(LOCK | UNLOCK) + ; + +privelegeClause + : privilege ( '(' uidList ')' )? + ; + +privilege + : ALL PRIVILEGES? + | ALTER ROUTINE? + | CREATE + (TEMPORARY TABLES | ROUTINE | VIEW | USER | TABLESPACE | ROLE)? + | DELETE | DROP (ROLE)? | EVENT | EXECUTE | FILE | GRANT OPTION + | INDEX | INSERT | LOCK TABLES | PROCESS | PROXY + | REFERENCES | RELOAD + | REPLICATION (CLIENT | SLAVE) + | SELECT + | SHOW (VIEW | DATABASES) + | SHUTDOWN | SUPER | TRIGGER | UPDATE | USAGE + | APPLICATION_PASSWORD_ADMIN | AUDIT_ABORT_EXEMPT | AUDIT_ADMIN | AUTHENTICATION_POLICY_ADMIN | BACKUP_ADMIN | BINLOG_ADMIN | BINLOG_ENCRYPTION_ADMIN | CLONE_ADMIN + | CONNECTION_ADMIN | ENCRYPTION_KEY_ADMIN | FIREWALL_ADMIN | FIREWALL_EXEMPT | FIREWALL_USER | FLUSH_OPTIMIZER_COSTS + | FLUSH_STATUS | FLUSH_TABLES | FLUSH_USER_RESOURCES | GROUP_REPLICATION_ADMIN + | INNODB_REDO_LOG_ARCHIVE | INNODB_REDO_LOG_ENABLE | NDB_STORED_USER | PASSWORDLESS_USER_ADMIN | PERSIST_RO_VARIABLES_ADMIN | REPLICATION_APPLIER + | REPLICATION_SLAVE_ADMIN | RESOURCE_GROUP_ADMIN | RESOURCE_GROUP_USER | ROLE_ADMIN + | SERVICE_CONNECTION_ADMIN + | SESSION_VARIABLES_ADMIN | SET_USER_ID | SKIP_QUERY_REWRITE | SHOW_ROUTINE | SYSTEM_USER | SYSTEM_VARIABLES_ADMIN + | TABLE_ENCRYPTION_ADMIN | TP_CONNECTION_ADMIN | VERSION_TOKEN_ADMIN | XA_RECOVER_ADMIN + // MySQL on Amazon RDS + | LOAD FROM S3 | SELECT INTO S3 | INVOKE LAMBDA + ; + +privilegeLevel + : '*' #currentSchemaPriviLevel + | '*' '.' '*' #globalPrivLevel + | uid '.' '*' #definiteSchemaPrivLevel + | uid '.' uid #definiteFullTablePrivLevel + | uid dottedId #definiteFullTablePrivLevel2 + | uid #definiteTablePrivLevel + ; + +renameUserClause + : fromFirst=userName TO toFirst=userName + ; + +// Table maintenance statements + +analyzeTable + : ANALYZE actionOption=(NO_WRITE_TO_BINLOG | LOCAL)? + (TABLE | TABLES) tables + ( UPDATE HISTOGRAM ON fullColumnName (',' fullColumnName)* (WITH decimalLiteral BUCKETS)? )? + ( DROP HISTOGRAM ON fullColumnName (',' fullColumnName)* )? + ; + +checkTable + : CHECK TABLE tables checkTableOption* + ; + +checksumTable + : CHECKSUM TABLE tables actionOption=(QUICK | EXTENDED)? + ; + +optimizeTable + : OPTIMIZE actionOption=(NO_WRITE_TO_BINLOG | LOCAL)? + (TABLE | TABLES) tables + ; + +repairTable + : REPAIR actionOption=(NO_WRITE_TO_BINLOG | LOCAL)? + TABLE tables + QUICK? EXTENDED? USE_FRM? + ; + +// details + +checkTableOption + : FOR UPGRADE | QUICK | FAST | MEDIUM | EXTENDED | CHANGED + ; + + +// Plugin and udf statements + +createUdfunction + : CREATE AGGREGATE? FUNCTION ifNotExists? uid + RETURNS returnType=(STRING | INTEGER | REAL | DECIMAL) + SONAME STRING_LITERAL + ; + +installPlugin + : INSTALL PLUGIN uid SONAME STRING_LITERAL + ; + +uninstallPlugin + : UNINSTALL PLUGIN uid + ; + + +// Set and show statements + +setStatement + : SET variableClause ('=' | ':=') (expression | ON) + (',' variableClause ('=' | ':=') (expression | ON))* #setVariable + | SET charSet (charsetName | DEFAULT) #setCharset + | SET NAMES + (charsetName (COLLATE collationName)? | DEFAULT) #setNames + | setPasswordStatement #setPassword + | setTransactionStatement #setTransaction + | setAutocommitStatement #setAutocommit + | SET fullId ('=' | ':=') expression + (',' fullId ('=' | ':=') expression)* #setNewValueInsideTrigger + ; + +showStatement + : SHOW logFormat=(BINARY | MASTER) LOGS #showMasterLogs + | SHOW logFormat=(BINLOG | RELAYLOG) + EVENTS (IN filename=STRING_LITERAL)? + (FROM fromPosition=decimalLiteral)? + (LIMIT + (offset=decimalLiteral ',')? + rowCount=decimalLiteral + )? #showLogEvents + | SHOW showCommonEntity showFilter? #showObjectFilter + | SHOW FULL? columnsFormat=(COLUMNS | FIELDS) + tableFormat=(FROM | IN) tableName + (schemaFormat=(FROM | IN) uid)? showFilter? #showColumns + | SHOW CREATE schemaFormat=(DATABASE | SCHEMA) + ifNotExists? uid #showCreateDb + | SHOW CREATE + namedEntity=( + EVENT | FUNCTION | PROCEDURE + | TABLE | TRIGGER | VIEW + ) + fullId #showCreateFullIdObject + | SHOW CREATE USER userName #showCreateUser + | SHOW ENGINE engineName engineOption=(STATUS | MUTEX) #showEngine + | SHOW showGlobalInfoClause #showGlobalInfo + | SHOW errorFormat=(ERRORS | WARNINGS) + (LIMIT + (offset=decimalLiteral ',')? + rowCount=decimalLiteral + )? #showErrors + | SHOW COUNT '(' '*' ')' errorFormat=(ERRORS | WARNINGS) #showCountErrors + | SHOW showSchemaEntity + (schemaFormat=(FROM | IN) uid)? showFilter? #showSchemaFilter + | SHOW routine=(FUNCTION | PROCEDURE) CODE fullId #showRoutine + | SHOW GRANTS (FOR userName)? #showGrants + | SHOW indexFormat=(INDEX | INDEXES | KEYS) + tableFormat=(FROM | IN) tableName + (schemaFormat=(FROM | IN) uid)? (WHERE expression)? #showIndexes + | SHOW OPEN TABLES ( schemaFormat=(FROM | IN) uid)? + showFilter? #showOpenTables + | SHOW PROFILE showProfileType (',' showProfileType)* + (FOR QUERY queryCount=decimalLiteral)? + (LIMIT + (offset=decimalLiteral ',')? + rowCount=decimalLiteral + ) #showProfile + | SHOW SLAVE STATUS (FOR CHANNEL STRING_LITERAL)? #showSlaveStatus + ; + +// details + +variableClause + : LOCAL_ID | GLOBAL_ID | ( ('@' '@')? (GLOBAL | SESSION | LOCAL) )? uid + ; + +showCommonEntity + : CHARACTER SET | COLLATION | DATABASES | SCHEMAS + | FUNCTION STATUS | PROCEDURE STATUS + | (GLOBAL | SESSION)? (STATUS | VARIABLES) + ; + +showFilter + : LIKE STRING_LITERAL + | WHERE expression + ; + +showGlobalInfoClause + : STORAGE? ENGINES | MASTER STATUS | PLUGINS + | PRIVILEGES | FULL? PROCESSLIST | PROFILES + | SLAVE HOSTS | AUTHORS | CONTRIBUTORS + ; + +showSchemaEntity + : EVENTS | TABLE STATUS | FULL? TABLES | TRIGGERS + ; + +showProfileType + : ALL | BLOCK IO | CONTEXT SWITCHES | CPU | IPC | MEMORY + | PAGE FAULTS | SOURCE | SWAPS + ; + + +// Other administrative statements + +binlogStatement + : BINLOG STRING_LITERAL + ; + +cacheIndexStatement + : CACHE INDEX tableIndexes (',' tableIndexes)* + ( PARTITION '(' (uidList | ALL) ')' )? + IN schema=uid + ; + +flushStatement + : FLUSH flushFormat=(NO_WRITE_TO_BINLOG | LOCAL)? + flushOption (',' flushOption)* + ; + +killStatement + : KILL connectionFormat=(CONNECTION | QUERY)? expression + ; + +loadIndexIntoCache + : LOAD INDEX INTO CACHE + loadedTableIndexes (',' loadedTableIndexes)* + ; + +// remark reset (maser | slave) describe in replication's +// statements section +resetStatement + : RESET QUERY CACHE + ; + +shutdownStatement + : SHUTDOWN + ; + +// details + +tableIndexes + : tableName ( indexFormat=(INDEX | KEY)? '(' uidList ')' )? + ; + +flushOption + : ( + DES_KEY_FILE | HOSTS + | ( + BINARY | ENGINE | ERROR | GENERAL | RELAY | SLOW + )? LOGS + | OPTIMIZER_COSTS | PRIVILEGES | QUERY CACHE | STATUS + | USER_RESOURCES | TABLES (WITH READ LOCK)? + ) #simpleFlushOption + | RELAY LOGS channelOption? #channelFlushOption + | (TABLE | TABLES) tables? flushTableOption? #tableFlushOption + ; + +flushTableOption + : WITH READ LOCK + | FOR EXPORT + ; + +loadedTableIndexes + : tableName + ( PARTITION '(' (partitionList=uidList | ALL) ')' )? + ( indexFormat=(INDEX | KEY)? '(' indexList=uidList ')' )? + (IGNORE LEAVES)? + ; + + +// Utility Statements + + +simpleDescribeStatement + : command=(EXPLAIN | DESCRIBE | DESC) tableName + (column=uid | pattern=STRING_LITERAL)? + ; + +fullDescribeStatement + : command=(EXPLAIN | DESCRIBE | DESC) + ( + formatType=(EXTENDED | PARTITIONS | FORMAT ) + '=' + formatValue=(TRADITIONAL | JSON) + )? + describeObjectClause + ; + +helpStatement + : HELP STRING_LITERAL + ; + +useStatement + : USE uid + ; + +signalStatement + : SIGNAL ( ( SQLSTATE VALUE? stringLiteral ) | ID | REVERSE_QUOTE_ID ) + ( SET signalConditionInformation ( ',' signalConditionInformation)* )? + ; + +resignalStatement + : RESIGNAL ( ( SQLSTATE VALUE? stringLiteral ) | ID | REVERSE_QUOTE_ID )? + ( SET signalConditionInformation ( ',' signalConditionInformation)* )? + ; + +signalConditionInformation + : ( CLASS_ORIGIN + | SUBCLASS_ORIGIN + | MESSAGE_TEXT + | MYSQL_ERRNO + | CONSTRAINT_CATALOG + | CONSTRAINT_SCHEMA + | CONSTRAINT_NAME + | CATALOG_NAME + | SCHEMA_NAME + | TABLE_NAME + | COLUMN_NAME + | CURSOR_NAME + ) '=' ( stringLiteral | DECIMAL_LITERAL | mysqlVariable | simpleId ) + ; + +withStatement + : WITH RECURSIVE? commonTableExpressions (',' commonTableExpressions)* + ; + +diagnosticsStatement + : GET ( CURRENT | STACKED )? DIAGNOSTICS ( + ( variableClause '=' ( NUMBER | ROW_COUNT ) ( ',' variableClause '=' ( NUMBER | ROW_COUNT ) )* ) + | ( CONDITION ( decimalLiteral | variableClause ) variableClause '=' diagnosticsConditionInformationName ( ',' variableClause '=' diagnosticsConditionInformationName )* ) + ) + ; + +diagnosticsConditionInformationName + : CLASS_ORIGIN + | SUBCLASS_ORIGIN + | RETURNED_SQLSTATE + | MESSAGE_TEXT + | MYSQL_ERRNO + | CONSTRAINT_CATALOG + | CONSTRAINT_SCHEMA + | CONSTRAINT_NAME + | CATALOG_NAME + | SCHEMA_NAME + | TABLE_NAME + | COLUMN_NAME + | CURSOR_NAME + ; + +// details + +describeObjectClause + : ( + selectStatement | deleteStatement | insertStatement + | replaceStatement | updateStatement + ) #describeStatements + | FOR CONNECTION uid #describeConnection + ; + + +// Common Clauses + +// DB Objects + +fullId + : uid (DOT_ID | '.' uid)? + ; + +tableName + : fullId + ; + +roleName + : userName | uid + ; + +fullColumnName + : uid (dottedId dottedId? )? + | .? dottedId dottedId? + ; + +indexColumnName + : ((uid | STRING_LITERAL) ('(' decimalLiteral ')')? | expression) sortType=(ASC | DESC)? + ; + +userName + : STRING_USER_NAME | ID | STRING_LITERAL | ADMIN | keywordsCanBeId; + +mysqlVariable + : LOCAL_ID + | GLOBAL_ID + ; + +charsetName + : BINARY + | charsetNameBase + | STRING_LITERAL + | CHARSET_REVERSE_QOUTE_STRING + ; + +collationName + : uid | STRING_LITERAL; + +engineName + : ARCHIVE | BLACKHOLE | CSV | FEDERATED | INNODB | MEMORY + | MRG_MYISAM | MYISAM | NDB | NDBCLUSTER | PERFORMANCE_SCHEMA + | TOKUDB + | ID + | STRING_LITERAL | REVERSE_QUOTE_ID + | CONNECT + ; + +uuidSet + : decimalLiteral '-' decimalLiteral '-' decimalLiteral + '-' decimalLiteral '-' decimalLiteral + (':' decimalLiteral '-' decimalLiteral)+ + ; + +xid + : globalTableUid=xuidStringId + ( + ',' qualifier=xuidStringId + (',' idFormat=decimalLiteral)? + )? + ; + +xuidStringId + : STRING_LITERAL + | BIT_STRING + | HEXADECIMAL_LITERAL+ + ; + +authPlugin + : uid | STRING_LITERAL + ; + +uid + : simpleId + //| DOUBLE_QUOTE_ID + | REVERSE_QUOTE_ID + | CHARSET_REVERSE_QOUTE_STRING + ; + +simpleId + : ID + | charsetNameBase + | transactionLevelBase + | engineName + | privilegesBase + | intervalTypeBase + | dataTypeBase + | keywordsCanBeId + | scalarFunctionName + ; + +dottedId + : DOT_ID + | '.' uid + ; + + +// Literals + +decimalLiteral + : DECIMAL_LITERAL | ZERO_DECIMAL | ONE_DECIMAL | TWO_DECIMAL | REAL_LITERAL + ; + +fileSizeLiteral + : FILESIZE_LITERAL | decimalLiteral; + +stringLiteral + : ( + STRING_CHARSET_NAME? STRING_LITERAL + | START_NATIONAL_STRING_LITERAL + ) STRING_LITERAL+ + | ( + STRING_CHARSET_NAME? STRING_LITERAL + | START_NATIONAL_STRING_LITERAL + ) (COLLATE collationName)? + ; + +booleanLiteral + : TRUE | FALSE; + +hexadecimalLiteral + : STRING_CHARSET_NAME? HEXADECIMAL_LITERAL; + +nullNotnull + : NOT? (NULL_LITERAL | NULL_SPEC_LITERAL) + ; + +constant + : stringLiteral | decimalLiteral + | '-' decimalLiteral + | hexadecimalLiteral | booleanLiteral + | REAL_LITERAL | BIT_STRING + | NOT? nullLiteral=(NULL_LITERAL | NULL_SPEC_LITERAL) + ; + + +// Data Types + +dataType + : typeName=( + CHAR | CHARACTER | VARCHAR | TINYTEXT | TEXT | MEDIUMTEXT | LONGTEXT + | NCHAR | NVARCHAR | LONG + ) + VARYING? + lengthOneDimension? BINARY? + (charSet charsetName)? + (COLLATE collationName | BINARY)? #stringDataType + | NATIONAL typeName=(CHAR | CHARACTER) VARYING + lengthOneDimension? BINARY? #nationalVaryingStringDataType + | NATIONAL typeName=(VARCHAR | CHARACTER | CHAR) + lengthOneDimension? BINARY? #nationalStringDataType + | NCHAR typeName=VARCHAR + lengthOneDimension? BINARY? #nationalStringDataType + | typeName=( + TINYINT | SMALLINT | MEDIUMINT | INT | INTEGER | BIGINT + | MIDDLEINT | INT1 | INT2 | INT3 | INT4 | INT8 + ) + lengthOneDimension? (SIGNED | UNSIGNED | ZEROFILL)* #dimensionDataType + | typeName=REAL + lengthTwoDimension? (SIGNED | UNSIGNED | ZEROFILL)* #dimensionDataType + | typeName=DOUBLE PRECISION? + lengthTwoDimension? (SIGNED | UNSIGNED | ZEROFILL)* #dimensionDataType + | typeName=(DECIMAL | DEC | FIXED | NUMERIC | FLOAT | FLOAT4 | FLOAT8) + lengthTwoOptionalDimension? (SIGNED | UNSIGNED | ZEROFILL)* #dimensionDataType + | typeName=( + DATE | TINYBLOB | MEDIUMBLOB | LONGBLOB + | BOOL | BOOLEAN | SERIAL + ) #simpleDataType + | typeName=( + BIT | TIME | TIMESTAMP | DATETIME | BINARY + | VARBINARY | BLOB | YEAR + ) + lengthOneDimension? #dimensionDataType + | typeName=(ENUM | SET) + collectionOptions BINARY? + (charSet charsetName)? #collectionDataType + | typeName=( + GEOMETRYCOLLECTION | GEOMCOLLECTION | LINESTRING | MULTILINESTRING + | MULTIPOINT | MULTIPOLYGON | POINT | POLYGON | JSON | GEOMETRY + ) (SRID decimalLiteral)? #spatialDataType + | typeName=LONG VARCHAR? + BINARY? + (charSet charsetName)? + (COLLATE collationName)? #longVarcharDataType // LONG VARCHAR is the same as LONG + | LONG VARBINARY #longVarbinaryDataType + ; + +collectionOptions + : '(' STRING_LITERAL (',' STRING_LITERAL)* ')' + ; + +convertedDataType + : + ( + typeName=(BINARY| NCHAR) lengthOneDimension? + | typeName=CHAR lengthOneDimension? (charSet charsetName)? + | typeName=(DATE | DATETIME | TIME | JSON | INT | INTEGER) + | typeName=DECIMAL lengthTwoOptionalDimension? + | (SIGNED | UNSIGNED) INTEGER? + ) ARRAY? + ; + +lengthOneDimension + : '(' decimalLiteral ')' + ; + +lengthTwoDimension + : '(' decimalLiteral ',' decimalLiteral ')' + ; + +lengthTwoOptionalDimension + : '(' decimalLiteral (',' decimalLiteral)? ')' + ; + + +// Common Lists + +uidList + : uid (',' uid)* + ; + +fullColumnNameList + : fullColumnName (',' fullColumnName)* + ; + +tables + : tableName (',' tableName)* + ; + +indexColumnNames + : '(' indexColumnName (',' indexColumnName)* ')' + ; + +expressions + : expression (',' expression)* + ; + +expressionsWithDefaults + : expressionOrDefault (',' expressionOrDefault)* + ; + +constants + : constant (',' constant)* + ; + +simpleStrings + : STRING_LITERAL (',' STRING_LITERAL)* + ; + +userVariables + : LOCAL_ID (',' LOCAL_ID)* + ; + + +// Common Expressons + +defaultValue + : NULL_LITERAL + | CAST '(' expression AS convertedDataType ')' + | unaryOperator? constant + | currentTimestamp (ON UPDATE currentTimestamp)? + | '(' expression ')' + | '(' fullId ')' + ; + +currentTimestamp + : + ( + (CURRENT_TIMESTAMP | LOCALTIME | LOCALTIMESTAMP) + ('(' decimalLiteral? ')')? + | NOW '(' decimalLiteral? ')' + ) + ; + +expressionOrDefault + : expression | DEFAULT + ; + +ifExists + : IF EXISTS + ; + + +ifNotExists + : IF NOT EXISTS + ; + +orReplace + : OR REPLACE + ; + +waitNowaitClause + : WAIT decimalLiteral + | NOWAIT + ; + +// Functions + +functionCall + : specificFunction #specificFunctionCall + | aggregateWindowedFunction #aggregateFunctionCall + | nonAggregateWindowedFunction #nonAggregateFunctionCall + | scalarFunctionName '(' functionArgs? ')' #scalarFunctionCall + | fullId '(' functionArgs? ')' #udfFunctionCall + | passwordFunctionClause #passwordFunctionCall + ; + +specificFunction + : ( + CURRENT_DATE | CURRENT_TIME | CURRENT_TIMESTAMP + | CURRENT_USER | LOCALTIME | UTC_TIMESTAMP | SCHEMA + ) ('(' ')')? #simpleFunctionCall + | CONVERT '(' expression separator=',' convertedDataType ')' #dataTypeFunctionCall + | CONVERT '(' expression USING charsetName ')' #dataTypeFunctionCall + | CAST '(' expression AS convertedDataType ')' #dataTypeFunctionCall + | VALUES '(' fullColumnName ')' #valuesFunctionCall + | CASE expression caseFuncAlternative+ + (ELSE elseArg=functionArg)? END #caseExpressionFunctionCall + | CASE caseFuncAlternative+ + (ELSE elseArg=functionArg)? END #caseFunctionCall + | CHAR '(' functionArgs (USING charsetName)? ')' #charFunctionCall + | POSITION + '(' + ( + positionString=stringLiteral + | positionExpression=expression + ) + IN + ( + inString=stringLiteral + | inExpression=expression + ) + ')' #positionFunctionCall + | (SUBSTR | SUBSTRING) + '(' + ( + sourceString=stringLiteral + | sourceExpression=expression + ) FROM + ( + fromDecimal=decimalLiteral + | fromExpression=expression + ) + ( + FOR + ( + forDecimal=decimalLiteral + | forExpression=expression + ) + )? + ')' #substrFunctionCall + | TRIM + '(' + positioinForm=(BOTH | LEADING | TRAILING) + ( + sourceString=stringLiteral + | sourceExpression=expression + )? + FROM + ( + fromString=stringLiteral + | fromExpression=expression + ) + ')' #trimFunctionCall + | TRIM + '(' + ( + sourceString=stringLiteral + | sourceExpression=expression + ) + FROM + ( + fromString=stringLiteral + | fromExpression=expression + ) + ')' #trimFunctionCall + | WEIGHT_STRING + '(' + (stringLiteral | expression) + (AS stringFormat=(CHAR | BINARY) + '(' decimalLiteral ')' )? levelsInWeightString? + ')' #weightFunctionCall + | EXTRACT + '(' + intervalType + FROM + ( + sourceString=stringLiteral + | sourceExpression=expression + ) + ')' #extractFunctionCall + | GET_FORMAT + '(' + datetimeFormat=(DATE | TIME | DATETIME) + ',' stringLiteral + ')' #getFormatFunctionCall + | JSON_VALUE + '(' expression + ',' expression + (RETURNING convertedDataType)? + jsonOnEmpty? + jsonOnError? + ')' #jsonValueFunctionCall + ; + +caseFuncAlternative + : WHEN condition=functionArg + THEN consequent=functionArg + ; + +levelsInWeightString + : LEVEL levelInWeightListElement + (',' levelInWeightListElement)* #levelWeightList + | LEVEL + firstLevel=decimalLiteral '-' lastLevel=decimalLiteral #levelWeightRange + ; + +levelInWeightListElement + : decimalLiteral orderType=(ASC | DESC | REVERSE)? + ; + +aggregateWindowedFunction + : (AVG | MAX | MIN | SUM) + '(' aggregator=(ALL | DISTINCT)? functionArg ')' overClause? + | COUNT '(' (starArg='*' | aggregator=ALL? functionArg | aggregator=DISTINCT functionArgs) ')' overClause? + | ( + BIT_AND | BIT_OR | BIT_XOR | STD | STDDEV | STDDEV_POP + | STDDEV_SAMP | VAR_POP | VAR_SAMP | VARIANCE + ) '(' aggregator=ALL? functionArg ')' overClause? + | GROUP_CONCAT '(' + aggregator=DISTINCT? functionArgs + (ORDER BY + orderByExpression (',' orderByExpression)* + )? (SEPARATOR separator=STRING_LITERAL)? + ')' + ; + +nonAggregateWindowedFunction + : (LAG | LEAD) '(' expression (',' decimalLiteral)? (',' decimalLiteral)? ')' overClause + | (FIRST_VALUE | LAST_VALUE) '(' expression ')' overClause + | (CUME_DIST | DENSE_RANK | PERCENT_RANK | RANK | ROW_NUMBER) '('')' overClause + | NTH_VALUE '(' expression ',' decimalLiteral ')' overClause + | NTILE '(' decimalLiteral ')' overClause + ; + +overClause + : OVER ('(' windowSpec ')' | windowName) + ; + +windowSpec + : windowName? partitionClause? orderByClause? frameClause? + ; + +windowName + : uid + ; + +frameClause + : frameUnits frameExtent + ; + +frameUnits + : ROWS + | RANGE + ; + +frameExtent + : frameRange + | frameBetween + ; + +frameBetween + : BETWEEN frameRange AND frameRange + ; + +frameRange + : CURRENT ROW + | UNBOUNDED (PRECEDING | FOLLOWING) + | expression (PRECEDING | FOLLOWING) + ; + +partitionClause + : PARTITION BY expression (',' expression)* + ; + +scalarFunctionName + : functionNameBase + | ASCII | CURDATE | CURRENT_DATE | CURRENT_TIME + | CURRENT_TIMESTAMP | CURTIME | DATE_ADD | DATE_SUB + | IF | INSERT | LOCALTIME | LOCALTIMESTAMP | MID | NOW + | REPLACE | SUBSTR | SUBSTRING | SYSDATE | TRIM + | UTC_DATE | UTC_TIME | UTC_TIMESTAMP + ; + +passwordFunctionClause + : functionName=(PASSWORD | OLD_PASSWORD) '(' functionArg ')' + ; + +functionArgs + : (constant | fullColumnName | functionCall | expression) + ( + ',' + (constant | fullColumnName | functionCall | expression) + )* + ; + +functionArg + : constant | fullColumnName | functionCall | expression + ; + + +// Expressions, predicates + +// Simplified approach for expression +expression + : notOperator=(NOT | '!') expression #notExpression + | expression logicalOperator expression #logicalExpression + | predicate IS NOT? testValue=(TRUE | FALSE | UNKNOWN) #isExpression + | predicate #predicateExpression + ; + +predicate + : predicate NOT? IN '(' (selectStatement | expressions) ')' #inPredicate + | predicate IS nullNotnull #isNullPredicate + | left=predicate comparisonOperator right=predicate #binaryComparisonPredicate + | predicate comparisonOperator + quantifier=(ALL | ANY | SOME) '(' selectStatement ')' #subqueryComparisonPredicate + | predicate NOT? BETWEEN predicate AND predicate #betweenPredicate + | predicate SOUNDS LIKE predicate #soundsLikePredicate + | predicate NOT? LIKE predicate (ESCAPE STRING_LITERAL)? #likePredicate + | predicate NOT? regex=(REGEXP | RLIKE) predicate #regexpPredicate + | (LOCAL_ID VAR_ASSIGN)? expressionAtom #expressionAtomPredicate + | predicate MEMBER OF '(' predicate ')' #jsonMemberOfPredicate + ; + + +// Add in ASTVisitor nullNotnull in constant +expressionAtom + : constant #constantExpressionAtom + | fullColumnName #fullColumnNameExpressionAtom + | functionCall #functionCallExpressionAtom + | expressionAtom COLLATE collationName #collateExpressionAtom + | mysqlVariable #mysqlVariableExpressionAtom + | unaryOperator expressionAtom #unaryExpressionAtom + | BINARY expressionAtom #binaryExpressionAtom + | '(' expression (',' expression)* ')' #nestedExpressionAtom + | ROW '(' expression (',' expression)+ ')' #nestedRowExpressionAtom + | EXISTS '(' selectStatement ')' #existsExpressionAtom + | '(' selectStatement ')' #subqueryExpressionAtom + | INTERVAL expression intervalType #intervalExpressionAtom + | left=expressionAtom bitOperator right=expressionAtom #bitExpressionAtom + | left=expressionAtom mathOperator right=expressionAtom #mathExpressionAtom + | left=expressionAtom jsonOperator right=expressionAtom #jsonExpressionAtom + ; + +unaryOperator + : '!' | '~' | '+' | '-' | NOT + ; + +comparisonOperator + : '=' | '>' | '<' | '<' '=' | '>' '=' + | '<' '>' | '!' '=' | '<' '=' '>' + ; + +logicalOperator + : AND | '&' '&' | XOR | OR | '|' '|' + ; + +bitOperator + : '<' '<' | '>' '>' | '&' | '^' | '|' + ; + +mathOperator + : '*' | '/' | '%' | DIV | MOD | '+' | '-' + ; + +jsonOperator + : '-' '>' | '-' '>' '>' + ; + +// Simple id sets +// (that keyword, which can be id) + +charsetNameBase + : ARMSCII8 | ASCII | BIG5 | BINARY | CP1250 | CP1251 | CP1256 | CP1257 + | CP850 | CP852 | CP866 | CP932 | DEC8 | EUCJPMS | EUCKR + | GB18030 | GB2312 | GBK | GEOSTD8 | GREEK | HEBREW | HP8 | KEYBCS2 + | KOI8R | KOI8U | LATIN1 | LATIN2 | LATIN5 | LATIN7 | MACCE + | MACROMAN | SJIS | SWE7 | TIS620 | UCS2 | UJIS | UTF16 + | UTF16LE | UTF32 | UTF8 | UTF8MB3 | UTF8MB4 + ; + +transactionLevelBase + : REPEATABLE | COMMITTED | UNCOMMITTED | SERIALIZABLE + ; + +privilegesBase + : TABLES | ROUTINE | EXECUTE | FILE | PROCESS + | RELOAD | SHUTDOWN | SUPER | PRIVILEGES + ; + +intervalTypeBase + : QUARTER | MONTH | DAY | HOUR + | MINUTE | WEEK | SECOND | MICROSECOND + ; + +dataTypeBase + : DATE | TIME | TIMESTAMP | DATETIME | YEAR | ENUM | TEXT + ; + +keywordsCanBeId + : ACCOUNT | ACTION | ADMIN | AFTER | AGGREGATE | ALGORITHM | ANY + | AT | AUDIT_ADMIN | AUDIT_ABORT_EXEMPT | AUTHORS | AUTOCOMMIT | AUTOEXTEND_SIZE + | AUTO_INCREMENT | AUTHENTICATION_POLICY_ADMIN | AVG | AVG_ROW_LENGTH | ATTRIBUTE + | BACKUP_ADMIN | BEGIN | BINLOG | BINLOG_ADMIN | BINLOG_ENCRYPTION_ADMIN | BIT | BIT_AND | BIT_OR | BIT_XOR + | BLOCK | BOOL | BOOLEAN | BTREE | BUCKETS | CACHE | CASCADED | CHAIN | CHANGED + | CHANNEL | CHECKSUM | PAGE_CHECKSUM | CATALOG_NAME | CIPHER + | CLASS_ORIGIN | CLIENT | CLONE_ADMIN | CLOSE | CLUSTERING | COALESCE | CODE + | COLUMNS | COLUMN_FORMAT | COLUMN_NAME | COMMENT | COMMIT | COMPACT + | COMPLETION | COMPRESSED | COMPRESSION | CONCURRENT | CONDITION | CONNECT + | CONNECTION | CONNECTION_ADMIN | CONSISTENT | CONSTRAINT_CATALOG | CONSTRAINT_NAME + | CONSTRAINT_SCHEMA | CONTAINS | CONTEXT + | CONTRIBUTORS | COPY | COUNT | CPU | CURRENT | CURRENT_USER | CURSOR_NAME + | DATA | DATAFILE | DEALLOCATE + | DEFAULT | DEFAULT_AUTH | DEFINER | DELAY_KEY_WRITE | DES_KEY_FILE | DIAGNOSTICS | DIRECTORY + | DISABLE | DISCARD | DISK | DO | DUMPFILE | DUPLICATE + | DYNAMIC | EMPTY | ENABLE | ENCRYPTION | ENCRYPTION_KEY_ADMIN | END | ENDS | ENGINE | ENGINE_ATTRIBUTE | ENGINES | ENFORCED + | ERROR | ERRORS | ESCAPE | EUR | EVEN | EVENT | EVENTS | EVERY | EXCEPT + | EXCHANGE | EXCLUSIVE | EXPIRE | EXPORT | EXTENDED | EXTENT_SIZE | FAILED_LOGIN_ATTEMPTS | FAST | FAULTS + | FIELDS | FILE_BLOCK_SIZE | FILTER | FIREWALL_ADMIN | FIREWALL_EXEMPT | FIREWALL_USER | FIRST | FIXED | FLUSH + | FOLLOWS | FOUND | FULL | FUNCTION | GENERAL | GLOBAL | GRANTS | GROUP | GROUP_CONCAT + | GROUP_REPLICATION | GROUP_REPLICATION_ADMIN | HANDLER | HASH | HELP | HISTORY | HOST | HOSTS | IDENTIFIED + | IGNORED | IGNORE_SERVER_IDS | IMPORT | INDEXES | INITIAL_SIZE | INNODB_REDO_LOG_ARCHIVE + | INPLACE | INSERT_METHOD | INSTALL | INSTANCE | INSTANT | INTERNAL | INVOKE | INVOKER | IO + | IO_THREAD | IPC | ISO | ISOLATION | ISSUER | JIS | JSON | KEY_BLOCK_SIZE + | LAMBDA | LANGUAGE | LAST | LATERAL | LEAVES | LESS | LEVEL | LIST | LOCAL + | LOGFILE | LOGS | MASTER | MASTER_AUTO_POSITION + | MASTER_CONNECT_RETRY | MASTER_DELAY + | MASTER_HEARTBEAT_PERIOD | MASTER_HOST | MASTER_LOG_FILE + | MASTER_LOG_POS | MASTER_PASSWORD | MASTER_PORT + | MASTER_RETRY_COUNT | MASTER_SSL | MASTER_SSL_CA + | MASTER_SSL_CAPATH | MASTER_SSL_CERT | MASTER_SSL_CIPHER + | MASTER_SSL_CRL | MASTER_SSL_CRLPATH | MASTER_SSL_KEY + | MASTER_TLS_VERSION | MASTER_USER + | MAX_CONNECTIONS_PER_HOUR | MAX_QUERIES_PER_HOUR + | MAX | MAX_ROWS | MAX_SIZE | MAX_UPDATES_PER_HOUR + | MAX_USER_CONNECTIONS | MEDIUM | MEMBER | MEMORY | MERGE | MESSAGE_TEXT + | MID | MIGRATE + | MIN | MIN_ROWS | MODE | MODIFY | MUTEX | MYSQL | MYSQL_ERRNO | NAME | NAMES + | NCHAR | NDB_STORED_USER | NESTED | NEVER | NEXT | NO | NOCOPY | NODEGROUP | NONE | NOWAIT | NUMBER | ODBC | OFFLINE | OFFSET + | OF | OJ | OLD_PASSWORD | ONE | ONLINE | ONLY | OPEN | OPTIMIZER_COSTS + | OPTIONAL | OPTIONS | ORDER | ORDINALITY | OWNER | PACK_KEYS | PAGE | PARSER | PARTIAL + | PARTITIONING | PARTITIONS | PASSWORD | PASSWORDLESS_USER_ADMIN | PASSWORD_LOCK_TIME | PATH | PERSIST_RO_VARIABLES_ADMIN | PHASE | PLUGINS + | PLUGIN_DIR | PLUGIN | PORT | PRECEDES | PREPARE | PRESERVE | PREV | PRIMARY + | PROCESSLIST | PROFILE | PROFILES | PROXY | QUERY | QUICK + | REBUILD | RECOVER | RECURSIVE | REDO_BUFFER_SIZE | REDUNDANT + | RELAY | RELAYLOG | RELAY_LOG_FILE | RELAY_LOG_POS | REMOVE + | REORGANIZE | REPAIR | REPLICATE_DO_DB | REPLICATE_DO_TABLE + | REPLICATE_IGNORE_DB | REPLICATE_IGNORE_TABLE + | REPLICATE_REWRITE_DB | REPLICATE_WILD_DO_TABLE + | REPLICATE_WILD_IGNORE_TABLE | REPLICATION | REPLICATION_APPLIER | REPLICATION_SLAVE_ADMIN | RESET + | RESOURCE_GROUP_ADMIN | RESOURCE_GROUP_USER | RESUME + | RETURNED_SQLSTATE | RETURNS | REUSE | ROLE | ROLE_ADMIN | ROLLBACK | ROLLUP | ROTATE | ROW | ROWS + | ROW_FORMAT | RTREE | S3 | SAVEPOINT | SCHEDULE | SCHEMA_NAME | SECURITY | SECONDARY_ENGINE_ATTRIBUTE | SERIAL | SERVER + | SESSION | SESSION_VARIABLES_ADMIN | SET_USER_ID | SHARE | SHARED | SHOW_ROUTINE | SIGNED | SIMPLE | SLAVE + | SLOW | SKIP_QUERY_REWRITE | SNAPSHOT | SOCKET | SOME | SONAME | SOUNDS | SOURCE + | SQL_AFTER_GTIDS | SQL_AFTER_MTS_GAPS | SQL_BEFORE_GTIDS + | SQL_BUFFER_RESULT | SQL_CACHE | SQL_NO_CACHE | SQL_THREAD + | STACKED | START | STARTS | STATS_AUTO_RECALC | STATS_PERSISTENT + | STATS_SAMPLE_PAGES | STATUS | STD | STDDEV | STDDEV_POP | STDDEV_SAMP | STOP | STORAGE | STRING + | SUBCLASS_ORIGIN | SUBJECT | SUBPARTITION | SUBPARTITIONS | SUM | SUSPEND | SWAPS + | SWITCHES | SYSTEM_VARIABLES_ADMIN | TABLE_NAME | TABLESPACE | TABLE_ENCRYPTION_ADMIN | TABLE_TYPE + | TEMPORARY | TEMPTABLE | THAN | TP_CONNECTION_ADMIN | TRADITIONAL + | TRANSACTION | TRANSACTIONAL | TRIGGERS | TRUNCATE | UNBOUNDED | UNDEFINED | UNDOFILE + | UNDO_BUFFER_SIZE | UNINSTALL | UNKNOWN | UNTIL | UPGRADE | USA | USER | USE_FRM | USER_RESOURCES + | VALIDATION | VALUE | VAR_POP | VAR_SAMP | VARIABLES | VARIANCE | VERSION_TOKEN_ADMIN | VIEW | VIRTUAL + | WAIT | WARNINGS | WITHOUT | WORK | WRAPPER | X509 | XA | XA_RECOVER_ADMIN | XML + ; + +functionNameBase + : ABS | ACOS | ADDDATE | ADDTIME | AES_DECRYPT | AES_ENCRYPT + | AREA | ASBINARY | ASIN | ASTEXT | ASWKB | ASWKT + | ASYMMETRIC_DECRYPT | ASYMMETRIC_DERIVE + | ASYMMETRIC_ENCRYPT | ASYMMETRIC_SIGN | ASYMMETRIC_VERIFY + | ATAN | ATAN2 | BENCHMARK | BIN | BIT_COUNT | BIT_LENGTH + | BUFFER | CEIL | CEILING | CENTROID | CHARACTER_LENGTH + | CHARSET | CHAR_LENGTH | COERCIBILITY | COLLATION + | COMPRESS | CONCAT | CONCAT_WS | CONNECTION_ID | CONV + | CONVERT_TZ | COS | COT | COUNT | CRC32 + | CREATE_ASYMMETRIC_PRIV_KEY | CREATE_ASYMMETRIC_PUB_KEY + | CREATE_DH_PARAMETERS | CREATE_DIGEST | CROSSES | CUME_DIST | DATABASE | DATE + | DATEDIFF | DATE_FORMAT | DAY | DAYNAME | DAYOFMONTH + | DAYOFWEEK | DAYOFYEAR | DECODE | DEGREES | DENSE_RANK | DES_DECRYPT + | DES_ENCRYPT | DIMENSION | DISJOINT | ELT | ENCODE + | ENCRYPT | ENDPOINT | ENVELOPE | EQUALS | EXP | EXPORT_SET + | EXTERIORRING | EXTRACTVALUE | FIELD | FIND_IN_SET | FIRST_VALUE | FLOOR + | FORMAT | FOUND_ROWS | FROM_BASE64 | FROM_DAYS + | FROM_UNIXTIME | GEOMCOLLFROMTEXT | GEOMCOLLFROMWKB + | GEOMETRYCOLLECTION | GEOMETRYCOLLECTIONFROMTEXT + | GEOMETRYCOLLECTIONFROMWKB | GEOMETRYFROMTEXT + | GEOMETRYFROMWKB | GEOMETRYN | GEOMETRYTYPE | GEOMFROMTEXT + | GEOMFROMWKB | GET_FORMAT | GET_LOCK | GLENGTH | GREATEST + | GTID_SUBSET | GTID_SUBTRACT | HEX | HOUR | IFNULL + | INET6_ATON | INET6_NTOA | INET_ATON | INET_NTOA | INSTR + | INTERIORRINGN | INTERSECTS | INVISIBLE + | ISCLOSED | ISEMPTY | ISNULL + | ISSIMPLE | IS_FREE_LOCK | IS_IPV4 | IS_IPV4_COMPAT + | IS_IPV4_MAPPED | IS_IPV6 | IS_USED_LOCK | LAG | LAST_INSERT_ID | LAST_VALUE + | LCASE | LEAD | LEAST | LEFT | LENGTH | LINEFROMTEXT | LINEFROMWKB + | LINESTRING | LINESTRINGFROMTEXT | LINESTRINGFROMWKB | LN + | LOAD_FILE | LOCATE | LOG | LOG10 | LOG2 | LOWER | LPAD + | LTRIM | MAKEDATE | MAKETIME | MAKE_SET | MASTER_POS_WAIT + | MBRCONTAINS | MBRDISJOINT | MBREQUAL | MBRINTERSECTS + | MBROVERLAPS | MBRTOUCHES | MBRWITHIN | MD5 | MICROSECOND + | MINUTE | MLINEFROMTEXT | MLINEFROMWKB | MOD| MONTH | MONTHNAME + | MPOINTFROMTEXT | MPOINTFROMWKB | MPOLYFROMTEXT + | MPOLYFROMWKB | MULTILINESTRING | MULTILINESTRINGFROMTEXT + | MULTILINESTRINGFROMWKB | MULTIPOINT | MULTIPOINTFROMTEXT + | MULTIPOINTFROMWKB | MULTIPOLYGON | MULTIPOLYGONFROMTEXT + | MULTIPOLYGONFROMWKB | NAME_CONST | NTH_VALUE | NTILE | NULLIF | NUMGEOMETRIES + | NUMINTERIORRINGS | NUMPOINTS | OCT | OCTET_LENGTH | ORD + | OVERLAPS | PERCENT_RANK | PERIOD_ADD | PERIOD_DIFF | PI | POINT + | POINTFROMTEXT | POINTFROMWKB | POINTN | POLYFROMTEXT + | POLYFROMWKB | POLYGON | POLYGONFROMTEXT | POLYGONFROMWKB + | POSITION | POW | POWER | QUARTER | QUOTE | RADIANS | RAND | RANK + | RANDOM_BYTES | RELEASE_LOCK | REVERSE | RIGHT | ROUND + | ROW_COUNT | ROW_NUMBER | RPAD | RTRIM | SCHEMA | SECOND | SEC_TO_TIME + | SESSION_USER | SESSION_VARIABLES_ADMIN + | SHA | SHA1 | SHA2 | SIGN | SIN | SLEEP + | SOUNDEX | SQL_THREAD_WAIT_AFTER_GTIDS | SQRT | SRID + | STARTPOINT | STRCMP | STR_TO_DATE | ST_AREA | ST_ASBINARY + | ST_ASTEXT | ST_ASWKB | ST_ASWKT | ST_BUFFER | ST_CENTROID + | ST_CONTAINS | ST_CROSSES | ST_DIFFERENCE | ST_DIMENSION + | ST_DISJOINT | ST_DISTANCE | ST_ENDPOINT | ST_ENVELOPE + | ST_EQUALS | ST_EXTERIORRING | ST_GEOMCOLLFROMTEXT + | ST_GEOMCOLLFROMTXT | ST_GEOMCOLLFROMWKB + | ST_GEOMETRYCOLLECTIONFROMTEXT + | ST_GEOMETRYCOLLECTIONFROMWKB | ST_GEOMETRYFROMTEXT + | ST_GEOMETRYFROMWKB | ST_GEOMETRYN | ST_GEOMETRYTYPE + | ST_GEOMFROMTEXT | ST_GEOMFROMWKB | ST_INTERIORRINGN + | ST_INTERSECTION | ST_INTERSECTS | ST_ISCLOSED | ST_ISEMPTY + | ST_ISSIMPLE | ST_LINEFROMTEXT | ST_LINEFROMWKB + | ST_LINESTRINGFROMTEXT | ST_LINESTRINGFROMWKB + | ST_NUMGEOMETRIES | ST_NUMINTERIORRING + | ST_NUMINTERIORRINGS | ST_NUMPOINTS | ST_OVERLAPS + | ST_POINTFROMTEXT | ST_POINTFROMWKB | ST_POINTN + | ST_POLYFROMTEXT | ST_POLYFROMWKB | ST_POLYGONFROMTEXT + | ST_POLYGONFROMWKB | ST_SRID | ST_STARTPOINT + | ST_SYMDIFFERENCE | ST_TOUCHES | ST_UNION | ST_WITHIN + | ST_X | ST_Y | SUBDATE | SUBSTRING_INDEX | SUBTIME + | SYSTEM_USER | TAN | TIME | TIMEDIFF | TIMESTAMP + | TIMESTAMPADD | TIMESTAMPDIFF | TIME_FORMAT | TIME_TO_SEC + | TOUCHES | TO_BASE64 | TO_DAYS | TO_SECONDS | UCASE + | UNCOMPRESS | UNCOMPRESSED_LENGTH | UNHEX | UNIX_TIMESTAMP + | UPDATEXML | UPPER | UUID | UUID_SHORT + | VALIDATE_PASSWORD_STRENGTH | VERSION | VISIBLE + | WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS | WEEK | WEEKDAY + | WEEKOFYEAR | WEIGHT_STRING | WITHIN | YEAR | YEARWEEK + | Y_FUNCTION | X_FUNCTION + | JSON_ARRAY | JSON_OBJECT | JSON_QUOTE | JSON_CONTAINS | JSON_CONTAINS_PATH + | JSON_EXTRACT | JSON_KEYS | JSON_OVERLAPS | JSON_SEARCH | JSON_VALUE + | JSON_ARRAY_APPEND | JSON_ARRAY_INSERT | JSON_INSERT | JSON_MERGE + | JSON_MERGE_PATCH | JSON_MERGE_PRESERVE | JSON_REMOVE | JSON_REPLACE + | JSON_SET | JSON_UNQUOTE | JSON_DEPTH | JSON_LENGTH | JSON_TYPE + | JSON_VALID | JSON_TABLE | JSON_SCHEMA_VALID | JSON_SCHEMA_VALIDATION_REPORT + | JSON_PRETTY | JSON_STORAGE_FREE | JSON_STORAGE_SIZE | JSON_ARRAYAGG + | JSON_OBJECTAGG + ; diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/AbstractPartition.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/AbstractPartition.java new file mode 100644 index 0000000000..4ddbf28be4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/AbstractPartition.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +public abstract class AbstractPartition implements Partition { + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/CatalogChanges.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/CatalogChanges.java new file mode 100644 index 0000000000..c835862eda --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/CatalogChanges.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.table.catalog.CatalogSchema; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.Table; + +import java.util.List; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents changes in a catalog, such as schema or table modifications. + */ +@Data +@NoArgsConstructor +public class CatalogChanges { + + /** + * The type of change (e.g., "T(Table)" or "D(Database)"). + * + * {@link SchemaChangeEventType} + * + */ + private String type; + + /** + * The specific operation type (e.g., "C(Create)", "D(Drop)", "A(Alert)"). + * + * {@link SchemaChangeEventType} + * + */ + private String operationType; + // The catalog schema associated with the changes + private CatalogSchema catalog; + // The table associated with the changes + private Table table; + // The list of columns affected by the changes + private List> columns; + + private CatalogChanges(String type, String operationType, CatalogSchema catalog, Table table, + List> columns) { + this.type = type; + this.operationType = operationType; + this.catalog = catalog; + this.table = table; + this.columns = columns; + } + + /** + * Creates a new instance of the Builder for constructing CatalogChanges. + * + * @return The Builder instance. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Builder class for constructing CatalogChanges. + */ + public static class Builder { + + private String type; + private String operationType; + private CatalogSchema catalog; + private Table table; + private List> columns; + + /** + * Sets the operation type for the change. + * + * @param changeEventType The SchemaChangeEventType representing the change. + * @return The Builder instance. + */ + public Builder operationType(SchemaChangeEventType changeEventType) { + this.type = changeEventType.ofType(); + this.operationType = changeEventType.ofOperationType(); + return this; + } + + /** + * Sets the catalog schema associated with the changes. + * + * @param catalog The CatalogSchema instance. + * @return The Builder instance. + */ + public Builder catalog(CatalogSchema catalog) { + this.catalog = catalog; + return this; + } + + /** + * Sets the table associated with the changes. + * + * @param table The Table instance. + * @return The Builder instance. + */ + public Builder table(Table table) { + this.table = table; + return this; + } + + /** + * Sets the list of columns affected by the changes. + * + * @param columns The list of Column instances. + * @return The Builder instance. + */ + public Builder columns(List> columns) { + this.columns = columns; + return this; + } + + /** + * Builds a new CatalogChanges instance. + * + * @return The constructed CatalogChanges instance. + */ + public CatalogChanges build() { + return new CatalogChanges(type, operationType, catalog, table, columns); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/DataChanges.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/DataChanges.java new file mode 100644 index 0000000000..a23e521cf2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/DataChanges.java @@ -0,0 +1,126 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +/** + * DataChanges class representing changes in data associated with a JDBC connection. + */ +public class DataChanges { + + private Object after; + + private Object before; + + /** + * The type of change. + * + * {@link org.apache.eventmesh.connector.jdbc.event.DataChangeEventType} + * + */ + private String type; + + /** + * Constructs a DataChanges instance with 'after' and 'before' data. + * + * @param after The data after the change. + * @param before The data before the change. + */ + public DataChanges(Object after, Object before) { + this.after = after; + this.before = before; + } + + /** + * Constructs a DataChanges instance with 'after', 'before' data, and a change type. + * + * @param after The data after the change. + * @param before The data before the change. + * @param type The type of change. + */ + public DataChanges(Object after, Object before, String type) { + this.after = after; + this.before = before; + this.type = type; + } + + /** + * Creates a new DataChanges builder. + * + * @return The DataChanges builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Builder class for constructing DataChanges instances. + */ + public static class Builder { + + private String type; + private Object after; + private Object before; + + /** + * Sets the change type in the builder. + * + * @param type The type of change. + * @return The DataChanges builder. + */ + public Builder withType(String type) { + this.type = type; + return this; + } + + /** + * Sets the 'after' data in the builder. + * + * @param after The data after the change. + * @return The DataChanges builder. + */ + public Builder withAfter(Object after) { + this.after = after; + return this; + } + + /** + * Sets the 'before' data in the builder. + * + * @param before The data before the change. + * @return The DataChanges builder. + */ + public Builder withBefore(Object before) { + this.before = before; + return this; + } + + /** + * Builds the DataChanges instance. + * + * @return The constructed DataChanges. + */ + public DataChanges build() { + return new DataChanges(after, before, type); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/DataTypeConvertor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/DataTypeConvertor.java new file mode 100644 index 0000000000..61b1e2749a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/DataTypeConvertor.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import org.apache.eventmesh.connector.jdbc.exception.DataTypeConvertException; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.sql.JDBCType; +import java.util.Map; + +/** + * convert data types between EventMesh and connector. + */ +public interface DataTypeConvertor { + + /** + * Converts a string representation of a connector data type to the corresponding JDBCType. + * + * @param connectorDataType The string representation of the connector data type. + * @return The corresponding JDBCType, or null if the connector data type is not recognized. + */ + JDBCType toJDBCType(String connectorDataType); + + /** + * Converts a connector data type to an EventMesh data type. + * + * @param connectorDataType The connector data type to be converted. + * @return The converted EventMesh data type. + * @throws DataTypeConvertException If the conversion fails. + */ + EventMeshDataType toEventMeshType(String connectorDataType) throws DataTypeConvertException; + + /** + * Converts JDBCType and dataTypeProperties to EventMeshDataType. + * + * @param jdbcType the JDBCType to be converted + * @param dataTypeProperties the properties of the data type + * @return the converted EventMeshDataType + * @throws DataTypeConvertException if there is an error during conversion + */ + EventMeshDataType toEventMeshType(JDBCType jdbcType, Map dataTypeProperties) throws DataTypeConvertException; + + /** + * Converts a connector data type to an EventMesh data type with additional data type properties. + * + * @param connectorDataType The connector data type to be converted. + * @param dataTypeProperties Additional data type properties. + * @return The converted EventMesh data type. + * @throws DataTypeConvertException If the conversion fails. + */ + EventMeshDataType toEventMeshType(T connectorDataType, Map dataTypeProperties) throws DataTypeConvertException; + + /** + * Converts an EventMesh data type to a connector data type with additional data type properties. + * + * @param eventMeshDataType The EventMesh data type to be converted. + * @param dataTypeProperties Additional data type properties. + * @return The converted connector data type. + * @throws DataTypeConvertException If the conversion fails. + */ + T toConnectorType(EventMeshDataType eventMeshDataType, Map dataTypeProperties) throws DataTypeConvertException; +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Field.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Field.java new file mode 100644 index 0000000000..bdbf7aa686 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Field.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Field { + + private boolean required; + + private String field; + + private String name; + + private Column column; + + private List fields; + + public Field(Column column, boolean required, String field, String name) { + this.column = column; + this.required = required; + this.field = field; + this.name = name; + } + + public Field withColumn(Column column) { + this.column = column; + return this; + } + + public Field withRequired(boolean required) { + this.required = required; + return this; + } + + public Field withField(String field) { + this.field = field; + return this; + } + + public Field withName(String name) { + this.name = name; + return this; + } + + public Field withFields(List fields) { + this.fields = fields; + return this; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcConnectData.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcConnectData.java new file mode 100644 index 0000000000..df749947e7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcConnectData.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +/** + * Represents data associated with a JDBC connector. + */ +public final class JdbcConnectData { + + /** + * Constant representing data changes in the JDBC connector. + */ + public static final byte DATA_CHANGES = 1; + + /** + * Constant representing schema changes in the JDBC connector. + */ + public static final byte SCHEMA_CHANGES = 1 << 1; + + private Payload payload = new Payload(); + + private Schema schema; + + private byte type = 0; + + public JdbcConnectData() { + } + + public JdbcConnectData(byte type) { + this.type = type; + } + + public Payload getPayload() { + return payload; + } + + public void setPayload(Payload payload) { + this.payload = payload; + } + + public Schema getSchema() { + return schema; + } + + public void setSchema(Schema schema) { + this.schema = schema; + } + + public byte getType() { + return type; + } + + public void setType(byte type) { + this.type = type; + } + + public void markDataChanges() { + this.type |= DATA_CHANGES; + } + + public void markSchemaChanges() { + this.type |= SCHEMA_CHANGES; + } + + public boolean isDataChanges() { + return (this.type & DATA_CHANGES) != 0; + } + + public boolean isSchemaChanges() { + return (this.type & SCHEMA_CHANGES) != 0; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcContext.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcContext.java new file mode 100644 index 0000000000..1c6eeb58b8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcContext.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +/** + * Interface representing a JDBC context. + */ +public interface JdbcContext { + + Part getPartition(); + + OffSetCtx getOffsetContext(); + + TableId ofCurrentTableId(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcDriverMetaData.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcDriverMetaData.java new file mode 100644 index 0000000000..fdc1e0fcde --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/JdbcDriverMetaData.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.ToString; + +/** + * Represents metadata information about a JDBC driver + */ +@Data +@AllArgsConstructor +@ToString +public class JdbcDriverMetaData { + + // The major version number of the JDBC driver + private final int jdbcMajorVersion; + + // The minor version number of the JDBC driver + private final int jdbcMinorVersion; + + // The name of the JDBC driver + private final String jdbcDriverName; + + // The name of the database product + private final String databaseProductName; + + // The version of the database product + private final String databaseProductVersion; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/OffsetContext.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/OffsetContext.java new file mode 100644 index 0000000000..a74af0259c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/OffsetContext.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import java.util.Map; + +/** + * The OffsetContext interface represents the offset context for event processing. It provides methods to retrieve the offset map and check if a + * snapshot is currently running. + */ +public interface OffsetContext { + + /** + * Retrieves the offset map associated with the context. + * + * @return The offset map. + */ + Map getOffset(); + + /** + * Checks if a snapshot is currently running. + * + * @return True if a snapshot is running, false otherwise. + */ + boolean isSnapshotRunning(); + + boolean isSnapshotCompleted(); + + void markSnapshotRunning(); + + void markSnapshotCompleted(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Partition.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Partition.java new file mode 100644 index 0000000000..e1394a4f7c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Partition.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import java.util.Map; + +/** + * This interface represents a partition. + */ +public interface Partition { + + /** + *

Returns a map representing the partition.The keys of the map represent the partition keys, and the values represent the corresponding + * partition values.

+ * + * @return a map representing the partition + */ + Map getPartition(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/PartitionOffSetContextPair.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/PartitionOffSetContextPair.java new file mode 100644 index 0000000000..30ec03d111 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/PartitionOffSetContextPair.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +public final class PartitionOffSetContextPair { + + private Part partition; + + private Offset offsetContext; + + private PartitionOffSetContextPair(Part partition, Offset offsetContext) { + this.partition = partition; + this.offsetContext = offsetContext; + } + + public static PartitionOffSetContextPair of(Part partition, Offset offset) { + return new PartitionOffSetContextPair<>(partition, offset); + } + + public Part getPartition() { + return partition; + } + + public Offset getOffsetContext() { + return offsetContext; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Payload.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Payload.java new file mode 100644 index 0000000000..f861445aa3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Payload.java @@ -0,0 +1,201 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; + +import lombok.Getter; +import lombok.Setter; + +/** + * Payload class representing the data associated with a JDBC connection. + */ +public final class Payload { + + /** + * Field name for the 'after' payload. + */ + public static final String AFTER_FIELD = "after"; + + /** + * Field name for the 'before' payload. + */ + public static final String BEFORE_FIELD = "before"; + + /** + * Field name for the 'source' payload. + */ + public static final String SOURCE = "source"; + + /** + * Field name for the 'payload.before' payload. + */ + public static final String PAYLOAD_BEFORE = "payload.before"; + + /** + * Field name for the 'payload.after' payload. + */ + public static final String PAYLOAD_AFTER = "payload.after"; + + @Getter + @Setter + private SourceMateData source; + + // Source connector's original DDL script + @Getter + @Setter + private String ddl; + + @Getter + @Setter + private CatalogChanges catalogChanges; + + @Getter + @Setter + private DataChanges dataChanges; + + @Getter + @Setter + private long timestamp; + + /** + * Constructs an empty Payload with the default initial capacity (16) and the default load factor (0.75). + */ + public Payload() { + this.timestamp = System.currentTimeMillis(); + } + + /** + * Sets the 'source' field in the payload. + * + * @param source The SourceMateData to set. + * @return The Payload instance. + */ + public Payload withSource(S source) { + this.source = source; + return this; + } + + /** + * Sets the 'ddl' field in the payload. + * + * @param ddl The DDL string to set. + * @return The Payload instance. + */ + public Payload withDdl(String ddl) { + this.ddl = ddl; + return this; + } + + /** + * Sets the 'catalogChanges' field in the payload. + * + * @param catalogChanges The CatalogChanges to set. + * @return The Payload instance. + */ + public Payload withCatalogChanges(CatalogChanges catalogChanges) { + this.catalogChanges = catalogChanges; + return this; + } + + /** + * Sets the 'dataChanges' field in the payload. + * + * @param dataChanges The DataChanges to set. + * @return The Payload instance. + */ + public Payload withDataChanges(DataChanges dataChanges) { + this.dataChanges = dataChanges; + return this; + } + + /** + * Retrieves the 'source' field from the payload. + * + * @return The SourceMateData. + */ + public SourceMateData ofSourceMateData() { + return getSource(); + } + + /** + * Retrieves the 'catalogChanges' field from the payload. + * + * @return The CatalogChanges. + */ + public CatalogChanges ofCatalogChanges() { + return getCatalogChanges(); + } + + /** + * Retrieves the 'dataChanges' field from the payload. + * + * @return The DataChanges. + */ + public DataChanges ofDataChanges() { + return getDataChanges(); + } + + /** + * Retrieves the 'ddl' field from the payload. + * + * @return The DDL string. + */ + public String ofDdl() { + return getDdl(); + } + + /** + * Builder class for constructing Payload instances. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for constructing Payload instances. + */ + public static class Builder { + + private final Payload payload; + + private Builder() { + payload = new Payload(); + } + + /** + * Sets the 'source' field in the payload. + * + * @param source The SourceMateData to set. + * @return The Builder instance. + */ + public Builder withSource(SourceMateData source) { + payload.withSource(source); + return this; + } + + /** + * Builds the Payload instance. + * + * @return The constructed Payload. + */ + public Payload build() { + return payload; + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Schema.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Schema.java new file mode 100644 index 0000000000..75674bd798 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/Schema.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import lombok.Data; + +@Data +public class Schema { + + // contains primary key and unique key + private Set keySet; + + private List fields; + + public Schema(List fields) { + this.fields = fields; + } + + public Schema() { + this.fields = new ArrayList<>(); + } + + public void add(Field field) { + this.fields.add(field); + } + + public void addKey(String key) { + if (keySet == null) { + keySet = new HashSet<>(); + } + this.keySet.add(key); + } + + public void addKeys(Collection keys) { + if (keySet == null) { + keySet = new HashSet<>(); + } + this.keySet.addAll(keys); + } + + public boolean containsKey() { + return keySet != null && !keySet.isEmpty(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/UniversalJdbcContext.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/UniversalJdbcContext.java new file mode 100644 index 0000000000..e0f656da23 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/UniversalJdbcContext.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +import org.apache.eventmesh.connector.jdbc.ddl.DdlParser; +import org.apache.eventmesh.connector.jdbc.table.catalog.CatalogTableSet; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public abstract class UniversalJdbcContext implements + JdbcContext { + + private PartitionOffSetContextPair poCtx; + + private Parser parser; + + private CatalogTableSet tableSet = new CatalogTableSet(); + + private volatile TableId tableId; + + public UniversalJdbcContext(PartitionOffSetContextPair poCtx, Parser parser) { + this.poCtx = poCtx; + this.parser = parser; + } + + public UniversalJdbcContext(Part part, OffSetCtx offSetCtx, Parser parser) { + this.poCtx = PartitionOffSetContextPair.of(part, offSetCtx); + this.parser = parser; + } + + @Override + public Part getPartition() { + return poCtx.getPartition(); + } + + @Override + public OffSetCtx getOffsetContext() { + return poCtx.getOffsetContext(); + } + + @Override + public TableId ofCurrentTableId() { + return tableId; + } + + public Parser getParser() { + return parser; + } + + public CatalogTableSet getCatalogTableSet() { + return this.tableSet; + } + + public void withTableId(TableId tableId) { + this.tableId = tableId; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/UniversalOffsetContext.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/UniversalOffsetContext.java new file mode 100644 index 0000000000..baa7ba3554 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/UniversalOffsetContext.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc; + +public abstract class UniversalOffsetContext implements OffsetContext { + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/Antlr4DdlParser.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/Antlr4DdlParser.java new file mode 100644 index 0000000000..61e79eede2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/Antlr4DdlParser.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.antlr4; + +import org.apache.eventmesh.connector.jdbc.antlr4.listener.Antlr4DdlParserListener; +import org.apache.eventmesh.connector.jdbc.ddl.AbstractDdlParser; +import org.apache.eventmesh.connector.jdbc.ddl.DdlParserCallback; +import org.apache.eventmesh.connector.jdbc.table.catalog.CatalogTableSet; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CodePointCharStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeWalker; + +public abstract class Antlr4DdlParser extends AbstractDdlParser { + + private Antlr4DdlParserListener antlr4DdlParserListener; + + private CatalogTableSet tableSet; + + public Antlr4DdlParser(boolean skipViews, boolean skipComments) { + super(skipViews, skipComments); + } + + /** + * Parses the given DDL SQL statement. + * + * @param ddlSql the DDL SQL statement to be parsed + */ + @Override + public void parse(String ddlSql, DdlParserCallback callback) { + CodePointCharStream ddlSqlStream = CharStreams.fromString(ddlSql); + L lexer = buildLexerInstance(ddlSqlStream); + P parser = buildParserInstance(new CommonTokenStream(lexer)); + ParseTree parseTree = parseTree(parser); + antlr4DdlParserListener = createParseTreeWalkerListener(callback); + ParseTreeWalker.DEFAULT.walk(antlr4DdlParserListener, parseTree); + } + + protected abstract L buildLexerInstance(CharStream charStreams); + + protected abstract P buildParserInstance(CommonTokenStream commonTokenStream); + + protected abstract ParseTree parseTree(P parser); + + protected abstract Antlr4DdlParserListener createParseTreeWalkerListener(DdlParserCallback callback); + + public void setCatalogTableSet(CatalogTableSet tableSet) { + this.tableSet = tableSet; + } + + public CatalogTableSet getCatalogTableSet() { + return this.tableSet; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/listener/Antlr4DdlParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/listener/Antlr4DdlParserListener.java new file mode 100644 index 0000000000..d4128324f8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/antlr4/listener/Antlr4DdlParserListener.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.antlr4.listener; + +import org.antlr.v4.runtime.tree.ParseTreeListener; + +/** + * An interface to extend the Antlr4 {@link ParseTreeListener} for DDL parsing events. + */ +public interface Antlr4DdlParserListener extends ParseTreeListener { + + // You can add any specific methods related to DDL parsing events here, + // if necessary. + +} + diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/common/EnumeratedValue.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/common/EnumeratedValue.java new file mode 100644 index 0000000000..484b6a2910 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/common/EnumeratedValue.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.common; + +/** + * An interface representing an enumerated value. + * + * @param The type of the enumerated value. + */ +public interface EnumeratedValue { + + /** + * Gets the value of the enumerated item. + * + * @return The value of the enumerated item. + */ + T getValue(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/common/SourceInfo.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/common/SourceInfo.java new file mode 100644 index 0000000000..0bbe0354b9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/common/SourceInfo.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.common; + +/** + * Interface representing source information. + */ +public interface SourceInfo { + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/config/JdbcServerConfig.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/config/JdbcServerConfig.java new file mode 100644 index 0000000000..2b3e614774 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/config/JdbcServerConfig.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.config; + + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * configuration for the JDBC server. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class JdbcServerConfig extends Config { + + // Indicates whether the source is enabled or not + private boolean sourceEnable; + + // Indicates whether the sink is enabled or not + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/JdbcConnection.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/JdbcConnection.java new file mode 100644 index 0000000000..70d553517f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/JdbcConnection.java @@ -0,0 +1,569 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.connection; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.connector.jdbc.JdbcDriverMetaData; + +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.annotation.concurrent.ThreadSafe; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * JdbcConnection class representing a JDBC connection. + * Implements the AutoCloseable interface. + */ +@Slf4j +public class JdbcConnection implements AutoCloseable { + + private static final int CONNECTION_VALID_CHECK_TIMEOUT_IN_SEC = 3; + + private static final String STATEMENT_DELIMITER = ";"; + + @Getter + private final JdbcConfig jdbcConfig; + + private volatile Connection connection; + + private final InitialOperation initialOperation; + + private final ConnectionFactory connectionFactory; + + private JdbcDriverMetaData jdbcDriverMetaData; + + private boolean lazyConnection = true; + + public JdbcConnection(JdbcConfig jdbcConfig, InitialOperation initialOperation, ConnectionFactory connectionFactory) { + this(jdbcConfig, initialOperation, connectionFactory, true); + } + + public JdbcConnection(JdbcConfig jdbcConfig, InitialOperation initialOperation, ConnectionFactory connectionFactory, boolean lazyConnection) { + this.jdbcConfig = jdbcConfig; + this.initialOperation = initialOperation; + this.connectionFactory = connectionFactory; + this.lazyConnection = lazyConnection; + if (!this.lazyConnection) { + try { + connection(); + } catch (SQLException e) { + log.warn("Get Connection error", e); + throw new RuntimeException(e); + } + } + } + + /** + * Closes the JDBC connection. + * + * @throws Exception if an error occurs while closing the connection. + */ + @Override + public void close() throws Exception { + if (connection != null) { + connection.close(); + } + } + + /** + * Sets the auto-commit mode for the connection. + * + * @param autoCommit The auto-commit mode. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection setAutoCommit(boolean autoCommit) throws SQLException { + connection().setAutoCommit(autoCommit); + return this; + } + + /** + * Retrieves the JDBC connection. Creates a new connection if not already connected. + * + * @return The JDBC connection. + * @throws SQLException if a database access error occurs. + */ + public synchronized Connection connection() throws SQLException { + return connection(true); + } + + /** + * Retrieves the JDBC connection. Creates a new connection if not already connected. + * + * @param executeOnConnect Flag indicating whether to execute initial statements on connect. + * @return The JDBC connection. + * @throws SQLException if a database access error occurs. + */ + public synchronized Connection connection(boolean executeOnConnect) throws SQLException { + if (!isConnected()) { + connection = connectionFactory.connect(jdbcConfig); + if (!isConnected()) { + throw new SQLException("Unable to obtain a JDBC connection"); + } + + if (initialOperation != null) { + execute(initialOperation); + } + final String statements = jdbcConfig.getInitialStatements(); + if (StringUtils.isNotBlank(statements) && executeOnConnect) { + String[] split = statements.split(STATEMENT_DELIMITER); + execute(split); + } + jdbcDriverMetaData = createJdbcDriverInfo(); + } + return connection; + } + + /** + * Creates the JDBC driver metadata by retrieving information from the provided connection's database metadata. + * + * @return The JDBC driver metadata. + * @throws SQLException if a database access error occurs. + */ + private JdbcDriverMetaData createJdbcDriverInfo() throws SQLException { + DatabaseMetaData metadata = connection.getMetaData(); + + // Retrieve the JDBC driver information from the database metadata + int majorVersion = metadata.getJDBCMajorVersion(); + int minorVersion = metadata.getJDBCMinorVersion(); + String driverName = metadata.getDriverName(); + String productName = metadata.getDatabaseProductName(); + String productVersion = metadata.getDatabaseProductVersion(); + + // Create and return the JdbcDriverMetaData instance + return new JdbcDriverMetaData(majorVersion, minorVersion, driverName, productName, productVersion); + } + + public JdbcDriverMetaData getJdbcDriverMetaData() { + return jdbcDriverMetaData; + } + + /** + * Executes SQL statements on the JDBC connection. + * + * @param sqlStatements The SQL statements to execute. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection execute(String... sqlStatements) throws SQLException { + return execute(statement -> { + for (String sqlStatement : sqlStatements) { + if (sqlStatement != null) { + log.debug("Executing '{}'", sqlStatement); + statement.execute(sqlStatement); + } + } + }); + } + + /** + * Executes a custom initial operation on the JDBC connection. + * + * @param operation The initial operation to execute. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection execute(InitialOperation operation) throws SQLException { + Connection conn = connection(); + try (Statement statement = conn.createStatement()) { + operation.apply(statement); + commit(); + } + return this; + } + + /** + * Execute the given SQL statements without committing the changes. + * + * @param sqlStatements The SQL statements to execute + * @return This JdbcConnection instance + * @throws SQLException If an SQL error occurs + */ + public JdbcConnection executeWithoutCommitting(String... sqlStatements) throws SQLException { + Connection conn = connection(); + if (conn.getAutoCommit()) { + throw new SQLException("Cannot execute without committing because auto-commit is enabled"); + } + + try (Statement statement = conn.createStatement()) { + for (String sqlStatement : sqlStatements) { + log.debug("Executing sql statement: {}", sqlStatement); + statement.execute(sqlStatement); + } + } + return this; + } + + /** + * Checks if the JDBC connection is connected. + * + * @return true if the connection is connected, false otherwise. + * @throws SQLException if a database access error occurs. + */ + public synchronized boolean isConnected() throws SQLException { + if (connection == null) { + return false; + } + return !connection.isClosed(); + } + + /** + * Checks if the JDBC connection is valid. + * + * @return true if the connection is valid, false otherwise. + * @throws SQLException if a database access error occurs. + */ + public synchronized boolean isValid() throws SQLException { + return isConnected() && connection.isValid(CONNECTION_VALID_CHECK_TIMEOUT_IN_SEC); + } + + /** + * Commits the changes on the JDBC connection. + * + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection commit() throws SQLException { + Connection conn = connection(); + if (!conn.getAutoCommit()) { + conn.commit(); + } + return this; + } + + /** + * Executes a query on the JDBC connection and consumes the result set using the provided consumer. + * + * @param sql The SQL query to execute. + * @param resultConsumer The consumer to process the result set. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection query(String sql, JdbcResultSetConsumer resultConsumer) throws SQLException { + // Check if the connection is connected and valid + if (isConnected() && isValid()) { + connection(); + } + return query(sql, Connection::createStatement, resultConsumer); + } + + /** + * Executes a query on the JDBC connection and consumes the result set using the provided consumer. + * + * @param sql The SQL query to execute. + * @param statementFactory The factory to create the statement. + * @param resultConsumer The consumer to process the result set. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection query(String sql, StatementFactory statementFactory, JdbcResultSetConsumer resultConsumer) throws SQLException { + Connection conn = connection(); + try (Statement statement = statementFactory.createStatement(conn)) { + log.debug("Query sql '{}'", sql); + try (ResultSet resultSet = statement.executeQuery(sql)) { + if (resultConsumer != null) { + resultConsumer.accept(resultSet); + } + } + } + return this; + } + + /** + * Executes a query on the JDBC connection and maps the result set using the provided ResultSetMapper. + * + * @param sql The SQL query to execute. + * @param resultSetMapper The mapper to map the result set to an object. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + public T query(String sql, ResultSetMapper resultSetMapper) throws SQLException { + // Check if the connection is connected and valid + if (isConnected() && isValid()) { + connection(); + } + return query(sql, Connection::createStatement, resultSetMapper); + } + + /** + * Executes a query on the JDBC connection and maps the result set using the provided ResultSetMapper. + * + * @param sql The SQL query to execute. + * @param statementFactory The factory to create the statement. + * @param resultSetMapper The mapper to map the result set to an object. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + public T query(String sql, StatementFactory statementFactory, ResultSetMapper resultSetMapper) throws SQLException { + Connection conn = connection(); + try (Statement statement = statementFactory.createStatement(conn)) { + log.debug("Query sql '{}'", sql); + try (ResultSet resultSet = statement.executeQuery(sql)) { + if (resultSetMapper != null) { + return resultSetMapper.map(resultSet); + } + } + } + return null; + } + + /** + * Executes a prepared query on the JDBC connection and consumes the result set using the provided consumer. + * + * @param sql The SQL query to execute. + * @param resultConsumer The consumer to process the result set. + * @param preparedParameters The prepared parameters for the query. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection preparedQuery(String sql, JdbcResultSetConsumer resultConsumer, PreparedParameter... preparedParameters) + throws SQLException { + // Check if the connection is connected and valid + if (isConnected() && isValid()) { + connection(); + } + return preparedQuery(sql, (conn, statement) -> conn.prepareStatement(sql), resultConsumer, preparedParameters); + } + + /** + * Executes a prepared query on the JDBC connection and consumes the result set using the provided consumer. + * + * @param sql The SQL query to execute. + * @param preparedStatementFactory The factory to create the prepared statement. + * @param resultConsumer The consumer to process the result set. + * @param preparedParameters The prepared parameters for the query. + * @return The JdbcConnection instance. + * @throws SQLException if a database access error occurs. + */ + public JdbcConnection preparedQuery(String sql, PreparedStatementFactory preparedStatementFactory, JdbcResultSetConsumer resultConsumer, + PreparedParameter... preparedParameters) throws SQLException { + + Connection conn = connection(); + try (PreparedStatement preparedStatement = preparedStatementFactory.createPreparedStatement(conn, sql)) { + log.debug("Query sql '{}'", sql); + if (preparedParameters != null) { + for (int index = 0; index < preparedParameters.length; ++index) { + final PreparedParameter preparedParameter = preparedParameters[index]; + if (preparedParameter.getJdbcType() == null) { + preparedStatement.setObject(index + 1, preparedParameter.getValue()); + } else { + preparedStatement.setObject(index + 1, preparedParameter.getValue(), preparedParameter.getJdbcType().getVendorTypeNumber()); + } + } + } + try (ResultSet resultSet = preparedStatement.executeQuery()) { + if (resultConsumer != null) { + resultConsumer.accept(resultSet); + } + } + } + return this; + } + + /** + * Executes a prepared query on the JDBC connection and maps the result set using the provided ResultSetMapper. + * + * @param sql The SQL query to execute. + * @param resultSetMapper The mapper to map the result set to an object. + * @param preparedParameters The prepared parameters for the query. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + public T preparedQuery(String sql, ResultSetMapper resultSetMapper, PreparedParameter... preparedParameters) + throws SQLException { + // Check if the connection is connected and valid + if (isConnected() && isValid()) { + connection(); + } + return preparedQuery(sql, (conn, statement) -> conn.prepareStatement(sql), resultSetMapper, preparedParameters); + } + + /** + * Executes a prepared query on the JDBC connection and maps the result set using the provided ResultSetMapper. + * + * @param sql The SQL query to execute. + * @param preparedStatementFactory The factory to create the prepared statement. + * @param resultSetMapper The mapper to map the result set to an object. + * @param preparedParameters The prepared parameters for the query. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + public T preparedQuery(String sql, PreparedStatementFactory preparedStatementFactory, ResultSetMapper resultSetMapper, + PreparedParameter... preparedParameters) throws SQLException { + + Connection conn = connection(); + try (PreparedStatement preparedStatement = preparedStatementFactory.createPreparedStatement(conn, sql)) { + log.debug("Query sql '{}'", sql); + if (preparedParameters != null) { + for (int index = 0; index < preparedParameters.length; ++index) { + final PreparedParameter preparedParameter = preparedParameters[index]; + if (preparedParameter.getJdbcType() == null) { + preparedStatement.setObject(index + 1, preparedParameter.getValue()); + } else { + preparedStatement.setObject(index + 1, preparedParameter.getValue(), preparedParameter.getJdbcType().getVendorTypeNumber()); + } + } + } + try (ResultSet resultSet = preparedStatement.executeQuery()) { + if (resultSetMapper != null) { + return resultSetMapper.map(resultSet); + } + } + } + return null; + } + + public Statement createStatement(int fetchSize, int defaultFetchSize) throws SQLException { + final Statement statement = connection().createStatement(); + statement.setFetchSize(fetchSize <= 0 ? defaultFetchSize : fetchSize); + return statement; + } + + /** + * Functional interface for the initial operation on the JDBC connection. + */ + @FunctionalInterface + public interface InitialOperation { + + /** + * Applies the operation on the JDBC statement. + * + * @param statement The JDBC statement. + * @throws SQLException if a database access error occurs. + */ + void apply(Statement statement) throws SQLException; + } + + /** + * Functional interface for creating JDBC statements. + */ + @FunctionalInterface + public interface StatementFactory { + + /** + * Creates a JDBC statement. + * + * @param connection The JDBC connection. + * @return The JDBC statement. + * @throws SQLException if a database access error occurs. + */ + Statement createStatement(Connection connection) throws SQLException; + } + + /** + * Functional interface for creating JDBC prepared statements. + */ + @FunctionalInterface + public interface PreparedStatementFactory { + + /** + * Creates a JDBC prepared statement with the provided connection and SQL query. + * + * @param connection The JDBC connection. + * @param sql The SQL query. + * @return The JDBC prepared statement. + * @throws SQLException if a database access error occurs. + */ + PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException; + } + + /** + * Functional interface for creating JDBC connections. + */ + @FunctionalInterface + @ThreadSafe + public interface ConnectionFactory { + + /** + * Creates a JDBC connection. + * + * @param config The JDBC configuration. + * @return The JDBC connection. + * @throws SQLException if a database access error occurs. + */ + Connection connect(JdbcConfig config) throws SQLException; + } + + /** + * Functional interface for mapping a ResultSet to an object of type T. + * + * @param The type of object to be mapped. + */ + @FunctionalInterface + public interface ResultSetMapper { + + /** + * Maps a ResultSet to an object of type T. + * + * @param rs The ResultSet to be mapped. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + T map(ResultSet rs) throws SQLException; + } + + /** + * Functional interface for consuming a ResultSet. + */ + @FunctionalInterface + public interface JdbcResultSetConsumer { + + /** + * Accepts a ResultSet and performs an operation on it. + * + * @param resultSet The ResultSet to be consumed. + * @throws SQLException if a database access error occurs. + */ + void accept(ResultSet resultSet) throws SQLException; + + } + + /** + * Creates a ConnectionFactory that uses a pattern-based URL with placeholder values. + * + * @param urlWithPlaceholder The URL pattern with placeholders. + * @param replaces The replacement values for the placeholders. + * @return The ConnectionFactory instance. + */ + @SuppressWarnings("unchecked") + public static ConnectionFactory createPatternConnectionFactory(String urlWithPlaceholder, String... replaces) { + return config -> { + String url; + if (replaces != null && replaces.length > 0) { + url = String.format(urlWithPlaceholder, (Object[]) replaces); + } else { + url = urlWithPlaceholder; + } + log.debug("URL: {}", url); + Connection connection = DriverManager.getConnection(url, config.asProperties()); + log.debug("User [{}] Connected to {}", config.getUser(), url); + return connection; + }; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/JdbcConnectionProvider.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/JdbcConnectionProvider.java new file mode 100644 index 0000000000..602208eb63 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/JdbcConnectionProvider.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.connection; + +import org.apache.eventmesh.connector.jdbc.exception.JdbcConnectionException; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Obtaining a database connection and checking its validity. + */ +public interface JdbcConnectionProvider extends AutoCloseable { + + /** + * Obtains a database connection. + * + * @return A database connection. + */ + JC getConnection(); + + JC newConnection(); + + /** + * Checks if a database connection is valid. + * + * @param connection The database connection to check. + * @param timeout The timeout in seconds. + * @return True if the connection is valid, false otherwise. + * @throws JdbcConnectionException If there is an error checking the connection. + * @throws SQLException If there is an error with the SQL query. + */ + boolean isValid(Connection connection, int timeout) throws JdbcConnectionException, SQLException; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/PreparedParameter.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/PreparedParameter.java new file mode 100644 index 0000000000..4461e1041b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/PreparedParameter.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.connection; + +import java.sql.JDBCType; + +import lombok.Data; + +/** + * Represents a parameter for a prepared statement. + */ +@Data +public class PreparedParameter { + + private Object value; + + private JDBCType jdbcType; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/mysql/MysqlJdbcConnection.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/mysql/MysqlJdbcConnection.java new file mode 100644 index 0000000000..d62aebba56 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/connection/mysql/MysqlJdbcConnection.java @@ -0,0 +1,189 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.connection.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.connector.jdbc.connection.JdbcConnection; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlDialectSql; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.utils.MysqlUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.OptionalLong; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlJdbcConnection extends JdbcConnection { + + private static final int DEFAULT_CONNECT_TIMEOUT_SECOND = 10; + + public static final String URL_WITH_PLACEHOLDER = "jdbc:mysql://%s:%s/?useInformationSchema=true" + + "&nullCatalogMeansCurrent=false&useUnicode=true&characterEncoding=UTF-8" + + "&characterSetResults=UTF-8&zeroDateTimeBehavior=CONVERT_TO_NULL&connectTimeout=%s"; + + public MysqlJdbcConnection(JdbcConfig jdbcConfig, InitialOperation initialOperation, ConnectionFactory connectionFactory) { + super(jdbcConfig, initialOperation, connectionFactory); + } + + public MysqlJdbcConnection(JdbcConfig jdbcConfig, InitialOperation initialOperation, ConnectionFactory connectionFactory, + boolean lazyConnection) { + super(jdbcConfig, initialOperation, connectionFactory, lazyConnection); + } + + public MysqlJdbcConnection(JdbcConfig jdbcConfig, InitialOperation initialOperation) { + super(jdbcConfig, initialOperation, getPatternConnectionFactory(jdbcConfig)); + } + + public MysqlJdbcConnection(JdbcConfig jdbcConfig, InitialOperation initialOperation, boolean lazyConnection) { + super(jdbcConfig, initialOperation, getPatternConnectionFactory(jdbcConfig), lazyConnection); + } + + private static ConnectionFactory getPatternConnectionFactory(JdbcConfig jdbcConfig) { + return JdbcConnection.createPatternConnectionFactory(URL_WITH_PLACEHOLDER, jdbcConfig.getHostname(), String.valueOf(jdbcConfig.getPort()), + String.valueOf(jdbcConfig.getConnectTimeout() <= 0 ? DEFAULT_CONNECT_TIMEOUT_SECOND : jdbcConfig.getConnectTimeout())); + } + + /** + * Checks if GTID (Global Transaction Identifier) is enabled on the database server. + * + * @return true if GTID is enabled, false otherwise. + */ + public boolean enableGTID() { + + boolean enableGTID = false; + try { + enableGTID = query(MysqlDialectSql.SHOW_GTID_STATUS.ofSQL(), new ResultSetMapper() { + + /** + * Maps a ResultSet to an object of type T. + * + * @param rs The ResultSet to be mapped. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + @Override + public Boolean map(ResultSet rs) throws SQLException { + while (rs.next()) { + if ("ON".equalsIgnoreCase(rs.getString(2))) { + return true; + } + } + return false; + } + }); + } catch (SQLException e) { + log.error("Get executed gtid error", e); + } + + return enableGTID; + } + + /** + * Retrieves the executed GTID from the Mysql database. + * + * @return The executed GTID as a String. + */ + public String executedGTID() { + + try { + return query(MysqlDialectSql.SHOW_MASTER_STATUS.ofSQL(), new ResultSetMapper() { + + /** + * Maps a ResultSet to an object of type T. + * + * @param rs The ResultSet to be mapped. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + @Override + public String map(ResultSet rs) throws SQLException { + if (rs.next() && rs.getMetaData().getColumnCount() > 4) { + return rs.getString(5); + } + // Return an empty string if no GTID is found. + return ""; + } + }); + } catch (SQLException e) { + log.error("Get executed gtid error", e); + } + return ""; + } + + /** + * Get the purged GTID values from MySQL (gtid_purged value) + * + * @return A GTID String; may be empty if not using GTIDs or none have been purged yet + */ + public String purgedGTID() { + + try { + + /** + * +----------------------------------------------+ + * | @@global.gtid_purged | + * +----------------------------------------------+ + * | e584735d-fde7-11ed-bf67-0242ac110002:1-12918 | + * +----------------------------------------------+ + */ + return query(MysqlDialectSql.SELECT_PURGED_GTID.ofSQL(), new ResultSetMapper() { + + /** + * Maps a ResultSet to an object of type T. + * + * @param rs The ResultSet to be mapped. + * @return The mapped object. + * @throws SQLException if a database access error occurs. + */ + @Override + public String map(ResultSet rs) throws SQLException { + if (rs.next() && rs.getMetaData().getColumnCount() > 4) { + return rs.getString(1); + } + // Return an empty string if no GTID is found. + return ""; + } + }); + } catch (SQLException e) { + log.error("Get executed gtid error", e); + } + return ""; + } + + public OptionalLong getRowCount4Table(TableId tableId) { + try { + // select database + execute(MysqlDialectSql.SELECT_DATABASE.ofWrapperSQL(MysqlUtils.wrapper(tableId.getCatalogName()))); + // The number of rows. Some storage engines, such as MyISAM, store the exact count. For other storage engines, + // such as InnoDB, this value is an approximation, and may vary from the actual value by as much as 40% to 50%. + // In such cases, use SELECT COUNT(*) to obtain an accurate count. + return query(MysqlDialectSql.SHOW_TABLE_STATUS.ofWrapperSQL(tableId.getTableName()), rs -> { + if (rs.next()) { + return OptionalLong.of(rs.getLong(5)); + } + return OptionalLong.empty(); + }); + } catch (SQLException e) { + log.error("Error get number of rows in table {} : {}", tableId, e.getMessage()); + } + return OptionalLong.empty(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/context/mysql/MysqlOffsetContext.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/context/mysql/MysqlOffsetContext.java new file mode 100644 index 0000000000..4a19ae6b31 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/context/mysql/MysqlOffsetContext.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.context.mysql; + +import org.apache.eventmesh.connector.jdbc.UniversalOffsetContext; + +import java.util.Map; + +public class MysqlOffsetContext extends UniversalOffsetContext { + + private volatile boolean snapshotRunning = false; + + private volatile boolean snapshotCompleted = false; + + @Override + public Map getOffset() { + return null; + } + + @Override + public boolean isSnapshotRunning() { + return snapshotRunning; + } + + @Override + public void markSnapshotRunning() { + this.snapshotRunning = true; + } + + @Override + public void markSnapshotCompleted() { + this.snapshotCompleted = true; + } + + @Override + public boolean isSnapshotCompleted() { + return this.snapshotCompleted; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/context/mysql/MysqlPartition.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/context/mysql/MysqlPartition.java new file mode 100644 index 0000000000..bfba727775 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/context/mysql/MysqlPartition.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.context.mysql; + +import org.apache.eventmesh.connector.jdbc.AbstractPartition; +import org.apache.eventmesh.connector.jdbc.Partition; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import java.util.HashMap; +import java.util.Map; + +public class MysqlPartition extends AbstractPartition implements Partition { + + private static final String TABLE_ID = "tableId"; + + private Map partitions = new HashMap<>(); + + public MysqlPartition(TableId tableId) { + partitions.put(TABLE_ID, tableId.toString()); + } + + public MysqlPartition() { + + } + + @Override + public Map getPartition() { + return partitions; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/AbstractDdlParser.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/AbstractDdlParser.java new file mode 100644 index 0000000000..d61d8d9b1f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/AbstractDdlParser.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.ddl; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import lombok.Getter; + +public abstract class AbstractDdlParser implements DdlParser { + + // Indicates whether to skip parsing views. + private final boolean skipViews; + + // Indicates whether to skip parsing comments. + private final boolean skipComments; + + @Getter + private final TableId tableId; + + public AbstractDdlParser(boolean skipViews, boolean skipComments) { + this.skipViews = skipViews; + this.skipComments = skipComments; + this.tableId = new TableId(); + } + + @Override + public void setCurrentDatabase(String databaseName) { + this.tableId.setCatalogName(databaseName); + } + + @Override + public void setCurrentSchema(String schema) { + this.tableId.setSchemaName(schema); + } + + public String getCurrentDatabase() { + return this.tableId.getCatalogName(); + } + + public boolean isSkipViews() { + return skipViews; + } + + public boolean isSkipComments() { + return skipComments; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/DdlParser.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/DdlParser.java new file mode 100644 index 0000000000..0199fbcd92 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/DdlParser.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.ddl; + +/** + * Interface for parsing Data Definition Language (DDL) SQL statements. + */ +public interface DdlParser { + + /** + * Parses the given DDL SQL statement with a default callback. + * + * @param ddlSql The DDL SQL statement to parse. + */ + default void parse(String ddlSql) { + parse(ddlSql, null); + } + + /** + * Parses the given DDL SQL statement and provides a callback for handling the parsed events. + * + * @param ddlSql The DDL SQL statement to parse. + * @param callback The DdlParserCallback to handle the parsed events. + */ + void parse(String ddlSql, DdlParserCallback callback); + + /** + * Sets the current database name for the parser. + * + * @param databaseName The name of the current database. + */ + void setCurrentDatabase(String databaseName); + + /** + * Sets the current schema for the parser. + * + * @param schema The name of the current schema. + */ + void setCurrentSchema(String schema); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/DdlParserCallback.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/DdlParserCallback.java new file mode 100644 index 0000000000..392e4420a0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/ddl/DdlParserCallback.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.ddl; + +import org.apache.eventmesh.connector.jdbc.event.Event; + +/** + * A functional interface for handling events generated during DDL parsing. + */ +@FunctionalInterface +public interface DdlParserCallback { + + /** + * Handles the specified event. + * + * @param event The event generated during DDL parsing. + */ + void handle(Event event); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/AbstractGeneralDatabaseDialect.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/AbstractGeneralDatabaseDialect.java new file mode 100644 index 0000000000..0ba6ab715f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/AbstractGeneralDatabaseDialect.java @@ -0,0 +1,156 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.connector.jdbc.connection.JdbcConnection; +import org.apache.eventmesh.connector.jdbc.exception.JdbcConnectionException; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.type.Type; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BooleanEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BytesEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DateEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DateTimeEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DecimalEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Float32EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Float64EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int16EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int32EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int64EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int8EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.StringEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.TimeEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.YearEventMeshDataType; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.hibernate.dialect.Dialect; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractGeneralDatabaseDialect implements DatabaseDialect { + + private static final int DEFAULT_BATCH_MAX_ROWS = 20; + + private JdbcConfig config; + + private int batchMaxRows = DEFAULT_BATCH_MAX_ROWS; + + private final Map typeRegisters = new HashMap<>(32); + + private Dialect hibernateDialect; + + public AbstractGeneralDatabaseDialect(JdbcConfig config) { + this.config = config; + } + + @Override + public void configure(Dialect hibernateDialect) { + this.hibernateDialect = hibernateDialect; + } + + @Override + public boolean isValid(Connection connection, int timeout) throws JdbcConnectionException, SQLException { + return connection == null ? false : connection.isValid(timeout); + } + + @Override + public PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException { + PreparedStatement preparedStatement = connection.prepareStatement(sql); + if (batchMaxRows > 0) { + preparedStatement.setFetchSize(batchMaxRows); + } + return preparedStatement; + } + + @Override + public Type getType(Column column) { + final String nativeType = column.getNativeType(); + if (nativeType != null) { + final Type type = typeRegisters.get(nativeType); + if (type != null) { + log.debug("found type {} for column {}", type.getClass().getName(), column.getName()); + return type; + } + } + final String dataTypeName = column.getDataType().getName(); + if (dataTypeName != null) { + final Type type = typeRegisters.get(dataTypeName); + if (type != null) { + log.debug("found type {} for column {}", type.getClass().getName(), column.getName()); + return type; + } + } + + final String jdbcTypeName = column.getJdbcType().name(); + if (jdbcTypeName != null) { + final Type type = typeRegisters.get(jdbcTypeName); + if (type != null) { + log.debug("found type {} for column {}", type.getClass().getName(), column.getName()); + return type; + } + } + + return null; + } + + protected void registerTypes() { + registerType(BooleanEventMeshDataType.INSTANCE); + registerType(Float32EventMeshDataType.INSTANCE); + registerType(Float64EventMeshDataType.INSTANCE); + registerType(Int8EventMeshDataType.INSTANCE); + registerType(Int16EventMeshDataType.INSTANCE); + registerType(Int32EventMeshDataType.INSTANCE); + registerType(Int64EventMeshDataType.INSTANCE); + registerType(StringEventMeshDataType.INSTANCE); + registerType(DateEventMeshDataType.INSTANCE); + registerType(TimeEventMeshDataType.INSTANCE); + registerType(DateTimeEventMeshDataType.INSTANCE); + registerType(DecimalEventMeshDataType.INSTANCE); + registerType(BytesEventMeshDataType.INSTANCE); + registerType(YearEventMeshDataType.INSTANCE); + } + + protected void registerType(Type type) { + type.configure(this, hibernateDialect); + Optional.ofNullable(type.ofRegistrationKeys()).orElse(new ArrayList<>(0)).forEach(key -> typeRegisters.put(key, type)); + } + + public abstract String getQualifiedTableName(TableId tableId); + + public abstract String getQualifiedText(String text); + + @Override + public String getTypeName(Dialect hibernateDialect, Column column) { + Type type = this.getType(column); + if (type != null) { + return type.getTypeName(column); + } + Long length = Optional.ofNullable(column.getColumnLength()).orElse(0L); + return hibernateDialect.getTypeName(column.getJdbcType().getVendorTypeNumber(), length, length.intValue(), + Optional.ofNullable(column.getDecimal()).orElse(0)); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseDialect.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseDialect.java new file mode 100644 index 0000000000..86befeae85 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseDialect.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect; + +import org.apache.eventmesh.connector.jdbc.JdbcDriverMetaData; +import org.apache.eventmesh.connector.jdbc.connection.JdbcConnection; +import org.apache.eventmesh.connector.jdbc.connection.JdbcConnectionProvider; +import org.apache.eventmesh.connector.jdbc.table.catalog.Catalog; +import org.apache.eventmesh.connector.jdbc.type.DatabaseTypeDialect; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * Interface for a database dialect, which extends the ConnectionProvider and Catalog interfaces. + */ +public interface DatabaseDialect extends JdbcConnectionProvider, Catalog, DatabaseTypeDialect { + + /** + * Initializes the database dialect. + */ + void init(); + + /** + * Starts the database dialect. + */ + void start(); + + /** + * Retrieves the type of the database dialect. + * + * @return The type of the database dialect. + */ + DatabaseType getDatabaseType(); + + /** + * Creates a prepared statement for the given SQL query using the provided database connection. + * + * @param connection The database connection. + * @param sql The SQL query. + * @return The prepared statement. + * @throws SQLException If an error occurs while creating the prepared statement. + */ + PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException; + + /** + * Retrieves the JDBC driver meta-data associated with the database dialect. + * + * @return The JDBC driver meta-data. + */ + JdbcDriverMetaData getJdbcDriverMetaData(); + + /** + * Retrieves the JDBC protocol associated with the database dialect. + * + * @return The JDBC protocol. + */ + String jdbcProtocol(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseDialectFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseDialectFactory.java new file mode 100644 index 0000000000..3ad607e455 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseDialectFactory.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * Interface for creating a database dialect based on the provided source configuration. + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.JDBC_DATABASE_DIALECT) +public interface DatabaseDialectFactory { + + /** + * Creates a database dialect based on the provided source configuration. + * + * @param config the jdbc configuration to create a database dialect for + * @return the created database dialect + */ + DatabaseDialect createDatabaseDialect(JdbcConfig config); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseType.java new file mode 100644 index 0000000000..b1db56c526 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/DatabaseType.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect; + +import org.apache.commons.lang3.StringUtils; + +import lombok.Getter; + +public enum DatabaseType { + + MYSQL("mysql"); + + @Getter + private String code; + + DatabaseType(String code) { + this.code = code; + } + + public static DatabaseType ofValue(String name) { + DatabaseType[] databaseTypes = values(); + for (DatabaseType databaseType : databaseTypes) { + if (StringUtils.equalsIgnoreCase(databaseType.code, name)) { + return databaseType; + } + } + return null; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/SqlStatementAssembler.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/SqlStatementAssembler.java new file mode 100644 index 0000000000..6e3858369a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/SqlStatementAssembler.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Collection; +import java.util.Iterator; +import java.util.function.Function; + +/** + * The {@code SqlStatementAssembler} class is used to assemble SQL statements by appending SQL slices. + */ +public final class SqlStatementAssembler { + + private final StringBuilder statement; + + public SqlStatementAssembler() { + statement = new StringBuilder(); + } + + public SqlStatementAssembler appendSqlSlice(String slice) { + statement.append(slice); + return this; + } + + public SqlStatementAssembler appendSqlSliceLists(String delimiter, Collection columnNames, Function function) { + for (Iterator iterator = columnNames.iterator(); iterator.hasNext();) { + statement.append(function.apply(iterator.next())); + if (iterator.hasNext()) { + statement.append(delimiter); + } + } + return this; + } + + public SqlStatementAssembler appendSqlSliceOfColumns(String delimiter, Collection> columns, Function, String> function) { + for (Iterator> iterator = columns.iterator(); iterator.hasNext();) { + statement.append(function.apply(iterator.next())); + if (iterator.hasNext()) { + statement.append(delimiter); + } + } + return this; + } + + public String build() { + return statement.toString(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/mysql/MysqlDatabaseDialect.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/mysql/MysqlDatabaseDialect.java new file mode 100644 index 0000000000..1a4bb02fb6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/mysql/MysqlDatabaseDialect.java @@ -0,0 +1,438 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.connector.jdbc.DataTypeConvertor; +import org.apache.eventmesh.connector.jdbc.JdbcDriverMetaData; +import org.apache.eventmesh.connector.jdbc.connection.mysql.MysqlJdbcConnection; +import org.apache.eventmesh.connector.jdbc.dialect.AbstractGeneralDatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseType; +import org.apache.eventmesh.connector.jdbc.exception.CatalogException; +import org.apache.eventmesh.connector.jdbc.exception.DatabaseNotExistException; +import org.apache.eventmesh.connector.jdbc.exception.TableNotExistException; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlDataTypeConvertor; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlDialectSql; +import org.apache.eventmesh.connector.jdbc.table.catalog.CatalogTable; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.DefaultColumn; +import org.apache.eventmesh.connector.jdbc.table.catalog.Options; +import org.apache.eventmesh.connector.jdbc.table.catalog.PrimaryKey; +import org.apache.eventmesh.connector.jdbc.table.catalog.Table; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableSchema; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlColumn; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlOptions.MysqlTableOptions; +import org.apache.eventmesh.connector.jdbc.type.Type; +import org.apache.eventmesh.connector.jdbc.type.mysql.BitType; +import org.apache.eventmesh.connector.jdbc.type.mysql.BytesType; +import org.apache.eventmesh.connector.jdbc.type.mysql.DecimalType; +import org.apache.eventmesh.connector.jdbc.type.mysql.EnumType; +import org.apache.eventmesh.connector.jdbc.type.mysql.GeometryCollectionType; +import org.apache.eventmesh.connector.jdbc.type.mysql.GeometryType; +import org.apache.eventmesh.connector.jdbc.type.mysql.IntType; +import org.apache.eventmesh.connector.jdbc.type.mysql.JsonType; +import org.apache.eventmesh.connector.jdbc.type.mysql.LineStringType; +import org.apache.eventmesh.connector.jdbc.type.mysql.MediumintType; +import org.apache.eventmesh.connector.jdbc.type.mysql.MultiLineStringType; +import org.apache.eventmesh.connector.jdbc.type.mysql.MultiPointType; +import org.apache.eventmesh.connector.jdbc.type.mysql.MultiPolygonType; +import org.apache.eventmesh.connector.jdbc.type.mysql.PointType; +import org.apache.eventmesh.connector.jdbc.type.mysql.PolygonType; +import org.apache.eventmesh.connector.jdbc.type.mysql.SetType; +import org.apache.eventmesh.connector.jdbc.type.mysql.TextType; +import org.apache.eventmesh.connector.jdbc.type.mysql.TinyIntType; +import org.apache.eventmesh.connector.jdbc.type.mysql.YearType; +import org.apache.eventmesh.connector.jdbc.utils.MysqlUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import com.mysql.cj.MysqlType; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlDatabaseDialect extends AbstractGeneralDatabaseDialect { + + private MysqlJdbcConnection connection; + + private DataTypeConvertor dataTypeConvertor = new MysqlDataTypeConvertor(); + + private JdbcConfig config; + + public MysqlDatabaseDialect(JdbcConfig config) { + super(config); + this.config = config; + } + + @Override + public void init() { + + boolean initSuccess; + do { + try { + this.connection = initJdbcConnection(); + initSuccess = true; + } catch (Exception e) { + log.error("Init jdbc connection error,The connection will be retried in three seconds", e); + initSuccess = false; + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } while (!initSuccess); + + // handle type register + super.registerTypes(); + registerType(BitType.INSTANCE); + registerType(SetType.INSTANCE); + registerType(EnumType.INSTANCE); + registerType(TinyIntType.INSTANCE); + registerType(JsonType.INSTANCE); + registerType(IntType.INSTANCE); + registerType(MediumintType.INSTANCE); + registerType(DecimalType.INSTANCE); + registerType(TextType.INSTANCE); + + // override YearEventMeshDateType + registerType(YearType.INSTANCE); + registerType(BytesType.INSTANCE); + + // Spatial Data Types + registerType(PointType.INSTANCE); + registerType(MultiPointType.INSTANCE); + registerType(GeometryType.INSTANCE); + registerType(GeometryCollectionType.INSTANCE); + registerType(LineStringType.INSTANCE); + registerType(MultiLineStringType.INSTANCE); + registerType(PolygonType.INSTANCE); + registerType(MultiPolygonType.INSTANCE); + } + + @Override + public void start() { + // TODO? + } + + private MysqlJdbcConnection initJdbcConnection() { + try { + return new MysqlJdbcConnection(config, null, false); + } catch (Exception e) { + throw new CatalogException(e); + } + } + + @Override + public void open() throws CatalogException { + + } + + @Override + public String getDefaultDatabase() { + return null; + } + + @Override + public boolean databaseExists(String databaseName) throws CatalogException { + if (databaseName == null || databaseName.trim().isEmpty()) { + return false; + } + List databases = listDatabases(); + return databases.contains(databaseName); + } + + @Override + public List listDatabases() throws CatalogException { + List databases = new ArrayList<>(16); + try { + this.connection.query(MysqlDialectSql.SHOW_DATABASE.ofSQL(), resultSet -> { + while (resultSet.next()) { + databases.add(resultSet.getString("Database")); + } + }); + } catch (SQLException e) { + log.error("List Mysql database error", e); + throw new CatalogException(e); + } + return databases; + } + + @Override + public List listTables(String databaseName) throws CatalogException, DatabaseNotExistException, SQLException { + + List tableIds = new ArrayList<>(32); + + // Build the SQL query to return a list of tables for the given database + String sql = MysqlDialectSql.SHOW_DATABASE_TABLE.ofWrapperSQL("`" + databaseName + "`"); + log.debug("List tables SQL:{}", sql); + this.connection.query(sql, resultSet -> { + // Execute the query and add each table ID to the list + while (resultSet.next()) { + TableId tableId = new TableId(databaseName, null, resultSet.getString(1)); + tableIds.add(tableId); + } + }); + return tableIds; + } + + @Override + public boolean tableExists(TableId tableId) throws CatalogException, SQLException { + + List tableIds = listTables(tableId.getCatalogName()); + + return tableIds.contains(tableId); + } + + @Override + public CatalogTable getTable(TableId tableId) throws CatalogException, TableNotExistException, SQLException { + + Objects.requireNonNull(tableId, "TableId is null"); + if (!tableExists(tableId)) { + log.error("Table {} not exist in database", tableId); + throw new CatalogException(String.format("Table %s not exist in database", tableId)); + } + + CatalogTable table = new CatalogTable(); + table.setTableId(tableId); + TableSchema tableSchema = new TableSchema(); + table.setTableSchema(tableSchema); + + // Get table creation SQL + final String createTableSql = MysqlDialectSql.SHOW_CREATE_TABLE.ofWrapperSQL(tableId.getId()); + log.debug("Show create table SQL:{}", createTableSql); + + this.connection.query(createTableSql, resultSet -> { + boolean hasNext = resultSet.next(); + if (!hasNext) { + throw new CatalogException(String.format("Table %s not exist in database", tableId.getId())); + } + String creatTableSql = resultSet.getString("Create Table"); + // table.setDdlSql(creatTableSql); + }); + + // Get table columns SQL + final String selectTableSql = MysqlDialectSql.SELECT_TABLE_COLUMNS.ofWrapperSQL(tableId.getId()); + log.debug("Select table SQL:{}", selectTableSql); + Map columns = new HashMap<>(16); + // Execute query to get table columns + this.connection.query(selectTableSql, resultSet -> { + ResultSetMetaData tableMetaData = resultSet.getMetaData(); + int columnCount = tableMetaData.getColumnCount(); + for (int columnIndex = 1; columnIndex <= columnCount; ++columnIndex) { + String columnName = tableMetaData.getColumnName(columnIndex); + DefaultColumn column = columns.computeIfAbsent(columnName, key -> new DefaultColumn()); + column.setName(columnName); + int precision = tableMetaData.getPrecision(columnIndex); + // column.setColumnLength(precision); + Map dataTypeProperties = new HashMap<>(); + dataTypeProperties.put(MysqlDataTypeConvertor.PRECISION, precision); + int scale = tableMetaData.getScale(columnIndex); + dataTypeProperties.put(MysqlDataTypeConvertor.SCALE, scale); + column.setDataType( + dataTypeConvertor.toEventMeshType(MysqlType.getByJdbcType(tableMetaData.getColumnType(columnIndex)), dataTypeProperties)); + column.setDecimal(scale); + } + }); + + // Get table columns details SQL + final String showTableSql = MysqlDialectSql.SHOW_TABLE_COLUMNS.ofWrapperSQL(tableId.getTableName(), tableId.getCatalogName()); + log.debug("Show table columns SQL:{}", showTableSql); + // Execute query to get table columns details + List columnList = new ArrayList<>(columns.size()); + this.connection.query(showTableSql, resultSet -> { + boolean hasNext = resultSet.next(); + if (!hasNext) { + throw new CatalogException(String.format("Table %s without columns", tableId.getId())); + } + List columnNames = new ArrayList<>(4); + do { + String field = resultSet.getString("Field"); + DefaultColumn column = columns.get(field); + String comment = resultSet.getString("Comment"); + column.setComment(comment); + // The column nullability. The value is YES if NULL values can be stored in the column, NO if not. + String enableNull = resultSet.getString("Null"); + column.setNotNull("NO".equalsIgnoreCase(enableNull)); + + String type = resultSet.getString("Type"); + // column.setSqlDesc(type); + + // Get default value + Object defaultValue = resultSet.getObject("Default"); + column.setDefaultValue(defaultValue); + + String key = resultSet.getString("Key"); + if ("PRI".equalsIgnoreCase(key)) { + columnNames.add(field); + } + columnList.add(column); + } while (resultSet.next()); + tableSchema.setColumns(columnList); + tableSchema.setColumnMap(columns); + if (!columnNames.isEmpty()) { + tableSchema.setPrimaryKey(new PrimaryKey(columnNames)); + } + }); + return table; + } + + @Override + public DatabaseType getDatabaseType() { + return DatabaseType.MYSQL; + } + + @Override + public PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException { + Objects.requireNonNull(connection, "Connection is null"); + Objects.requireNonNull(sql, "SQL is null"); + return connection.prepareStatement(sql); + } + + @Override + public String getQualifiedTableName(TableId tableId) { + return MysqlUtils.wrapper(tableId); + } + + @Override + public String getQualifiedText(String text) { + return MysqlUtils.wrapper(text); + } + + /** + * Retrieves the JDBC driver meta-data associated with the database dialect. + * + * @return The JDBC driver meta-data. + */ + @Override + public JdbcDriverMetaData getJdbcDriverMetaData() { + return this.connection.getJdbcDriverMetaData(); + } + + /** + * Retrieves the JDBC protocol associated with the database dialect. + * + * @return The JDBC protocol. + */ + @Override + public String jdbcProtocol() { + return MysqlJdbcConnection.URL_WITH_PLACEHOLDER; + } + + /** + * Obtains a database connection. + * + * @return A database connection. + */ + @Override + public MysqlJdbcConnection getConnection() { + return this.connection; + } + + @Override + public MysqlJdbcConnection newConnection() { + return initJdbcConnection(); + } + + @Override + public void close() throws Exception { + if (this.connection != null) { + this.connection.close(); + } + } + + @Override + public String getAutoIncrementFormatted(Column column) { + return " AUTO_INCREMENT "; + } + + @Override + public String getDefaultValueFormatted(Column column) { + Type type = this.getType(column); + String defaultValue = type.getDefaultValue(this, column); + return defaultValue; + } + + @Override + public String getCharsetOrCollateFormatted(Column column) { + StringBuilder builder = new StringBuilder(); + String charsetName = column.getCharsetName(); + if (StringUtils.isNotBlank(charsetName)) { + builder.append(" CHARACTER SET ").append(charsetName).append(" "); + } + String collationName = column.getCollationName(); + if (StringUtils.isNotBlank(collationName)) { + builder.append(" COLLATE ").append(collationName).append(" "); + } + + return builder.toString(); + } + + @Override + public String getTableOptionsFormatted(Table table) { + + Options options = table.getOptions(); + if (Objects.isNull(options) || options.isEmpty()) { + return EMPTY_STRING; + } + StringBuilder builder = new StringBuilder(); + String engine = (String) options.get(MysqlTableOptions.ENGINE); + if (StringUtils.isNotBlank(engine)) { + builder.append(String.format("ENGINE=%s ", engine)); + } + String autoIncrementNumber = (String) options.get(MysqlTableOptions.AUTO_INCREMENT); + if (StringUtils.isNotBlank(autoIncrementNumber)) { + builder.append(String.format("AUTO_INCREMENT=%s ", autoIncrementNumber)); + } + String charset = (String) options.get(MysqlTableOptions.CHARSET); + if (StringUtils.isNotBlank(charset)) { + builder.append(String.format("DEFAULT CHARSET=%s ", charset)); + } + + String collate = (String) options.get(MysqlTableOptions.COLLATE); + if (StringUtils.isNotBlank(collate)) { + builder.append(String.format(" COLLATE=%s ", collate)); + } + + String comment = table.getComment(); + if (StringUtils.isNotBlank(comment)) { + builder.append(String.format(" COMMENT='%s' ", comment)); + } + return builder.toString(); + } + + @Override + public String getCommentFormatted(Column column) { + if (StringUtils.isEmpty(column.getComment())) { + return EMPTY_STRING; + } + return "COMMENT '" + column.getComment() + "'"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/mysql/MysqlDatabaseDialectFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/mysql/MysqlDatabaseDialectFactory.java new file mode 100644 index 0000000000..b5fb87a016 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/dialect/mysql/MysqlDatabaseDialectFactory.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.dialect.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory; + +public class MysqlDatabaseDialectFactory implements DatabaseDialectFactory { + + @Override + public DatabaseDialect createDatabaseDialect(JdbcConfig config) { + DatabaseDialect databaseDialect = new MysqlDatabaseDialect(config); + return databaseDialect; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AbstractEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AbstractEvent.java new file mode 100644 index 0000000000..a2aaf6a5e4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AbstractEvent.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public abstract class AbstractEvent implements Event { + + private final TableId tableId; + + private JdbcConnectData data; + + public AbstractEvent(TableId tableId) { + this.tableId = tableId; + this.data = new JdbcConnectData(); + } + + public AbstractEvent(TableId tableId, JdbcConnectData data) { + this.tableId = tableId; + this.data = data; + } + + /** + * Gets the table ID of the event. + * + * @return The table ID. + */ + @Override + public TableId getTableId() { + return tableId; + } + + @Override + public JdbcConnectData getJdbcConnectData() { + return data; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AlertDatabaseEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AlertDatabaseEvent.java new file mode 100644 index 0000000000..f0d700cdc9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AlertDatabaseEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class AlertDatabaseEvent extends GeneralSchemaChangeEvent { + + public AlertDatabaseEvent(TableId tableId) { + super(tableId); + } + + public AlertDatabaseEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public SchemaChangeEventType getSchemaChangeEventType() { + return SchemaChangeEventType.DATABASE_ALERT; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AlertTableEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AlertTableEvent.java new file mode 100644 index 0000000000..dfb8250fa2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/AlertTableEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class AlertTableEvent extends GeneralSchemaChangeEvent { + + public AlertTableEvent(TableId tableId) { + super(tableId); + } + + public AlertTableEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public SchemaChangeEventType getSchemaChangeEventType() { + return SchemaChangeEventType.TABLE_ALERT; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/CreateDatabaseEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/CreateDatabaseEvent.java new file mode 100644 index 0000000000..ed00188a0d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/CreateDatabaseEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class CreateDatabaseEvent extends GeneralSchemaChangeEvent { + + public CreateDatabaseEvent(TableId tableId) { + super(tableId); + } + + public CreateDatabaseEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public SchemaChangeEventType getSchemaChangeEventType() { + return SchemaChangeEventType.DATABASE_CREATE; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/CreateTableEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/CreateTableEvent.java new file mode 100644 index 0000000000..76d1ff6968 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/CreateTableEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class CreateTableEvent extends GeneralSchemaChangeEvent { + + public CreateTableEvent(TableId tableId) { + super(tableId); + } + + public CreateTableEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public SchemaChangeEventType getSchemaChangeEventType() { + return SchemaChangeEventType.TABLE_CREATE; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DataChangeEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DataChangeEvent.java new file mode 100644 index 0000000000..2e22de34a8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DataChangeEvent.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +/** + * Represents a data change event, extending the common event interface. + */ +public interface DataChangeEvent extends Event { + + /** + * Gets the type of data change event. + * + * @return The data change event type. + */ + DataChangeEventType getDataChangeEventType(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DataChangeEventType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DataChangeEventType.java new file mode 100644 index 0000000000..67051603ca --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DataChangeEventType.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +/** + * Enumeration representing different types of data change events. + */ +public enum DataChangeEventType { + + /** + * Represents an INSERT data change event. + */ + INSERT("I"), + + /** + * Represents an UPDATE data change event. + */ + UPDATE("U"), + + /** + * Represents a DELETE data change event. + */ + DELETE("D"); + + private final String code; + + /** + * Constructs a DataChangeEventType with the specified code. + * + * @param code The code representing the data change event type. + */ + DataChangeEventType(String code) { + this.code = code; + } + + /** + * Parses a DataChangeEventType from the given code. + * + * @param code The code to parse. + * @return The corresponding DataChangeEventType. + * @throws IllegalArgumentException If the provided code is unknown. + */ + public static DataChangeEventType parseFromCode(String code) { + for (DataChangeEventType type : DataChangeEventType.values()) { + if (type.code.equals(code)) { + return type; + } + } + throw new IllegalArgumentException("Unknown DataChangeEventType code: " + code); + } + + /** + * Gets the code representing the DataChangeEventType. + * + * @return The code of the DataChangeEventType. + */ + public String ofCode() { + return this.code; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DeleteDataEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DeleteDataEvent.java new file mode 100644 index 0000000000..987984bfce --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DeleteDataEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class DeleteDataEvent extends GeneralDataChangeEvent { + + public DeleteDataEvent(TableId tableId) { + super(tableId); + } + + public DeleteDataEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public DataChangeEventType getDataChangeEventType() { + return DataChangeEventType.DELETE; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DropDatabaseEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DropDatabaseEvent.java new file mode 100644 index 0000000000..0b5459514c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DropDatabaseEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class DropDatabaseEvent extends GeneralSchemaChangeEvent { + + public DropDatabaseEvent(TableId tableId) { + super(tableId); + } + + public DropDatabaseEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public SchemaChangeEventType getSchemaChangeEventType() { + return SchemaChangeEventType.DATABASE_DROP; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DropTableEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DropTableEvent.java new file mode 100644 index 0000000000..395bbf4686 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/DropTableEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class DropTableEvent extends GeneralSchemaChangeEvent { + + public DropTableEvent(TableId tableId) { + super(tableId); + } + + public DropTableEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public SchemaChangeEventType getSchemaChangeEventType() { + return SchemaChangeEventType.TABLE_DROP; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/Event.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/Event.java new file mode 100644 index 0000000000..7b254f960d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/Event.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +/** + * Top Event interface + */ +public interface Event { + + /** + * Gets the table ID of the event. + * + * @return The table ID. + */ + TableId getTableId(); + + JdbcConnectData getJdbcConnectData(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/EventConsumer.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/EventConsumer.java new file mode 100644 index 0000000000..9ad6d453c4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/EventConsumer.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +/** + * Functional interface for consuming events. + */ +@FunctionalInterface +public interface EventConsumer { + + /** + * Accepts a snapshot event. + * + * @param event the snapshot event to be consumed + */ + void accept(Event event); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/EventHandler.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/EventHandler.java new file mode 100644 index 0000000000..f37c5a9018 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/EventHandler.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +/** + * Represents a handler for snapshot events. + */ +@FunctionalInterface +public interface EventHandler { + + /** + * Handles a snapshot event. + * + * @param event The SnapshotEvent to handle. + */ + void handle(Event event); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/GeneralDataChangeEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/GeneralDataChangeEvent.java new file mode 100644 index 0000000000..c6a9222376 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/GeneralDataChangeEvent.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public abstract class GeneralDataChangeEvent extends AbstractEvent implements DataChangeEvent { + + public GeneralDataChangeEvent(TableId tableId) { + super(tableId, new JdbcConnectData(JdbcConnectData.DATA_CHANGES)); + } + + public GeneralDataChangeEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/GeneralSchemaChangeEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/GeneralSchemaChangeEvent.java new file mode 100644 index 0000000000..80996203c5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/GeneralSchemaChangeEvent.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public abstract class GeneralSchemaChangeEvent extends AbstractEvent implements SchemaChangeEvent { + + public GeneralSchemaChangeEvent(TableId tableId) { + super(tableId, new JdbcConnectData(JdbcConnectData.SCHEMA_CHANGES)); + } + + public GeneralSchemaChangeEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/InsertDataEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/InsertDataEvent.java new file mode 100644 index 0000000000..593f14574d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/InsertDataEvent.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class InsertDataEvent extends GeneralDataChangeEvent { + + public InsertDataEvent(TableId tableId) { + super(tableId); + } + + public InsertDataEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public DataChangeEventType getDataChangeEventType() { + return DataChangeEventType.INSERT; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/SchemaChangeEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/SchemaChangeEvent.java new file mode 100644 index 0000000000..9cfe336072 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/SchemaChangeEvent.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +/** + * Represents a schema change event, extending the common event interface. + */ +public interface SchemaChangeEvent extends Event { + + /** + * Gets the type of schema change event. + * + * @return The schema change event type. + */ + SchemaChangeEventType getSchemaChangeEventType(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/SchemaChangeEventType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/SchemaChangeEventType.java new file mode 100644 index 0000000000..19558f2dfe --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/SchemaChangeEventType.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.commons.lang3.StringUtils; + +public enum SchemaChangeEventType { + + DATABASE_CREATE("D", "C"), + DATABASE_DROP("D", "D"), + DATABASE_ALERT("D", "A"), + TABLE_CREATE("T", "C"), + TABLE_DROP("T", "D"), + TABLE_ALERT("T", "A"), + ; + private final String type; + private final String operationType; + + SchemaChangeEventType(String type, String operationType) { + this.type = type; + this.operationType = operationType; + } + + public String ofType() { + return this.type; + } + + public String ofOperationType() { + return this.operationType; + } + + public static SchemaChangeEventType ofSchemaChangeEventType(String type, String operationType) { + SchemaChangeEventType[] types = values(); + for (SchemaChangeEventType eventType : types) { + if (StringUtils.equalsIgnoreCase(eventType.type, type) && StringUtils.equalsIgnoreCase(eventType.operationType, operationType)) { + return eventType; + } + } + return null; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/UpdateDataEvent.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/UpdateDataEvent.java new file mode 100644 index 0000000000..1f38c3ff12 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/event/UpdateDataEvent.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.event; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +/** + * Represents an event that indicates an update in data. + */ +public class UpdateDataEvent extends GeneralDataChangeEvent { + + public UpdateDataEvent(TableId tableId) { + super(tableId); + } + + public UpdateDataEvent(TableId tableId, JdbcConnectData data) { + super(tableId, data); + } + + @Override + public DataChangeEventType getDataChangeEventType() { + return DataChangeEventType.UPDATE; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/CatalogException.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/CatalogException.java new file mode 100644 index 0000000000..17fa873fbf --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/CatalogException.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.exception; + +public class CatalogException extends RuntimeException { + + /** + * Constructs a new runtime exception with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized + * by a call to {@link #initCause}. + */ + public CatalogException() { + } + + /** + * Constructs a new runtime exception with the specified detail message. The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. + */ + public CatalogException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and cause.

Note that the detail message associated with {@code cause} + * is + * not automatically incorporated in this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public CatalogException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of + * cause). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public CatalogException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled + * or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + * @since 1.7 + */ + public CatalogException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/DataTypeConvertException.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/DataTypeConvertException.java new file mode 100644 index 0000000000..f0bbb02593 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/DataTypeConvertException.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.exception; + +public class DataTypeConvertException extends RuntimeException { + + /** + * Constructs a new runtime exception with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized + * by a call to {@link #initCause}. + */ + public DataTypeConvertException() { + } + + /** + * Constructs a new runtime exception with the specified detail message. The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. + */ + public DataTypeConvertException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and cause.

Note that the detail message associated with {@code cause} + * is + * not automatically incorporated in this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public DataTypeConvertException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of + * cause). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public DataTypeConvertException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled + * or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + * @since 1.7 + */ + public DataTypeConvertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/DatabaseNotExistException.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/DatabaseNotExistException.java new file mode 100644 index 0000000000..5c363d28f4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/DatabaseNotExistException.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.exception; + +public class DatabaseNotExistException extends RuntimeException { + + /** + * Constructs a new runtime exception with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized + * by a call to {@link #initCause}. + */ + public DatabaseNotExistException() { + } + + /** + * Constructs a new runtime exception with the specified detail message. The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. + */ + public DatabaseNotExistException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and cause.

Note that the detail message associated with {@code cause} + * is + * not automatically incorporated in this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public DatabaseNotExistException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of + * cause). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public DatabaseNotExistException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled + * or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + * @since 1.7 + */ + public DatabaseNotExistException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/JdbcConnectionException.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/JdbcConnectionException.java new file mode 100644 index 0000000000..dde57fc349 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/JdbcConnectionException.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.exception; + +public class JdbcConnectionException extends RuntimeException { + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/TableNotExistException.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/TableNotExistException.java new file mode 100644 index 0000000000..dc5a58dc03 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/exception/TableNotExistException.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.exception; + +public class TableNotExistException extends RuntimeException { + + /** + * Constructs a new runtime exception with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized + * by a call to {@link #initCause}. + */ + public TableNotExistException() { + } + + /** + * Constructs a new runtime exception with the specified detail message. The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. + */ + public TableNotExistException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and cause.

Note that the detail message associated with {@code cause} + * is not automatically incorporated in this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public TableNotExistException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of + * cause). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public TableNotExistException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled + * or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + * @since 1.7 + */ + public TableNotExistException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/server/JdbcConnectorServer.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/server/JdbcConnectorServer.java new file mode 100644 index 0000000000..4c40370671 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/server/JdbcConnectorServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.server; + +import org.apache.eventmesh.connector.jdbc.config.JdbcServerConfig; +import org.apache.eventmesh.connector.jdbc.sink.JdbcSinkConnector; +import org.apache.eventmesh.connector.jdbc.source.JdbcSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +/** + * JDBC connector server + */ +public class JdbcConnectorServer { + + public static void main(String[] args) throws Exception { + JdbcServerConfig serverConfig = ConfigUtil.parse(JdbcServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application jdbcSourceApp = new Application(); + jdbcSourceApp.run(JdbcSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application jdbcSinkApp = new Application(); + jdbcSinkApp.run(JdbcSinkConnector.class); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/JdbcSinkConnector.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/JdbcSinkConnector.java new file mode 100644 index 0000000000..cc00f1e142 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/JdbcSinkConnector.java @@ -0,0 +1,170 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSinkConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory; +import org.apache.eventmesh.connector.jdbc.sink.handle.DefaultSinkRecordHandler; +import org.apache.eventmesh.connector.jdbc.sink.handle.SinkRecordHandler; +import org.apache.eventmesh.connector.jdbc.sink.hibernate.HibernateConfiguration; +import org.apache.eventmesh.connector.jdbc.source.JdbcAllFactoryLoader; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +import org.hibernate.SessionFactory; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.SessionFactoryImplementor; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class JdbcSinkConnector implements Sink { + + private JdbcSinkConfig sinkConfig; + + private SessionFactory sessionFactory; + + private DatabaseDialect databaseDialect; + + private SinkRecordHandler sinkRecordHandler; + + /** + * Returns the class type of the configuration for this Connector. + * + * @return Class type of the configuration + */ + @Override + public Class configClass() { + return JdbcSinkConfig.class; + } + + /** + * Initializes the Connector with the provided configuration. + * + * @param config Configuration object + * @throws Exception if initialization fails + */ + @Override + public void init(Config config) throws Exception { + if (!(config instanceof JdbcSinkConfig)) { + throw new IllegalArgumentException("Config not be JdbcSinkConfig"); + } + this.sinkConfig = (JdbcSinkConfig) config; + doInit(); + } + + /** + * Initializes the Connector with the provided context. + * + * @param connectorContext connectorContext + * @throws Exception if initialization fails + */ + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (JdbcSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + private void doInit() { + JdbcConfig jdbcConfig = this.sinkConfig.getSinkConnectorConfig().getJdbcConfig(); + this.sessionFactory = HibernateConfiguration.newBuilder().withDruidMaxActive("20").withPassword(jdbcConfig.getPassword()) + .withUrl(jdbcConfig.getUrl()) + .withShowSql(true) + .withUser(jdbcConfig.getUser()).build(); + + String databaseType = this.sinkConfig.getSinkConnectorConfig().getDatabaseType(); + + // Get the database dialect factory and create the database dialect. + final DatabaseDialectFactory databaseDialectFactory = JdbcAllFactoryLoader.getDatabaseDialectFactory(databaseType); + this.databaseDialect = databaseDialectFactory.createDatabaseDialect(this.sinkConfig.getSinkConnectorConfig().getJdbcConfig()); + Dialect dialect = this.sessionFactory.unwrap(SessionFactoryImplementor.class).getJdbcServices().getDialect(); + this.databaseDialect.configure(dialect); + this.databaseDialect.init(); + this.sinkRecordHandler = new DefaultSinkRecordHandler(databaseDialect, sessionFactory, sinkConfig); + + } + + /** + * Starts the Connector. + * + * @throws Exception if the start operation fails + */ + @Override + public void start() throws Exception { + + } + + /** + * Commits the specified ConnectRecord object. + * + * @param record ConnectRecord object to commit + */ + @Override + public void commit(ConnectRecord record) { + + } + + /** + * Returns the name of the Connector. + * + * @return String name of the Connector + */ + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + /** + * Stops the Connector. + * + * @throws Exception if stopping fails + */ + @Override + public void stop() throws Exception { + + } + + @Override + public void put(List sinkRecords) { + + for (ConnectRecord record : sinkRecords) { + Object data = record.getData(); + try { + JdbcConnectData jdbcConnectData = JsonUtils.parseObject((byte[]) data, JdbcConnectData.class); + this.sinkRecordHandler.handle(jdbcConnectData); + } catch (Exception e) { + log.error("Handle ConnectRecord error", e); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DefaultSinkRecordHandler.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DefaultSinkRecordHandler.java new file mode 100644 index 0000000000..db684d63c7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DefaultSinkRecordHandler.java @@ -0,0 +1,333 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.handle; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSinkConfig; +import org.apache.eventmesh.common.utils.LogUtil; +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.DataChanges; +import org.apache.eventmesh.connector.jdbc.Field; +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.Payload; +import org.apache.eventmesh.connector.jdbc.Schema; +import org.apache.eventmesh.connector.jdbc.common.EnumeratedValue; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.event.DataChangeEventType; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.type.Type; + +import org.apache.commons.collections4.CollectionUtils; + +import java.sql.SQLException; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import org.hibernate.SessionFactory; +import org.hibernate.StatelessSession; +import org.hibernate.Transaction; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.query.NativeQuery; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DefaultSinkRecordHandler implements SinkRecordHandler { + + protected DatabaseDialect eventMeshDialect; + + protected Dialect hibernateDialect; + + protected DialectAssemblyLine dialectAssemblyLine; + + private SessionFactory sessionFactory; + + private final StatelessSession session; + + private final JdbcSinkConfig jdbcSinkConfig; + + public DefaultSinkRecordHandler(DatabaseDialect eventMeshDialect, SessionFactory sessionFactory, JdbcSinkConfig jdbcSinkConfig) { + this.eventMeshDialect = eventMeshDialect; + this.sessionFactory = sessionFactory; + this.hibernateDialect = sessionFactory.unwrap(SessionFactoryImplementor.class).getJdbcServices().getDialect(); + this.session = this.sessionFactory.openStatelessSession(); + this.dialectAssemblyLine = DialectAssemblyLineFactory.build(eventMeshDialect, hibernateDialect); + this.jdbcSinkConfig = jdbcSinkConfig; + } + + /** + * Handles schema and data changes using the specified JDBC connection data. The method determines the type of changes (schema or data) and + * performs the necessary operations accordingly. + * + * @param connectData the JDBC connection data + * @throws Exception if an error occurs during the handling of schema or data changes + */ + @Override + public void handle(JdbcConnectData connectData) throws Exception { + Payload payload = connectData.getPayload(); + SourceMateData sourceMateData = payload.ofSourceMateData(); + if (connectData.isSchemaChanges()) { + //DDL + schemaChangeHandle(sourceMateData, payload); + } else if (connectData.isDataChanges()) { + //DML + dataChangesHandle(connectData, sourceMateData, payload); + } else { + log.warn("Unknown connect data type: {}", connectData.getType()); + } + } + + private void dataChangesHandle(JdbcConnectData connectData, SourceMateData sourceMateData, Payload payload) throws SQLException { + String sql; + // If the connectData requests for data changes + // Parse the data change event type from the payload + DataHandleMode dataHandleMode = convert2DataHandleMode( + DataChangeEventType.parseFromCode(connectData.getPayload().getDataChanges().getType())); + // Depending on the type of the data change event, handle INSERT, UPDATE or DELETE operations + switch (dataHandleMode) { + case INSERT: + // For INSERT event, create an insert statement and execute it + sql = this.dialectAssemblyLine.getInsertStatement(sourceMateData, connectData.getSchema(), payload.ofDdl()); + insert(sql, connectData.getSchema(), payload.ofDataChanges()); + break; + case UPDATE: + sql = this.dialectAssemblyLine.getUpdateStatement(sourceMateData, connectData.getSchema(), payload.ofDdl()); + update(sql, connectData.getSchema(), payload.ofDataChanges()); + break; + case UPSERT: + sql = this.dialectAssemblyLine.getUpsertStatement(sourceMateData, connectData.getSchema(), payload.ofDdl()); + upsert(sql, connectData.getSchema(), payload.ofDataChanges()); + break; + case DELETE: + // If support for DELETE is set, create a delete statement and execute it + if (jdbcSinkConfig.isSupportDelete()) { + sql = this.dialectAssemblyLine.getDeleteStatement(sourceMateData, connectData.getSchema(), payload.ofDdl()); + delete(sql, connectData.getSchema(), payload.ofDataChanges()); + } else { + log.warn("No support for DELETE"); + } + break; + case NONE: + log.warn("No data changes to handle"); + break; + default: + log.warn("Unknown data changes type: {}", connectData.getPayload().getDataChanges().getType()); + break; + } + } + + private void schemaChangeHandle(SourceMateData sourceMateData, Payload payload) throws SQLException { + final CatalogChanges catalogChanges = payload.ofCatalogChanges(); + final SchemaChangeEventType schemaChangeEventType = SchemaChangeEventType.ofSchemaChangeEventType(catalogChanges.getType(), + catalogChanges.getOperationType()); + if (schemaChangeEventType == SchemaChangeEventType.DATABASE_CREATE && this.eventMeshDialect.databaseExists( + catalogChanges.getCatalog().getName())) { + log.warn("Database {} already exists", catalogChanges.getCatalog().getName()); + return; + } + if (schemaChangeEventType == SchemaChangeEventType.TABLE_CREATE && this.eventMeshDialect.tableExists( + catalogChanges.getTable().getTableId())) { + log.warn("Table {} already exists", catalogChanges.getTable().getTableId()); + return; + } + // Create a SQL statement for database or table changes + String sql = this.dialectAssemblyLine.getDatabaseOrTableStatement(sourceMateData, catalogChanges, payload.ofDdl()); + // Apply the database and table changes with the created SQL statement + applyDatabaseAndTableChanges(sql); + } + + private void applyDatabaseAndTableChanges(String sql) { + Transaction transaction = session.beginTransaction(); + try { + LogUtil.debug(log, "Execute database/table sql: {}", () -> sql); + session.createNativeQuery(sql).executeUpdate(); + transaction.commit(); + } catch (Exception e) { + transaction.rollback(); + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + private void insert(String sql, Schema schema, DataChanges dataChanges) throws SQLException { + final Transaction transaction = session.beginTransaction(); + try { + if (log.isDebugEnabled()) { + log.debug("execute insert sql: {}", sql); + } + final NativeQuery query = session.createNativeQuery(sql); + AtomicInteger index = new AtomicInteger(1); + Map dataChangesAfter = (Map) dataChanges.getAfter(); + Field after = schema.getFields().get(0); + after.getFields().stream().map(field -> field.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)).forEach(column -> { + Type type = eventMeshDialect.getType(column); + final int bindValueNum = type.bindValue(index.get(), type.convert2DatabaseTypeValue(dataChangesAfter.get(column.getName())), query); + index.addAndGet(bindValueNum); + }); + final int result = query.executeUpdate(); + if (result != 1) { + throw new SQLException("Failed to insert row from table"); + } + transaction.commit(); + } catch (SQLException e) { + transaction.rollback(); + throw e; + } + } + + @SuppressWarnings("unchecked") + private void update(String sql, Schema schema, DataChanges dataChanges) throws SQLException { + final Transaction transaction = session.beginTransaction(); + try { + if (log.isDebugEnabled()) { + log.debug("execute update sql: {}", sql); + } + final NativeQuery query = session.createNativeQuery(sql); + AtomicInteger index = new AtomicInteger(1); + Map dataChangesAfter = (Map) dataChanges.getAfter(); + Field after = schema.getFields().get(0); + final Map> columnMap = after.getFields().stream().map(field -> field.getColumn()) + .collect(Collectors.toMap(Column::getName, column -> column)); + final Set keySet = schema.getKeySet(); + after.getFields().stream().map(field -> field.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)) + .filter(column -> !keySet.contains(column.getName())).forEach(column -> { + Type type = eventMeshDialect.getType(column); + int bindValueNum = type.bindValue(index.get(), type.convert2DatabaseTypeValue(dataChangesAfter.get(column.getName())), query); + index.addAndGet(bindValueNum); + }); + schema.getKeySet().stream().forEach(key -> { + if (columnMap.containsKey(key)) { + Type type = eventMeshDialect.getType(columnMap.get(key)); + final int bindValueNum = type.bindValue(index.get(), type.convert2DatabaseTypeValue(dataChangesAfter.get(key)), query); + index.addAndGet(bindValueNum); + } + }); + final int result = query.executeUpdate(); + if (result != 1) { + throw new SQLException("Failed to update row from table"); + } + transaction.commit(); + } catch (SQLException e) { + transaction.rollback(); + throw e; + } + } + + @SuppressWarnings("unchecked") + private void upsert(String sql, Schema schema, DataChanges dataChanges) throws SQLException { + final Transaction transaction = session.beginTransaction(); + try { + if (log.isDebugEnabled()) { + log.debug("execute upsert sql: {}", sql); + } + final NativeQuery query = session.createNativeQuery(sql); + AtomicInteger index = new AtomicInteger(1); + Map dataChangesAfter = (Map) dataChanges.getAfter(); + Field after = schema.getFields().get(0); + after.getFields().stream().map(field -> field.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)).forEach(column -> { + Type type = eventMeshDialect.getType(column); + final int bindValueNum = type.bindValue(index.get(), type.convert2DatabaseTypeValue(dataChangesAfter.get(column.getName())), query); + index.addAndGet(bindValueNum); + }); + final int result = query.executeUpdate(); + if (result == 0) { + throw new SQLException("Failed to update row from table"); + } + transaction.commit(); + } catch (SQLException e) { + transaction.rollback(); + throw e; + } + } + + @SuppressWarnings("unchecked") + private void delete(String sql, Schema schema, DataChanges dataChanges) throws SQLException { + final Transaction transaction = session.beginTransaction(); + + try { + LogUtil.debug(log, "execute delete sql: {}", () -> sql); + if (CollectionUtils.isEmpty(schema.getKeySet())) { + log.warn("No primary key found, skip delete"); + return; + } + final NativeQuery query = session.createNativeQuery(sql); + AtomicInteger index = new AtomicInteger(1); + Map dataChangesAfter = (Map) dataChanges.getBefore(); + final Map> columnMap = schema.getFields().get(0).getFields().stream().map(field -> field.getColumn()) + .collect(Collectors.toMap(Column::getName, column -> column)); + schema.getKeySet().stream().forEach(columnName -> { + final Column column = columnMap.get(columnName); + Type type = eventMeshDialect.getType(column); + final int bindValueNum = type.bindValue(index.get(), type.convert2DatabaseTypeValue(dataChangesAfter.get(column.getName())), query); + index.addAndGet(bindValueNum); + }); + final int result = query.executeUpdate(); + if (result != 1) { + throw new SQLException("Failed to delete row from table"); + } + transaction.commit(); + } catch (SQLException e) { + transaction.rollback(); + throw e; + } + } + + private DataHandleMode convert2DataHandleMode(DataChangeEventType type) { + + switch (type) { + case INSERT: + return DataHandleMode.INSERT; + case UPDATE: + return this.jdbcSinkConfig.isSupportUpsert() ? DataHandleMode.UPSERT : DataHandleMode.UPDATE; + case DELETE: + return this.jdbcSinkConfig.isSupportDelete() ? DataHandleMode.DELETE : DataHandleMode.NONE; + default: + return DataHandleMode.NONE; + } + } + + public enum DataHandleMode implements EnumeratedValue { + + INSERT("insert"), UPSERT("upsert"), UPDATE("update"), DELETE("delete"), NONE("none"); + + private String value; + + DataHandleMode(String value) { + this.value = value; + } + + public static DataHandleMode forValue(String value) { + for (DataHandleMode mode : DataHandleMode.values()) { + if (mode.getValue().equalsIgnoreCase(value)) { + return mode; + } + } + throw new IllegalArgumentException("No enum constant " + DataHandleMode.class.getName() + "." + value); + } + + @Override + public String getValue() { + return value; + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DialectAssemblyLine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DialectAssemblyLine.java new file mode 100644 index 0000000000..f0ca24ecb2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DialectAssemblyLine.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.handle; + +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.Schema; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; + +/** + * Represents an assembly line for transforming and generating SQL statements based on specific database dialects. + */ +public interface DialectAssemblyLine { + + /** + * Retrieves the database or table statement from the given {@code SourceMateData}, {@code CatalogChanges}, and {@code statement}. + * + * @param sourceMateData the source mate data object containing the information about the source + * @param catalogChanges the catalog changes object containing the information about the catalog changes + * @param statement the statement for which the database or table statement needs to be retrieved + * @return the database or table statement of the given {@code statement} + */ + String getDatabaseOrTableStatement(SourceMateData sourceMateData, CatalogChanges catalogChanges, String statement); + + /** + * Generates an insert statement for the given source mate data, schema, and origin statement. + * + * @param sourceMateData The source mate data of the database. + * @param schema The schema of the table. + * @param originStatement The original insert statement. + * @return The insert statement with the correct syntax for the given database and table. + */ + String getInsertStatement(SourceMateData sourceMateData, Schema schema, String originStatement); + + /** + * Generates an upsert statement using the given sourceMateData, schema, and originStatement. + * + * @param sourceMateData The metadata of the data source. + * @param schema The schema to upsert into. + * @param originStatement The original upsert statement. + * @return The upsert statement as a string. + */ + String getUpsertStatement(SourceMateData sourceMateData, Schema schema, String originStatement); + + /** + * Generates a delete statement based on the given sourceMateData, schema, and original statement. + * + * @param sourceMateData The source metadata used to generate the delete statement. + * @param schema The schema used to generate the delete statement. + * @param originStatement The original statement used as a basis for the delete statement. + * @return The generated delete statement as a string. + */ + String getDeleteStatement(SourceMateData sourceMateData, Schema schema, String originStatement); + + /** + * Generates an SQL update statement based on the provided source metadata, schema, and origin statement. + * + * @param sourceMateData The source metadata to be used for generating the update statement. + * @param schema The schema to be used for generating the update statement. + * @param originStatement The original SQL statement that needs to be updated. + * @return The generated SQL update statement as a string. + */ + String getUpdateStatement(SourceMateData sourceMateData, Schema schema, String originStatement); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DialectAssemblyLineFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DialectAssemblyLineFactory.java new file mode 100644 index 0000000000..185c201f5b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/DialectAssemblyLineFactory.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.handle; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.sink.mysql.MysqlDialectAssemblyLine; + +import org.hibernate.dialect.Dialect; + +public final class DialectAssemblyLineFactory { + + public static DialectAssemblyLine build(DatabaseDialect databaseDialect, Dialect hibernateDialect) { + switch (databaseDialect.getDatabaseType()) { + case MYSQL: + return new MysqlDialectAssemblyLine(databaseDialect, hibernateDialect); + default: + return new GeneralDialectAssemblyLine(databaseDialect, hibernateDialect); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/GeneralDialectAssemblyLine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/GeneralDialectAssemblyLine.java new file mode 100644 index 0000000000..971c8479ca --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/GeneralDialectAssemblyLine.java @@ -0,0 +1,287 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.handle; + +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.Field; +import org.apache.eventmesh.connector.jdbc.Schema; +import org.apache.eventmesh.connector.jdbc.dialect.AbstractGeneralDatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.SqlStatementAssembler; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.Table; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.type.Type; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.hibernate.dialect.Dialect; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GeneralDialectAssemblyLine implements DialectAssemblyLine { + + @Getter + private final DatabaseDialect databaseDialect; + + @Getter + private final Dialect hibernateDialect; + + public GeneralDialectAssemblyLine(DatabaseDialect databaseDialect, Dialect hibernateDialect) { + this.databaseDialect = databaseDialect; + this.hibernateDialect = hibernateDialect; + } + + @Override + public String getDatabaseOrTableStatement(SourceMateData sourceMateData, CatalogChanges catalogChanges, String statement) { + String type = catalogChanges.getType(); + String operationType = catalogChanges.getOperationType(); + SchemaChangeEventType schemaChangeEventType = SchemaChangeEventType.ofSchemaChangeEventType(type, operationType); + String sql = null; + switch (schemaChangeEventType) { + case DATABASE_CREATE: + sql = assembleCreateDatabaseSql(catalogChanges); + break; + case DATABASE_DROP: + sql = assembleDropDatabaseSql(catalogChanges); + break; + case DATABASE_ALERT: + sql = assembleAlertDatabaseSql(catalogChanges); + break; + case TABLE_CREATE: + sql = assembleCreateTableSql(catalogChanges); + break; + case TABLE_DROP: + sql = assembleDropTableSql(catalogChanges); + break; + case TABLE_ALERT: + sql = assembleAlertTableSql(catalogChanges); + break; + default: + log.warn("Type={}, OperationType={} not support", type, operationType); + } + return sql; + } + + /** + * Generates an upsert statement using the given sourceMateData, schema, and originStatement. + * + * @param sourceMateData The metadata of the data source. + * @param schema The schema to upsert into. + * @param originStatement The original upsert statement. + * @return The upsert statement as a string. + */ + @Override + public String getUpsertStatement(SourceMateData sourceMateData, Schema schema, String originStatement) { + return null; + } + + /** + * Generates a delete statement based on the given sourceMateData, schema, and original statement. + * + * @param sourceMateData The source metadata used to generate the delete statement. + * @param schema The schema used to generate the delete statement. + * @param originStatement The original statement used as a basis for the delete statement. + * @return The generated delete statement as a string. + */ + @Override + public String getDeleteStatement(SourceMateData sourceMateData, Schema schema, String originStatement) { + SqlStatementAssembler sqlStatementAssembler = new SqlStatementAssembler(); + sqlStatementAssembler.appendSqlSlice("DELETE FROM ") + .appendSqlSlice(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedTableName(sourceMateData.ofTableId())); + sqlStatementAssembler.appendSqlSlice(" WHERE "); + if (schema.containsKey()) { + sqlStatementAssembler.appendSqlSliceLists(" AND ", schema.getKeySet(), (columnName) -> columnName + " =?"); + } else { + Field after = schema.getFields().get(0); + sqlStatementAssembler.appendSqlSliceOfColumns(" AND ", + after.getFields().stream().map(field -> field.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)) + .collect(Collectors.toList()), + (column) -> column.getName() + " =?"); + } + return sqlStatementAssembler.build(); + } + + /** + * Generates an SQL update statement based on the provided source metadata, schema, and origin statement. + * + * @param sourceMateData The source metadata to be used for generating the update statement. + * @param schema The schema to be used for generating the update statement. + * @param originStatement The original SQL statement that needs to be updated. + * @return The generated SQL update statement as a string. + */ + @Override + public String getUpdateStatement(SourceMateData sourceMateData, Schema schema, String originStatement) { + final SqlStatementAssembler sqlStatementAssembler = new SqlStatementAssembler(); + final TableId tableId = sourceMateData.ofTableId(); + // primary key set + final Set keySet = schema.getKeySet(); + Field tableColumns = schema.getFields().get(0); + sqlStatementAssembler.appendSqlSlice("UPDATE "); + sqlStatementAssembler.appendSqlSlice(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedTableName(tableId)); + sqlStatementAssembler.appendSqlSlice(" SET "); + sqlStatementAssembler.appendSqlSliceLists(", ", + tableColumns.getFields().stream().map(Field::getColumn).sorted(Comparator.comparingInt(Column::getOrder)) + .filter(column -> !keySet.contains(column.getName())).map(column -> column.getName()).collect(Collectors.toList()), + (columnName) -> columnName + " =?"); + if (schema.containsKey()) { + sqlStatementAssembler.appendSqlSlice(" WHERE "); + sqlStatementAssembler.appendSqlSliceLists(" AND ", keySet, (columnName) -> columnName + " =?"); + } else { + sqlStatementAssembler.appendSqlSlice(" WHERE "); + sqlStatementAssembler.appendSqlSliceOfColumns(" AND ", + tableColumns.getFields().stream().map(field -> field.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)) + .collect(Collectors.toList()), + column -> column.getName() + " =?"); + } + return sqlStatementAssembler.build(); + } + + @Override + public String getInsertStatement(SourceMateData sourceMateData, Schema schema, String originStatement) { + final TableId tableId = sourceMateData.ofTableId(); + + List afterFields = schema.getFields().stream().filter(field -> StringUtils.equals(field.getField(), "after")) + .collect(Collectors.toList()); + + final SqlStatementAssembler sqlAssembler = new SqlStatementAssembler(); + sqlAssembler.appendSqlSlice("INSERT INTO "); + sqlAssembler.appendSqlSlice(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedTableName(tableId)); + sqlAssembler.appendSqlSlice(" ("); + // assemble columns + Field afterField = afterFields.get(0); + List> columns = afterField.getFields().stream().map(item -> item.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)) + .collect(Collectors.toList()); + sqlAssembler.appendSqlSliceOfColumns(", ", columns, column -> column.getName()); + sqlAssembler.appendSqlSlice(") VALUES ("); + // assemble values + sqlAssembler.appendSqlSliceOfColumns(", ", columns, column -> getDmlBindingValue(column)); + sqlAssembler.appendSqlSlice(")"); + + return sqlAssembler.build(); + } + + private String getDmlBindingValue(Column column) { + Type type = this.databaseDialect.getType(column); + if (type == null) { + return this.databaseDialect.getQueryBindingWithValueCast(column); + } + return type.getQueryBindingWithValue(this.databaseDialect, column); + } + + private String assembleCreateDatabaseSql(CatalogChanges catalogChanges) { + SqlStatementAssembler assembler = new SqlStatementAssembler(); + assembler.appendSqlSlice("CREATE DATABASE IF NOT EXISTS "); + assembler.appendSqlSlice(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedText(catalogChanges.getCatalog().getName())); + return assembler.build(); + } + + private String assembleDropDatabaseSql(CatalogChanges catalogChanges) { + SqlStatementAssembler assembler = new SqlStatementAssembler(); + assembler.appendSqlSlice("DROP DATABASE IF EXISTS "); + assembler.appendSqlSlice(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedText(catalogChanges.getCatalog().getName())); + return assembler.build(); + } + + private String assembleAlertDatabaseSql(CatalogChanges catalogChanges) { + SqlStatementAssembler assembler = new SqlStatementAssembler(); + // todo + return assembler.build(); + } + + private String assembleCreateTableSql(CatalogChanges catalogChanges) { + SqlStatementAssembler assembler = new SqlStatementAssembler(); + assembler.appendSqlSlice("CREATE TABLE IF NOT EXISTS "); + Table table = catalogChanges.getTable(); + assembler.appendSqlSlice(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedTableName(table.getTableId())); + assembler.appendSqlSlice(" ("); + // assemble columns + List columns = catalogChanges.getColumns().stream().sorted(Comparator.comparingInt(Column::getOrder)) + .collect(Collectors.toList()); + List columnNames = columns.stream().map(item -> item.getName()).collect(Collectors.toList()); + Map columnMap = columns.stream().collect(Collectors.toMap(Column::getName, item -> item)); + assembler.appendSqlSliceLists(", ", columnNames, (columnName) -> { + StringBuilder builder = new StringBuilder(); + // assemble column name + builder.append(((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedText(columnName)); + // assemble column type + Column column = columnMap.get(columnName); + String typeName = this.databaseDialect.getTypeName(hibernateDialect, column); + builder.append(" ").append(typeName); + + builder.append(" ").append(this.databaseDialect.getCharsetOrCollateFormatted(column)); + if (Optional.ofNullable(table.getPrimaryKey().getColumnNames()).orElse(new ArrayList<>(0)).contains(columnName)) { + builder.append(" NOT NULL "); + if (column.isAutoIncremented()) { + builder.append(this.databaseDialect.getAutoIncrementFormatted(column)); + } + } else { + if (column.isNotNull()) { + builder.append(" NOT NULL "); + } + } + addColumnDefaultValue(column, builder); + builder.append(" ").append(this.databaseDialect.getCommentFormatted(column)); + // assemble column default value + return builder.toString(); + }); + // assemble primary key and others key + assembler.appendSqlSlice(", PRIMARY KEY("); + assembler.appendSqlSliceLists(",", catalogChanges.getTable().getPrimaryKey().getColumnNames(), + (columnName) -> ((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedText(columnName)); + assembler.appendSqlSlice(")"); + assembler.appendSqlSlice(")"); + assembler.appendSqlSlice(this.databaseDialect.getTableOptionsFormatted(catalogChanges.getTable())); + return assembler.build(); + } + + private void addColumnDefaultValue(Column column, StringBuilder builder) { + if (column.isNotNull() && column.getDefaultValue() == null) { + return; + } + final String defaultValueFormatted = this.databaseDialect.getDefaultValueFormatted(column); + if (StringUtils.isNotEmpty(defaultValueFormatted)) { + builder.append(" DEFAULT ").append(defaultValueFormatted); + } + } + + private String assembleDropTableSql(CatalogChanges catalogChanges) { + SqlStatementAssembler assembler = new SqlStatementAssembler(); + assembler.appendSqlSlice("DROP TABLE IF EXISTS "); + assembler.appendSqlSlice( + ((AbstractGeneralDatabaseDialect) databaseDialect).getQualifiedTableName(catalogChanges.getTable().getTableId())); + return assembler.build(); + } + + private String assembleAlertTableSql(CatalogChanges catalogChanges) { + SqlStatementAssembler assembler = new SqlStatementAssembler(); + return assembler.build(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/SinkRecordHandler.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/SinkRecordHandler.java new file mode 100644 index 0000000000..fa6a5b841c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/handle/SinkRecordHandler.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.handle; + +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; + +/** + * This interface represents a schema change handler. + */ +public interface SinkRecordHandler { + + /** + * Handles a schema change using the specified JDBC connection data. + * + * @param connectData the JDBC connection data + */ + void handle(JdbcConnectData connectData) throws Exception; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/hibernate/DruidConnectionProvider.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/hibernate/DruidConnectionProvider.java new file mode 100644 index 0000000000..e261978b7a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/hibernate/DruidConnectionProvider.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.hibernate; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +import org.hibernate.HibernateException; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.service.spi.Configurable; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidDataSourceFactory; + +public class DruidConnectionProvider implements ConnectionProvider, Configurable { + + private DruidDataSource dataSource = new DruidDataSource(); + + /** + * Obtains a connection for Hibernate use according to the underlying strategy of this provider. + * + * @return The obtained JDBC connection + * @throws SQLException Indicates a problem opening a connection + * @throws HibernateException Indicates a problem otherwise obtaining a connection. + */ + @Override + public Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + /** + * Release a connection from Hibernate use. + * + * @param conn The JDBC connection to release + * @throws SQLException Indicates a problem closing the connection + * @throws HibernateException Indicates a problem otherwise releasing a connection. + */ + @Override + public void closeConnection(Connection conn) throws SQLException { + conn.close(); + } + + /** + *

+ * Does this connection provider support aggressive release of JDBC connections and re-acquisition of those connections (if need be) later? + *

+ *

+ * This is used in conjunction with {@link Environment#RELEASE_CONNECTIONS} to aggressively release JDBC connections. However, the configured + * ConnectionProvider must support re-acquisition of the same underlying connection for that semantic to work. + *

+ * Typically, this is only true in managed environments where a container tracks connections by transaction or thread. + *

+ * Note that JTA semantic depends on the fact that the underlying connection provider does support aggressive release. + *

+ * @return {@code true} if aggressive releasing is supported; {@code false} otherwise. + */ + @Override + public boolean supportsAggressiveRelease() { + return false; + } + + /** + * Configure the service. + * + * @param configurationValues The configuration properties. + */ + @Override + public void configure(Map configurationValues) { + try { + DruidDataSourceFactory.config(dataSource, configurationValues); + } catch (SQLException e) { + throw new IllegalArgumentException("Config druid error", e); + } + } + + /** + * Can this wrapped service be unwrapped as the indicated type? + * + * @param unwrapType The type to check. + * @return True/false. + */ + @Override + public boolean isUnwrappableAs(Class unwrapType) { + return dataSource.isWrapperFor(unwrapType); + } + + /** + * Unproxy the service proxy + * + * @param unwrapType The java type as which to unwrap this instance. + * @return The unwrapped reference + */ + @Override + public T unwrap(Class unwrapType) { + return dataSource.unwrap(unwrapType); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/hibernate/HibernateConfiguration.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/hibernate/HibernateConfiguration.java new file mode 100644 index 0000000000..fd5d49de74 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/hibernate/HibernateConfiguration.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.hibernate; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.service.ServiceRegistry; + +public final class HibernateConfiguration { + + public static HibernateConfigurationBuilder newBuilder() { + return new HibernateConfigurationBuilder(); + } + + public static class HibernateConfigurationBuilder { + + private Configuration configuration; + + public HibernateConfigurationBuilder() { + this.configuration = new Configuration(); + this.configuration.setProperty("hibernate.connection.provider_class", DruidConnectionProvider.class.getName()); + } + + public HibernateConfigurationBuilder withUser(String username) { + configuration.setProperty("username", username); + return this; + } + + public HibernateConfigurationBuilder withPassword(String password) { + configuration.setProperty("password", password); + return this; + } + + public HibernateConfigurationBuilder withUrl(String url) { + configuration.setProperty("url", url); + return this; + } + + public HibernateConfigurationBuilder withDruidMaxActive(String maxActive) { + configuration.setProperty("maxActive", maxActive); + return this; + } + + public HibernateConfigurationBuilder withShowSql(boolean showSql) { + configuration.setProperty("hibernate.show_sql", Boolean.toString(showSql)); + return this; + } + + public SessionFactory build() { + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()) + .build(); + return configuration.buildSessionFactory(serviceRegistry); + } + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/mysql/MysqlDialectAssemblyLine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/mysql/MysqlDialectAssemblyLine.java new file mode 100644 index 0000000000..670a2d0258 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/sink/mysql/MysqlDialectAssemblyLine.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.sink.mysql; + +import org.apache.eventmesh.connector.jdbc.Field; +import org.apache.eventmesh.connector.jdbc.Schema; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.SqlStatementAssembler; +import org.apache.eventmesh.connector.jdbc.sink.handle.GeneralDialectAssemblyLine; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import org.hibernate.dialect.Dialect; + +public class MysqlDialectAssemblyLine extends GeneralDialectAssemblyLine { + + public MysqlDialectAssemblyLine(DatabaseDialect databaseDialect, Dialect hibernateDialect) { + super(databaseDialect, hibernateDialect); + } + + /** + * Generates an upsert statement using the given sourceMateData, schema, and originStatement. + * + * @param sourceMateData The metadata of the data source. + * @param schema The schema to upsert into. + * @param originStatement The original upsert statement. + * @return The upsert statement as a string. + */ + @Override + public String getUpsertStatement(SourceMateData sourceMateData, Schema schema, String originStatement) { + final SqlStatementAssembler sqlStatementAssembler = new SqlStatementAssembler(); + sqlStatementAssembler.appendSqlSlice(getInsertStatement(sourceMateData, schema, originStatement)); + Field afterField = schema.getFields().get(0); + List> columns = afterField.getFields().stream().map(item -> item.getColumn()).sorted(Comparator.comparingInt(Column::getOrder)) + .collect(Collectors.toList()); + if (JdbcStringUtils.compareVersion(getDatabaseDialect().getJdbcDriverMetaData().getDatabaseProductVersion(), "8.0.20") >= 0) { + // mysql doc:https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html + // Beginning with MySQL 8.0.20, an INSERT ... SELECT ... ON DUPLICATE KEY UPDATE statement that uses VALUES() in the UPDATE clause + sqlStatementAssembler.appendSqlSlice("AS new ON DUPLICATE KEY UPDATE "); + sqlStatementAssembler.appendSqlSliceOfColumns(",", columns, column -> { + final String columnName = column.getName(); + return columnName + "=new." + columnName; + }); + + } else { + sqlStatementAssembler.appendSqlSlice(" ON DUPLICATE KEY UPDATE "); + sqlStatementAssembler.appendSqlSliceOfColumns(",", columns, column -> { + final String columnName = column.getName(); + return columnName + "=VALUES(" + columnName + ")"; + }); + + } + return sqlStatementAssembler.build(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEngine.java new file mode 100644 index 0000000000..2088e75632 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEngine.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.ThreadWrapper; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.SourceConnectorConfig; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import org.apache.commons.collections4.CollectionUtils; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractEngine extends ThreadWrapper implements Engine { + + private final Set includeDatabaseTable = new HashSet<>(64); + + protected final JdbcSourceConfig jdbcSourceConfig; + + protected final SourceConnectorConfig sourceConnectorConfig; + + protected final DbDialect databaseDialect; + + public AbstractEngine(JdbcSourceConfig jdbcSourceConfig, DbDialect databaseDialect) { + this.jdbcSourceConfig = jdbcSourceConfig; + this.sourceConnectorConfig = this.jdbcSourceConfig.getSourceConnectorConfig(); + this.databaseDialect = databaseDialect; + + calculateNeedHandleTable(); + } + + @Override + public Set getHandledTables() { + return includeDatabaseTable; + } + + protected Set calculateNeedHandleTable() { + // Get the database and table include and exclude lists from the connector configuration + List databaseIncludeList = sourceConnectorConfig.getDatabaseIncludeList(); + + // If the database include list is empty, get a list of all databases and use that as the include list + if (CollectionUtils.isEmpty(databaseIncludeList)) { + List allDatabases = databaseDialect.listDatabases(); + databaseIncludeList = new ArrayList<>(allDatabases); + } + Set defaultExcludeDatabase = defaultExcludeDatabase(); + if (CollectionUtils.isNotEmpty(defaultExcludeDatabase)) { + databaseIncludeList.removeAll(defaultExcludeDatabase); + } + + List databaseExcludeList = sourceConnectorConfig.getDatabaseExcludeList(); + // Remove the default excluded databases from the include list + if (CollectionUtils.isNotEmpty(databaseExcludeList)) { + databaseIncludeList.removeAll(databaseExcludeList); + } + + List tableIncludeList = sourceConnectorConfig.getTableIncludeList(); + // Create a list of included tables based on the table include list + List includeTableList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(tableIncludeList)) { + List tableIdList = buildTableId(tableIncludeList); + includeTableList.addAll(tableIdList); + } + + // If the table include list is empty, get a list of all tables for each database in the include list + if (CollectionUtils.isEmpty(tableIncludeList)) { + for (String database : databaseIncludeList) { + try { + List tableIds = databaseDialect.listTables(database); + includeTableList.addAll(tableIds); + } catch (SQLException e) { + log.warn("List database[{}] table error", database, e); + } + } + } + + List tableExcludeList = sourceConnectorConfig.getTableExcludeList(); + // Remove any tables in the exclude list from the included tables list + if (CollectionUtils.isNotEmpty(tableExcludeList)) { + includeTableList.removeAll(buildTableId(tableExcludeList)); + } + + includeDatabaseTable.addAll(includeTableList); + + return includeDatabaseTable; + } + + private List buildTableId(List tables) { + return Optional.ofNullable(tables).orElse(new ArrayList<>(0)).stream().map(table -> { + String[] split = table.split("\\."); + return new TableId(split[0], null, split[1]); + }).collect(Collectors.toList()); + } + + protected abstract Set defaultExcludeDatabase(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEventMeshJdbcEventTask.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEventMeshJdbcEventTask.java new file mode 100644 index 0000000000..3f7301fa7a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEventMeshJdbcEventTask.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.ThreadWrapper; +import org.apache.eventmesh.connector.jdbc.event.Event; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public abstract class AbstractEventMeshJdbcEventTask extends ThreadWrapper implements EventMeshJdbcEventTask { + + protected BlockingQueue eventBlockingQueue = new LinkedBlockingQueue<>(10000); + + @Override + public void shutdown() { + super.shutdown(); + } + + @Override + public void close() throws Exception { + shutdown(); + } + + @Override + public void put(Event event) throws InterruptedException { + eventBlockingQueue.put(event); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEventMeshJdbcTask.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEventMeshJdbcTask.java new file mode 100644 index 0000000000..536ef5d18e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractEventMeshJdbcTask.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.ThreadWrapper; + +public abstract class AbstractEventMeshJdbcTask extends ThreadWrapper implements EventMeshJdbcTask { + + @Override + public void shutdown() { + super.shutdown(); + } + + @Override + public void close() throws Exception { + shutdown(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractJdbcTaskManager.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractJdbcTaskManager.java new file mode 100644 index 0000000000..ff2fd8ba00 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/AbstractJdbcTaskManager.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class AbstractJdbcTaskManager implements JdbcTaskManager { + + protected Map tableIdJdbcTaskMap = new ConcurrentHashMap<>(); + + protected Set includeDatabaseTable; + + protected JdbcSourceConfig jdbcSourceConfig; + + protected List taskList = new ArrayList<>(128); + + protected List listeners = new ArrayList<>(16); + + @Override + public void start() { + taskList.forEach(EventMeshJdbcTask::start); + } + + @Override + public void shutdown() { + taskList.forEach(EventMeshJdbcTask::shutdown); + } + + @Override + public void close() throws Exception { + shutdown(); + } + + @Override + public void registerListener(TaskManagerListener listener) { + if (!Objects.isNull(listener)) { + listeners.add(listener); + } + } + + public abstract Task select(TableId tableId); +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/Engine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/Engine.java new file mode 100644 index 0000000000..fa2cc73b4a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/Engine.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import java.util.Set; + +/** + * Engine interface represents the core engine + */ +public interface Engine { + + /** + * Initializes the engine. + */ + void init(); + + /** + * Starts the engine. + */ + void start(); + + /** + * Retrieves the set of TableId objects representing the tables that the engine handles. + * + * @return The set of handled TableId objects. + */ + Set getHandledTables(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventDispatcher.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventDispatcher.java new file mode 100644 index 0000000000..17e59335eb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventDispatcher.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventDispatcher { + + private SourceJdbcTaskManager sourceJdbcTaskManager; + + public EventDispatcher(SourceJdbcTaskManager sourceJdbcTaskManager) { + this.sourceJdbcTaskManager = sourceJdbcTaskManager; + } + + /** + * Dispatch CDC events. + * + * @param event The CDC event to be dispatched. + */ + public void dispatch(Event event) { + TableId tableId = event.getTableId(); + SourceEventMeshJdbcEventTask task = sourceJdbcTaskManager.select(tableId); + try { + // Put the CDC event into the selected JDBC task. + task.put(event); + } catch (InterruptedException e) { + log.warn("Dispatch CdcEvent error", e); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventMeshJdbcEventTask.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventMeshJdbcEventTask.java new file mode 100644 index 0000000000..95294f3eae --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventMeshJdbcEventTask.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.event.EventHandler; + +/** + * The EventMeshJdbcTask interface represents a task that interacts with the EventMesh through a JDBC connection. It extends the AutoCloseable + * interface, allowing the task to be managed efficiently. + */ +public interface EventMeshJdbcEventTask extends EventMeshJdbcTask { + + /** + * Puts an event into the task for processing. + * + * @param event The event to be processed. + * @throws InterruptedException If the operation is interrupted while waiting to put the event. + */ + void put(E event) throws InterruptedException; + + /** + * Registers a snapshot event handler to be executed when snapshot events occur. + * + * @param handler The SnapshotEventHandler to be registered. + */ + void registerEventHandler(EventHandler handler); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventMeshJdbcTask.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventMeshJdbcTask.java new file mode 100644 index 0000000000..c54d9e4d2f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/EventMeshJdbcTask.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +/** + * The EventMeshJdbcTask interface represents a task that interacts with the EventMesh through a JDBC connection. It extends the AutoCloseable + * interface, allowing the task to be managed efficiently. + */ +public interface EventMeshJdbcTask extends AutoCloseable { + + /** + * Starts the EventMesh JDBC task, initializing any necessary resources or connections. + */ + void start(); + + /** + * Shuts down the EventMesh JDBC task, releasing any acquired resources or connections. + */ + void shutdown(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcAllFactoryLoader.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcAllFactoryLoader.java new file mode 100644 index 0000000000..2529d9a5a8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcAllFactoryLoader.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngineFactory; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngineFactory; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.Objects; + +import lombok.experimental.UtilityClass; + +/** + * Get a CdcEngineFactory for a given database name + */ +@UtilityClass +public class JdbcAllFactoryLoader { + + /** + * Returns a CdcEngineFactory for the given database name. + *

Throws NullPointerException if databaseName is null.

+ *

Throws IllegalArgumentException if CdcEngineFactory is not supported for the given database name.

+ * + * @param databaseName Name of the database for which CdcEngineFactory is required. + * @return CdcEngineFactory for the given database name. + */ + public static CdcEngineFactory getCdcEngineFactory(String databaseName) { + checkNotNull(databaseName, "database name can not be null"); + CdcEngineFactory engineFactory = EventMeshExtensionFactory.getExtension(CdcEngineFactory.class, databaseName); + return checkNotNull(engineFactory, "CdcEngineFactory: " + databaseName + " is not supported"); + } + + /** + * Returns a DatabaseDialectFactory based on the specified database name. + * + * @param databaseName the name of the database + * @return the DatabaseDialectFactory for the specified database name + * @throws NullPointerException if the database name is null + * @throws IllegalArgumentException if the specified database name is not supported + */ + public static DatabaseDialectFactory getDatabaseDialectFactory(String databaseName) { + Objects.requireNonNull(databaseName, "database name can not be null"); + DatabaseDialectFactory databaseDialectFactory = EventMeshExtensionFactory.getExtension(DatabaseDialectFactory.class, databaseName); + Objects.requireNonNull(databaseDialectFactory, "DatabaseDialectFactory: " + databaseName + " is not supported"); + return databaseDialectFactory; + } + + public static SnapshotEngineFactory getSnapshotEngineFactory(String databaseName) { + Objects.requireNonNull(databaseName, "database name can not be null"); + SnapshotEngineFactory databaseDialectFactory = EventMeshExtensionFactory.getExtension(SnapshotEngineFactory.class, databaseName); + Objects.requireNonNull(databaseDialectFactory, "SnapshotEngineFactory: " + databaseName + " is not supported"); + return databaseDialectFactory; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcSourceConnector.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcSourceConnector.java new file mode 100644 index 0000000000..ecc5a44154 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcSourceConnector.java @@ -0,0 +1,216 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory; +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngine; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngineFactory; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngine; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngineFactory; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotResult; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotResult.SnapshotResultStatus; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnector; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; +import java.util.Set; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class JdbcSourceConnector extends SourceConnector { + + private DatabaseDialect databaseDialect; + + private CdcEngine cdcEngine; + + private JdbcSourceConfig sourceConfig; + + private EventDispatcher dispatcher; + + private SourceJdbcTaskManager sourceJdbcTaskManager; + + private SnapshotEngine snapshotEngine; + + private TaskManagerCoordinator taskManagerCoordinator; + + public JdbcSourceConnector() { + this(null); + } + + protected JdbcSourceConnector(SourceConfig sourceConfig) { + super(sourceConfig); + } + + /** + * Returns the class type of the configuration for this Connector. + * + * @return Class type of the configuration + */ + @Override + public Class configClass() { + return JdbcSourceConfig.class; + } + + /** + * Initializes the Connector with the provided configuration. + * + * @param config Configuration object + * @throws Exception if initialization fails + */ + @Override + public void init(Config config) throws Exception { + + if (!(config instanceof JdbcSourceConfig)) { + throw new IllegalArgumentException("Config not be JdbcSourceConfig"); + } + this.sourceConfig = (JdbcSourceConfig) config; + doInit(); + } + + /** + * Initializes the Connector with the provided context. + * + * @param connectorContext connectorContext + * @throws Exception if initialization fails + */ + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (JdbcSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + String databaseType = this.sourceConfig.getSourceConnectorConfig().getDatabaseType(); + + // Get the database dialect factory and create the database dialect. + final DatabaseDialectFactory databaseDialectFactory = JdbcAllFactoryLoader.getDatabaseDialectFactory(databaseType); + this.databaseDialect = databaseDialectFactory.createDatabaseDialect(this.sourceConfig.getSourceConnectorConfig().getJdbcConfig()); + this.databaseDialect.init(); + + // Get the snapshot engine factory and create the snapshot engine + final SnapshotEngineFactory snapshotEngineFactory = JdbcAllFactoryLoader.getSnapshotEngineFactory(databaseType); + this.snapshotEngine = snapshotEngineFactory.createSnapshotEngine(this.sourceConfig, this.databaseDialect); + this.snapshotEngine.registerSnapshotEventConsumer(this::eventConsumer); + this.snapshotEngine.init(); + + // Get the CDC engine factory and create the CDC engine. + final CdcEngineFactory cdcEngineFactory = JdbcAllFactoryLoader.getCdcEngineFactory(databaseType); + // Check if the CDC engine factory supports the JDBC protocol. + if (!cdcEngineFactory.acceptJdbcProtocol(this.databaseDialect.jdbcProtocol())) { + throw new IllegalArgumentException("CdcEngineFactory not supports " + databaseType); + } + // Set the CDC engine and register the CDC event consumer. + this.cdcEngine = cdcEngineFactory.createCdcEngine(this.sourceConfig, this.databaseDialect); + if (CollectionUtils.isEmpty(this.cdcEngine.getHandledTables())) { + throw new RuntimeException("No database tables need to be processed"); + } + this.cdcEngine.registerCdcEventConsumer(this::eventConsumer); + this.cdcEngine.init(); + + Set handledTables = this.snapshotEngine.getHandledTables(); + + // Create the task manager and dispatcher. + this.sourceJdbcTaskManager = new SourceJdbcTaskManager(handledTables, this.sourceConfig); + this.sourceJdbcTaskManager.init(); + + this.dispatcher = new EventDispatcher(this.sourceJdbcTaskManager); + + this.taskManagerCoordinator = new TaskManagerCoordinator(sourceConfig.getPollConfig().getCapacity(), + sourceConfig.getPollConfig().getMaxBatchSize(), + sourceConfig.getPollConfig().getMaxWaitTime()); + this.taskManagerCoordinator.registerTaskManager(SourceJdbcTaskManager.class.getName(), sourceJdbcTaskManager); + this.taskManagerCoordinator.init(); + } + + private void eventConsumer(Event event) { + this.dispatcher.dispatch(event); + } + + /** + * Starts the Connector. + * + * @throws Exception if the start operation fails + */ + @Override + @SuppressWarnings("unchecked") + public void start() throws Exception { + this.databaseDialect.start(); + this.taskManagerCoordinator.start(); + this.snapshotEngine.start(); + SnapshotResult result = this.snapshotEngine.execute(); + this.snapshotEngine.close(); + // success and skip status can run cdc engine + if (result.getStatus() != SnapshotResultStatus.ABORTED) { + log.info("Start Cdc Engine to handle cdc event"); + this.cdcEngine.setContext(result.getContext()); + this.cdcEngine.start(); + } + } + + /** + * Commits the specified ConnectRecord object. + * + * @param record ConnectRecord object to commit + */ + @Override + public void commit(ConnectRecord record) { + + } + + /** + * Returns the name of the Connector. + * + * @return String name of the Connector + */ + @Override + public String name() { + return "JDBC Source Connector"; + } + + @Override + public void onException(ConnectRecord record) { + + } + + /** + * Stops the Connector. + * + * @throws Exception if stopping fails + */ + @Override + public void stop() throws Exception { + + } + + @Override + public List poll() { + return this.taskManagerCoordinator.poll(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcTaskManager.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcTaskManager.java new file mode 100644 index 0000000000..a7d3c5000e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/JdbcTaskManager.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +/** + * The JdbcTaskManager interface represents a manager for JDBC tasks. It extends the AutoCloseable interface, allowing the manager to be managed + * efficiently. + */ +public interface JdbcTaskManager extends AutoCloseable { + + /** + * Initializes the JDBC task manager, setting up any required configurations or resources. + */ + void init(); + + /** + * Starts the JDBC task manager, allowing it to begin managing tasks. + */ + void start(); + + /** + * Shuts down the JDBC task manager, releasing any acquired resources or stopping task management. + */ + void shutdown(); + + /** + * Registers a listener to receive events and notifications from the JDBC task manager. + * + * @param listener The listener to be registered. + */ + void registerListener(TaskManagerListener listener); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceEventMeshJdbcEventTask.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceEventMeshJdbcEventTask.java new file mode 100644 index 0000000000..0daa641cc6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceEventMeshJdbcEventTask.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.event.EventHandler; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class SourceEventMeshJdbcEventTask extends AbstractEventMeshJdbcEventTask { + + private final String taskName; + + private EventHandler eventHandler; + + public SourceEventMeshJdbcEventTask(String taskName) { + this.taskName = taskName; + + } + + @Override + public String getThreadName() { + return taskName; + } + + /** + * When an object implementing interface Runnable is used to create a thread, starting the thread causes the object's + * run method to be called in that separately executing + * thread. + *

+ * The general contract of the method run is that it may take any action whatsoever. + * + * @see Thread#run() + */ + @Override + public void run() { + while (isRunning) { + try { + Event event = eventBlockingQueue.poll(5, TimeUnit.SECONDS); + if (Objects.isNull(event)) { + continue; + } + eventHandler.handle(event); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + /** + * Registers a snapshot event handler to be executed when snapshot events occur. + * + * @param handler The SnapshotEventHandler to be registered. + */ + @Override + public void registerEventHandler(EventHandler handler) { + this.eventHandler = handler; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceJdbcTaskManager.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceJdbcTaskManager.java new file mode 100644 index 0000000000..0625dbfad7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceJdbcTaskManager.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.jdbc.JdbcRecordOffset; +import org.apache.eventmesh.common.remote.offset.jdbc.JdbcRecordPartition; +import org.apache.eventmesh.connector.jdbc.JdbcConnectData; +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.RandomTaskSelectStrategy; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.TaskSelectStrategy; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SourceJdbcTaskManager extends AbstractJdbcTaskManager { + + private final Set includeDatabaseTable; + + private final JdbcSourceConfig jdbcSourceConfig; + + private TaskSelectStrategy cdcTaskSelectStrategy; + + public SourceJdbcTaskManager(Set includeDatabaseTable, JdbcSourceConfig jdbcSourceConfig) { + this.jdbcSourceConfig = jdbcSourceConfig; + this.includeDatabaseTable = includeDatabaseTable == null ? new HashSet<>() : includeDatabaseTable; + } + + @SuppressWarnings("unchecked") + public void init() { + // init Jdbc Task + int maxTaskNum = this.jdbcSourceConfig.getSourceConnectorConfig().getMaxTask(); + int taskNum = Math.min(maxTaskNum, this.includeDatabaseTable.size()); + log.info("Source jdbc task num {}", taskNum); + for (int index = 0; index < taskNum; ++index) { + SourceEventMeshJdbcEventTask eventTask = new SourceEventMeshJdbcEventTask("source-jdbc-task-" + (index + 1)); + eventTask.registerEventHandler(this::doHandleEvent); + taskList.add(eventTask); + } + cdcTaskSelectStrategy = new RandomTaskSelectStrategy(taskList); + + } + + private void doHandleEvent(Event event) { + if (event == null) { + return; + } + JdbcConnectData jdbcConnectData = event.getJdbcConnectData(); + RecordPartition partition = new JdbcRecordPartition(); + RecordOffset offset = new JdbcRecordOffset(); + ConnectRecord record = new ConnectRecord(partition, offset, System.currentTimeMillis(), jdbcConnectData); + List records = Collections.singletonList(record); + for (TaskManagerListener listener : listeners) { + listener.listen(records); + } + } + + @Override + public SourceEventMeshJdbcEventTask select(TableId tableId) { + return tableIdJdbcTaskMap.computeIfAbsent(tableId, key -> cdcTaskSelectStrategy.select(tableId)); + } + + public int getTaskCount() { + return tableIdJdbcTaskMap.size(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceMateData.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceMateData.java new file mode 100644 index 0000000000..bf12a36d97 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/SourceMateData.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlSourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import lombok.Data; + +/** + * Represents metadata related to a data source. + */ +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "connector") +@JsonSubTypes({@JsonSubTypes.Type(value = MysqlSourceMateData.class, name = "mysql")}) +public class SourceMateData { + + /** + * The connector used for the connector source. e.g: mysql, oracle etc. + */ + private String connector; + + /** + * The name of the connector source. + */ + private String name; + + /** + * The timestamp when the metadata was captured. + */ + private long timestamp; + + /** + * Flag indicating whether this metadata belongs to a snapshot. + */ + private boolean snapshot; + + /** + * The catalog name associated with the connector source. + */ + private String catalogName; + + /** + * The schema name associated with the connector source. + */ + private String schemaName; + + /** + * The table name associated with the connector source. + */ + private String tableName; + + /** + * This method returns the TableId object with the specified catalog name, schema name, and table name. + * + * @return the TableId object + */ + public TableId ofTableId() { + return new TableId(catalogName, schemaName, tableName); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/TaskManagerCoordinator.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/TaskManagerCoordinator.java new file mode 100644 index 0000000000..8efb8cbc71 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/TaskManagerCoordinator.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +/** + * The TaskManagerCoordinator is responsible for coordinating multiple JDBC task managers and managing the processing of ConnectRecords. It provides + * methods for registering task managers, initializing them, and starting their processing. + */ +@Slf4j +public class TaskManagerCoordinator { + + private final BlockingQueue recordBlockingQueue; + private final Map taskManagerCache = new HashMap<>(8); + private final int maxBatchSize; + private final long maxPollTimeout; + + + public TaskManagerCoordinator(int capacity, int maxBatchSize, long maxPollTimeout) { + this.recordBlockingQueue = new LinkedBlockingQueue<>(capacity); + this.maxBatchSize = maxBatchSize; + this.maxPollTimeout = maxPollTimeout; + } + + /** + * Registers a JDBC task manager with the given name. + * + * @param name The name of the task manager. + * @param taskManager The JDBC task manager to register. + */ + public void registerTaskManager(String name, JdbcTaskManager taskManager) { + taskManagerCache.put(name, taskManager); + } + + /** + * Initializes all registered JDBC task managers. + */ + public void init() { + taskManagerCache.values().forEach(JdbcTaskManager::init); + + // Register a listener on each task manager to process incoming records and add them to the blocking queue. + taskManagerCache.values().forEach(taskManager -> taskManager.registerListener(records -> { + if (CollectionUtils.isEmpty(records)) { + return; + } + records.forEach(record -> { + try { + recordBlockingQueue.put(record); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + })); + } + + /** + * Starts the processing of all registered JDBC task managers. + */ + public void start() { + taskManagerCache.values().forEach(JdbcTaskManager::start); + } + + /** + * Polls for a batch of ConnectRecords from the blocking queue. + * + * @return A list of ConnectRecords, up to the maximum batch size defined by BATCH_MAX. + */ + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollTimeout; + + List records = new ArrayList<>(maxBatchSize); + for (int index = 0; index < maxBatchSize; ++index) { + try { + ConnectRecord record = recordBlockingQueue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (Objects.isNull(record)) { + break; + } + if (log.isDebugEnabled()) { + log.debug("record:{}", JsonUtils.toJSONString(record)); + } + records.add(record); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollTimeout > elapsedTime ? maxPollTimeout - elapsedTime : 0; + } catch (InterruptedException e) { + break; + } + } + return records; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/TaskManagerListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/TaskManagerListener.java new file mode 100644 index 0000000000..abfbfcc5d6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/TaskManagerListener.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source; + +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +/** + * The TaskManagerListener is a functional interface used to listen for events from the TaskManager. It defines a single method, "listen", that takes + * a list of ConnectRecord objects as its parameter. + */ +@FunctionalInterface +public interface TaskManagerListener { + + /** + * Listens for events from the TaskManager and processes the given list of ConnectRecords. + * + * @param records The list of ConnectRecord objects to be processed. + */ + void listen(List records); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/MysqlAntlr4DdlParser.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/MysqlAntlr4DdlParser.java new file mode 100644 index 0000000000..261da6192b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/MysqlAntlr4DdlParser.java @@ -0,0 +1,180 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.connector.jdbc.antlr4.Antlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlLexer; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CharsetNameContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CollationNameContext; +import org.apache.eventmesh.connector.jdbc.antlr4.listener.Antlr4DdlParserListener; +import org.apache.eventmesh.connector.jdbc.ddl.DdlParserCallback; +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener.MySqlAntlr4DdlParserListener; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashSet; +import java.util.Set; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.tree.ParseTree; + +public class MysqlAntlr4DdlParser extends Antlr4DdlParser { + + private DdlParserCallback callback; + + private final Set includeDatabaseTable; + + private final JdbcSourceConfig sourceConfig; + + public MysqlAntlr4DdlParser(boolean skipViews, boolean skipComments, Set includeDatabaseTable, JdbcSourceConfig sourceConfig) { + super(skipViews, skipComments); + this.includeDatabaseTable = includeDatabaseTable; + this.sourceConfig = sourceConfig; + } + + public MysqlAntlr4DdlParser(boolean skipViews, boolean skipComments, JdbcSourceConfig sourceConfig) { + this(skipViews, skipComments, new HashSet<>(), sourceConfig); + } + + public MysqlAntlr4DdlParser(boolean skipViews, boolean skipComments) { + this(skipViews, skipComments, new HashSet<>(), null); + } + + @Override + protected MySqlLexer buildLexerInstance(CharStream charStreams) { + return new MySqlLexer(charStreams); + } + + @Override + protected MySqlParser buildParserInstance(CommonTokenStream commonTokenStream) { + return new MySqlParser(commonTokenStream); + } + + @Override + protected ParseTree parseTree(MySqlParser parser) { + return parser.root(); + } + + @Override + protected Antlr4DdlParserListener createParseTreeWalkerListener(DdlParserCallback callback) { + this.callback = callback; + return new MySqlAntlr4DdlParserListener(this); + } + + /** + * Runs the given EventMeshRunner if all the nullableObjects are not null. + * + * @param runner the Runnable to be run + * @param nullableObjects the objects to be checked for null + */ + public void runIfAllNotNull(Runnable runner, Object... nullableObjects) { + // If nullableObjects is null or empty, run the runner + if (nullableObjects == null || nullableObjects.length == 0) { + runner.run(); + } + // Check each nullableObject for null + for (Object nullableObject : nullableObjects) { + // If any nullableObject is null, return without running the runner + if (nullableObject == null) { + return; + } + } + // Run the runner if all nullableObjects are not null + runner.run(); + } + + /** + * Parses a table ID from the given full ID text. + * + * @param fullIdText The full ID text. + * @return The parsed TableId object. + */ + public TableId parseTableId(String fullIdText) { + // Remove special characters from the full ID text + String sanitizedText = StringUtils.replaceEach(fullIdText, new String[] {"'\\''", "\"", "`"}, new String[] {"", "", ""}); + + // Split the sanitized text by dot (.) to separate catalog and table name + String[] split = sanitizedText.split("\\."); + + TableId tableId = new TableId(); + + // Set the table name if there is no catalog specified + if (split.length == 1) { + tableId.setTableName(split[0]); + } else { + // Set the catalog and table name if both are specified + tableId.setCatalogName(split[0]); + tableId.setTableName(split[1]); + } + + return tableId; + } + + public DdlParserCallback getCallback() { + return callback; + } + + public void handleEvent(Event event) { + if (callback != null) { + callback.handle(event); + } + } + + public boolean includeTableId(TableId tableId) { + return includeDatabaseTable.contains(tableId); + } + + public void addTableIdSet(Set tableIdSet) { + if (CollectionUtils.isEmpty(tableIdSet)) { + return; + } + this.includeDatabaseTable.addAll(tableIdSet); + } + + public JdbcSourceConfig getSourceConfig() { + return sourceConfig; + } + + public String parseCharset(CharsetNameContext charsetNameContext) { + String charsetName = null; + if (charsetNameContext != null && charsetNameContext.getText() != null) { + charsetName = JdbcStringUtils.withoutWrapper(charsetNameContext.getText()); + } + return charsetName; + } + + public String parseCollation(CollationNameContext collationNameContext) { + String collationName = null; + if (collationNameContext != null && collationNameContext.getText() != null) { + collationName = JdbcStringUtils.withoutWrapper(collationNameContext.getText()).toLowerCase(); + /* + * for (int index = 0; index < CharsetMapping.MAP_SIZE; index++) { if + * (collationName.equals(CharsetMapping.getStaticCollationNameForCollationIndex(index))) { collationName = + * CharsetMapping.getStaticMysqlCharsetNameForCollationIndex(index); break; } } + */ + } + return collationName; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/ColumnDefinitionParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/ColumnDefinitionParserListener.java new file mode 100644 index 0000000000..23e3728d47 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/ColumnDefinitionParserListener.java @@ -0,0 +1,261 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.AutoIncrementColumnConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CollateColumnConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CollectionDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.ColumnDefinitionContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CommentColumnConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DecimalLiteralContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DimensionDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.LongVarcharDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.NationalStringDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.NationalVaryingStringDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.NullNotnullContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.PrimaryKeyColumnConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.SimpleDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.SpatialDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.StringDataTypeContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.UniqueKeyColumnConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParserBaseListener; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlDataTypeConvertor; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableEditor; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlColumnEditor; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlOptions.MysqlColumnOptions; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import org.antlr.v4.runtime.tree.ParseTreeListener; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Getter +@Setter +@Slf4j +public class ColumnDefinitionParserListener extends MySqlParserBaseListener { + + private DefaultValueParserListener defaultValueParserListener; + + private final List listeners; + + private TableEditor tableEditor; + + private MysqlColumnEditor columnEditor; + + private final MysqlAntlr4DdlParser parser; + + private MysqlDataTypeConvertor dataTypeConvertor; + + // Determines whether the current column definition should be ignored. e.g. PRIMARY KEY, UNIQUE KEY + private AtomicReference ignoreColumn = new AtomicReference<>(false); + + public ColumnDefinitionParserListener(List listeners, TableEditor tableEditor, MysqlColumnEditor columnEditor, + MysqlAntlr4DdlParser parser) { + this.listeners = listeners; + this.tableEditor = tableEditor; + this.columnEditor = columnEditor; + this.parser = parser; + this.dataTypeConvertor = new MysqlDataTypeConvertor(); + } + + @Override + public void enterColumnDefinition(ColumnDefinitionContext ctx) { + // parse Column data type + this.parser.runIfAllNotNull(() -> { + DataTypeContext dataTypeContext = ctx.dataType(); + String dataTypeString = null; + if (dataTypeContext instanceof StringDataTypeContext) { + StringDataTypeContext stringDataTypeCtx = (StringDataTypeContext) dataTypeContext; + dataTypeString = stringDataTypeCtx.typeName.getText(); + // parse data type length + if (stringDataTypeCtx.lengthOneDimension() != null) { + this.columnEditor.length(Integer.parseInt(stringDataTypeCtx.lengthOneDimension().decimalLiteral().getText())); + } + // parse data type charset and collation + String charsetName = parser.parseCharset(stringDataTypeCtx.charsetName()); + String collationName = parser.parseCollation(stringDataTypeCtx.collationName()); + columnEditor.charsetName(charsetName); + columnEditor.collation(collationName); + } else if (dataTypeContext instanceof NationalStringDataTypeContext) { + NationalStringDataTypeContext nationalStringDataTypeCtx = (NationalStringDataTypeContext) dataTypeContext; + dataTypeString = nationalStringDataTypeCtx.typeName.getText(); + if (nationalStringDataTypeCtx.lengthOneDimension() != null) { + this.columnEditor.length(Integer.parseInt(nationalStringDataTypeCtx.lengthOneDimension().decimalLiteral().getText())); + } + } else if (dataTypeContext instanceof NationalVaryingStringDataTypeContext) { + NationalVaryingStringDataTypeContext nationalVaryingStringDataTypeCtx = (NationalVaryingStringDataTypeContext) dataTypeContext; + dataTypeString = nationalVaryingStringDataTypeCtx.typeName.getText(); + if (nationalVaryingStringDataTypeCtx.lengthOneDimension() != null) { + this.columnEditor.length(Integer.parseInt(nationalVaryingStringDataTypeCtx.lengthOneDimension().decimalLiteral().getText())); + } + } else if (dataTypeContext instanceof DimensionDataTypeContext) { + DimensionDataTypeContext dimensionDataTypeCtx = (DimensionDataTypeContext) dataTypeContext; + dataTypeString = dimensionDataTypeCtx.typeName.getText(); + // parse column length + if (dimensionDataTypeCtx.lengthOneDimension() != null) { + this.columnEditor.length(Integer.parseInt(dimensionDataTypeCtx.lengthOneDimension().decimalLiteral().getText())); + } + // parse column scale if has scale + if (dimensionDataTypeCtx.lengthTwoDimension() != null) { + List decimalLiteralContexts = dimensionDataTypeCtx.lengthTwoDimension().decimalLiteral(); + this.columnEditor.length(Integer.parseInt(decimalLiteralContexts.get(0).getText())); + this.columnEditor.scale(Integer.parseInt(decimalLiteralContexts.get(1).getText())); + } + + if (dimensionDataTypeCtx.lengthTwoOptionalDimension() != null) { + List decimalLiteralContexts = dimensionDataTypeCtx.lengthTwoOptionalDimension().decimalLiteral(); + if (decimalLiteralContexts.get(0).REAL_LITERAL() != null) { + String[] digits = decimalLiteralContexts.get(0).getText().split("."); + if (StringUtils.isBlank(digits[0]) || Integer.valueOf(digits[0]) == 0) { + this.columnEditor.length(10); + } else { + this.columnEditor.length(Integer.valueOf(digits[0])); + } + } else { + this.columnEditor.length(Integer.parseInt(decimalLiteralContexts.get(0).getText())); + } + if (decimalLiteralContexts.size() > 1) { + this.columnEditor.scale(Integer.parseInt(decimalLiteralContexts.get(1).getText())); + } + } + if (CollectionUtils.isNotEmpty(dimensionDataTypeCtx.SIGNED())) { + this.columnEditor.withOption(MysqlColumnOptions.SIGNED, dimensionDataTypeCtx.SIGNED().get(0).getText()); + } + if (CollectionUtils.isNotEmpty(dimensionDataTypeCtx.UNSIGNED())) { + this.columnEditor.withOption(MysqlColumnOptions.UNSIGNED, dimensionDataTypeCtx.UNSIGNED().get(0).getText()); + } + if (CollectionUtils.isNotEmpty(dimensionDataTypeCtx.ZEROFILL())) { + this.columnEditor.withOption(MysqlColumnOptions.ZEROFILL, dimensionDataTypeCtx.ZEROFILL().get(0).getText()); + } + } else if (dataTypeContext instanceof SimpleDataTypeContext) { + // Do nothing for example: DATE, TINYBLOB, etc. + SimpleDataTypeContext simpleDataTypeCtx = (SimpleDataTypeContext) dataTypeContext; + dataTypeString = simpleDataTypeCtx.typeName.getText(); + } else if (dataTypeContext instanceof CollectionDataTypeContext) { + CollectionDataTypeContext collectionDataTypeContext = (CollectionDataTypeContext) dataTypeContext; + dataTypeString = collectionDataTypeContext.typeName.getText(); + if (collectionDataTypeContext.charsetName() != null) { + String charsetName = collectionDataTypeContext.charsetName().getText(); + columnEditor.charsetName(charsetName); + } + } else if (dataTypeContext instanceof SpatialDataTypeContext) { + // do nothing + SpatialDataTypeContext spatialDataTypeCtx = (SpatialDataTypeContext) dataTypeContext; + dataTypeString = spatialDataTypeCtx.typeName.getText(); + } else if (dataTypeContext instanceof LongVarcharDataTypeContext) { + LongVarcharDataTypeContext longVarcharDataTypeCtx = (LongVarcharDataTypeContext) dataTypeContext; + dataTypeString = longVarcharDataTypeCtx.typeName.getText(); + String charsetName = parser.parseCharset(longVarcharDataTypeCtx.charsetName()); + String collationName = parser.parseCollation(longVarcharDataTypeCtx.collationName()); + columnEditor.charsetName(charsetName); + columnEditor.collation(collationName); + } + // handle enum and set type values + if (StringUtils.equalsAnyIgnoreCase(dataTypeString, "ENUM", "SET")) { + CollectionDataTypeContext collectionDataTypeContext = (CollectionDataTypeContext) dataTypeContext; + List values = collectionDataTypeContext.collectionOptions().STRING_LITERAL().stream() + .map(node -> JdbcStringUtils.withoutWrapper(node.getText())).collect(Collectors.toList()); + columnEditor.enumValues(values); + } + + if (StringUtils.isNotBlank(dataTypeString)) { + EventMeshDataType eventMeshType = this.dataTypeConvertor.toEventMeshType(dataTypeString); + this.columnEditor.withEventMeshType(eventMeshType); + this.columnEditor.withJdbcType(this.dataTypeConvertor.toJDBCType(dataTypeString)); + this.columnEditor.withType(dataTypeString); + } + }, columnEditor); + + this.parser.runIfAllNotNull(() -> { + // parse column default value + ColumnDefinitionParserListener.this.defaultValueParserListener = new DefaultValueParserListener(columnEditor); + ColumnDefinitionParserListener.this.listeners.add(defaultValueParserListener); + }, tableEditor, columnEditor); + + super.enterColumnDefinition(ctx); + } + + @Override + public void enterNullNotnull(NullNotnullContext ctx) { + columnEditor.notNull(ctx.NOT() != null); + super.enterNullNotnull(ctx); + } + + @Override + public void enterAutoIncrementColumnConstraint(AutoIncrementColumnConstraintContext ctx) { + columnEditor.autoIncremented(true); + columnEditor.generated(true); + super.enterAutoIncrementColumnConstraint(ctx); + } + + @Override + public void enterCommentColumnConstraint(CommentColumnConstraintContext ctx) { + if (ctx.COMMENT() != null && ctx.STRING_LITERAL() != null) { + columnEditor.comment(JdbcStringUtils.withoutWrapper(ctx.STRING_LITERAL().getText())); + } + super.enterCommentColumnConstraint(ctx); + } + + @Override + public void enterPrimaryKeyColumnConstraint(PrimaryKeyColumnConstraintContext ctx) { + /** + * sql example: `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, + */ + ignoreColumn.set(false); + this.tableEditor.withPrimaryKeyNames(this.columnEditor.ofName()); + super.enterPrimaryKeyColumnConstraint(ctx); + } + + @Override + public void enterUniqueKeyColumnConstraint(UniqueKeyColumnConstraintContext ctx) { + ignoreColumn.set(false); + super.enterUniqueKeyColumnConstraint(ctx); + } + + @Override + @SuppressWarnings("unchecked") + public void exitColumnDefinition(ColumnDefinitionContext ctx) { + if (!ignoreColumn.get().booleanValue()) { + this.ignoreColumn.set(false); + } + + // When exit column definition needs to remove DefaultValueParserListener from listener list + parser.runIfAllNotNull(() -> listeners.remove(defaultValueParserListener), tableEditor); + super.exitColumnDefinition(ctx); + } + + @Override + public void enterCollateColumnConstraint(CollateColumnConstraintContext ctx) { + if (ctx.COLLATE() != null) { + columnEditor.collation(ctx.collationName().getText()); + } + super.enterCollateColumnConstraint(ctx); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/CreateDatabaseParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/CreateDatabaseParserListener.java new file mode 100644 index 0000000000..71b4866e74 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/CreateDatabaseParserListener.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.SourceConnectorConfig; +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.Payload; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CreateDatabaseContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CreateDatabaseOptionContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParserBaseListener; +import org.apache.eventmesh.connector.jdbc.event.CreateDatabaseEvent; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlSourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.CatalogSchema; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.utils.Antlr4Utils; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +/** + * Listener for parsing create database statements using ANTLR4. + *

+ * Mysql CREATE DATABASE Statement: + *

+ *  CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
+ *     [create_option] ...
+ *  create_option: [DEFAULT] {
+ *     CHARACTER SET [=] charset_name
+ *   | COLLATE [=] collation_name
+ *   | ENCRYPTION [=] {'Y' | 'N'}
+ * }
+ * 
+ */ +public class CreateDatabaseParserListener extends MySqlParserBaseListener { + + private String databaseName; + + private String charSetName; + + private String collate; + + private String encryption; + + private MysqlAntlr4DdlParser parser; + + public CreateDatabaseParserListener(MysqlAntlr4DdlParser parser) { + this.parser = parser; + } + + @Override + public void enterCreateDatabase(CreateDatabaseContext ctx) { + this.databaseName = JdbcStringUtils.withoutWrapper(ctx.uid().getText()); + super.enterCreateDatabase(ctx); + } + + @Override + public void exitCreateDatabase(CreateDatabaseContext ctx) { + if (parser.getCallback() != null) { + String sql = Antlr4Utils.getText(ctx); + CatalogSchema catalogSchema = new CatalogSchema(databaseName, charSetName); + CreateDatabaseEvent event = new CreateDatabaseEvent(new TableId(databaseName)); + Payload payload = event.getJdbcConnectData().getPayload(); + SourceConnectorConfig sourceConnectorConfig = parser.getSourceConfig().getSourceConnectorConfig(); + MysqlSourceMateData sourceMateData = MysqlSourceMateData.newBuilder() + .name(sourceConnectorConfig.getName()) + .catalogName(databaseName) + .serverId(sourceConnectorConfig.getMysqlConfig().getServerId()) + .build(); + CatalogChanges changes = CatalogChanges.newBuilder().operationType(SchemaChangeEventType.DATABASE_CREATE).catalog(catalogSchema).build(); + payload.withSource(sourceMateData).withDdl(sql).withCatalogChanges(changes); + parser.getCallback().handle(event); + } + super.exitCreateDatabase(ctx); + } + + @Override + public void enterCreateDatabaseOption(CreateDatabaseOptionContext ctx) { + this.charSetName = ctx.charsetName().getText(); + this.collate = ctx.COLLATE().getText(); + this.encryption = ctx.ENCRYPTION().getText(); + super.enterCreateDatabaseOption(ctx); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/CreateTableParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/CreateTableParserListener.java new file mode 100644 index 0000000000..044403f778 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/CreateTableParserListener.java @@ -0,0 +1,183 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.SourceConnectorConfig; +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.Payload; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.ColumnCreateTableContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CopyCreateTableContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DecimalLiteralContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.QueryCreateTableContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.TableOptionAutoIncrementContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.TableOptionCharsetContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.TableOptionCollateContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.TableOptionEngineContext; +import org.apache.eventmesh.connector.jdbc.event.CreateTableEvent; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlSourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.Table; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlOptions.MysqlTableOptions; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlTableEditor; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlTableSchema; +import org.apache.eventmesh.connector.jdbc.utils.Antlr4Utils; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.TerminalNode; + +/** + *
+ * listen for events while parsing a CREATE TABLE statement in a MySQL DDL (Data Definition Language) script.
+ * 
+ * + * MYSQL CREATE TABLE + * + *
+ * CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
+ *     (create_definition,...)
+ *     [table_options]
+ *     [partition_options]
+ * 
+ * + *
+ * CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
+ *     [(create_definition,...)]
+ *     [table_options]
+ *     [partition_options]
+ *     [IGNORE | REPLACE]
+ *     [AS] query_expression
+ * 
+ *
+ * CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
+ *     { LIKE old_tbl_name | (LIKE old_tbl_name) }
+ * 
+ */ +public class CreateTableParserListener extends TableBaseParserListener { + + public CreateTableParserListener(List listeners, MysqlAntlr4DdlParser parser) { + super(listeners, parser); + } + + @Override + public void enterCopyCreateTable(CopyCreateTableContext ctx) { + // TODO support next version + super.enterCopyCreateTable(ctx); + } + + @Override + public void enterQueryCreateTable(QueryCreateTableContext ctx) { + // TODO support next version + super.enterQueryCreateTable(ctx); + } + + @Override + public void enterColumnCreateTable(ColumnCreateTableContext ctx) { + String tableName = ctx.tableName().fullId().getText(); + this.tableEditor = createTableEditor(tableName); + super.enterColumnCreateTable(ctx); + } + + @Override + public void exitColumnCreateTable(ColumnCreateTableContext ctx) { + String ddl = Antlr4Utils.getText(ctx); + parser.runIfAllNotNull(() -> { + listeners.remove(columnDefinitionListener); + // help JVM GC + columnDefinitionListener = null; + MysqlTableSchema tableSchema = tableEditor.build(); + parser.getCatalogTableSet().overrideTable(tableSchema); + String currentDatabase = parser.getCurrentDatabase(); + CreateTableEvent event = new CreateTableEvent(new TableId(currentDatabase, null, tableSchema.getSimpleName())); + Payload payload = event.getJdbcConnectData().getPayload(); + SourceConnectorConfig sourceConnectorConfig = parser.getSourceConfig().getSourceConnectorConfig(); + MysqlSourceMateData sourceMateData = MysqlSourceMateData.newBuilder() + .name(sourceConnectorConfig.getName()) + .catalogName(currentDatabase) + .serverId(sourceConnectorConfig.getMysqlConfig().getServerId()) + .build(); + Table table = Table.newBuilder().withTableId(tableSchema.getTableId()) + .withPrimaryKey(tableSchema.getPrimaryKey()) + .withUniqueKeys(tableSchema.getUniqueKeys()) + .withComment(tableSchema.getComment()) + .withOptions(tableSchema.getTableOptions()) + .build(); + CatalogChanges changes = CatalogChanges.newBuilder().operationType(SchemaChangeEventType.TABLE_CREATE).table(table) + .columns(tableSchema.getColumns()).build(); + payload.withSource(sourceMateData).withDdl(ddl).withCatalogChanges(changes); + parser.handleEvent(event); + }, tableEditor); + // reset column order + columnOrder.set(1); + super.exitColumnCreateTable(ctx); + } + + private MysqlTableEditor createTableEditor(String tableName) { + TableId tableId = parser.parseTableId(tableName); + if (StringUtils.isBlank(tableId.getCatalogName())) { + tableId.setCatalogName(parser.getCurrentDatabase()); + } + return MysqlTableEditor.ofCatalogTableEditor(tableId); + } + + @Override + public void enterTableOptionEngine(TableOptionEngineContext ctx) { + if (ctx.ENGINE() != null) { + this.tableEditor.withOption(MysqlTableOptions.ENGINE, ctx.engineName().getText()); + } + super.enterTableOptionEngine(ctx); + } + + @Override + public void enterTableOptionCharset(TableOptionCharsetContext ctx) { + + List nodes = ctx.DEFAULT(); + if (CollectionUtils.isNotEmpty(nodes) && nodes.size() == 2) { + TerminalNode node = nodes.get(1); + this.tableEditor.withOption(MysqlTableOptions.CHARSET, node.getText()); + } else { + this.tableEditor.withOption(MysqlTableOptions.CHARSET, ctx.charsetName().getText()); + } + + super.enterTableOptionCharset(ctx); + } + + @Override + public void enterTableOptionAutoIncrement(TableOptionAutoIncrementContext ctx) { + DecimalLiteralContext decimalLiteralContext = ctx.decimalLiteral(); + if (decimalLiteralContext != null) { + String autoIncrementNumber = Antlr4Utils.getText(decimalLiteralContext); + this.tableEditor.withOption(MysqlTableOptions.AUTO_INCREMENT, autoIncrementNumber); + } + super.enterTableOptionAutoIncrement(ctx); + } + + @Override + public void enterTableOptionCollate(TableOptionCollateContext ctx) { + if (ctx.COLLATE() != null) { + this.tableEditor.withOption(MysqlTableOptions.COLLATE, ctx.collationName().getText()); + } + super.enterTableOptionCollate(ctx); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/DefaultValueParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/DefaultValueParserListener.java new file mode 100644 index 0000000000..51bb5fe579 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/DefaultValueParserListener.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.CurrentTimestampContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DefaultValueContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.StringLiteralContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParserBaseListener; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlColumnEditor; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; + +/** + * Listener for parsing default values in MySQL parser. + */ +public class DefaultValueParserListener extends MySqlParserBaseListener { + + private final MysqlColumnEditor columnEditor; + + public DefaultValueParserListener(MysqlColumnEditor columnEditor) { + this.columnEditor = columnEditor; + } + + @Override + public void enterDefaultValue(DefaultValueContext ctx) { + + /** + * defaultValue + * : NULL_LITERAL + * | CAST '(' expression AS convertedDataType ')' + * | unaryOperator? constant + * | currentTimestamp (ON UPDATE currentTimestamp)? + * | '(' expression ')' + * | '(' fullId ')' + * ; + */ + String sign = ""; + + // Default value is NULL + if (ctx.NULL_LITERAL() != null) { + return; + } + + if (ctx.CAST() != null && ctx.expression() != null) { + columnEditor.defaultValueExpression(ctx.getText()); + return; + } + + if (ctx.unaryOperator() != null) { + sign = ctx.unaryOperator().getText(); + } + + /** + * Process expression + * constant + * : stringLiteral | decimalLiteral + * | '-' decimalLiteral + * | hexadecimalLiteral | booleanLiteral + * | REAL_LITERAL | BIT_STRING + * | NOT? nullLiteral=(NULL_LITERAL | NULL_SPEC_LITERAL) + * ; + */ + if (ctx.constant() != null) { + StringLiteralContext stringLiteralContext = ctx.constant().stringLiteral(); + if (stringLiteralContext != null) { + if (stringLiteralContext.COLLATE() == null) { + columnEditor.defaultValueExpression(sign + unquote(stringLiteralContext.getText())); + } else { + columnEditor.collation(sign + unquote(stringLiteralContext.STRING_LITERAL(0).getText())); + } + } else if (ctx.constant().decimalLiteral() != null) { + columnEditor.defaultValueExpression(sign + ctx.constant().decimalLiteral().getText()); + } else if (ctx.constant().BIT_STRING() != null) { + columnEditor.defaultValueExpression(unquoteBinary(ctx.constant().BIT_STRING().getText())); + } else if (ctx.constant().booleanLiteral() != null) { + columnEditor.defaultValueExpression(ctx.constant().booleanLiteral().getText()); + } else if (ctx.constant().REAL_LITERAL() != null) { + columnEditor.defaultValueExpression(ctx.constant().REAL_LITERAL().getText()); + } + } else if (CollectionUtils.isNotEmpty(ctx.currentTimestamp())) { + + /** + * timestamp-initialization + * cast-functions + * defaultValue + * : NULL_LITERAL + * | CAST '(' expression AS convertedDataType ')' + * | unaryOperator? constant + * | currentTimestamp (ON UPDATE currentTimestamp)? + * | '(' expression ')' + * | '(' fullId ')' + * ; + * currentTimestamp + * : + * ( + * (CURRENT_TIMESTAMP | LOCALTIME | LOCALTIMESTAMP) + * ('(' decimalLiteral? ')')? + * | NOW '(' decimalLiteral? ')' + * ) + * ; + */ + List currentTimestampContexts = ctx.currentTimestamp(); + if (currentTimestampContexts.size() > 1 && (ctx.ON() != null && ctx.UPDATE() != null)) { + StringBuilder builder = new StringBuilder(); + builder.append(currentTimestampContexts.get(0).getText()).append(" ").append(ctx.ON().getText()).append(" ").append(ctx.UPDATE()) + .append(" ").append(currentTimestampContexts.get(1).getText()); + columnEditor.defaultValueExpression(builder.toString()); + } else if (currentTimestampContexts.size() == 1) { + CurrentTimestampContext currentTimestampContext = currentTimestampContexts.get(0); + columnEditor.defaultValueExpression(currentTimestampContext.getText()); + } + } else if (ctx.expression() != null) { + // e.g. CREATE TABLE t2 (b BLOB DEFAULT ('abc')); + columnEditor.defaultValueExpression(ctx.expression().getText()); + } else if (ctx.fullId() != null) { + columnEditor.defaultValueExpression(ctx.expression().getText()); + } + super.enterDefaultValue(ctx); + } + + @Override + public void exitDefaultValue(DefaultValueContext ctx) { + super.exitDefaultValue(ctx); + } + + private String unquote(String stringLiteral) { + if (stringLiteral != null && ((stringLiteral.startsWith("'") && stringLiteral.endsWith("'")) + || (stringLiteral.startsWith("\"") && stringLiteral.endsWith("\"")))) { + return stringLiteral.substring(1, stringLiteral.length() - 1); + } + return stringLiteral; + } + + private String unquoteBinary(String stringLiteral) { + return stringLiteral.substring(2, stringLiteral.length() - 1); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/DropDatabaseParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/DropDatabaseParserListener.java new file mode 100644 index 0000000000..c582df4a15 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/DropDatabaseParserListener.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.SourceConnectorConfig; +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.Payload; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DropDatabaseContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParserBaseListener; +import org.apache.eventmesh.connector.jdbc.event.DropDatabaseEvent; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlSourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.CatalogSchema; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.utils.Antlr4Utils; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +public class DropDatabaseParserListener extends MySqlParserBaseListener { + + private MysqlAntlr4DdlParser parser; + + public DropDatabaseParserListener(MysqlAntlr4DdlParser parser) { + this.parser = parser; + } + + @Override + public void enterDropDatabase(DropDatabaseContext ctx) { + + String databaseName = JdbcStringUtils.withoutWrapper(ctx.uid().getText()); + parser.getCatalogTableSet().removeDatabase(databaseName); + if (parser.getCallback() != null) { + String sql = Antlr4Utils.getText(ctx); + CatalogSchema catalogSchema = new CatalogSchema(databaseName); + DropDatabaseEvent event = new DropDatabaseEvent(new TableId(databaseName)); + Payload payload = event.getJdbcConnectData().getPayload(); + SourceConnectorConfig sourceConnectorConfig = parser.getSourceConfig().getSourceConnectorConfig(); + MysqlSourceMateData sourceMateData = MysqlSourceMateData.newBuilder() + .name(sourceConnectorConfig.getName()) + .catalogName(databaseName) + .serverId(sourceConnectorConfig.getMysqlConfig().getServerId()) + .build(); + CatalogChanges changes = CatalogChanges.newBuilder().operationType(SchemaChangeEventType.DATABASE_DROP).catalog(catalogSchema).build(); + payload.withSource(sourceMateData).withDdl(sql).withCatalogChanges(changes); + parser.getCallback().handle(event); + } + super.enterDropDatabase(ctx); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/MySqlAntlr4DdlParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/MySqlAntlr4DdlParserListener.java new file mode 100644 index 0000000000..8049c6b2d0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/MySqlAntlr4DdlParserListener.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.connector.jdbc.antlr4.listener.Antlr4DdlParserListener; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.TerminalNode; + +public class MySqlAntlr4DdlParserListener implements Antlr4DdlParserListener { + + private final List listeners = new CopyOnWriteArrayList<>(); + + public MySqlAntlr4DdlParserListener(MysqlAntlr4DdlParser parser) { + listeners.add(new CreateDatabaseParserListener(parser)); + listeners.add(new DropDatabaseParserListener(parser)); + listeners.add(new CreateTableParserListener(listeners, parser)); + listeners.add(new TruncateTableParserListener(parser)); + } + + @Override + public void visitTerminal(TerminalNode node) { + for (ParseTreeListener listener : listeners) { + listener.visitTerminal(node); + } + } + + @Override + public void visitErrorNode(ErrorNode node) { + for (ParseTreeListener listener : listeners) { + listener.visitErrorNode(node); + } + } + + @Override + public void enterEveryRule(ParserRuleContext ctx) { + + for (ParseTreeListener listener : listeners) { + listener.enterEveryRule(ctx); + ctx.enterRule(listener); + } + } + + @Override + public void exitEveryRule(ParserRuleContext ctx) { + for (ParseTreeListener listener : listeners) { + ctx.exitRule(listener); + listener.exitEveryRule(ctx); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/TableBaseParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/TableBaseParserListener.java new file mode 100644 index 0000000000..3789cbf6f9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/TableBaseParserListener.java @@ -0,0 +1,186 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.ColumnDeclarationContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.DottedIdContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.FullColumnNameContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.IndexColumnNamesContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.IndexOptionContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.PrimaryKeyTableConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.UidContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.UniqueKeyTableConstraintContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParserBaseListener; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlColumnEditor; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlTableEditor; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import org.antlr.v4.runtime.tree.ParseTreeListener; + +public class TableBaseParserListener extends MySqlParserBaseListener { + + protected final List listeners; + + protected final MysqlAntlr4DdlParser parser; + + protected MysqlTableEditor tableEditor; + + protected ColumnDefinitionParserListener columnDefinitionListener; + + protected AtomicInteger columnOrder = new AtomicInteger(1); + + public TableBaseParserListener(List listeners, MysqlAntlr4DdlParser parser) { + this.listeners = listeners; + this.parser = parser; + } + + /** + * Called when entering a column declaration context. + * + * @param ctx The column declaration context. + */ + @Override + public void enterColumnDeclaration(ColumnDeclarationContext ctx) { + + /** + * Parse + * createDefinition + * : fullColumnName columnDefinition #columnDeclaration + * | tableConstraint NOT? ENFORCED? #constraintDeclaration + * | indexColumnDefinition #indexDeclaration + * ; + */ + parser.runIfAllNotNull(() -> { + FullColumnNameContext fullColumnNameContext = ctx.fullColumnName(); + // parse column name + UidContext uidContext = fullColumnNameContext.uid(); + List dottedIdContextList = fullColumnNameContext.dottedId(); + if (CollectionUtils.isNotEmpty(dottedIdContextList)) { + uidContext = dottedIdContextList.get(dottedIdContextList.size() - 1).uid(); + } + String columnName = JdbcStringUtils.withoutWrapper(uidContext.getText()); + MysqlColumnEditor columnEditor = MysqlColumnEditor.ofEditor(columnName); + if (Objects.isNull(columnDefinitionListener)) { + columnDefinitionListener = new ColumnDefinitionParserListener(listeners, tableEditor, columnEditor, parser); + // add ColumnDefinitionParserListener to listener list + listeners.add(columnDefinitionListener); + } else { + columnDefinitionListener.setColumnEditor(columnEditor); + } + }, tableEditor); + + super.enterColumnDeclaration(ctx); + } + + @Override + public void exitColumnDeclaration(ColumnDeclarationContext ctx) { + + parser.runIfAllNotNull(() -> { + MysqlColumnEditor columnEditor = columnDefinitionListener.getColumnEditor(); + columnEditor.withOrder(columnOrder.getAndIncrement()); + tableEditor.addColumns(columnEditor.build()); + }, tableEditor, columnDefinitionListener); + + super.exitColumnDeclaration(ctx); + } + + @Override + public void enterPrimaryKeyTableConstraint(PrimaryKeyTableConstraintContext ctx) { + /** + *Although the creation of a Primary Key is defined within the column definitions when creating a table, + * it can be considered as part of table management in practice. + * SQL example: PRIMARY KEY (`id`), + */ + parser.runIfAllNotNull(() -> { + IndexColumnNamesContext indexColumnNamesContext = ctx.indexColumnNames(); + List pkColumnNames = indexColumnNamesContext.indexColumnName().stream().map(indexColumnNameCtx -> { + /** + * indexColumnName + * : ((uid | STRING_LITERAL) ('(' decimalLiteral ')')? | expression) sortType=(ASC | DESC)? + * + */ + String pkColumnName; + if (indexColumnNameCtx.uid() != null) { + pkColumnName = JdbcStringUtils.withoutWrapper(indexColumnNameCtx.uid().getText()); + } else if (indexColumnNameCtx.STRING_LITERAL() != null) { + pkColumnName = JdbcStringUtils.withoutWrapper(indexColumnNameCtx.STRING_LITERAL().getText()); + } else { + pkColumnName = indexColumnNameCtx.expression().getText(); + } + return pkColumnName; + }).collect(Collectors.toList()); + String comment = null; + List indexOptionContexts = ctx.indexOption(); + for (IndexOptionContext indexOptionContext : indexOptionContexts) { + if (indexOptionContext.COMMENT() != null && indexOptionContext.STRING_LITERAL() != null) { + comment = indexOptionContext.STRING_LITERAL().getText(); + } + } + tableEditor.withPrimaryKeyNames(pkColumnNames, comment); + }, tableEditor); + + super.enterPrimaryKeyTableConstraint(ctx); + } + + @Override + public void enterUniqueKeyTableConstraint(UniqueKeyTableConstraintContext ctx) { + + // sql example: UNIQUE KEY `eventmesh` (`event_mesh`) USING BTREE COMMENT 'event mesh' + + parser.runIfAllNotNull(() -> { + IndexColumnNamesContext indexColumnNamesContext = ctx.indexColumnNames(); + List ukColumnNames = indexColumnNamesContext.indexColumnName().stream().map(indexColumnNameCtx -> { + /** + * indexColumnName + * : ((uid | STRING_LITERAL) ('(' decimalLiteral ')')? | expression) sortType=(ASC | DESC)? + * + */ + String ukColumnName; + if (indexColumnNameCtx.uid() != null) { + ukColumnName = JdbcStringUtils.withoutWrapper(indexColumnNameCtx.uid().getText()); + } else if (indexColumnNameCtx.STRING_LITERAL() != null) { + ukColumnName = JdbcStringUtils.withoutWrapper(indexColumnNameCtx.STRING_LITERAL().getText()); + } else { + ukColumnName = indexColumnNameCtx.expression().getText(); + } + return ukColumnName; + }).collect(Collectors.toList()); + List indexOptionContexts = ctx.indexOption(); + String comment = null; + if (CollectionUtils.isNotEmpty(indexOptionContexts)) { + for (IndexOptionContext context : indexOptionContexts) { + if (context.COMMENT() != null && context.STRING_LITERAL() != null) { + comment = context.STRING_LITERAL().getText(); + } + } + } + String ukName = ctx.index != null ? ctx.index.getText() : null; + tableEditor.withUniqueKeyColumnsNames(ukName, ukColumnNames, comment); + }, tableEditor); + + super.enterUniqueKeyTableConstraint(ctx); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/TruncateTableParserListener.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/TruncateTableParserListener.java new file mode 100644 index 0000000000..ab4a674e64 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/antlr4/mysql/listener/TruncateTableParserListener.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.listener; + +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParser.TruncateTableContext; +import org.apache.eventmesh.connector.jdbc.antlr4.autogeneration.MySqlParserBaseListener; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.utils.Antlr4Utils; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +/** + * A custom ANTLR listener for parsing TRUNCATE TABLE statements. + * TRUNCATE TABLE Statement + *
+ *     TRUNCATE [TABLE] tbl_name
+ * 
+ */ +public class TruncateTableParserListener extends MySqlParserBaseListener { + + private MysqlAntlr4DdlParser parser; + + /** + * Constructs a TruncateTableParserListener with the specified parser. + * + * @param parser The MysqlAntlr4DdlParser used for parsing. + */ + public TruncateTableParserListener(MysqlAntlr4DdlParser parser) { + this.parser = parser; + } + + @Override + public void enterTruncateTable(TruncateTableContext ctx) { + String sql = Antlr4Utils.getText(ctx); + String tableName = JdbcStringUtils.withoutWrapper(ctx.tableName().fullId().getText()); + // TruncateTableEvent event = new TruncateTableEvent(parser.getCurrentDatabase(), tableName, sql); + parser.handleEvent(null); + super.enterTruncateTable(ctx); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/AbstractCdcEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/AbstractCdcEngine.java new file mode 100644 index 0000000000..e7538659bd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/AbstractCdcEngine.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc; + +import org.apache.eventmesh.common.ThreadWrapper; +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.SourceConnectorConfig; +import org.apache.eventmesh.connector.jdbc.JdbcContext; +import org.apache.eventmesh.connector.jdbc.ddl.DdlParser; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import org.apache.commons.collections4.CollectionUtils; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractCdcEngine extends + ThreadWrapper implements CdcEngine { + + protected final JdbcSourceConfig jdbcSourceConfig; + + protected final DbDialect databaseDialect; + + protected final SourceConnectorConfig sourceConnectorConfig; + + private final Set includeDatabaseTable = new HashSet<>(64); + + public AbstractCdcEngine(SourceConfig config, DbDialect databaseDialect) { + if (!(config instanceof JdbcSourceConfig)) { + throw new IllegalArgumentException("config "); + } + this.jdbcSourceConfig = (JdbcSourceConfig) config; + this.databaseDialect = databaseDialect; + this.sourceConnectorConfig = this.jdbcSourceConfig.getSourceConnectorConfig(); + + calculateNeedHandleTable(); + } + + @Override + public Set getHandledTables() { + return includeDatabaseTable; + } + + protected Set calculateNeedHandleTable() { + // Get the database and table include and exclude lists from the connector configuration + List databaseIncludeList = sourceConnectorConfig.getDatabaseIncludeList(); + + // If the database include list is empty, get a list of all databases and use that as the include list + if (CollectionUtils.isEmpty(databaseIncludeList)) { + List allDatabases = databaseDialect.listDatabases(); + databaseIncludeList = new ArrayList<>(allDatabases); + } + Set defaultExcludeDatabase = defaultExcludeDatabase(); + if (CollectionUtils.isNotEmpty(defaultExcludeDatabase)) { + databaseIncludeList.removeAll(defaultExcludeDatabase); + } + + List databaseExcludeList = sourceConnectorConfig.getDatabaseExcludeList(); + // Remove the default excluded databases from the include list + if (CollectionUtils.isNotEmpty(databaseExcludeList)) { + databaseIncludeList.removeAll(databaseExcludeList); + } + + List tableIncludeList = sourceConnectorConfig.getTableIncludeList(); + // Create a list of included tables based on the table include list + List includeTableList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(tableIncludeList)) { + List tableIdList = buildTableId(tableIncludeList); + includeTableList.addAll(tableIdList); + } + + // If the table include list is empty, get a list of all tables for each database in the include list + if (CollectionUtils.isEmpty(tableIncludeList)) { + for (String database : databaseIncludeList) { + try { + List tableIds = databaseDialect.listTables(database); + includeTableList.addAll(tableIds); + } catch (SQLException e) { + log.warn("List database[{}] table error", database, e); + } + } + } + + List tableExcludeList = sourceConnectorConfig.getTableExcludeList(); + // Remove any tables in the exclude list from the included tables list + if (CollectionUtils.isNotEmpty(tableExcludeList)) { + includeTableList.removeAll(buildTableId(tableExcludeList)); + } + + includeDatabaseTable.addAll(includeTableList); + + return includeDatabaseTable; + } + + private List buildTableId(List tables) { + return Optional.ofNullable(tables).orElse(new ArrayList<>(0)).stream().map(table -> { + String[] split = table.split("\\."); + return new TableId(split[0], null, split[1]); + }).collect(Collectors.toList()); + } + + protected abstract Set defaultExcludeDatabase(); + + protected abstract Parse getDdlParser(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/AbstractCdcEngineFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/AbstractCdcEngineFactory.java new file mode 100644 index 0000000000..d00d4c56fa --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/AbstractCdcEngineFactory.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc; + +public abstract class AbstractCdcEngineFactory implements CdcEngineFactory { + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/CdcEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/CdcEngine.java new file mode 100644 index 0000000000..566ffccf4c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/CdcEngine.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc; + +import org.apache.eventmesh.connector.jdbc.JdbcContext; +import org.apache.eventmesh.connector.jdbc.event.EventConsumer; +import org.apache.eventmesh.connector.jdbc.source.Engine; + +/** + * CdcEngine is a service that captures data change events. + */ +public interface CdcEngine extends Engine, AutoCloseable { + + /** + * Stops the CDC Engine. + */ + @Override + void close() throws Exception; + + /** + * Returns the name of the CDC Engine. + * + * @return String representing the name of the CDC Engine. + */ + String getCdcEngineName(); + + /** + * Registers the CDC event consumer. + * + * @param consumer The CDC event consumer to register. + */ + void registerCdcEventConsumer(EventConsumer consumer); + + void setContext(Context context); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/CdcEngineFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/CdcEngineFactory.java new file mode 100644 index 0000000000..d53499e147 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/CdcEngineFactory.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc; + +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * This interface defines the methods required to create a Change Data Capture (CDC) engine + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.JDBC_CDC_ENGINE) +public interface CdcEngineFactory { + + /** + * Determines whether the provided JDBC URL is compatible with the CDC engine + * + * @param url jdbc url, e.g. mysql: jdbc:mysql://localhost:3306/ + * @return true if the JDBC URL is compatible with the CDC engine, false otherwise + */ + boolean acceptJdbcProtocol(String url); + + /** + * Creates a CDC engine based on the provided source configuration and database dialect. + * + * @param config the source configuration for the CDC engine + * @param databaseDialect the database dialect for the CDC engine + * @return the created CDC engine + */ + CdcEngine createCdcEngine(SourceConfig config, DatabaseDialect databaseDialect); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/RandomTaskSelectStrategy.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/RandomTaskSelectStrategy.java new file mode 100644 index 0000000000..4b05d41b31 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/RandomTaskSelectStrategy.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc; + +import org.apache.eventmesh.connector.jdbc.source.EventMeshJdbcTask; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import java.util.List; +import java.util.Random; + +public class RandomTaskSelectStrategy implements TaskSelectStrategy { + + private List cdcTasks; + + public RandomTaskSelectStrategy(List cdcTasks) { + this.cdcTasks = cdcTasks; + } + + /** + * Selects a JdbcTask for the specified TableId. + * + * @param tableId the TableId for which to select a JdbcTask + * @return the selected JdbcTask + */ + @Override + public Task select(TableId tableId) { + Random random = new Random(System.currentTimeMillis()); + int randomNum = random.nextInt(cdcTasks.size()); + return cdcTasks.get(randomNum); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/TaskSelectStrategy.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/TaskSelectStrategy.java new file mode 100644 index 0000000000..62e04c0507 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/TaskSelectStrategy.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc; + +import org.apache.eventmesh.connector.jdbc.source.EventMeshJdbcTask; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +/** + * Represents a strategy for selecting a CdcTask for a given TableId. + */ +public interface TaskSelectStrategy { + + /** + * Selects a CdcTask for the specified TableId. + * + * @param tableId the TableId for which to select a CdcTask + * @return the selected CdcTask + */ + Task select(TableId tableId); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/MysqlCdcEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/MysqlCdcEngine.java new file mode 100644 index 0000000000..22e9366f1e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/MysqlCdcEngine.java @@ -0,0 +1,827 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.MysqlConfig; +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.DataChanges; +import org.apache.eventmesh.connector.jdbc.DataChanges.Builder; +import org.apache.eventmesh.connector.jdbc.Field; +import org.apache.eventmesh.connector.jdbc.Payload; +import org.apache.eventmesh.connector.jdbc.Schema; +import org.apache.eventmesh.connector.jdbc.connection.mysql.MysqlJdbcConnection; +import org.apache.eventmesh.connector.jdbc.dialect.mysql.MysqlDatabaseDialect; +import org.apache.eventmesh.connector.jdbc.event.DeleteDataEvent; +import org.apache.eventmesh.connector.jdbc.event.EventConsumer; +import org.apache.eventmesh.connector.jdbc.event.GeneralDataChangeEvent; +import org.apache.eventmesh.connector.jdbc.event.InsertDataEvent; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.event.UpdateDataEvent; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.AbstractCdcEngine; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql.RowDeserializers.DeleteRowsEventMeshDeserializer; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql.RowDeserializers.UpdateRowsEventMeshDeserializer; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql.RowDeserializers.WriteRowsEventMeshDeserializer; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.EventDataDeserializationExceptionData; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.EventMeshGtidSet; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlConstants; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlJdbcContext; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlSourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.DefaultValueConvertor; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableSchema; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlDefaultValueConvertorImpl; +import org.apache.eventmesh.connector.jdbc.table.type.Pair; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import com.github.shyiko.mysql.binlog.BinaryLogClient; +import com.github.shyiko.mysql.binlog.BinaryLogClient.LifecycleListener; +import com.github.shyiko.mysql.binlog.event.DeleteRowsEventData; +import com.github.shyiko.mysql.binlog.event.Event; +import com.github.shyiko.mysql.binlog.event.EventData; +import com.github.shyiko.mysql.binlog.event.EventHeader; +import com.github.shyiko.mysql.binlog.event.EventHeaderV4; +import com.github.shyiko.mysql.binlog.event.EventType; +import com.github.shyiko.mysql.binlog.event.GtidEventData; +import com.github.shyiko.mysql.binlog.event.QueryEventData; +import com.github.shyiko.mysql.binlog.event.RotateEventData; +import com.github.shyiko.mysql.binlog.event.TableMapEventData; +import com.github.shyiko.mysql.binlog.event.TransactionPayloadEventData; +import com.github.shyiko.mysql.binlog.event.UpdateRowsEventData; +import com.github.shyiko.mysql.binlog.event.WriteRowsEventData; +import com.github.shyiko.mysql.binlog.event.XidEventData; +import com.github.shyiko.mysql.binlog.event.deserialization.EventDataDeserializationException; +import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer; +import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlCdcEngine extends AbstractCdcEngine { + + private BinaryLogClient client; + + private BlockingQueue eventQueue = new LinkedBlockingQueue<>(10000); + + private final EnumMap> eventHandlers = new EnumMap<>(EventType.class); + + private Map tableIdMap = new HashMap<>(64); + + private MysqlJdbcContext context; + + private List consumers = new ArrayList<>(16); + + private MysqlAntlr4DdlParser ddlParser; + + private MysqlJdbcConnection connection; + + private com.github.shyiko.mysql.binlog.GtidSet localGtidSet; + + private DefaultValueConvertor defaultValueConvertor = new MysqlDefaultValueConvertorImpl(); + + public MysqlCdcEngine(Config config, MysqlDatabaseDialect databaseDialect) { + super((JdbcSourceConfig) config, databaseDialect); + this.ddlParser = new MysqlAntlr4DdlParser(false, false, getHandledTables(), (JdbcSourceConfig) config); + this.connection = databaseDialect.getConnection(); + } + + /** + * Initializes the CDC Engine. + */ + @Override + public void init() { + final JdbcConfig jdbcConfig = this.sourceConnectorConfig.getJdbcConfig(); + client = new BinaryLogClient(jdbcConfig.getHostname(), jdbcConfig.getPort(), jdbcConfig.getUser(), jdbcConfig.getPassword()); + client.setThreadFactory(new EventMeshThreadFactory("mysql-binlog-client")); + final MysqlConfig mysqlConfig = this.sourceConnectorConfig.getMysqlConfig(); + client.setServerId(mysqlConfig.getServerId()); + client.setKeepAlive(mysqlConfig.isKeepAlive()); + final long keepAliveInterval = mysqlConfig.getKeepAliveInterval(); + client.setKeepAliveInterval(keepAliveInterval); + + final Map tableMapEventByTableId = new HashMap<>(32); + + // mysql dev url:https://dev.mysql.com/doc/dev/mysql-server/latest/ + EventDeserializer eventDeserializer = new EventDeserializer() { + + /** + * @param inputStream input stream to fetch event from + * @return deserialized event or null in case of end-of-stream + * @throws IOException if connection gets closed + */ + @Override + public Event nextEvent(ByteArrayInputStream inputStream) throws IOException { + try { + // Delegate to the superclass + Event event = super.nextEvent(inputStream); + log.debug("MYSQL Binlog---EventType={}, EventData={}", event.getHeader().getEventType(), event); + // We have to record the most recent TableMapEventData for each table number for our custom deserializers + if (event.getHeader().getEventType() == EventType.TABLE_MAP) { + TableMapEventData tableMapEvent = event.getData(); + tableMapEventByTableId.put(tableMapEvent.getTableId(), tableMapEvent); + } + + // Handle for transaction payload and capture the table map event and add it to the map + if (event.getHeader().getEventType() == EventType.TRANSACTION_PAYLOAD) { + TransactionPayloadEventData transactionPayloadEventData = event.getData(); + /** + * Loop over the uncompressed events in the transaction payload event and add the table map + * event in the map of table events + **/ + for (Event uncompressedEvent : transactionPayloadEventData.getUncompressedEvents()) { + if (uncompressedEvent.getHeader().getEventType() == EventType.TABLE_MAP && uncompressedEvent.getData() != null) { + TableMapEventData tableMapEvent = uncompressedEvent.getData(); + tableMapEventByTableId.put(tableMapEvent.getTableId(), tableMapEvent); + } + } + } + // Clean cache on rotate event to prevent it from growing indefinitely. + if (event.getHeader().getEventType() == EventType.ROTATE) { + tableMapEventByTableId.clear(); + } + return event; + } catch (EventDataDeserializationException ex) { + if (ex.getCause() instanceof IOException) { + throw ex; + } + EventHeaderV4 header = new EventHeaderV4(); + header.setEventType(EventType.INCIDENT); + header.setTimestamp(ex.getEventHeader().getTimestamp()); + header.setServerId(ex.getEventHeader().getServerId()); + if (ex.getEventHeader() instanceof EventHeaderV4) { + header.setEventLength(((EventHeaderV4) ex.getEventHeader()).getEventLength()); + header.setNextPosition(((EventHeaderV4) ex.getEventHeader()).getNextPosition()); + header.setFlags(((EventHeaderV4) ex.getEventHeader()).getFlags()); + } + EventData data = new EventDataDeserializationExceptionData(ex); + return new Event(header, data); + } + } + }; + + eventDeserializer.setEventDataDeserializer(EventType.WRITE_ROWS, new WriteRowsEventMeshDeserializer(tableMapEventByTableId)); + eventDeserializer.setEventDataDeserializer(EventType.UPDATE_ROWS, new UpdateRowsEventMeshDeserializer(tableMapEventByTableId)); + eventDeserializer.setEventDataDeserializer(EventType.DELETE_ROWS, new DeleteRowsEventMeshDeserializer(tableMapEventByTableId)); + eventDeserializer.setEventDataDeserializer(EventType.EXT_WRITE_ROWS, + new WriteRowsEventMeshDeserializer(tableMapEventByTableId).setMayContainExtraInformation(true)); + eventDeserializer.setEventDataDeserializer(EventType.EXT_UPDATE_ROWS, + new UpdateRowsEventMeshDeserializer(tableMapEventByTableId).setMayContainExtraInformation(true)); + eventDeserializer.setEventDataDeserializer(EventType.EXT_DELETE_ROWS, + new DeleteRowsEventMeshDeserializer(tableMapEventByTableId).setMayContainExtraInformation(true)); + + // Set the event deserializer for the MySQL client + client.setEventDeserializer(eventDeserializer); + // Register an event listener for the MySQL client + client.registerEventListener((event) -> eventMeshMysqlEventListener(event, context)); + // Register a lifecycle listener for the MySQL client + client.registerLifecycleListener(new LifecycleListener() { + + @Override + public void onConnect(BinaryLogClient client) { + log.info("Client connect MySQL Server success"); + } + + @Override + public void onCommunicationFailure(BinaryLogClient client, Exception ex) { + log.error("Communicate with mysql error", ex); + } + + @Override + public void onEventDeserializationFailure(BinaryLogClient client, Exception ex) { + log.error("Event deserialization failure", ex); + } + + @Override + public void onDisconnect(BinaryLogClient client) { + log.info("Disconnect Mysql"); + } + }); + + // Register custom event handlers... + eventHandlers.put(EventType.STOP, event -> handleStopEvent(context, event)); + eventHandlers.put(EventType.HEARTBEAT, event -> handleHeartbeatEvent(context, event)); + eventHandlers.put(EventType.INCIDENT, event -> handleServerIncident(context, event)); + eventHandlers.put(EventType.ROTATE, event -> handleRotateEvent(context, event)); + eventHandlers.put(EventType.TABLE_MAP, event -> handleTableMapEvent(context, event)); + eventHandlers.put(EventType.QUERY, event -> handleQueryEvent(context, event)); + eventHandlers.put(EventType.TRANSACTION_PAYLOAD, event -> handleTransactionPayload(context, event)); + + // Used to support 5.1.16 - mysql-trunk + eventHandlers.put(EventType.WRITE_ROWS, event -> handleInsertEvent(context, event)); + eventHandlers.put(EventType.UPDATE_ROWS, event -> handleUpdateEvent(context, event)); + eventHandlers.put(EventType.DELETE_ROWS, event -> handleDeleteEvent(context, event)); + + // Used in case of RBR (5.1.18+). + eventHandlers.put(EventType.EXT_WRITE_ROWS, event -> handleInsertEvent(context, event)); + eventHandlers.put(EventType.EXT_UPDATE_ROWS, event -> handleUpdateEvent(context, event)); + eventHandlers.put(EventType.EXT_DELETE_ROWS, event -> handleDeleteEvent(context, event)); + + eventHandlers.put(EventType.VIEW_CHANGE, (event) -> handleViewChangeEvent(context, event)); + eventHandlers.put(EventType.XA_PREPARE, (event) -> handleXAPrepareTransactionEvent(context, event)); + eventHandlers.put(EventType.XID, (event) -> handleTransactionCompletionEvent(context, event)); + } + + public EventMeshGtidSet filterGtidSet(MysqlJdbcContext offsetContext, EventMeshGtidSet availableServerEventMeshGtidSet, + EventMeshGtidSet purgedServerGtid) { + String gtidStr = offsetContext.getGtidSet(); + if (gtidStr == null) { + return null; + } + + EventMeshGtidSet filteredEventMeshGtidSet = new EventMeshGtidSet(gtidStr); + + final EventMeshGtidSet knownEventMeshGtidSet = filteredEventMeshGtidSet; + final EventMeshGtidSet relevantAvailableServerEventMeshGtidSet = availableServerEventMeshGtidSet; + + EventMeshGtidSet mergedEventMeshGtidSet = relevantAvailableServerEventMeshGtidSet + .retainAll(uuid -> knownEventMeshGtidSet.forServerWithId(uuid) != null) + .with(purgedServerGtid) + .with(filteredEventMeshGtidSet); + + return mergedEventMeshGtidSet; + } + + /** + * handles events from the MySQL + * + * @param event mysql binlog event + * @param context mysql context + */ + private void eventMeshMysqlEventListener(Event event, MysqlJdbcContext context) { + + if (event == null) { + return; + } + final EventHeader eventHeader = event.getHeader(); + final EventType eventType = eventHeader.getEventType(); + /** + * @see ROTATE_EVENT + * +----------------------------------------------------+ + * | ROTATE_EVENT | + * +----------------------------------------------------+ + * | Event Header | Position Info | Filename| + * +----------------------------------------------------+ + * The rotate event is added to the binlog as last event to tell the reader what binlog to request next. + */ + if (eventType == EventType.ROTATE) { + RotateEventData rotateEventData = unwrapData(event); + context.setBinlogStartPoint(rotateEventData.getBinlogFilename(), rotateEventData.getBinlogPosition()); + } else if (eventHeader instanceof EventHeaderV4) { + EventHeaderV4 eventHeaderV4 = (EventHeaderV4) eventHeader; + context.setEventPosition(eventHeaderV4.getPosition(), eventHeaderV4.getEventLength()); + } + if (eventType == EventType.HEARTBEAT) { + return; + } + try { + eventQueue.put(event); + } catch (InterruptedException e) { + log.warn("Put event to queue error", e); + } + context.complete(); + } + + @Override + public String getThreadName() { + return "MySQL-CdcEngine"; + } + + /** + * Returns the name of the CDC Engine. + * + * @return String representing the name of the CDC Engine. + */ + @Override + public String getCdcEngineName() { + return "MySQL CDC Engine"; + } + + @Override + public void close() throws Exception { + client.disconnect(); + } + + /** + * When an object implementing interface Runnable is used to create a thread, starting the thread causes the object's + * run method to be called in that separately executing + * thread. + *

+ * The general contract of the method run is that it may take any action whatsoever. + * + * @see Thread#run() + */ + @Override + public void run() { + enableGtidHandle(); + do { + try { + client.connect(TimeUnit.SECONDS.toMillis(5)); + } catch (IOException | TimeoutException e) { + log.error("Binary log client connect to mysql server error, The connection will be retried in three seconds", e); + await(3, TimeUnit.SECONDS); + } + } while (!client.isConnected()); + + while (isRunning) { + Event event = null; + try { + event = eventQueue.poll(5, TimeUnit.SECONDS); + if (event == null) { + continue; + } + eventHandlers.getOrDefault(event.getHeader().getEventType(), ignore -> ignoreEvent(context, ignore)).accept(event); + } catch (Exception e) { + if (event != null) { + log.warn("Handle EventType={} error", event.getHeader().getEventType(), e); + } + } + } + } + + private void enableGtidHandle() { + // Query whether mysql supports GTID + if (this.connection.enableGTID()) { + eventHandlers.put(EventType.GTID, event -> handleGtidEvent(context, event)); + + // Query GtidSet from the MySQL Server + String availableServerGtid = this.connection.executedGTID(); + EventMeshGtidSet executedEventMeshGtidSet = new EventMeshGtidSet(availableServerGtid); + + // Get purged GTID + String purgedServerGtid = this.connection.purgedGTID(); + EventMeshGtidSet purgedServerEventMeshGtidSet = new EventMeshGtidSet(purgedServerGtid); + + EventMeshGtidSet filteredEventMeshGtidSet = filterGtidSet(context, executedEventMeshGtidSet, purgedServerEventMeshGtidSet); + if (filteredEventMeshGtidSet != null) { + client.setGtidSet(filteredEventMeshGtidSet.toString()); + this.context.completedGtidSet(filteredEventMeshGtidSet.toString()); + localGtidSet = new com.github.shyiko.mysql.binlog.GtidSet(filteredEventMeshGtidSet.toString()); + } else { + client.setBinlogFilename(this.context.getSourceInfo().getCurrentBinlogFileName()); + client.setBinlogPosition(this.context.getSourceInfo().getCurrentBinlogPosition()); + localGtidSet = new com.github.shyiko.mysql.binlog.GtidSet(""); + } + } else { + client.setBinlogFilename(this.context.getSourceInfo().getCurrentBinlogFileName()); + client.setBinlogPosition(this.context.getSourceInfo().getCurrentBinlogPosition()); + } + } + + /** + * Handles the STOP_EVENT + * + * @param context the MySQL context + * @param event the event to be handled + */ + protected void handleStopEvent(MysqlJdbcContext context, Event event) { + // The purpose of STOP_EVENT is to inform MySQL that the slave or replication client has reached the end of the binary log + // and no new events will be generated. When the slave receives a STOP_EVENT, it can take appropriate actions based on its needs, + // such as closing the connection to the master server or reconnecting to obtain a new binary log file. + log.debug("Replication client has reached the end of the binary log: {}", event); + } + + /** + * Handles the HEARTBEAT_EVENT + * + * @param context the MySQL context + * @param event the event to be handled + */ + protected void handleHeartbeatEvent(MysqlJdbcContext context, Event event) { + log.debug("Replication client handle {}", event.getHeader().getEventType()); + } + + /** + * Handles the INCIDENT_EVENT + * + * @param context the MySQL context + * @param event the event to be handled + */ + protected void handleServerIncident(MysqlJdbcContext context, Event event) { + + final EventData eventData = event.getData(); + if (eventData instanceof EventDataDeserializationExceptionData) { + log.error("Server incident: {}", event); + } + + } + + /** + * Handles the ROTATE_EVENT + * + * @param context the MySQL context + * @param event the event to be handled + */ + protected void handleRotateEvent(MysqlJdbcContext context, Event event) { + RotateEventData eventData = unwrapData(event); + assert eventData != null; + tableIdMap.clear(); + } + + @SuppressWarnings("unchecked") + protected T unwrapData(Event event) { + EventData eventData = event.getData(); + if (eventData instanceof EventDeserializer.EventDataWrapper) { + eventData = ((EventDeserializer.EventDataWrapper) eventData).getInternal(); + } + return (T) eventData; + } + + /** + * Handles the TABLE_MAP_EVENT Format @see TABLE_MAP_EVENT + * + * @param context the MySQL context + * @param event the event to be handled + */ + protected void handleTableMapEvent(MysqlJdbcContext context, Event event) { + TableMapEventData tableMapEventData = event.getData(); + final long tableId = tableMapEventData.getTableId(); + final String tableName = tableMapEventData.getTable(); + final String database = tableMapEventData.getDatabase(); + tableIdMap.put(tableId, new TableId(database, null, tableName)); + } + + /** + * Handles the QUERY_EVENT + * + * @param context mysql context + * @param event query event + */ + protected void handleQueryEvent(MysqlJdbcContext context, Event event) { + QueryEventData queryEventData = unwrapData(event); + final String sql = queryEventData.getSql().trim(); + log.debug("Received query event SQL:{}", sql); + if (StringUtils.equalsIgnoreCase("BEGIN", sql)) { + // start transaction + context.startTransaction(); + return; + } + + if (StringUtils.equalsIgnoreCase("COMMIT", sql)) { + context.commitTransaction(); + return; + } + + if (StringUtils.startsWithIgnoreCase("XA", sql)) { + // TODO: next version support + + return; + } + String sqlBegin = sql.substring(0, 6).toUpperCase(); + if (StringUtils.startsWithAny(sqlBegin, "INSERT", "UPDATE", "DELETE")) { + log.warn("Received DML '[SQL={}]' for processing, binlog probably contains events generated with statement", sql); + return; + } + + // set current parse database to Ddl parser + ddlParser.setCurrentDatabase(queryEventData.getDatabase()); + ddlParser.setCatalogTableSet(context.getCatalogTableSet()); + ddlParser.parse(sql, this::handleDdlEvent); + } + + private void handleDdlEvent(org.apache.eventmesh.connector.jdbc.event.Event event) { + if (event == null) { + return; + } + // handle default value expression + if (event.getJdbcConnectData().isSchemaChanges()) { + CatalogChanges catalogChanges = event.getJdbcConnectData().getPayload().getCatalogChanges(); + SchemaChangeEventType schemaChangeEventType = SchemaChangeEventType.ofSchemaChangeEventType(catalogChanges.getType(), + catalogChanges.getOperationType()); + if (SchemaChangeEventType.TABLE_CREATE == schemaChangeEventType || SchemaChangeEventType.TABLE_ALERT == schemaChangeEventType) { + catalogChanges.getColumns().forEach(column -> { + column.setDefaultValue(defaultValueConvertor.parseDefaultValue(column, column.getDefaultValueExpression())); + }); + } + } + event.getJdbcConnectData().getPayload().ofSourceMateData().setSnapshot(false); + consumers.stream().forEach(consumer -> consumer.accept(event)); + } + + /** + * Handles the TRANSACTION_PAYLOAD_EVENT + *

+ * "binlog_transaction_compression" is a new feature introduced in MySQL 8.0.23, used for compressing transactions in the binary log (binlog). + * This event is a wrapper event and encloses many other events.It is mostly used for carrying compressed payloads as its content can be + * compressed, in which case, its metadata shall contain information about the compression metadata as well. + * + *

+ * + * @param context the MySQL context + * @param event the event to be handled + */ + protected void handleTransactionPayload(MysqlJdbcContext context, Event event) { + + TransactionPayloadEventData transactionPayloadEventData = event.getData(); + // unpack Event and handle + ArrayList uncompressedEvents = transactionPayloadEventData.getUncompressedEvents(); + for (Event uncompressedEvent : uncompressedEvents) { + final EventType eventType = uncompressedEvent.getHeader().getEventType(); + eventHandlers.getOrDefault(eventType, et -> ignoreEvent(context, et)).accept(uncompressedEvent); + } + } + + /** + * Handles the insert event. + * + * @param context The MySQL context. + * @param event The insert event. + */ + protected void handleInsertEvent(MysqlJdbcContext context, Event event) { + WriteRowsEventData writeRowsEventData = unwrapData(event); + log.debug("Received Write rows event, TableId={}", writeRowsEventData.getTableId()); + long tableNumber = writeRowsEventData.getTableId(); + TableId tableId = tableIdMap.get(tableNumber); + + if (!getHandledTables().contains(tableId)) { + log.warn("Write rows-Table {} is excluded", tableId); + return; + } + MysqlSourceMateData sourceMateData = buildMysqlSourceMateData(context, event, tableId); + List insertRows = writeRowsEventData.getRows(); + if (CollectionUtils.isEmpty(insertRows)) { + return; + } + List, Pair>> rows = new ArrayList<>(); + for (Serializable[] row : insertRows) { + Pair item = new Pair<>(row, writeRowsEventData.getIncludedColumns()); + rows.add(new Pair<>(null, item)); + } + handleCdcDmlData(context, sourceMateData, tableId, rows, CdcDmlType.INSERT); + } + + private MysqlSourceMateData buildMysqlSourceMateData(MysqlJdbcContext context, Event event, TableId tableId) { + MysqlSourceMateData sourceMateData = MysqlSourceMateData.newBuilder() + .name(sourceConnectorConfig.getName()) + .withTableId(tableId) + .serverId(sourceConnectorConfig.getMysqlConfig().getServerId()) + .binlogFile(context.getSourceInfo().getCurrentBinlogFileName()) + .position(((EventHeaderV4) event.getHeader()).getPosition()) + .build(); + return sourceMateData; + } + + public enum CdcDmlType { + INSERT, + UPDATE, + DELETE + } + + private GeneralDataChangeEvent buildEvent(CdcDmlType type, TableId tableId) { + switch (type) { + case UPDATE: + return new UpdateDataEvent(tableId); + case INSERT: + return new InsertDataEvent(tableId); + case DELETE: + return new DeleteDataEvent(tableId); + default: + return null; + } + } + + private void handleCdcDmlData(MysqlJdbcContext context, MysqlSourceMateData sourceMateData, TableId tableId, + List, Pair>> rows, CdcDmlType type) { + + TableSchema tableSchema = context.getCatalogTableSet().getTableSchema(tableId); + Map> orderColumnMap = tableSchema.getOrderColumnMap(); + List> columns = tableSchema.getColumns(); + List fields = null; + Builder builder = DataChanges.newBuilder(); + if (CollectionUtils.isNotEmpty(columns)) { + fields = columns.stream() + .map(col -> { + Column rebuild = Column.newBuilder().withName(col.getName()).withDataType(col.getDataType()).withJdbcType(col.getJdbcType()) + .withNativeType(col.getNativeType()).withOrder(col.getOrder()).build(); + return new Field(rebuild, col.isNotNull(), col.getName(), tableId.toString()); + }).collect(Collectors.toList()); + } + int columnsSize = orderColumnMap.size(); + for (Pair, Pair> pair : rows) { + GeneralDataChangeEvent dataEvent = buildEvent(type, tableId); + builder.withType(dataEvent.getDataChangeEventType().ofCode()); + Schema schema = new Schema(); + // set primary key + schema.addKeys(tableSchema.getPrimaryKey().getColumnNames()); + Pair beforePair = Optional.ofNullable(pair.getLeft()).orElse(new Pair<>()); + Serializable[] beforeRows = beforePair.getLeft(); + if (beforeRows != null && beforeRows.length != 0) { + BitSet includedColumns = beforePair.getRight(); + Map beforeValues = new HashMap<>(beforeRows.length); + for (int index = 0; index < columnsSize; ++index) { + // Filter out empty fields + if (!includedColumns.get(index)) { + continue; + } + beforeValues.put(orderColumnMap.get(index + 1).getName(), beforeRows[index]); + } + builder.withBefore(beforeValues); + Field beforeField = new Field().withField(Payload.BEFORE_FIELD).withName(Payload.PAYLOAD_BEFORE).withRequired(false); + beforeField.withRequired(true).withFields(fields); + schema.add(beforeField); + } + + Pair afterPair = Optional.ofNullable(pair.getRight()).orElse(new Pair<>()); + Serializable[] afterRows = afterPair.getLeft(); + if (afterRows != null && afterRows.length != 0) { + BitSet includedColumns = afterPair.getRight(); + Map afterValues = new HashMap<>(afterRows.length); + for (int index = 0; index < columnsSize; ++index) { + // Filter out empty fields + if (!includedColumns.get(index)) { + continue; + } + afterValues.put(orderColumnMap.get(index + 1).getName(), afterRows[index]); + } + builder.withAfter(afterValues); + Field afterField = new Field().withField(Payload.AFTER_FIELD).withName(Payload.PAYLOAD_AFTER).withRequired(false); + afterField.withRequired(true).withFields(fields); + schema.add(afterField); + } + Payload payload = dataEvent.getJdbcConnectData().getPayload(); + payload.withSource(sourceMateData).withDataChanges(builder.build()); + dataEvent.getJdbcConnectData().setSchema(schema); + consumers.stream().forEach(consumer -> consumer.accept(dataEvent)); + } + } + + /** + * Handles the update event. + * + * @param context The MySQL context. + * @param event The update event. + */ + protected void handleUpdateEvent(MysqlJdbcContext context, Event event) { + UpdateRowsEventData updateRowsEventData = unwrapData(event); + log.debug("Received Update rows event, Update table is {}", tableIdMap.get(updateRowsEventData.getTableId())); + long id = updateRowsEventData.getTableId(); + TableId tableId = tableIdMap.get(id); + if (!getHandledTables().contains(tableId)) { + log.debug("Update rows-Table {} is excluded", tableId); + return; + } + MysqlSourceMateData sourceMateData = buildMysqlSourceMateData(context, event, tableId); + List> updateRows = updateRowsEventData.getRows(); + if (CollectionUtils.isEmpty(updateRows)) { + return; + } + List, Pair>> rows = new ArrayList<>(); + for (Entry row : updateRows) { + Pair before = new Pair<>(row.getKey(), updateRowsEventData.getIncludedColumnsBeforeUpdate()); + Pair after = new Pair<>(row.getValue(), updateRowsEventData.getIncludedColumns()); + rows.add(new Pair<>(before, after)); + } + handleCdcDmlData(context, sourceMateData, tableId, rows, CdcDmlType.UPDATE); + } + + /** + * Handles the delete event. + * + * @param context The MySQL context. + * @param event The delete event. + */ + protected void handleDeleteEvent(MysqlJdbcContext context, Event event) { + DeleteRowsEventData deleteRowsEventData = unwrapData(event); + log.debug("Received Delete rows event, Delete table is {}", tableIdMap.get(deleteRowsEventData.getTableId())); + long id = deleteRowsEventData.getTableId(); + TableId tableId = tableIdMap.get(id); + + if (!getHandledTables().contains(tableId)) { + log.debug("Update rows-Table {} is excluded", tableId); + return; + } + MysqlSourceMateData sourceMateData = buildMysqlSourceMateData(context, event, tableId); + List deleteRows = deleteRowsEventData.getRows(); + if (CollectionUtils.isEmpty(deleteRows)) { + return; + } + List, Pair>> rows = new ArrayList<>(); + for (Serializable[] row : deleteRows) { + Pair item = new Pair<>(row, deleteRowsEventData.getIncludedColumns()); + rows.add(new Pair<>(item, null)); + } + handleCdcDmlData(context, sourceMateData, tableId, rows, CdcDmlType.DELETE); + } + + /** + * Handles the GTID event. + * + * @param context The MySQL context. + * @param event The GTID event. + */ + protected void handleGtidEvent(MysqlJdbcContext context, Event event) { + GtidEventData gtidEvent = unwrapData(event); + String gtid = gtidEvent.getMySqlGtid().toString(); + log.debug("Received GTID event: {}", gtid); + localGtidSet.add(gtid); + context.beginGtid(gtid); + } + + /** + * Handles the view change event. + * + * @param context The MySQL context. + * @param event The view change event. + */ + protected void handleViewChangeEvent(MysqlJdbcContext context, Event event) { + // TODO: Add support for handling view change event + } + + /** + * Handles the XA prepare transaction event. + * + * @param context The MySQL context. + * @param event The XA prepare transaction event. + */ + protected void handleXAPrepareTransactionEvent(MysqlJdbcContext context, Event event) { + // TODO: Add support for handling XA prepare transaction event + } + + /** + * Handles the transaction completion event. + * + * @param context The MySQL context. + * @param event The transaction completion event. + */ + protected void handleTransactionCompletionEvent(MysqlJdbcContext context, Event event) { + XidEventData xidEventData = unwrapData(event); + log.debug("Received XID event, Xid={}", xidEventData.getXid()); + context.commitTransaction(); + } + + /** + * Default handler that ignores events. + * + * @param context The MySQL context. + * @param event The event to be ignored. + */ + protected void ignoreEvent(MysqlJdbcContext context, Event event) { + log.debug("Ignoring event due to missing handler: {}", event); + } + + @Override + public void registerCdcEventConsumer(EventConsumer consumer) { + if (consumer == null) { + return; + } + consumers.add(consumer); + } + + @Override + protected Set defaultExcludeDatabase() { + return MysqlConstants.DEFAULT_EXCLUDE_DATABASE; + } + + @Override + protected MysqlAntlr4DdlParser getDdlParser() { + return ddlParser; + } + + @Override + public void setContext(MysqlJdbcContext context) { + if (context == null) { + context = MysqlJdbcContext.initialize(this.jdbcSourceConfig); + } + this.context = context; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/MysqlCdcEngineFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/MysqlCdcEngineFactory.java new file mode 100644 index 0000000000..2a87969cf8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/MysqlCdcEngineFactory.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql; + +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.mysql.MysqlDatabaseDialect; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.AbstractCdcEngineFactory; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngine; +import org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngineFactory; + +import org.apache.commons.lang3.StringUtils; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlCdcEngineFactory extends AbstractCdcEngineFactory implements CdcEngineFactory { + + @Override + public boolean acceptJdbcProtocol(String url) { + if (StringUtils.isBlank(url)) { + return true; + } + return url.toLowerCase().startsWith("jdbc:mysql"); + } + + /** + * Creates a CDC engine based on the provided source configuration and database dialect. + * + * @param config the source configuration for the CDC engine + * @param databaseDialect the database dialect for the CDC engine + * @return the created CDC engine + */ + @Override + public CdcEngine createCdcEngine(SourceConfig config, DatabaseDialect databaseDialect) { + return new MysqlCdcEngine(config, (MysqlDatabaseDialect) databaseDialect); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/RowDeserializers.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/RowDeserializers.java new file mode 100644 index 0000000000..e23839563f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/cdc/mysql/RowDeserializers.java @@ -0,0 +1,470 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql; + +import java.io.IOException; +import java.io.Serializable; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.BitSet; +import java.util.Map; + +import com.github.shyiko.mysql.binlog.event.TableMapEventData; +import com.github.shyiko.mysql.binlog.event.deserialization.DeleteRowsEventDataDeserializer; +import com.github.shyiko.mysql.binlog.event.deserialization.UpdateRowsEventDataDeserializer; +import com.github.shyiko.mysql.binlog.event.deserialization.WriteRowsEventDataDeserializer; +import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream; + +import lombok.extern.slf4j.Slf4j; + +/** + * Custom deserializers for the MySQL Binlog Client.MySQL Binlog Client row deserializers convert MySQL raw row data into {@link java.sql.Date}, + * {@link java.sql.Time}, and {@link java.sql.Timestamp} values using {@link java.util.Calendar} instances. EventMesh convert the raw MySQL row values + * directly into {@link LocalDate}, {@link LocalTime}, {@link LocalDateTime}, and {@link java.time.OffsetDateTime}. + */ +@Slf4j +public class RowDeserializers { + + public static class WriteRowsEventMeshDeserializer extends WriteRowsEventDataDeserializer { + + public WriteRowsEventMeshDeserializer(Map tableMapEventByTableId) { + super(tableMapEventByTableId); + } + + @Override + protected Serializable deserializeString(int length, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeString(length, inputStream); + } + + @Override + protected Serializable deserializeVarString(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeVarString(meta, inputStream); + } + + @Override + protected Serializable deserializeDate(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDate(inputStream); + } + + @Override + protected Serializable deserializeDatetime(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDatetime(inputStream); + } + + @Override + protected Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDatetimeV2(meta, inputStream); + } + + @Override + protected Serializable deserializeTimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimeV2(meta, inputStream); + } + + @Override + protected Serializable deserializeTime(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTime(inputStream); + } + + @Override + protected Serializable deserializeTimestamp(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimestamp(inputStream); + } + + @Override + protected Serializable deserializeTimestampV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimestampV2(meta, inputStream); + } + + @Override + protected Serializable deserializeYear(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeYear(inputStream); + } + + @Override + protected Serializable deserializeBit(int meta, ByteArrayInputStream inputStream) throws IOException { + return ((BitSet) super.deserializeBit(meta, inputStream)).toByteArray(); + } + } + + public static class UpdateRowsEventMeshDeserializer extends UpdateRowsEventDataDeserializer { + + public UpdateRowsEventMeshDeserializer(Map tableMapEventByTableId) { + super(tableMapEventByTableId); + } + + @Override + protected Serializable deserializeString(int length, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeString(length, inputStream); + } + + @Override + protected Serializable deserializeVarString(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeVarString(meta, inputStream); + } + + @Override + protected Serializable deserializeDate(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDate(inputStream); + } + + @Override + protected Serializable deserializeDatetime(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDatetime(inputStream); + } + + @Override + protected Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDatetimeV2(meta, inputStream); + } + + @Override + protected Serializable deserializeTimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimeV2(meta, inputStream); + } + + @Override + protected Serializable deserializeTime(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTime(inputStream); + } + + @Override + protected Serializable deserializeTimestamp(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimestamp(inputStream); + } + + @Override + protected Serializable deserializeTimestampV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimestampV2(meta, inputStream); + } + + @Override + protected Serializable deserializeYear(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeYear(inputStream); + } + + @Override + protected Serializable deserializeBit(int meta, ByteArrayInputStream inputStream) throws IOException { + return ((BitSet) super.deserializeBit(meta, inputStream)).toByteArray(); + + } + } + + public static class DeleteRowsEventMeshDeserializer extends DeleteRowsEventDataDeserializer { + + public DeleteRowsEventMeshDeserializer(Map tableMapEventByTableId) { + super(tableMapEventByTableId); + } + + @Override + protected Serializable deserializeString(int length, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeString(length, inputStream); + } + + @Override + protected Serializable deserializeVarString(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeVarString(meta, inputStream); + } + + @Override + protected Serializable deserializeDate(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDate(inputStream); + } + + @Override + protected Serializable deserializeDatetime(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDatetime(inputStream); + } + + @Override + protected Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeDatetimeV2(meta, inputStream); + } + + @Override + protected Serializable deserializeTimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimeV2(meta, inputStream); + } + + @Override + protected Serializable deserializeTime(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTime(inputStream); + } + + @Override + protected Serializable deserializeTimestamp(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimestamp(inputStream); + } + + @Override + protected Serializable deserializeTimestampV2(int meta, ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeTimestampV2(meta, inputStream); + } + + @Override + protected Serializable deserializeYear(ByteArrayInputStream inputStream) throws IOException { + return RowDeserializers.deserializeYear(inputStream); + } + + protected Serializable deserializeBit(int meta, ByteArrayInputStream inputStream) throws IOException { + return ((BitSet) super.deserializeBit(meta, inputStream)).toByteArray(); + } + } + + protected static Serializable deserializeTimestamp(ByteArrayInputStream inputStream) throws IOException { + long epochSecond = inputStream.readLong(4); + int nanoSeconds = 0; // no fractional seconds + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond, nanoSeconds), ZoneOffset.UTC); + } + + protected static Serializable deserializeTimestampV2(int meta, ByteArrayInputStream inputStream) throws IOException { + long epochSecond = bigEndianLong(inputStream.read(4), 0, 4); + int nanoSeconds = deserializeFractionalSecondsInNanos(meta, inputStream); + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond, nanoSeconds), ZoneOffset.UTC); + } + + protected static Serializable deserializeYear(ByteArrayInputStream inputStream) throws IOException { + return LocalDate.parse(String.format("%d-01-01", 1900 + inputStream.readInteger(1))); + } + + /** + * Deserializes a string from the given input stream. Since the charset is not present in the binary log, it is impossible to distinguish between + * CHAR and BINARY types. Therefore, the method returns a byte array instead of a String. + * + * @param length The length of the string. + * @param inputStream The input stream from which to read the string. + * @return A byte array representing the deserialized string. + * @throws IOException If an I/O error occurs while reading the input stream. + */ + private static Serializable deserializeString(int length, ByteArrayInputStream inputStream) throws IOException { + // charset is not present in the binary log (meaning there is no way to distinguish between CHAR / BINARY) + // as a result - return byte[] instead of an actual String + int stringLength = length < 256 ? inputStream.readInteger(1) : inputStream.readInteger(2); + return inputStream.read(stringLength); + } + + private static Serializable deserializeVarString(int meta, ByteArrayInputStream inputStream) throws IOException { + int varcharLength = meta < 256 ? inputStream.readInteger(1) : inputStream.readInteger(2); + return inputStream.read(varcharLength); + } + + private static Serializable deserializeDate(ByteArrayInputStream inputStream) throws IOException { + int value = inputStream.readInteger(3); + int day = value % 32; + value >>>= 5; + int month = value % 16; + int year = value >> 4; + // https://dev.mysql.com/doc/refman/8.0/en/datetime.html + if (year == 0 || month == 0 || day == 0) { + return null; + } + return LocalDate.of(year, month, day); + } + + protected static Serializable deserializeDatetime(ByteArrayInputStream inputStream) throws IOException { + int[] split = split(inputStream.readLong(8), 100, 6); + int year = split[5]; + int month = split[4]; // 1-based month number + int day = split[3]; // 1-based day of the month + int hours = split[2]; + int minutes = split[1]; + int seconds = split[0]; + int nanoOfSecond = 0; // This version does not support fractional seconds + if (year == 0 || month == 0 || day == 0) { + return null; + } + return LocalDateTime.of(year, month, day, hours, minutes, seconds, nanoOfSecond); + } + + private static final int MASK_10_BITS = (1 << 10) - 1; + private static final int MASK_6_BITS = (1 << 6) - 1; + + protected static Serializable deserializeTimeV2(int meta, ByteArrayInputStream inputStream) throws IOException { + + /** + * Binary Format for TIME in MySQL binlog: + * TIME + * +------+---------------+----------------------------------------------------+ + * | Bits | Field | Value Range | + * +------+---------------+----------------------------------------------------+ + * | 1 | sign | (Used for sign, when on disk) | + * | 1 | unused | (Reserved for wider hour range, e.g. for intervals)| + * | 10 | hour | (0-838) | + * | 6 | minute | (0-59) | + * | 6 | second | (0-59) | + * | 24 | microseconds | (0-999999) | + * +------+---------------+----------------------------------------------------+ + * + * + fractional-seconds storage (size depends on meta) + */ + long time = bigEndianLong(inputStream.read(3), 0, 3); + boolean isNegative = bitSlice(time, 0, 1, 24) == 0; + int hours = bitSlice(time, 2, 10, 24); + int minutes = bitSlice(time, 12, 6, 24); + int seconds = bitSlice(time, 18, 6, 24); + int nanoSeconds; + if (isNegative) { // mysql binary arithmetic for negative encoded values + hours = ~hours & MASK_10_BITS; + hours = hours & ~(1 << 10); // unset sign bit + minutes = ~minutes & MASK_6_BITS; + minutes = minutes & ~(1 << 6); // unset sign bit + seconds = ~seconds & MASK_6_BITS; + seconds = seconds & ~(1 << 6); // unset sign bit + nanoSeconds = deserializeFractionalSecondsInNanosNegative(meta, inputStream); + if (nanoSeconds == 0 && seconds < 59) { // weird java Duration behavior + ++seconds; + } + hours = -hours; + minutes = -minutes; + seconds = -seconds; + nanoSeconds = -nanoSeconds; + } else { + nanoSeconds = deserializeFractionalSecondsInNanos(meta, inputStream); + } + + return LocalTime.of(hours, minutes, seconds, nanoSeconds); + } + + protected static Serializable deserializeTime(ByteArrayInputStream inputStream) throws IOException { + // Times are stored as an integer as `HHMMSS`, so we need to split out the digits ... + int value = inputStream.readInteger(3); + int[] split = split(value, 100, 3); + int hours = split[2]; + int minutes = split[1]; + int seconds = split[0]; + return LocalTime.of(hours, minutes, seconds); + } + + protected static int deserializeFractionalSecondsInNanosNegative(int fsp, ByteArrayInputStream inputStream) throws IOException { + // Calculate the number of bytes to read, which is + // '1' when fsp=(1,2) + // '2' when fsp=(3,4) and + // '3' when fsp=(5,6) + int length = (fsp + 1) / 2; + if (length > 0) { + long fraction = bigEndianLong(inputStream.read(length), 0, length); + int maskBits = 0; + switch (length) { // mask bits according to field precision + case 1: + maskBits = 8; + break; + case 2: + maskBits = 15; + break; + case 3: + maskBits = 20; + break; + default: + break; + } + fraction = ~fraction & ((1 << maskBits) - 1); + fraction = (fraction & ~(1 << maskBits)) + 1; // unset sign bit + // Convert the fractional value (which has extra trailing digit for fsp=1,3, and 5) to nanoseconds ... + return (int) (fraction / (0.0000001 * Math.pow(100, length - 1))); + } + return 0; + } + + private static int bigEndianInteger(byte[] bytes, int offset, int length) { + int result = 0; + for (int i = offset; i < (offset + length); i++) { + byte b = bytes[i]; + result = (result << 8) | (b >= 0 ? (int) b : (b + 256)); + } + return result; + } + + protected static Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inputStream) + throws IOException { + + /** + * DATETIME + * 1 sign (used when on disk) + * 17 year*13+month (year 0-9999, month 0-12) + * 5 day (0-31) + * 5 hour (0-23) + * 6 minute (0-59) + * 6 second (0-59) + * 24 microseconds (0-999999) + * + * (5 bytes in total) + * + * + fractional-seconds storage (size depends on meta) + */ + long datetime = bigEndianLong(inputStream.read(5), 0, 5); + int yearMonth = bitSlice(datetime, 1, 17, 40); + int year = yearMonth / 13; + int month = yearMonth % 13; // 1-based month number + int day = bitSlice(datetime, 18, 5, 40); // 1-based day of the month + int hours = bitSlice(datetime, 23, 5, 40); + int minutes = bitSlice(datetime, 28, 6, 40); + int seconds = bitSlice(datetime, 34, 6, 40); + int nanoOfSecond = deserializeFractionalSecondsInNanos(meta, inputStream); + if (year == 0 || month == 0 || day == 0) { + return null; + } + return LocalDateTime.of(year, month, day, hours, minutes, seconds, nanoOfSecond); + } + + private static int[] split(long value, int divider, int length) { + int[] result = new int[length]; + for (int i = 0; i < length - 1; i++) { + result[i] = (int) (value % divider); + value /= divider; + } + result[length - 1] = (int) value; + return result; + } + + protected static long bigEndianLong(byte[] bytes, int offset, int length) { + long result = 0; + for (int i = offset; i < (offset + length); i++) { + byte b = bytes[i]; + result = (result << 8) | (b >= 0 ? (int) b : (b + 256)); + } + return result; + } + + protected static int bitSlice(long value, int bitOffset, int numberOfBits, int payloadSize) { + long result = value >> payloadSize - (bitOffset + numberOfBits); + return (int) (result & ((1 << numberOfBits) - 1)); + } + + protected static int deserializeFractionalSecondsInNanos(int fsp, ByteArrayInputStream inputStream) throws IOException { + // Calculate the number of bytes to read, which is + // '1' when fsp=(1,2) -- 7 + // '2' when fsp=(3,4) and -- 12 + // '3' when fsp=(5,6) -- 21 + int length = (fsp + 1) / 2; + if (length > 0) { + long fraction = bigEndianLong(inputStream.read(length), 0, length); + // Convert the fractional value (which has extra trailing digit for fsp=1,3, and 5) to nanoseconds ... + return (int) (fraction / (0.0000001 * Math.pow(100, length - 1))); + } + return 0; + } + + protected static byte[] deserializeBit(int meta, ByteArrayInputStream inputStream) throws IOException { + return inputStream.read(meta); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/EventDataDeserializationExceptionData.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/EventDataDeserializationExceptionData.java new file mode 100644 index 0000000000..4d06b6cc21 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/EventDataDeserializationExceptionData.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import com.github.shyiko.mysql.binlog.event.EventData; +import com.github.shyiko.mysql.binlog.event.deserialization.EventDataDeserializationException; + +public class EventDataDeserializationExceptionData implements EventData { + + private static final long serialVersionUID = 7990993358724828999L; + + private final EventDataDeserializationException cause; + + public EventDataDeserializationExceptionData(EventDataDeserializationException cause) { + this.cause = cause; + } + + public EventDataDeserializationException getCause() { + return cause; + } + + @Override + public String toString() { + return "EventDataDeserializationExceptionData [cause=" + cause + "]"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/EventMeshGtidSet.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/EventMeshGtidSet.java new file mode 100644 index 0000000000..0b2aca1c77 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/EventMeshGtidSet.java @@ -0,0 +1,483 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public final class EventMeshGtidSet { + + private final Map uuidSetsByServerId = new TreeMap<>(); // sorts on keys + public static Pattern GTID_DELIMITER = Pattern.compile(":"); + + protected EventMeshGtidSet(Map uuidSetsByServerId) { + this.uuidSetsByServerId.putAll(uuidSetsByServerId); + } + + /** + * @param gtids the string representation of the GTIDs. + */ + public EventMeshGtidSet(String gtids) { + new com.github.shyiko.mysql.binlog.GtidSet(gtids).getUUIDSets().forEach(uuidSet -> { + uuidSetsByServerId.put(uuidSet.getServerId().toString(), new UUIDSet(uuidSet)); + }); + StringBuilder sb = new StringBuilder(); + uuidSetsByServerId.values().forEach(uuidSet -> { + if (sb.length() != 0) { + sb.append(','); + } + sb.append(uuidSet.toString()); + }); + } + + /** + * Obtain a copy of this {@link EventMeshGtidSet} except with only the GTID ranges that have server UUIDs that match the given predicate. + * + * @param sourceFilter the predicate that returns whether a server UUID is to be included + * @return the new GtidSet, or this object if {@code sourceFilter} is null; never null + */ + public EventMeshGtidSet retainAll(Predicate sourceFilter) { + if (sourceFilter == null) { + return this; + } + Map newSets = this.uuidSetsByServerId.entrySet() + .stream() + .filter(entry -> sourceFilter.test(entry.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + return new EventMeshGtidSet(newSets); + } + + /** + * Get an immutable collection of the {@link UUIDSet range of GTIDs for a single server}. + * + * @return the {@link UUIDSet GTID ranges for each server}; never null + */ + public Collection getUUIDSets() { + return Collections.unmodifiableCollection(uuidSetsByServerId.values()); + } + + /** + * Find the {@link UUIDSet} for the server with the specified Uuid. + * + * @param uuid the Uuid of the server + * @return the {@link UUIDSet} for the identified server, or {@code null} if there are no GTIDs from that server. + */ + public UUIDSet forServerWithId(String uuid) { + return uuidSetsByServerId.get(uuid); + } + + /** + * Determine if the GTIDs represented by this object are contained completely within the supplied set of GTIDs. + * + * @param other the other set of GTIDs; may be null + * @return {@code true} if all of the GTIDs in this set are completely contained within the supplied set of GTIDs, or {@code false} otherwise + */ + public boolean isContainedWithin(EventMeshGtidSet other) { + if (other == null) { + return false; + } + if (this.equals(other)) { + return true; + } + for (UUIDSet uuidSet : uuidSetsByServerId.values()) { + UUIDSet thatSet = other.forServerWithId(uuidSet.getUUID()); + if (!uuidSet.isContainedWithin(thatSet)) { + return false; + } + } + return true; + } + + /** + * Obtain a copy of this {@link EventMeshGtidSet} except overwritten with all of the GTID ranges in the supplied {@link EventMeshGtidSet}. + * + * @param other the other {@link EventMeshGtidSet} with ranges to add/overwrite on top of those in this set; + * @return the new GtidSet, or this object if {@code other} is null or empty; never null + */ + public EventMeshGtidSet with(EventMeshGtidSet other) { + if (other == null || other.uuidSetsByServerId.isEmpty()) { + return this; + } + Map newSet = new HashMap<>(); + newSet.putAll(this.uuidSetsByServerId); + newSet.putAll(other.uuidSetsByServerId); + return new EventMeshGtidSet(newSet); + } + + /** + * Retrieves the beginning GTID set. + * + * @return The starting state of the GTID set. + */ + public EventMeshGtidSet getGtidSetBeginning() { + // Create a new map to store the GTID set + Map newSet = new HashMap<>(); + + // Iterate over each UUID set for each server ID + for (UUIDSet uuidSet : uuidSetsByServerId.values()) { + // Store the beginning state of each UUID set as the value in the new set, with UUID as the key + newSet.put(uuidSet.getUUID(), uuidSet.asIntervalBeginning()); + } + + // Create and return a new GTID set object using the new map + return new EventMeshGtidSet(newSet); + } + + public boolean contains(String gtid) { + String[] split = GTID_DELIMITER.split(gtid); + String sourceId = split[0]; + UUIDSet uuidSet = forServerWithId(sourceId); + if (uuidSet == null) { + return false; + } + long transactionId = Long.parseLong(split[1]); + return uuidSet.contains(transactionId); + } + + public EventMeshGtidSet subtract(EventMeshGtidSet other) { + if (other == null) { + return this; + } + Map newSets = this.uuidSetsByServerId.entrySet() + .stream() + .filter(entry -> !entry.getValue().isContainedWithin(other.forServerWithId(entry.getKey()))) + .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().subtract(other.forServerWithId(entry.getKey())))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + return new EventMeshGtidSet(newSets); + } + + @Override + public int hashCode() { + return uuidSetsByServerId.keySet().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof EventMeshGtidSet) { + EventMeshGtidSet that = (EventMeshGtidSet) obj; + return this.uuidSetsByServerId.equals(that.uuidSetsByServerId); + } + return false; + } + + @Override + public String toString() { + List gtids = new ArrayList(); + for (UUIDSet uuidSet : uuidSetsByServerId.values()) { + gtids.add(uuidSet.toString()); + } + return String.join(",", gtids); + } + + /** + * A range of GTIDs for a single server with a specific Uuid. + */ + + public static class UUIDSet { + + private final String uuid; + private final LinkedList intervals = new LinkedList<>(); + + protected UUIDSet(com.github.shyiko.mysql.binlog.GtidSet.UUIDSet uuidSet) { + this.uuid = uuidSet.getServerId().toString(); + uuidSet.getIntervals().forEach(interval -> { + intervals.add(new Interval(interval.getStart(), interval.getEnd())); + }); + Collections.sort(this.intervals); + if (this.intervals.size() > 1) { + // Collapse adjacent intervals ... + for (int i = intervals.size() - 1; i != 0; --i) { + Interval before = this.intervals.get(i - 1); + Interval after = this.intervals.get(i); + if ((before.getEnd() + 1) == after.getStart()) { + this.intervals.set(i - 1, new Interval(before.getStart(), after.getEnd())); + this.intervals.remove(i); + } + } + } + } + + protected UUIDSet(String uuid, Interval interval) { + this.uuid = uuid; + this.intervals.add(interval); + } + + protected UUIDSet(String uuid, List intervals) { + this.uuid = uuid; + this.intervals.addAll(intervals); + } + + public UUIDSet asIntervalBeginning() { + Interval start = new Interval(intervals.get(0).getStart(), intervals.get(0).getStart()); + return new UUIDSet(this.uuid, start); + } + + /** + * Get the Uuid for the server that generated the GTIDs. + * + * @return the server's Uuid; never null + */ + public String getUUID() { + return uuid; + } + + /** + * Get the intervals of transaction numbers. + * + * @return the immutable transaction intervals; never null + */ + public List getIntervals() { + return Collections.unmodifiableList(intervals); + } + + /** + * Determine if the set of transaction numbers from this server is completely within the set of transaction numbers from the set of + * transaction numbers in the supplied set. + * + * @param other the set to compare with this set + * @return {@code true} if this server's transaction numbers are a subset of the transaction numbers of the supplied set, or false otherwise + */ + public boolean isContainedWithin(UUIDSet other) { + if (other == null) { + return false; + } + if (!this.getUUID().equalsIgnoreCase(other.getUUID())) { + // Not even the same server ... + return false; + } + if (this.intervals.isEmpty()) { + return true; + } + if (other.intervals.isEmpty()) { + return false; + } + assert this.intervals.size() > 0; + assert other.intervals.size() > 0; + + // Every interval in this must be within an interval of the other ... + for (Interval thisInterval : this.intervals) { + boolean found = false; + for (Interval otherInterval : other.intervals) { + if (thisInterval.isContainedWithin(otherInterval)) { + found = true; + break; + } + } + if (!found) { + return false; // didn't find a match + } + } + return true; + } + + public boolean contains(long transactionId) { + for (Interval interval : this.intervals) { + if (interval.contains(transactionId)) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return uuid.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof UUIDSet) { + UUIDSet that = (UUIDSet) obj; + return this.getUUID().equalsIgnoreCase(that.getUUID()) && this.getIntervals().equals(that.getIntervals()); + } + return super.equals(obj); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(uuid).append(':'); + Iterator iter = intervals.iterator(); + if (iter.hasNext()) { + sb.append(iter.next()); + } + while (iter.hasNext()) { + sb.append(':'); + sb.append(iter.next()); + } + return sb.toString(); + } + + public UUIDSet subtract(UUIDSet other) { + if (!uuid.equals(other.getUUID())) { + throw new IllegalArgumentException("UUIDSet subtraction is supported only within a single server UUID"); + } + List result = new ArrayList<>(); + for (Interval interval : intervals) { + result.addAll(interval.removeAll(other.getIntervals())); + } + return new UUIDSet(uuid, result); + } + } + + public static class Interval implements Comparable { + + private final long start; + private final long end; + + public Interval(long start, long end) { + this.start = start; + this.end = end; + } + + /** + * Get the starting transaction number in this interval. + * + * @return this interval's first transaction number + */ + public long getStart() { + return start; + } + + /** + * Get the ending transaction number in this interval. + * + * @return this interval's last transaction number + */ + public long getEnd() { + return end; + } + + /** + * Determine if this interval is completely within the supplied interval. + * + * @param other the interval to compare with + * @return {@code true} if the {@link #getStart() start} is greater than or equal to the supplied interval's {@link #getStart() start} and the + * {@link #getEnd() end} is less than or equal to the supplied interval's {@link #getEnd() end}, or {@code false} otherwise + */ + public boolean isContainedWithin(Interval other) { + if (other == this) { + return true; + } + if (other == null) { + return false; + } + return this.getStart() >= other.getStart() && this.getEnd() <= other.getEnd(); + } + + public boolean contains(long transactionId) { + return getStart() <= transactionId && transactionId <= getEnd(); + } + + public boolean contains(Interval other) { + return getStart() <= other.getStart() && getEnd() >= other.getEnd(); + } + + public boolean nonintersecting(Interval other) { + return other.getEnd() < this.getStart() || other.getStart() > this.getEnd(); + } + + public List remove(Interval other) { + if (nonintersecting(other)) { + return Collections.singletonList(this); + } + if (other.contains(this)) { + return Collections.emptyList(); + } + List result = new LinkedList<>(); + if (this.getStart() < other.getStart()) { + Interval part = new Interval(this.getStart(), other.getStart() - 1); + result.add(part); + } + if (other.getEnd() < this.getEnd()) { + Interval part = new Interval(other.getEnd() + 1, this.getEnd()); + result.add(part); + } + return result; + } + + public List removeAll(List otherIntervals) { + List thisIntervals = new LinkedList<>(); + thisIntervals.add(this); + List result = new LinkedList<>(); + result.add(this); + for (Interval other : otherIntervals) { + result = new LinkedList<>(); + for (Interval thisInterval : thisIntervals) { + result.addAll(thisInterval.remove(other)); + } + thisIntervals = result; + } + return result; + } + + @Override + public int compareTo(Interval that) { + if (that == this) { + return 0; + } + long diff = this.start - that.start; + if (diff > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + if (diff < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return (int) diff; + } + + @Override + public int hashCode() { + return (int) getStart(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Interval) { + Interval that = (Interval) obj; + return this.getStart() == that.getStart() && this.getEnd() == that.getEnd(); + } + return false; + } + + @Override + public String toString() { + return "" + getStart() + "-" + getEnd(); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlConstants.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlConstants.java new file mode 100644 index 0000000000..44f10cee6c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlConstants.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import java.util.HashSet; +import java.util.Set; + +public final class MysqlConstants { + + public static final Set DEFAULT_EXCLUDE_DATABASE = new HashSet<>(); + + static { + DEFAULT_EXCLUDE_DATABASE.add("information_schema"); + DEFAULT_EXCLUDE_DATABASE.add("mysql"); + DEFAULT_EXCLUDE_DATABASE.add("performance_schema"); + DEFAULT_EXCLUDE_DATABASE.add("sys"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlDataTypeConvertor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlDataTypeConvertor.java new file mode 100644 index 0000000000..322e4f5f18 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlDataTypeConvertor.java @@ -0,0 +1,240 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import org.apache.eventmesh.connector.jdbc.DataTypeConvertor; +import org.apache.eventmesh.connector.jdbc.exception.DataTypeConvertException; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BooleanEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BytesEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DateEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DateTimeEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DecimalEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Float32EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Float64EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int16EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int32EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int64EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int8EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.NullEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.StringEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.TimeEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.YearEventMeshDataType; + +import java.sql.JDBCType; +import java.util.Map; +import java.util.Objects; + +import com.mysql.cj.MysqlType; + +public class MysqlDataTypeConvertor implements DataTypeConvertor { + + public static final String PRECISION = "precision"; + + public static final String SCALE = "scale"; + + /** + * @see Fixed-Point Types (Exact Value) - DECIMAL, NUMERIC + */ + public static final Integer DEFAULT_PRECISION = 10; + + public static final Integer DEFAULT_SCALE = 0; + + /** + * Converts a string representation of a connector data type to the corresponding JDBCType. + * + * @param connectorDataType The string representation of the connector data type. + * @return The corresponding JDBCType, or null if the connector data type is not recognized. + */ + @Override + public JDBCType toJDBCType(String connectorDataType) { + MysqlType mysqlType = MysqlType.getByName(connectorDataType); + return JDBCType.valueOf(mysqlType.getJdbcType()); + } + + /** + * Converts a connector data type to an EventMesh data type. e.g. "int", "varchar(255)","decimal(10,2)" + * + * @param connectorDataType The connector data type to be converted. + * @return The converted EventMesh data type. + * @throws DataTypeConvertException If the conversion fails. + */ + @Override + public EventMeshDataType toEventMeshType(String connectorDataType) throws DataTypeConvertException { + MysqlType mysqlType = MysqlType.getByName(connectorDataType); + return toEventMeshType(mysqlType, null); + } + + /** + * Converts JDBCType and dataTypeProperties to EventMeshDataType. + * + * @param jdbcType the JDBCType to be converted + * @param dataTypeProperties the properties of the data type + * @return the converted EventMeshDataType + * @throws DataTypeConvertException if there is an error during conversion + */ + @Override + public EventMeshDataType toEventMeshType(JDBCType jdbcType, Map dataTypeProperties) throws DataTypeConvertException { + return toEventMeshType(MysqlType.getByJdbcType(jdbcType.getVendorTypeNumber()), dataTypeProperties); + } + + /** + * Converts a connector data type to an EventMesh data type with additional data type properties. + * + * @param connectorDataType The connector data type to be converted. + * @param dataTypeProperties Additional data type properties. + * @return The converted EventMesh data type. + * @throws DataTypeConvertException If the conversion fails. + */ + @Override + public EventMeshDataType toEventMeshType(MysqlType connectorDataType, Map dataTypeProperties) throws DataTypeConvertException { + + Objects.requireNonNull(connectorDataType, "MysqlType can't be null"); + + switch (connectorDataType) { + case NULL: + return NullEventMeshDataType.INSTANCE; + case BOOLEAN: + return BooleanEventMeshDataType.INSTANCE; + case BIT: { + /** + * @see Mysql doc + */ + if (dataTypeProperties == null) { + return BytesEventMeshDataType.INSTANCE; + } + Integer precision = (Integer) dataTypeProperties.get(MysqlDataTypeConvertor.PRECISION); + if (precision != null && precision == 1) { + return BooleanEventMeshDataType.INSTANCE; + } + return BytesEventMeshDataType.INSTANCE; + } + case TINYINT: + return Int8EventMeshDataType.INSTANCE; + case TINYINT_UNSIGNED: + case SMALLINT: + return Int16EventMeshDataType.INSTANCE; + case SMALLINT_UNSIGNED: + case INT: + case MEDIUMINT: + case MEDIUMINT_UNSIGNED: + return Int32EventMeshDataType.INSTANCE; + case INT_UNSIGNED: + case BIGINT: + return Int64EventMeshDataType.INSTANCE; + case FLOAT: + case FLOAT_UNSIGNED: + return Float32EventMeshDataType.INSTANCE; + case DOUBLE: + case DOUBLE_UNSIGNED: + return Float64EventMeshDataType.INSTANCE; + case TIME: + return TimeEventMeshDataType.INSTANCE; + case YEAR: + return YearEventMeshDataType.INSTANCE; + case DATE: + return DateEventMeshDataType.INSTANCE; + case TIMESTAMP: + case DATETIME: + return DateTimeEventMeshDataType.INSTANCE; + case CHAR: + case VARCHAR: + case TINYTEXT: + case TEXT: + case MEDIUMTEXT: + case LONGTEXT: + case JSON: + case ENUM: + case SET: + return StringEventMeshDataType.INSTANCE; + case BINARY: + case VARBINARY: + case TINYBLOB: + case BLOB: + case MEDIUMBLOB: + case LONGBLOB: + case GEOMETRY: + return BytesEventMeshDataType.INSTANCE; + case BIGINT_UNSIGNED: + case DECIMAL: + case DECIMAL_UNSIGNED: { + /** + * @see Mysql doc-DECIMAL, NUMERIC + */ + if (dataTypeProperties == null) { + return new DecimalEventMeshDataType(DEFAULT_PRECISION, DEFAULT_SCALE); + } + Integer precision = (Integer) dataTypeProperties.getOrDefault(PRECISION, DEFAULT_PRECISION); + Integer scale = (Integer) dataTypeProperties.getOrDefault(SCALE, DEFAULT_SCALE); + return new DecimalEventMeshDataType(precision, scale); + } + default: + throw new DataTypeConvertException(String.format("%s type is not supported", connectorDataType.getName())); + } + } + + /** + * Converts an EventMesh data type to a connector data type with additional data type properties. + * + * @param eventMeshDataType The EventMesh data type to be converted. + * @param dataTypeProperties Additional data type properties. + * @return The converted connector data type. + * @throws DataTypeConvertException If the conversion fails. + */ + @Override + public MysqlType toConnectorType(EventMeshDataType eventMeshDataType, Map dataTypeProperties) throws DataTypeConvertException { + + Objects.requireNonNull(eventMeshDataType, "Parameter eventMeshDataType can not be null"); + SQLType sqlType = eventMeshDataType.getSQLType(); + + switch (sqlType) { + case BOOLEAN: + return MysqlType.BOOLEAN; + case TINYINT: + return MysqlType.TINYINT; + case SMALLINT: + return MysqlType.SMALLINT; + case INTEGER: + return MysqlType.INT; + case BIGINT: + return MysqlType.BIGINT; + case FLOAT: + return MysqlType.FLOAT; + case DOUBLE: + return MysqlType.DOUBLE; + case DECIMAL: + return MysqlType.DECIMAL; + case NULL: + return MysqlType.NULL; + case BINARY: + return MysqlType.BIT; + case DATE: + return MysqlType.DATE; + case TIME: + return MysqlType.DATETIME; + case TIMESTAMP: + return MysqlType.TIMESTAMP; + case ARRAY: + case STRING: + return MysqlType.VARCHAR; + default: + throw new DataTypeConvertException(String.format("%s type is not supported", sqlType.name())); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlDialectSql.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlDialectSql.java new file mode 100644 index 0000000000..175ec93c99 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlDialectSql.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +public enum MysqlDialectSql { + + SHOW_DATABASE("SHOW DATABASES;", "show mysql database sql"), + + SELECT_DATABASE("USE %s", " Try to access database"), + + /** + * https://dev.mysql.com/doc/refman/8.0/en/show-tables.html + */ + SHOW_DATABASE_TABLE("SHOW FULL TABLES IN %s WHERE Table_type = 'BASE TABLE';", "show mysql database tables"), + + /** + * https://dev.mysql.com/doc/refman/8.0/en/show-columns.html + */ + SHOW_TABLE_COLUMNS("SHOW FULL COLUMNS FROM %s FROM %s;", "show mysql database table columns"), + + SELECT_TABLE_COLUMNS("SELECT * FROM %s WHERE 1=2", "show mysql database table columns"), + + /** + * https://dev.mysql.com/doc/refman/8.0/en/show-create-table.html + */ + SHOW_CREATE_TABLE("SHOW CREATE TABLE %s", "show mysql database table columns"), + + SHOW_GTID_STATUS("SHOW GLOBAL VARIABLES LIKE 'GTID_MODE'", "Show GTID_MODE Enable or not"), + + SHOW_MASTER_STATUS("SHOW MASTER STATUS", "Show master status"), + + SELECT_PURGED_GTID("SELECT @@global.gtid_purged", "SELECT the purged GTID values"), + + SHOW_GRANTS_FOR_CURRENT_USER("SHOW GRANTS FOR CURRENT_USER", "s=Show grants for current user"), + + SHOW_CREATE_DATABASE("SHOW CREATE DATABASE %s", "Show create database sql"), + + /** + * SHOW_TABLE_STATUS + */ + SHOW_TABLE_STATUS("SHOW TABLE STATUS LIKE '%s'", "Show table status"), + + SNAPSHOT_TABLE_SELECT_SQL("SELECT * FROM %s", "Select table data sql in snapshot"), + + LOCK_TABLE_GLOBAL("FLUSH TABLES WITH READ LOCK", "global lock tables"), + + LOCK_TABLES("FLUSH TABLES %s WITH READ LOCK", "lock tables"), + + UNLOCK_TABLES("UNLOCK TABLES", "unlock tables"); + + private final String sql; + + private final String desc; + + MysqlDialectSql(String sql, String desc) { + this.sql = sql; + this.desc = desc; + } + + public String ofSQL() { + return this.sql; + } + + public String ofWrapperSQL(Object... parameters) { + return String.format(this.sql, parameters); + } + + public String ofDescription() { + return this.desc; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlJdbcContext.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlJdbcContext.java new file mode 100644 index 0000000000..8775d4d488 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlJdbcContext.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.SourceConnectorConfig; +import org.apache.eventmesh.connector.jdbc.PartitionOffSetContextPair; +import org.apache.eventmesh.connector.jdbc.UniversalJdbcContext; +import org.apache.eventmesh.connector.jdbc.context.mysql.MysqlOffsetContext; +import org.apache.eventmesh.connector.jdbc.context.mysql.MysqlPartition; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; + +import org.apache.commons.lang3.StringUtils; + +import lombok.Getter; + +public class MysqlJdbcContext extends UniversalJdbcContext { + + @Getter + private MysqlSourceInfo sourceInfo = new MysqlSourceInfo(); + + private volatile long currentHandleEventSize = 0; + + private volatile boolean onTransaction = false; + + // need to load from store when start + private String restartGtidSet; + + private String currentGtidSet; + + private String restartBinlogFilename; + + private long restartBinlogPosition; + + private String transactionId; + + private JdbcSourceConfig jdbcSourceConfig; + + public MysqlJdbcContext(PartitionOffSetContextPair poCtx, MysqlAntlr4DdlParser parser) { + super(poCtx, parser); + } + + public MysqlJdbcContext(MysqlPartition mysqlPartition, MysqlOffsetContext mysqlOffsetContext, MysqlAntlr4DdlParser parser) { + super(mysqlPartition, mysqlOffsetContext, parser); + } + + public MysqlJdbcContext(JdbcSourceConfig jdbcSourceConfig, MysqlAntlr4DdlParser parser) { + this(new MysqlPartition(), new MysqlOffsetContext(), parser); + this.jdbcSourceConfig = jdbcSourceConfig; + } + + public void setBinlogStartPoint(String binlogFilename, long beginProcessPosition) { + assert beginProcessPosition >= 0; + if (binlogFilename != null) { + sourceInfo.setBinlogPosition(binlogFilename, beginProcessPosition); + + } else { + sourceInfo.setBinlogPosition(sourceInfo.getCurrentBinlogFileName(), beginProcessPosition); + } + } + + public void setEventPosition(long positionOfCurrentEvent, long eventSize) { + this.sourceInfo.setCurrentBinlogPosition(positionOfCurrentEvent); + this.currentHandleEventSize = eventSize; + } + + public static MysqlJdbcContext initialize(JdbcSourceConfig jdbcSourceConfig) { + SourceConnectorConfig sourceConnectorConfig = jdbcSourceConfig.getSourceConnectorConfig(); + MysqlAntlr4DdlParser mysqlAntlr4DdlParser = new MysqlAntlr4DdlParser(sourceConnectorConfig.isSkipViews(), + sourceConnectorConfig.isSkipComments(), jdbcSourceConfig); + return new MysqlJdbcContext(new MysqlPartition(), new MysqlOffsetContext(), mysqlAntlr4DdlParser); + } + + public void startTransaction() { + this.onTransaction = true; + } + + public void commitTransaction() { + this.onTransaction = false; + this.restartGtidSet = this.currentGtidSet; + this.restartBinlogFilename = sourceInfo.getCurrentBinlogFileName(); + this.restartBinlogPosition = sourceInfo.getCurrentBinlogPosition() + this.currentHandleEventSize; + resetTransactionId(); + } + + public void complete() { + this.currentHandleEventSize = 0; + } + + public void completedGtidSet(String gtidSet) { + if (StringUtils.isNotBlank(gtidSet)) { + String trimmedGtidSet = gtidSet.replace("\n", "").replace("\r", ""); + this.currentGtidSet = trimmedGtidSet; + this.restartGtidSet = trimmedGtidSet; + } + } + + public String getGtidSet() { + return this.currentGtidSet; + } + + public void beginGtid(String gtid) { + this.sourceInfo.beginGtid(gtid); + } + + private void resetTransactionId() { + transactionId = null; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlSourceInfo.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlSourceInfo.java new file mode 100644 index 0000000000..d6a0106b64 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlSourceInfo.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import org.apache.eventmesh.connector.jdbc.common.SourceInfo; + +import lombok.Data; + +@Data +public class MysqlSourceInfo implements SourceInfo { + + private String currentBinlogFileName; + + private volatile long currentBinlogPosition = 0L; + + private int currentRowNumber = 0; + + // Support mysql gtid + private String currentGtid; + + public void setBinlogPosition(String binlogFileName, long beginProcessPosition) { + if (binlogFileName != null) { + this.currentBinlogFileName = binlogFileName; + } + assert beginProcessPosition >= 0; + this.currentBinlogPosition = beginProcessPosition; + this.currentRowNumber = 0; + } + + public void beginGtid(String gtid) { + this.currentGtid = gtid; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlSourceMateData.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlSourceMateData.java new file mode 100644 index 0000000000..84a70e557f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/MysqlSourceMateData.java @@ -0,0 +1,162 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseType; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Represents MySQL-specific metadata related to a data source. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MysqlSourceMateData extends SourceMateData { + + /** + * The server ID of the MySQL instance. + */ + private int serverId; + + /** + * The Global Transaction Identifier (GTID) associated with the metadata. + */ + private String gtid; + + /** + * The name of the mysql binary log file. + */ + private String binlogFile; + + /** + * The position within the binary log file. + */ + private long position; + + /** + * The SQL statement associated with the metadata. + */ + private String sql; + + public static MysqlSourceMateDataBuilder newBuilder() { + return new MysqlSourceMateDataBuilder(); + } + + public static class MysqlSourceMateDataBuilder { + + private String connector = DatabaseType.MYSQL.getCode(); + private String name; + private long timestamp = System.currentTimeMillis(); + private boolean snapshot; + private String catalogName; + private String schemaName; + private String tableName; + private int serverId; + private String gtid; + private String binlogFile; + private long position; + private String sql; + + public MysqlSourceMateDataBuilder connector(String connector) { + this.connector = connector; + return this; + } + + public MysqlSourceMateDataBuilder name(String name) { + this.name = name; + return this; + } + + public MysqlSourceMateDataBuilder timestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + public MysqlSourceMateDataBuilder snapshot(boolean snapshot) { + this.snapshot = snapshot; + return this; + } + + public MysqlSourceMateDataBuilder withTableId(TableId tableId) { + this.catalogName = tableId.getCatalogName(); + this.schemaName = tableId.getSchemaName(); + this.tableName = tableId.getTableName(); + return this; + } + + public MysqlSourceMateDataBuilder catalogName(String catalogName) { + this.catalogName = catalogName; + return this; + } + + public MysqlSourceMateDataBuilder schemaName(String schemaName) { + this.schemaName = schemaName; + return this; + } + + public MysqlSourceMateDataBuilder tableName(String tableName) { + this.tableName = tableName; + return this; + } + + public MysqlSourceMateDataBuilder serverId(int serverId) { + this.serverId = serverId; + return this; + } + + public MysqlSourceMateDataBuilder gtid(String gtid) { + this.gtid = gtid; + return this; + } + + public MysqlSourceMateDataBuilder binlogFile(String binlogFile) { + this.binlogFile = binlogFile; + return this; + } + + public MysqlSourceMateDataBuilder position(long position) { + this.position = position; + return this; + } + + public MysqlSourceMateDataBuilder sql(String sql) { + this.sql = sql; + return this; + } + + public MysqlSourceMateData build() { + MysqlSourceMateData metadata = new MysqlSourceMateData(); + metadata.setConnector(connector); + metadata.setName(name); + metadata.setTimestamp(timestamp); + metadata.setSnapshot(snapshot); + metadata.setCatalogName(catalogName); + metadata.setSchemaName(schemaName); + metadata.setTableName(tableName); + metadata.setServerId(serverId); + metadata.setGtid(gtid); + metadata.setBinlogFile(binlogFile); + metadata.setPosition(position); + metadata.setSql(sql); + return metadata; + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/StopEventData.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/StopEventData.java new file mode 100644 index 0000000000..100516f00b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/StopEventData.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import com.github.shyiko.mysql.binlog.event.EventData; + +public class StopEventData implements EventData { + + private static final long serialVersionUID = -7056169406695094519L; + + @Override + public String toString() { + return "StopEventData"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/StopEventDataDeserializer.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/StopEventDataDeserializer.java new file mode 100644 index 0000000000..602d11dded --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/mysql/StopEventDataDeserializer.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.mysql; + +import java.io.IOException; + +import com.github.shyiko.mysql.binlog.event.deserialization.EventDataDeserializer; +import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream; + +public class StopEventDataDeserializer implements EventDataDeserializer { + + @Override + public StopEventData deserialize(ByteArrayInputStream inputStream) throws IOException { + return new StopEventData(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/AbstractSnapshotEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/AbstractSnapshotEngine.java new file mode 100644 index 0000000000..3c46970182 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/AbstractSnapshotEngine.java @@ -0,0 +1,383 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.connector.jdbc.DataChanges; +import org.apache.eventmesh.connector.jdbc.DataChanges.Builder; +import org.apache.eventmesh.connector.jdbc.Field; +import org.apache.eventmesh.connector.jdbc.JdbcContext; +import org.apache.eventmesh.connector.jdbc.OffsetContext; +import org.apache.eventmesh.connector.jdbc.Partition; +import org.apache.eventmesh.connector.jdbc.Payload; +import org.apache.eventmesh.connector.jdbc.Schema; +import org.apache.eventmesh.connector.jdbc.UniversalJdbcContext; +import org.apache.eventmesh.connector.jdbc.connection.JdbcConnection; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.event.InsertDataEvent; +import org.apache.eventmesh.connector.jdbc.source.AbstractEngine; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotResult.SnapshotResultStatus; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableSchema; + +import org.apache.commons.collections4.CollectionUtils; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalLong; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletionService; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +/** + * Abstract base class for snapshot engines. + * + * @param The Database Dialect + * @param The JDBC context type + * @param The partition type + * @param The offset context type + */ +@Slf4j +public abstract class AbstractSnapshotEngine, Jc extends JdbcContext, Part extends Partition, + Offset extends OffsetContext, Jconn extends JdbcConnection> extends AbstractEngine implements SnapshotEngine { + + private final Jconn jdbcConnection; + + private Jc context; + + private Part partition; + + private Offset offsetContext; + + protected BlockingQueue eventQueue = new LinkedBlockingQueue<>(10000); + + public AbstractSnapshotEngine(JdbcSourceConfig jdbcSourceConfig, DbDialect databaseDialect, Jc jdbcContext, Part partition, + Offset context) { + super(jdbcSourceConfig, databaseDialect); + this.context = jdbcContext; + this.partition = partition; + this.offsetContext = context; + this.jdbcConnection = databaseDialect.getConnection(); + } + + + @Override + public SnapshotResult execute() { + if (jdbcSourceConfig.getSourceConnectorConfig().isSkipSnapshot()) { + return new SnapshotResult<>(SnapshotResultStatus.SKIPPED, null); + } + SnapshotContext snapshotContext = new SnapshotContext<>(partition, offsetContext); + return doExecute(context, snapshotContext); + } + + + /** + * Template method that executes the snapshot logic. + * + * @param context the JDBC context + * @param snapshotContext the snapshot context + * @return the snapshot result + */ + protected SnapshotResult doExecute(Jc context, SnapshotContext snapshotContext) { + + Connection masterConnection = null; + Queue connectionPool = null; + try { + masterConnection = createMasterConnection(); + log.info("Snapshot 1: Preparations for Snapshot Work"); + preSnapshot(context, snapshotContext); + + log.info("Snapshot 2: Retrieve tables requiring snapshot handling"); + determineTable2Process(context, snapshotContext); + + log.info("Snapshot 3: Put locks on the tables that need to be processed"); + if (sourceConnectorConfig.isSnapshotSchema()) { + lockTables4SchemaSnapshot(context, snapshotContext); + } + + log.info("Snapshot 4: Determining snapshot offset"); + determineSnapshotOffset(context, snapshotContext); + + log.info("Snapshot 5: Obtain the schema of the captured tables"); + readStructureOfTables(context, snapshotContext); + + //Release locks + releaseSnapshotLocks(context, snapshotContext); + + //Whether to determine whether to process the table data? + if (sourceConnectorConfig.isSnapshotData()) { + connectionPool = createConnectionPool(snapshotContext); + createDataEvents(context, snapshotContext, connectionPool); + } + log.info("Snapshot 6: Release the locks"); + releaseSnapshotLocks(context, snapshotContext); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + //close connection pool's connection + try { + if (CollectionUtils.isNotEmpty(connectionPool)) { + for (JdbcConnection conn : connectionPool) { + conn.close(); + } + } + //Roll back master connection transaction + rollbackMasterConnTransaction(masterConnection); + } catch (Exception e) { + log.warn("Handle snapshot finally error", e); + } + } + return new SnapshotResult<>(SnapshotResultStatus.COMPLETED, context); + } + + private void rollbackMasterConnTransaction(Connection connection) { + if (connection != null) { + try { + connection.rollback(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + private Connection createMasterConnection() throws SQLException { + JdbcConnection connection = databaseDialect.getConnection(); + connection.setAutoCommit(false); + return connection.connection(); + } + + /** + * Creates data events. + * + * @param context The context. + * @param snapshotContext The snapshot context. + * @param connectionPool The connection pool. + * @throws SQLException If an error occurs. + */ + private void createDataEvents(Jc context, SnapshotContext snapshotContext, Queue connectionPool) + throws Exception { + + int handleDataThreadNum = connectionPool.size(); + //Create thread pool to process table data + ThreadPoolExecutor tableDataPoolExecutor = ThreadPoolFactory.createThreadPoolExecutor(handleDataThreadNum, handleDataThreadNum, + "snapshot-table-data-thread"); + CompletionService completionService = new ExecutorCompletionService<>(tableDataPoolExecutor); + try { + for (TableId tableId : snapshotContext.determineTables) { + String sql = getSnapshotTableSelectSql(context, snapshotContext, tableId).get(); + Callable callable = createSnapshotDataEvent4TableCallable(context, snapshotContext, connectionPool, sql, tableId); + completionService.submit(callable); + } + int tableSize = snapshotContext.determineTables.size(); + for (int index = 0; index < tableSize; ++index) { + completionService.take().get(); + } + } finally { + tableDataPoolExecutor.shutdownNow(); + } + } + + private Callable createSnapshotDataEvent4TableCallable(Jc context, SnapshotContext snapshotContext, + Queue connectionPool, String sql, TableId tableId) { + UniversalJdbcContext universalJdbcContext = (UniversalJdbcContext) context; + //universalJdbcContext.withTableId(tableId); + return () -> { + JdbcConnection connection = connectionPool.poll(); + SourceMateData sourceMateData = buildSourceMateData(context, snapshotContext, tableId); + TableSchema tableSchema = universalJdbcContext.getCatalogTableSet().getTableSchema(tableId); + Field field = new Field().withField("after").withName("payload.after").withRequired(false); + List columns = tableSchema.getColumns(); + if (CollectionUtils.isNotEmpty(columns)) { + List fields = columns.stream().map(col -> { + Column rebuild = Column.newBuilder().withName(col.getName()).withDataType(col.getDataType()) + .withJdbcType(col.getJdbcType()).withNativeType(col.getNativeType()).withOrder(col.getOrder()).build(); + return new Field(rebuild, col.isNotNull(), col.getName(), tableId.toString()); + }).collect(Collectors.toList()); + field.withRequired(true).withFields(fields); + } + try (Statement statement = connection.createStatement(jdbcSourceConfig.getSourceConnectorConfig().getSnapshotFetchSize(), 100)) { + ResultSet resultSet = statement.executeQuery(sql); + while (resultSet.next()) { + int columnCount = resultSet.getMetaData().getColumnCount(); + InsertDataEvent event = new InsertDataEvent(tableId); + Map values = new HashMap<>(columnCount); + for (int index = 1; index <= columnCount; ++index) { + values.put(resultSet.getMetaData().getColumnName(index), resultSet.getObject(index)); + } + Builder builder = DataChanges.newBuilder(); + builder.withAfter(values); + builder.withType(event.getDataChangeEventType().ofCode()); + final Payload payload = event.getJdbcConnectData().getPayload(); + payload.withDataChanges(builder.build()); + payload.withSource(sourceMateData); + event.getJdbcConnectData().setSchema(new Schema(Collections.singletonList(field))); + eventQueue.put(event); + } + } finally { + connectionPool.add(connection); + } + return null; + }; + } + + private Queue createConnectionPool(final SnapshotContext snapshotContext) throws SQLException { + Queue connectionPool = new ConcurrentLinkedQueue<>(); + int snapshotMaxThreads = Math.max(1, + Math.min(this.jdbcSourceConfig.getSourceConnectorConfig().getSnapshotMaxThreads(), snapshotContext.determineTables.size())); + + for (int i = 0; i < snapshotMaxThreads; i++) { + JdbcConnection conn = databaseDialect.newConnection().setAutoCommit(false); + //Get transaction isolation from master connection and then set to connection of pool + conn.connection().setTransactionIsolation(jdbcConnection.connection().getTransactionIsolation()); + connectionPool.add(conn); + } + log.info("Created connection pool with {} number", snapshotMaxThreads); + return connectionPool; + } + + /** + * Builds the source metadata. + * + * @param context The context. + * @param snapshotContext The snapshot context. + * @param tableId The table id + * @return The source metadata. + */ + protected abstract SourceMateData buildSourceMateData(Jc context, SnapshotContext snapshotContext, TableId tableId); + + /** + * Pre-snapshot preparations. + * + * @param jdbcContext the JDBC context + * @param snapshotContext the snapshot context + */ + protected abstract void preSnapshot(Jc jdbcContext, SnapshotContext snapshotContext); + + /** + * Determine tables that need snapshotting. + * + * @param jdbcContext the JDBC context + * @param snapshotContext the snapshot context + */ + protected abstract void determineTable2Process(Jc jdbcContext, SnapshotContext snapshotContext); + + /** + * Lock tables for consistent snapshot schema. + * + * @param jdbcContext the JDBC context + * @param snapshotContext the snapshot context + * @throws SQLException if a database error occurs + */ + protected abstract void lockTables4SchemaSnapshot(Jc jdbcContext, SnapshotContext snapshotContext) throws SQLException; + + /** + * Determine snapshot offset. + * + * @param jdbcContext the JDBC context + * @param snapshotContext the snapshot context + * @throws SQLException if a database error occurs + */ + protected abstract void determineSnapshotOffset(Jc jdbcContext, SnapshotContext snapshotContext) throws SQLException; + + /** + * Read and store table schemas. + * + * @param jdbcContext the JDBC context + * @param snapshotContext the snapshot context + * @throws SQLException if a database error occurs + * @throws InterruptedException if interrupted + */ + protected abstract void readStructureOfTables(Jc jdbcContext, SnapshotContext snapshotContext) + throws SQLException, InterruptedException; + + /** + * Release locks after snapshot. + * + * @param jdbcContext the JDBC context + * @param snapshotContext the snapshot context + */ + protected abstract void releaseSnapshotLocks(Jc jdbcContext, SnapshotContext snapshotContext) throws Exception; + + protected abstract Optional getSnapshotTableSelectSql(Jc jdbcContext, SnapshotContext snapshotContext, TableId tableId); + + protected OptionalLong getRowCount4Table(TableId tableId) { + return OptionalLong.empty(); + } + + public static class SnapshotContext

implements AutoCloseable { + + protected P partition; + + protected O offset; + + protected Set determineTables = new HashSet<>(); + + public SnapshotContext(P partition, O offset) { + this.partition = partition; + this.offset = offset; + } + + @Override + public void close() throws Exception { + + } + + public void add(TableId tableId) { + SnapshotContext.this.determineTables.add(tableId); + } + + public void addAll(Set tableIds) { + if (tableIds != null) { + SnapshotContext.this.determineTables.addAll(tableIds); + } + } + + public P getPartition() { + return partition; + } + + public O getOffset() { + return offset; + } + + public Set getDetermineTables() { + return determineTables; + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotEngine.java new file mode 100644 index 0000000000..727abcea0f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotEngine.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot; + +import org.apache.eventmesh.connector.jdbc.JdbcContext; +import org.apache.eventmesh.connector.jdbc.event.EventConsumer; +import org.apache.eventmesh.connector.jdbc.source.Engine; + +/** + * The SnapshotEngine interface extends the Engine interface and represents an engine capable of performing snapshots. + * + * @param The type of JdbcContext used for the snapshot. + */ +public interface SnapshotEngine extends Engine, AutoCloseable { + + /** + * Executes the snapshot operation and returns the result containing the snapshot offset. + * + * @return The SnapshotResult containing the snapshot offset. + */ + SnapshotResult execute(); + + /** + * Registers a SnapshotEventConsumer to receive snapshot events from the engine. + * + * @param consumer The SnapshotEventConsumer to register. + */ + void registerSnapshotEventConsumer(EventConsumer consumer); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotEngineFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotEngineFactory.java new file mode 100644 index 0000000000..30dfe2e997 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotEngineFactory.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.connector.jdbc.JdbcContext; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * The SnapshotEngineFactory interface represents a factory for creating snapshot engines. It provides a method to create a snapshot engine based on + * the given configuration and database dialect. + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.JDBC_SNAPSHOT_ENGINE) +public interface SnapshotEngineFactory { + + /** + * Creates a snapshot engine with the specified JDBC source configuration and database dialect. + * + * @param jdbcSourceConfig The JDBC source configuration. + * @param databaseDialect The database dialect. + * @return A snapshot engine that can perform snapshot operations. + */ + SnapshotEngine createSnapshotEngine(final JdbcSourceConfig jdbcSourceConfig, + final DatabaseDialect databaseDialect); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotResult.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotResult.java new file mode 100644 index 0000000000..d36c85468c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotResult.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot; + +import org.apache.eventmesh.connector.jdbc.JdbcContext; + +import lombok.Getter; + +@Getter +public class SnapshotResult { + + private final SnapshotResultStatus status; + + private final Jc context; + + public SnapshotResult(SnapshotResultStatus status, Jc jc) { + this.status = status; + this.context = jc; + } + + public enum SnapshotResultStatus { + COMPLETED, + ABORTED, + SKIPPED + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotType.java new file mode 100644 index 0000000000..9f995f689c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/SnapshotType.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot; + +public enum SnapshotType { + + /** + * Every time the service starts, it reads the data of the tables that need to be processed. + */ + INITIALIZATION, + + /** + * Continue processing from the last handled position. + */ + INCREASE // TODO Need to support next version +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/mysql/MysqlSnapshotEngine.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/mysql/MysqlSnapshotEngine.java new file mode 100644 index 0000000000..b6d6d7f8bf --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/mysql/MysqlSnapshotEngine.java @@ -0,0 +1,342 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.common.config.connector.rdb.jdbc.MysqlConfig; +import org.apache.eventmesh.connector.jdbc.CatalogChanges; +import org.apache.eventmesh.connector.jdbc.connection.mysql.MysqlJdbcConnection; +import org.apache.eventmesh.connector.jdbc.context.mysql.MysqlOffsetContext; +import org.apache.eventmesh.connector.jdbc.context.mysql.MysqlPartition; +import org.apache.eventmesh.connector.jdbc.dialect.mysql.MysqlDatabaseDialect; +import org.apache.eventmesh.connector.jdbc.event.Event; +import org.apache.eventmesh.connector.jdbc.event.EventConsumer; +import org.apache.eventmesh.connector.jdbc.event.SchemaChangeEventType; +import org.apache.eventmesh.connector.jdbc.source.SourceMateData; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlConstants; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlDialectSql; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlJdbcContext; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlSourceMateData; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.AbstractSnapshotEngine; +import org.apache.eventmesh.connector.jdbc.table.catalog.DefaultValueConvertor; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlDefaultValueConvertorImpl; +import org.apache.eventmesh.connector.jdbc.utils.MysqlUtils; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.OptionalLong; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlSnapshotEngine extends + AbstractSnapshotEngine { + + private volatile boolean globalLockAcquired = false; + + private volatile boolean tableLockAcquired = false; + + private List consumers = new ArrayList<>(16); + + private MysqlJdbcConnection connection; + + private DefaultValueConvertor defaultValueConvertor = new MysqlDefaultValueConvertorImpl(); + + public MysqlSnapshotEngine(JdbcSourceConfig jdbcSourceConfig, MysqlDatabaseDialect databaseDialect, MysqlJdbcContext jdbcContext) { + super(jdbcSourceConfig, databaseDialect, jdbcContext, jdbcContext.getPartition(), jdbcContext.getOffsetContext()); + this.connection = databaseDialect.getConnection(); + jdbcContext.getParser().addTableIdSet(getHandledTables()); + } + + @Override + protected Set defaultExcludeDatabase() { + return MysqlConstants.DEFAULT_EXCLUDE_DATABASE; + } + + @Override + public void close() throws Exception { + shutdown(); + } + + /** + * Builds the source metadata. + * + * @param context The context. + * @param snapshotContext The snapshot context. + * @param tableId The table id + * @return The source metadata. + */ + @Override + protected SourceMateData buildSourceMateData(MysqlJdbcContext context, SnapshotContext snapshotContext, + TableId tableId) { + + MysqlSourceMateData sourceMateData = MysqlSourceMateData.newBuilder() + .name(sourceConnectorConfig.getName()) + .withTableId(tableId) + .serverId(sourceConnectorConfig.getMysqlConfig().getServerId()) + .snapshot(true) + .position(context.getSourceInfo().getCurrentBinlogPosition()) + .build(); + + return sourceMateData; + } + + @Override + protected void preSnapshot(MysqlJdbcContext jdbcContext, SnapshotContext snapshotContext) { + // nothing to do + } + + @Override + protected void determineTable2Process(MysqlJdbcContext jdbcContext, SnapshotContext snapshotContext) { + snapshotContext.addAll(getHandledTables()); + } + + @Override + protected void lockTables4SchemaSnapshot(MysqlJdbcContext jdbcContext, SnapshotContext snapshotContext) + throws SQLException { + // Set the REPEATABLE_READ isolation level to avoid the MySQL transaction isolation level being changed unexpectedly. + connection.connection().setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); + connection.executeWithoutCommitting("SET SESSION lock_wait_timeout=10", "SET SESSION innodb_lock_wait_timeout=10"); + + // Lock tables + final MysqlConfig mysqlConfig = sourceConnectorConfig.getMysqlConfig(); + if (mysqlConfig.getSnapshotLockingMode().usesLocking() && mysqlConfig.isUseGlobalLock()) { + globalLockAcquiredTry(); + } + + } + + @Override + protected void determineSnapshotOffset(MysqlJdbcContext jdbcContext, SnapshotContext snapshotContext) + throws SQLException { + + if (!globalLockAcquired && !tableLockAcquired) { + return; + } + log.info("Read binlog info from Mysql Server"); + /** + * The result of executing the SHOW MASTER STATUS script is as follows: + * +-----------------+----------+--------------+------------------+-------------------------------------------+ + * | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | + * +-----------------+----------+--------------+------------------+-------------------------------------------+ + * | mysqlbin.000009 | 197 | | | 71a89bf3-0dd0-11ee-98b2-0242ac110002:1-76 | + * +-----------------+----------+--------------+------------------+-------------------------------------------+ + */ + connection.query(MysqlDialectSql.SHOW_MASTER_STATUS.ofSQL(), resultSet -> { + if (resultSet.next()) { + final String binlogFilename = resultSet.getString(1); + final long position = resultSet.getLong(2); + jdbcContext.setBinlogStartPoint(binlogFilename, position); + if (resultSet.getMetaData().getColumnCount() >= 5) { + final String gtidSet = resultSet.getString(5); + jdbcContext.completedGtidSet(gtidSet); + log.info("Using binlog '{}' at position '{}' and gtid '{}'", binlogFilename, position, gtidSet); + } else { + log.info("Using binlog '{}' at position '{}' ", binlogFilename, position); + } + } else { + throw new SQLException("Cannot read the binlog filename and position,Make sure Mysql server is correctly configured"); + } + }); + } + + @Override + protected void readStructureOfTables(MysqlJdbcContext jdbcContext, SnapshotContext snapshotContext) + throws SQLException, InterruptedException { + if (sourceConnectorConfig.getMysqlConfig().getSnapshotLockingMode().usesLocking() && !globalLockAcquired) { + lockTable(snapshotContext); + determineSnapshotOffset(jdbcContext, snapshotContext); + } + // Parse all Databases from the tableId, construct creation statements + Set determineTables = snapshotContext.getDetermineTables(); + for (TableId tableId : determineTables) { + StringBuilder dropTableDdl = new StringBuilder("DROP TABLE IF EXISTS "); + dropTableDdl.append(MysqlUtils.wrapper(tableId)); + addParseDdlAndEvent(jdbcContext, dropTableDdl.toString(), tableId); + } + final HashMap/* table list */> databaseMapTables = determineTables.stream() + .collect(Collectors.groupingBy(TableId::getCatalogName, HashMap::new, Collectors.toList())); + Set databaseSet = databaseMapTables.keySet(); + // Read all table structures, construct DDL statements + for (String database : databaseSet) { + StringBuilder dropDatabaseDdl = new StringBuilder("DROP DATABASE IF EXISTS ").append(MysqlUtils.wrapper(database)); + addParseDdlAndEvent(jdbcContext, dropDatabaseDdl.toString(), new TableId(database)); + String databaseCreateDdl = connection.query(MysqlDialectSql.SHOW_CREATE_DATABASE.ofWrapperSQL(MysqlUtils.wrapper(database)), rs -> { + if (rs.next() && rs.getMetaData().getColumnCount() > 1) { + String ddl = rs.getString(2); + return ddl; + } + return null; + }); + if (StringUtils.isBlank(databaseCreateDdl)) { + log.warn("Database {} ddl is empty", database); + continue; + } + TableId tableId = new TableId(database); + addParseDdlAndEvent(jdbcContext, databaseCreateDdl, tableId); + addParseDdlAndEvent(jdbcContext, "USE " + database, tableId); + + // build create table snapshot event + List tableIds = databaseMapTables.get(database); + createTableSnapshotEvent(tableIds, jdbcContext); + } + } + + private void addParseDdlAndEvent(MysqlJdbcContext jdbcContext, String ddl, TableId tableId) { + jdbcContext.getParser().setCurrentDatabase(tableId.getCatalogName()); + jdbcContext.getParser().setCatalogTableSet(jdbcContext.getCatalogTableSet()); + jdbcContext.getParser().parse(ddl, event -> { + try { + if (event == null) { + return; + } + // handle default value expression + if (event.getJdbcConnectData().isSchemaChanges()) { + CatalogChanges catalogChanges = event.getJdbcConnectData().getPayload().getCatalogChanges(); + SchemaChangeEventType schemaChangeEventType = SchemaChangeEventType.ofSchemaChangeEventType(catalogChanges.getType(), + catalogChanges.getOperationType()); + if (SchemaChangeEventType.TABLE_CREATE == schemaChangeEventType || SchemaChangeEventType.TABLE_ALERT == schemaChangeEventType) { + catalogChanges.getColumns().forEach( + column -> column.setDefaultValue(defaultValueConvertor.parseDefaultValue(column, column.getDefaultValueExpression()))); + } + } + event.getJdbcConnectData().getPayload().withDdl(ddl).ofSourceMateData().setSnapshot(true); + eventQueue.put(event); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + } + + private void createTableSnapshotEvent(List tableIds, MysqlJdbcContext jdbcContext) throws SQLException { + if (CollectionUtils.isEmpty(tableIds)) { + return; + } + for (TableId tableId : tableIds) { + connection.query(MysqlDialectSql.SHOW_CREATE_TABLE.ofWrapperSQL(tableId.toString()), resultSet -> { + if (resultSet.next()) { + // Get create table sql + String createTableDdl = resultSet.getString(2); + addParseDdlAndEvent(jdbcContext, createTableDdl, tableId); + } + }); + } + } + + private void lockTable(SnapshotContext snapshotContext) throws SQLException { + + Boolean lockedTable = connection.query(MysqlDialectSql.SHOW_GRANTS_FOR_CURRENT_USER.ofSQL(), rs -> { + while (rs.next()) { + String grantPrivilege = rs.getString(1); + if (StringUtils.isBlank(grantPrivilege)) { + continue; + } + if (StringUtils.containsAny(grantPrivilege.toUpperCase(), "ALL", "LOCK TABLES")) { + return true; + } + } + return false; + }); + if (!lockedTable) { + throw new SQLException("Current User does not have the 'LOCK TABLES' privilege"); + } + if (CollectionUtils.isNotEmpty(snapshotContext.getDetermineTables())) { + /** + * FLUSH + */ + String tableNameList = snapshotContext.getDetermineTables().stream().map(TableId::toString).collect(Collectors.joining(",")); + connection.executeWithoutCommitting(MysqlDialectSql.LOCK_TABLES.ofWrapperSQL(tableNameList)); + } + tableLockAcquired = true; + } + + @Override + protected void releaseSnapshotLocks(MysqlJdbcContext jdbcContext, SnapshotContext snapshotContext) + throws Exception { + if (globalLockAcquired) { + connection.executeWithoutCommitting(MysqlDialectSql.UNLOCK_TABLES.ofSQL()); + globalLockAcquired = false; + } + if (tableLockAcquired) { + connection.executeWithoutCommitting(MysqlDialectSql.UNLOCK_TABLES.ofSQL()); + globalLockAcquired = false; + } + } + + @Override + protected Optional getSnapshotTableSelectSql(MysqlJdbcContext jdbcContext, + SnapshotContext snapshotContext, TableId tableId) { + return Optional.of(MysqlDialectSql.SNAPSHOT_TABLE_SELECT_SQL.ofWrapperSQL(tableId.toString())); + } + + private void globalLockAcquiredTry() throws SQLException { + // Lock tables + connection.executeWithoutCommitting(MysqlDialectSql.LOCK_TABLE_GLOBAL.ofSQL()); + this.globalLockAcquired = true; + } + + @Override + public String getThreadName() { + return this.getClass().getSimpleName() + "-thread"; + } + + @Override + public void run() { + while (isRunning) { + try { + Event event = eventQueue.poll(5, TimeUnit.SECONDS); + if (event == null) { + continue; + } + consumers.forEach(consumer -> consumer.accept(event)); + } catch (Exception e) { + log.warn("Consume snapshot event error", e); + } + } + } + + @Override + public void init() { + + } + + @Override + public void registerSnapshotEventConsumer(EventConsumer consumer) { + if (consumer == null) { + return; + } + consumers.add(consumer); + } + + @Override + protected OptionalLong getRowCount4Table(TableId tableId) { + return connection.getRowCount4Table(tableId); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/mysql/MysqlSnapshotEngineFactory.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/mysql/MysqlSnapshotEngineFactory.java new file mode 100644 index 0000000000..bac2bdafba --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/source/dialect/snapshot/mysql/MysqlSnapshotEngineFactory.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.mysql; + +import org.apache.eventmesh.common.config.connector.rdb.jdbc.JdbcSourceConfig; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.dialect.mysql.MysqlDatabaseDialect; +import org.apache.eventmesh.connector.jdbc.source.dialect.antlr4.mysql.MysqlAntlr4DdlParser; +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlJdbcContext; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngine; +import org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngineFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlSnapshotEngineFactory implements SnapshotEngineFactory { + + @Override + public SnapshotEngine createSnapshotEngine(final JdbcSourceConfig jdbcSourceConfig, + final DatabaseDialect databaseDialect) { + return new MysqlSnapshotEngine(jdbcSourceConfig, (MysqlDatabaseDialect) databaseDialect, + new MysqlJdbcContext(jdbcSourceConfig, new MysqlAntlr4DdlParser(false, false, jdbcSourceConfig))); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/AbstractColumnEditorImpl.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/AbstractColumnEditorImpl.java new file mode 100644 index 0000000000..a3bcc97f8e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/AbstractColumnEditorImpl.java @@ -0,0 +1,349 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.sql.JDBCType; +import java.util.List; + +public abstract class AbstractColumnEditorImpl implements ColumnEditor { + + /** + * Name of the column + */ + private String name; + + /** + * Data type of the column + */ + private EventMeshDataType eventMeshDataType; + + /** + * Length of the column + */ + private Long columnLength; + + /** + * Decimal point of the column + */ + private Integer scale; + + /** + * Indicates if the column can be null or not + */ + private boolean notNull; + + /** + * Comment for the column + */ + private String comment; + + /** + * Default value for the column + */ + private Object defaultValue; + + private String typeName; + + private JDBCType jdbcType; + + private String defaultValueExpression; + + private boolean optional; + + private int order; + + private String charsetName; + + /** + * Indicates if the column is auto incremented. For example: MySQL + */ + private Boolean autoIncremented; + + private Boolean generated; + + private List enumValues; + + private Options options; + + public AbstractColumnEditorImpl(String name) { + this.name = name; + } + + public AbstractColumnEditorImpl() { + } + + /** + * Sets the name of the column. + * + * @param name The name of the column. + * @return The column editor instance. + */ + @Override + @SuppressWarnings("unchecked") + public CE withName(String name) { + this.name = name; + return (CE) this; + } + + /** + * Retrieves the name associated with this column editor. + * + * @return The name of the column. + */ + @Override + public String ofName() { + return this.name; + } + + /** + * Sets the data type of the column. + * + * @param typeName The data type name of the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE withType(String typeName) { + this.typeName = typeName; + return (CE) this; + } + + /** + * Sets the JDBC data type of the column. + * + * @param jdbcType The JDBC data type of the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE withJdbcType(JDBCType jdbcType) { + this.jdbcType = jdbcType; + return (CE) this; + } + + /** + * Sets the EventMesh data type of the column. + * + * @param eventMeshType The EventMesh data type of the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE withEventMeshType(EventMeshDataType eventMeshType) { + this.eventMeshDataType = eventMeshType; + return (CE) this; + } + + /** + * Sets the order or position of the column within a table. + * + * @param order The order or position of the column. + * @return The column editor instance. + */ + @Override + @SuppressWarnings("unchecked") + public CE withOrder(int order) { + this.order = order; + return (CE) this; + } + + /** + * Sets the length of the column (if applicable). + * + * @param length The length of the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE length(long length) { + this.columnLength = length; + return (CE) this; + } + + /** + * Sets the scale of the column (if applicable). + * + * @param scale The scale of the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE scale(Integer scale) { + this.scale = scale; + return (CE) this; + } + + /** + * Sets whether the column is optional (nullable). + * + * @param optional Indicates whether the column is optional (true) or not (false). + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE optional(boolean optional) { + this.optional = optional; + return (CE) this; + } + + /** + * Sets the comment for the column. + * + * @param comment The comment for the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE comment(String comment) { + this.comment = comment; + return (CE) this; + } + + /** + * Sets the default value expression for the column. + * + * @param defaultValueExpression The default value expression for the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE defaultValueExpression(String defaultValueExpression) { + this.defaultValueExpression = defaultValueExpression; + return (CE) this; + } + + /** + * Sets the default value for the column. + * + * @param value The default value for the column. + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE defaultValue(Object value) { + this.defaultValue = value; + return (CE) this; + } + + /** + * Sets whether the column is marked as not null. + * + * @param notNull Indicates whether the column is marked as not null (true) or not (false). + * @return The column editor instance. + */ + @SuppressWarnings("unchecked") + @Override + public CE notNull(boolean notNull) { + this.notNull = notNull; + return (CE) this; + } + + @SuppressWarnings("unchecked") + @Override + public CE charsetName(String charsetName) { + this.charsetName = charsetName; + return (CE) this; + } + + @SuppressWarnings("unchecked") + @Override + public CE enumValues(List enumValues) { + this.enumValues = enumValues; + return (CE) this; + } + + @SuppressWarnings("unchecked") + @Override + public CE withOption(String key, Object value) { + if (options == null) { + this.options = new Options(); + } + this.options.put(key, value); + return (CE) this; + } + + @SuppressWarnings("unchecked") + @Override + public CE withOptions(Options options) { + if (options != null) { + if (this.options == null) { + this.options = new Options(); + } + this.options.putAll(options); + } + return (CE) this; + } + + public EventMeshDataType ofEventMeshDataType() { + return eventMeshDataType; + } + + public Long ofColumnLength() { + return columnLength; + } + + public Integer ofScale() { + return scale; + } + + public boolean isNotNull() { + return notNull; + } + + public String ofComment() { + return comment; + } + + public Object ofDefaultValue() { + return defaultValue; + } + + public String ofTypeName() { + return typeName; + } + + public JDBCType ofJdbcType() { + return jdbcType; + } + + public String ofDefaultValueExpression() { + return defaultValueExpression; + } + + public boolean isOptional() { + return optional; + } + + public int ofOrder() { + return this.order; + } + + public String ofCharsetName() { + return this.charsetName; + } + + public List ofEnumValues() { + return this.enumValues; + } + + public Options ofOptions() { + return this.options; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/AbstractTableEditorImpl.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/AbstractTableEditorImpl.java new file mode 100644 index 0000000000..4d26b3cb85 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/AbstractTableEditorImpl.java @@ -0,0 +1,207 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class AbstractTableEditorImpl implements + TableEditor { + + private TableId tableId; + + private PrimaryKey primaryKey = new PrimaryKey(); + + private List uniqueKeys = new ArrayList<>(8); + + private Map columns = new HashMap<>(16); + + private String comment; + + private Options options = new Options(); + + public AbstractTableEditorImpl(TableId tableId) { + this.tableId = tableId; + } + + public AbstractTableEditorImpl() { + } + + /** + * Sets the unique identifier (ID) of the table. + * + * @param tableId The unique ID of the table. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withTableId(TableId tableId) { + this.tableId = tableId; + return (TE) this; + } + + /** + * Adds columns to the table. + * + * @param columns The columns to add to the table. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE addColumns(Col... columns) { + if (columns != null && columns.length > 0) { + for (Col column : columns) { + this.columns.put(column.getName(), column); + } + } + return (TE) this; + } + + /** + * Sets a comment or description for the table. + * + * @param comment A comment or description for the table. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withComment(String comment) { + this.comment = comment; + return (TE) this; + } + + /** + * Removes a column from the table. + * + * @param columnName The name of the column to remove. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE removeColumn(String columnName) { + this.columns.remove(columnName); + return (TE) this; + } + + /** + * Sets the primary key columns for the table. + * + * @param pkColumnNames The names of the columns that form the primary key. + * @param comment A comment or description for the primary key. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withPrimaryKeyNames(List pkColumnNames, String comment) { + this.primaryKey = new PrimaryKey(pkColumnNames, comment); + return (TE) this; + } + + /** + * Sets the primary key columns for the table. + * + * @param pkColumnNames The names of the columns that form the primary key. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withPrimaryKeyNames(String... pkColumnNames) { + if (pkColumnNames != null && pkColumnNames.length > 0) { + primaryKey.addColumnNames(pkColumnNames); + } + return (TE) this; + } + + /** + * Sets the primary key for the table. + * + * @param primaryKey The primary key definition. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withPrimaryKey(PrimaryKey primaryKey) { + this.primaryKey = primaryKey; + return (TE) this; + } + + /** + * Sets the unique key columns and their names for the table. + * + * @param ukName The name of the unique key constraint. + * @param ukColumnNames The names of the columns that form the unique key. + * @param comment A comment or description for the unique key. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withUniqueKeyColumnsNames(String ukName, List ukColumnNames, String comment) { + this.uniqueKeys.add(new UniqueKey(ukName, ukColumnNames, comment)); + return (TE) this; + } + + /** + * Sets the unique key constraints for the table. + * + * @param uniqueKeys The unique key constraints. + * @return A reference to the table editor for further configuration. + */ + @Override + @SuppressWarnings("unchecked") + public TE withUniqueKeys(UniqueKey... uniqueKeys) { + if (uniqueKeys != null && uniqueKeys.length > 0) { + for (UniqueKey uniqueKey : uniqueKeys) { + this.uniqueKeys.add(uniqueKey); + } + } + return (TE) this; + } + + @Override + @SuppressWarnings("unchecked") + public TE withOption(String key, Object value) { + this.options.put(key, value); + return (TE) this; + } + + protected TableId ofTableId() { + return tableId; + } + + protected PrimaryKey ofPrimaryKey() { + return primaryKey; + } + + protected List ofUniqueKeys() { + return uniqueKeys; + } + + protected Map ofColumns() { + return columns; + } + + protected String ofComment() { + return comment; + } + + protected Options ofOptions() { + return options; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Catalog.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Catalog.java new file mode 100644 index 0000000000..d0a1fa2996 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Catalog.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.exception.CatalogException; +import org.apache.eventmesh.connector.jdbc.exception.DatabaseNotExistException; +import org.apache.eventmesh.connector.jdbc.exception.TableNotExistException; + +import java.sql.SQLException; +import java.util.List; + +/** + * Interacting with a catalog of databases and tables. + */ +public interface Catalog extends AutoCloseable { + + /** + * Opens the catalog. + * + * @throws CatalogException if there is an error opening the catalog. + */ + void open() throws CatalogException; + + /** + * Gets the name of the default database. + * + * @return the name of the default database. + */ + String getDefaultDatabase(); + + /** + * Checks if a database with the given name exists. + * + * @param databaseName the name of the database to check. + * @return true if the database exists, false otherwise. + * @throws CatalogException if there is an error checking for the database. + */ + boolean databaseExists(String databaseName) throws CatalogException; + + /** + * Gets a list of all databases in the catalog. + * + * @return a list of all databases in the catalog. + * @throws CatalogException if there is an error getting the list of databases. + */ + List listDatabases() throws CatalogException; + + /** + * Gets a list of all tables in the given database. + * + * @param databaseName the name of the database to get the tables for. + * @return a list of all tables in the given database. + * @throws CatalogException if there is an error getting the list of tables. + * @throws DatabaseNotExistException if the database does not exist. + * @throws SQLException if there is an error accessing the database. + */ + List listTables(String databaseName) throws CatalogException, DatabaseNotExistException, SQLException; + + /** + * Checks if a table with the given ID exists. + * + * @param tableId the ID of the table to check. + * @return true if the table exists, false otherwise. + * @throws CatalogException if there is an error checking for the table. + * @throws SQLException if there is an error accessing the database. + */ + boolean tableExists(TableId tableId) throws CatalogException, SQLException; + + /** + * Gets the table with the given ID. + * + * @param tableId the ID of the table to get. + * @return the table with the given ID. + * @throws CatalogException if there is an error getting the table. + * @throws TableNotExistException if the table does not exist. + * @throws SQLException if there is an error accessing the database. + */ + CatalogTable getTable(TableId tableId) throws CatalogException, TableNotExistException, SQLException; + + // TODO: support create table, drop table and update table +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogSchema.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogSchema.java new file mode 100644 index 0000000000..2caae2a841 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogSchema.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents catalog schema information, including its name and character set. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CatalogSchema implements Serializable { + + /** + * The name of the catalog schema. + */ + private String name; + + /** + * The character set used by the catalog schema. + */ + private String characterSet; + + public CatalogSchema(String name) { + this.name = name; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogTable.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogTable.java new file mode 100644 index 0000000000..4aa2b89351 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogTable.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.io.Serializable; + +import lombok.Data; + +/** + * Represents a catalog table. + */ +@Data +public class CatalogTable implements Serializable { + + private static final long serialVersionUID = -9159821671858779282L; + + // The ID of the table. + private TableId tableId; + + // The schema of the table. + private TableSchema tableSchema; + + // A comment describing the table. + private String comment; + + private Options options; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogTableSet.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogTableSet.java new file mode 100644 index 0000000000..16c083f06a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/CatalogTableSet.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.commons.lang3.StringUtils; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public final class CatalogTableSet { + + private final TableIdSet tableIdSet; + + private final TableSchemaMap tableSchemaMap; + + public CatalogTableSet() { + + this.tableIdSet = new TableIdSet(); + this.tableSchemaMap = new TableSchemaMap(); + + } + + public void removeDatabase(String catalogName) { + removeDatabase(catalogName, null); + } + + public void removeDatabase(String catalogName, String schemaName) { + tableSchemaMap.removeDatabase(catalogName, schemaName); + tableIdSet.removeDatabase(catalogName, schemaName); + } + + public void overrideTable(TableSchema tableSchema) { + if (tableSchema == null || tableSchema.getTableId() == null) { + return; + } + tableSchemaMap.putTableSchema(tableSchema); + tableIdSet.addTableId(tableSchema.getTableId()); + } + + public TableSchema getTableSchema(TableId tableId) { + return tableSchemaMap.getTableSchema(tableId); + } + + private static class TableIdSet { + + private final Set values; + + public TableIdSet() { + values = new HashSet<>(32); + } + + public void addTableId(TableId tableId) { + values.add(tableId); + } + + public void removeDatabase(String catalogName, String schemaName) { + values.removeIf( + entry -> StringUtils.equals(entry.getCatalogName(), catalogName) && StringUtils.equals(entry.getSchemaName(), schemaName)); + } + } + + private static class TableSchemaMap { + + private final ConcurrentMap values; + + public TableSchemaMap() { + this.values = new ConcurrentHashMap<>(32); + } + + public void removeDatabase(String catalogName, String schemaName) { + values.entrySet().removeIf(entry -> { + TableId key = entry.getKey(); + return StringUtils.equals(key.getCatalogName(), catalogName) && StringUtils.equals(key.getSchemaName(), schemaName); + }); + } + + public TableSchema getTableSchema(TableId tableId) { + return values.get(tableId); + } + + public TableSchema putTableSchema(TableSchema tableSchema) { + return values.put(tableSchema.getTableId(), tableSchema); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Column.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Column.java new file mode 100644 index 0000000000..363a50c147 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Column.java @@ -0,0 +1,284 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.io.Serializable; +import java.sql.JDBCType; +import java.sql.Types; +import java.util.List; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Column of {@link TableSchema}. + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Column implements Serializable { + + /** + * Name of the column + */ + protected String name; + + /** + * Data type of the column + */ + @JsonSerialize(using = EventMeshDataTypeJsonSerializer.class) + @JsonDeserialize(using = EventMeshDataTypeJsonDeserializer.class) + protected EventMeshDataType dataType; + + /** + * {@link Types JDBC type} + */ + protected JDBCType jdbcType; + + /** + * Length of the column + */ + protected Long columnLength; + + /** + * Decimal point of the column + */ + protected Integer decimal; + + /** + * Indicates if the column can be null or not + */ + protected boolean notNull = false; + + /** + * Comment for the column + */ + protected String comment; + + /** + * Default value for the column + */ + protected Object defaultValue; + + @JsonIgnore + protected String defaultValueExpression; + + // order of the column in the table + protected int order = 1; + + protected String charsetName; + + // Use wrapper types to reduce data transmission during serialization + protected Boolean autoIncremented; + + protected Boolean generated; + + protected String collationName; + + protected List enumValues; + + // for mysql: varchar or json + protected String nativeType; + + protected Options options; + + public Column(String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, String comment, + Object defaultValue, String defaultValueExpression, int order, String charsetName, boolean autoIncremented, boolean generated, + String collationName) { + this.name = name; + this.dataType = dataType; + this.jdbcType = jdbcType; + this.columnLength = columnLength; + this.decimal = decimal; + this.notNull = notNull; + this.comment = comment; + this.defaultValue = defaultValue; + this.defaultValueExpression = defaultValueExpression; + this.order = order; + this.charsetName = charsetName; + this.autoIncremented = autoIncremented; + this.generated = generated; + this.collationName = collationName; + } + + private Column(Builder builder) { + this.name = builder.name; + this.dataType = builder.dataType; + this.jdbcType = builder.jdbcType; + this.columnLength = builder.columnLength; + this.decimal = builder.decimal; + this.notNull = builder.notNull; + this.comment = builder.comment; + this.defaultValue = builder.defaultValue; + this.defaultValueExpression = builder.defaultValueExpression; + this.order = builder.order; + this.charsetName = builder.charsetName; + this.autoIncremented = builder.autoIncremented; + this.generated = builder.generated; + this.collationName = builder.collationName; + this.enumValues = builder.enumValues; + this.nativeType = builder.nativeType; + this.options = builder.options; + } + + public boolean isAutoIncremented() { + return Optional.ofNullable(this.autoIncremented).orElse(false); + } + + public static Builder newBuilder() { + return new Builder(); + } + + /** + * creates a clone of the Column + * + * @return clone of column + */ + public Col clone() { + return null; + } + + /** + * Builder for the Column class + */ + public static class Builder { + + protected String name; + protected EventMeshDataType dataType; + protected JDBCType jdbcType; + protected Long columnLength; + protected Integer decimal; + protected boolean notNull = false; + protected String comment; + protected Object defaultValue; + protected String defaultValueExpression; + protected int order = 1; + protected String charsetName; + protected Boolean autoIncremented; + protected Boolean generated; + protected String collationName; + protected List enumValues; + // for mysql: varchar or json + protected String nativeType; + + protected Options options; + + public Builder withName(String name) { + this.name = name; + return this; + } + + public Builder withDataType(EventMeshDataType dataType) { + this.dataType = dataType; + return this; + } + + public Builder withJdbcType(JDBCType jdbcType) { + this.jdbcType = jdbcType; + return this; + } + + public Builder withColumnLength(Long columnLength) { + this.columnLength = columnLength; + return this; + } + + public Builder withDecimal(Integer decimal) { + this.decimal = decimal; + return this; + } + + public Builder withNotNull(boolean notNull) { + this.notNull = notNull; + return this; + } + + public Builder withComment(String comment) { + this.comment = comment; + return this; + } + + public Builder withDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public Builder withDefaultValueExpression(String defaultValueExpression) { + this.defaultValueExpression = defaultValueExpression; + return this; + } + + public Builder withOrder(int order) { + this.order = order; + return this; + } + + public Builder withCharsetName(String charsetName) { + this.charsetName = charsetName; + return this; + } + + public Builder withAutoIncremented(boolean autoIncremented) { + this.autoIncremented = autoIncremented; + return this; + } + + public Builder withGenerated(boolean generated) { + this.generated = generated; + return this; + } + + public Builder withCollationName(String collationName) { + this.collationName = collationName; + return this; + } + + public Builder withEnumValues(List enumValues) { + this.enumValues = enumValues; + return this; + } + + public Builder withNativeType(String nativeType) { + this.nativeType = nativeType; + return this; + } + + public Builder withOptions(Options options) { + this.options = options; + return this; + } + + /** + * Builds the Column instance. + * + * @return Column instance + */ + public Column build() { + return new Column(this); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/ColumnEditor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/ColumnEditor.java new file mode 100644 index 0000000000..e99abaccd8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/ColumnEditor.java @@ -0,0 +1,151 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.sql.JDBCType; +import java.util.List; + +/** + * An interface for building and configuring columns in a database table. + * + * @param The concrete type of the column editor. + * @param The concrete type of the column being edited. + */ +public interface ColumnEditor { + + /** + * Sets the name of the column. + * + * @param name The name of the column. + * @return The column editor instance. + */ + CE withName(String name); + + /** + * Retrieves the name associated with this column editor. + * + * @return The name of the column. + */ + String ofName(); + + /** + * Sets the data type of the column. + * + * @param typeName The data type name of the column. + * @return The column editor instance. + */ + CE withType(String typeName); + + /** + * Sets the JDBC data type of the column. + * + * @param jdbcType The JDBC data type of the column. + * @return The column editor instance. + */ + CE withJdbcType(JDBCType jdbcType); + + /** + * Sets the EventMesh data type of the column. + * + * @param eventMeshType The EventMesh data type of the column. + * @return The column editor instance. + */ + CE withEventMeshType(EventMeshDataType eventMeshType); + + /** + * Sets the order or position of the column within a table. + * + * @param order The order or position of the column. + * @return The column editor instance. + */ + CE withOrder(int order); + + /** + * Sets the length of the column (if applicable). + * + * @param length The length of the column. + * @return The column editor instance. + */ + CE length(long length); + + /** + * Sets the scale of the column (if applicable). + * + * @param scale The scale of the column. + * @return The column editor instance. + */ + CE scale(Integer scale); + + /** + * Sets whether the column is optional (nullable). + * + * @param optional Indicates whether the column is optional (true) or not (false). + * @return The column editor instance. + */ + CE optional(boolean optional); + + /** + * Sets the comment for the column. + * + * @param comment The comment for the column. + * @return The column editor instance. + */ + CE comment(String comment); + + /** + * Sets the default value expression for the column. + * + * @param defaultValueExpression The default value expression for the column. + * @return The column editor instance. + */ + CE defaultValueExpression(String defaultValueExpression); + + /** + * Sets the default value for the column. + * + * @param value The default value for the column. + * @return The column editor instance. + */ + CE defaultValue(Object value); + + /** + * Sets whether the column is marked as not null. + * + * @param notNull Indicates whether the column is marked as not null (true) or not (false). + * @return The column editor instance. + */ + CE notNull(boolean notNull); + + CE charsetName(String charsetName); + + CE enumValues(List enumValues); + + CE withOption(String key, Object value); + + CE withOptions(Options options); + + /** + * Builds and returns the configured column. + * + * @return The configured column. + */ + Col build(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/DefaultColumn.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/DefaultColumn.java new file mode 100644 index 0000000000..e0dae1e617 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/DefaultColumn.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.sql.JDBCType; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class DefaultColumn extends Column { + + public DefaultColumn(String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, String charsetName, boolean autoIncremented, boolean generated, + String collationName) { + super(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, 0, charsetName, + autoIncremented, generated, collationName); + } + + public DefaultColumn(String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, int order, String charsetName, boolean autoIncremented, boolean generated, + String collationName) { + super(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, order, charsetName, + autoIncremented, generated, collationName); + } + + public static DefaultColumn of( + String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, String charsetName, boolean autoIncremented, boolean generated, + String collationName) { + return new DefaultColumn(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, + charsetName, autoIncremented, generated, collationName); + } + + public static DefaultColumn of( + String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, int order, String charsetName, boolean autoIncremented, boolean generated, + String collationName) { + return new DefaultColumn(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, order, + charsetName, autoIncremented, generated, collationName); + } + + /** + * creates a clone of the Column + * + * @return clone of column + */ + @Override + public DefaultColumn clone() { + return DefaultColumn.of(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, order, + charsetName, autoIncremented, generated, collationName); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/DefaultValueConvertor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/DefaultValueConvertor.java new file mode 100644 index 0000000000..9c3e6d4185 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/DefaultValueConvertor.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +/** + * Functional interface for converting default values. + */ +@FunctionalInterface +public interface DefaultValueConvertor { + + /** + * Parses the default value expression for a column. + * + * @param column The column for which the default value is being parsed. + * @param defaultValueExpression The expression representing the default value. + * @return The parsed default value. + */ + Object parseDefaultValue(Column column, String defaultValueExpression); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/EventMeshDataTypeJsonDeserializer.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/EventMeshDataTypeJsonDeserializer.java new file mode 100644 index 0000000000..86b5530614 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/EventMeshDataTypeJsonDeserializer.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshTypeNameConverter; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.NullEventMeshDataType; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +public class EventMeshDataTypeJsonDeserializer extends JsonDeserializer { + + @Override + public EventMeshDataType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException, JacksonException { + JsonNode treeNode = jsonParser.readValueAsTree(); + Iterator> fields = treeNode.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + if (StringUtils.equals("eventMeshDataType", field.getKey())) { + String value = field.getValue().asText(); + return EventMeshTypeNameConverter.ofEventMeshDataType(value); + } + } + return NullEventMeshDataType.INSTANCE; + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/EventMeshDataTypeJsonSerializer.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/EventMeshDataTypeJsonSerializer.java new file mode 100644 index 0000000000..68fd9a6954 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/EventMeshDataTypeJsonSerializer.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +public class EventMeshDataTypeJsonSerializer extends JsonSerializer { + + @Override + public void serialize(EventMeshDataType value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeStartObject(); + gen.writeStringField("eventMeshDataType", value.getName()); + gen.writeEndObject(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Index.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Index.java new file mode 100644 index 0000000000..751d26cb13 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Index.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.io.Serializable; +import java.util.List; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * This class represents an Index object with attributes such as name, column names, index type, index method, and comment. + * It provides a Builder pattern for creating Index objects. + */ +@Getter +@Setter +@NoArgsConstructor +public class Index implements Serializable { + + // Name of the index + private String name; + + // List of column names included in the index + private List columnNames; + + // Type of the index (e.g., unique, normal, etc.) + private String indexType; + + // Method used for the index (e.g., B-tree, Hash, etc.) + private String indexMethod; + + // Comment associated with the index + private String comment; + + protected Index(Builder builder) { + this.name = builder.name; + this.columnNames = builder.columnNames; + this.indexType = builder.indexType; + this.indexMethod = builder.indexMethod; + this.comment = builder.comment; + } + + public Index(List columnNames) { + this.columnNames = columnNames; + } + + public Index(String name, List columnNames) { + this.name = name; + this.columnNames = columnNames; + } + + public Index(String name, List columnNames, String comment) { + this.name = name; + this.columnNames = columnNames; + this.comment = comment; + } + + public void addColumnNames(String... columnNames) { + if (columnNames != null && columnNames.length > 0) { + for (String columnName : columnNames) { + this.columnNames.add(columnName); + } + } + } + + public Index(String name, List columnNames, String indexType, String indexMethod, String comment) { + this.name = name; + this.columnNames = columnNames; + this.indexType = indexType; + this.indexMethod = indexMethod; + this.comment = comment; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + protected String name; + protected List columnNames; + protected String indexType; + protected String indexMethod; + protected String comment; + + public static Builder newIndex() { + return new Builder(); + } + + public Builder withName(String name) { + this.name = name; + return this; + } + + public Builder withColumnNames(List columnNames) { + this.columnNames = columnNames; + return this; + } + + public Builder withIndexType(String indexType) { + this.indexType = indexType; + return this; + } + + public Builder withIndexMethod(String indexMethod) { + this.indexMethod = indexMethod; + return this; + } + + public Builder withComment(String comment) { + this.comment = comment; + return this; + } + + public Index build() { + return new Index(this); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Options.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Options.java new file mode 100644 index 0000000000..de2429695e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Options.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.util.HashMap; + +public class Options extends HashMap { + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/PrimaryKey.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/PrimaryKey.java new file mode 100644 index 0000000000..48fa27d936 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/PrimaryKey.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.util.List; + +public class PrimaryKey extends UniqueKey { + + public PrimaryKey() { + + } + + public PrimaryKey(String name, List columnNames, String comment) { + super(name, columnNames, comment); + } + + public PrimaryKey(String name, List columnNames) { + super(name, columnNames); + } + + public PrimaryKey(List columnNames) { + super(columnNames); + } + + public PrimaryKey(List columnNames, String comment) { + super(null, columnNames, comment); + } + + /** + * Creates a new PrimaryKey instance with the given name and column names. + * + * @param columnNames The list of column names that make up the primary key. + * @return A new PrimaryKey instance. + */ + public static PrimaryKey of(List columnNames) { + return new PrimaryKey(columnNames); + } + + /** + * Creates a copy of this PrimaryKey instance. + * + * @return A new PrimaryKey instance with the same name and column names. + */ + public PrimaryKey copy() { + return new PrimaryKey(getName(), getColumnNames(), getComment()); + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Table.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Table.java new file mode 100644 index 0000000000..158ffc81da --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/Table.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.util.List; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class Table { + + private TableId tableId; + + private PrimaryKey primaryKey; + + private List uniqueKeys; + + private String comment; + + private Options options = new Options(); + + public Table(TableId tableId, PrimaryKey primaryKey, List uniqueKeys, String comment) { + this.tableId = tableId; + this.primaryKey = primaryKey; + this.uniqueKeys = uniqueKeys; + this.comment = comment; + } + + public Table(TableId tableId, PrimaryKey primaryKey, List uniqueKeys, String comment, Options options) { + this.tableId = tableId; + this.primaryKey = primaryKey; + this.uniqueKeys = uniqueKeys; + this.comment = comment; + if (options != null) { + this.options.putAll(options); + } + } + + public void put(String key, Object value) { + options.put(key, value); + } + + public void putAll(Options options) { + this.options.putAll(options); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + + private TableId tableId; + private PrimaryKey primaryKey; + private List uniqueKeys; + private String comment; + private Options options; + + public Builder withTableId(TableId tableId) { + this.tableId = tableId; + return this; + } + + public Builder withPrimaryKey(PrimaryKey primaryKey) { + this.primaryKey = primaryKey; + return this; + } + + public Builder withUniqueKeys(List uniqueKeys) { + this.uniqueKeys = uniqueKeys; + return this; + } + + public Builder withComment(String comment) { + this.comment = comment; + return this; + } + + public Builder withOptions(Options options) { + this.options = options; + return this; + } + + public Table build() { + return new Table(tableId, primaryKey, uniqueKeys, comment, options); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableEditor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableEditor.java new file mode 100644 index 0000000000..18d298ac7b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableEditor.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.util.List; + +/** + * An interface for editing and configuring properties of a database table schema. + * + * @param The specific type of table editor. + * @param The type of columns in the table. + * @param The type of the resulting table schema. + */ +public interface TableEditor { + + /** + * Sets the unique identifier (ID) of the table. + * + * @param tableId The unique ID of the table. + * @return A reference to the table editor for further configuration. + */ + TE withTableId(TableId tableId); + + /** + * Adds columns to the table. + * + * @param columns The columns to add to the table. + * @return A reference to the table editor for further configuration. + */ + @SuppressWarnings("unchecked") + TE addColumns(Col... columns); + + /** + * Sets a comment or description for the table. + * + * @param comment A comment or description for the table. + * @return A reference to the table editor for further configuration. + */ + TE withComment(String comment); + + /** + * Removes a column from the table. + * + * @param columnName The name of the column to remove. + * @return A reference to the table editor for further configuration. + */ + TE removeColumn(String columnName); + + /** + * Sets the primary key columns for the table. + * + * @param pkColumnNames The names of the columns that form the primary key. + * @param comment A comment or description for the primary key. + * @return A reference to the table editor for further configuration. + */ + TE withPrimaryKeyNames(List pkColumnNames, String comment); + + /** + * Sets the primary key columns for the table. + * + * @param pkColumnNames The names of the columns that form the primary key. + * @return A reference to the table editor for further configuration. + */ + TE withPrimaryKeyNames(String... pkColumnNames); + + /** + * Sets the primary key for the table. + * + * @param primaryKey The primary key definition. + * @return A reference to the table editor for further configuration. + */ + TE withPrimaryKey(PrimaryKey primaryKey); + + /** + * Sets the unique key columns and their names for the table. + * + * @param ukName The name of the unique key constraint. + * @param ukColumnNames The names of the columns that form the unique key. + * @param comment A comment or description for the unique key. + * @return A reference to the table editor for further configuration. + */ + TE withUniqueKeyColumnsNames(String ukName, List ukColumnNames, String comment); + + /** + * Sets the unique key constraints for the table. + * + * @param uniqueKeys The unique key constraints. + * @return A reference to the table editor for further configuration. + */ + TE withUniqueKeys(UniqueKey... uniqueKeys); + + TE withOption(String key, Object value); + + /** + * Builds and returns the table schema with the configured properties. + * + * @return The resulting table schema. + */ + TB build(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableId.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableId.java new file mode 100644 index 0000000000..37be433298 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableId.java @@ -0,0 +1,166 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.Objects; + +import lombok.Getter; +import lombok.Setter; + +/** + * Represents a table identifier with catalog name, schema name and table name. + */ +@Getter +@Setter +public class TableId implements Serializable { + + /** + * The default mapper that converts a TableId to its string representation. + */ + public static final TableIdToStringMapper DEFAULT_TABLEIDTOSTRINGMAPPER = new DefaultTableIdToStringMapper(); + + private String catalogName; + + private String schemaName; + + private String tableName; + + private String id; + + public TableId() { + } + + /** + * Constructs a TableId instance without a TableIdToStringMapper. + * + * @param catalogName the catalog name of the table + * @param schemaName the schema name of the table + * @param tableName the name of the table + */ + public TableId(String catalogName, String schemaName, String tableName) { + this(catalogName, schemaName, tableName, null); + } + + /** + * Constructs a TableId instance without a TableIdToStringMapper. + * + * @param catalogName the catalog name of the table + */ + public TableId(String catalogName) { + this(catalogName, null, null, null); + } + + /** + * Constructs a TableId instance with a TableIdToStringMapper. If the mapper is null, the default mapper will be used. + * + * @param catalogName the catalog name of the table + * @param schemaName the schema name of the table + * @param tableName the name of the table + * @param mapper the mapper that converts a TableId to its string representation + */ + public TableId(String catalogName, String schemaName, String tableName, TableIdToStringMapper mapper) { + this.catalogName = catalogName; + this.schemaName = schemaName; + this.tableName = tableName; + this.id = mapper == null ? DEFAULT_TABLEIDTOSTRINGMAPPER.toString(this) : mapper.toString(this); + + } + + @Override + public String toString() { + return id == null ? DEFAULT_TABLEIDTOSTRINGMAPPER.toString(this) : id; + } + + /** + * Returns the string representation of the TableId, which is the same as calling toString(). + * + * @return the string representation of the TableId + */ + public String tablePath() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TableId)) { + return false; + } + TableId tableId = (TableId) o; + return Objects.equals(getCatalogName(), tableId.getCatalogName()) && Objects.equals(getSchemaName(), tableId.getSchemaName()) + && Objects.equals(getTableName(), tableId.getTableName()); + } + + @Override + public int hashCode() { + return Objects.hash(getCatalogName(), getSchemaName(), getTableName()); + } + + /** + * A functional interface that converts a TableId to its string representation. + */ + @FunctionalInterface + public interface TableIdToStringMapper { + + String toString(TableId tableId); + } + + /** + * Returns the string representation of a TableId. If catalog or schema is null or empty, they will be excluded from the string. + * + * @param catalog the catalog name of the table + * @param schema the schema name of the table + * @param table the name of the table + * @return the string representation of the TableId + */ + private static String tableId(String catalog, String schema, String table) { + StringBuilder tableId = new StringBuilder(); + if (StringUtils.isNotBlank(catalog)) { + tableId.append(catalog).append("."); + } + if (StringUtils.isNotBlank(schema)) { + tableId.append(schema).append("."); + } + if (StringUtils.isNotBlank(table)) { + tableId.append(table).append("."); + } + if (tableId.length() == 0) { + return null; + } + return tableId.substring(0, tableId.length() - 1); + } + + /** + * The default mapper that converts a TableId to its string representation. + */ + private static class DefaultTableIdToStringMapper implements TableIdToStringMapper { + + public String toString(TableId tableId) { + return tableId(tableId.getCatalogName(), tableId.getSchemaName(), tableId.getTableName()); + } + } + + public TableId copy() { + return new TableId(this.catalogName, this.schemaName, this.tableName); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableSchema.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableSchema.java new file mode 100644 index 0000000000..fa4ed243d8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableSchema.java @@ -0,0 +1,206 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlColumn; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlTableSchema; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class TableSchema implements Serializable { + + private TableId tableId = new TableId(); + + /** + * A map of column names to their respective column objects. + */ + private Map> columnMap; + + /** + * A list of columns in the table. + */ + private List> columns; + + private Map> orderColumnMap; + + /** + * The primary key of the table. + */ + private PrimaryKey primaryKey; + + private List uniqueKeys; + + private String comment; + + public TableSchema(TableId tableId, Map> columnMap, List> columns, + Map> orderColumnMap, PrimaryKey primaryKey, List uniqueKeys, String comment) { + this.tableId = tableId; + this.columnMap = columnMap; + this.columns = columns; + this.orderColumnMap = orderColumnMap; + this.primaryKey = primaryKey; + this.uniqueKeys = uniqueKeys; + this.comment = comment; + } + + public TableSchema(String name) { + this.tableId.setTableName(name); + } + + public TableSchema(TableId tableId) { + this.tableId = tableId; + } + + public String getSimpleName() { + return this.tableId.getTableName(); + } + + public static TableSchemaBuilder newTableSchemaBuilder() { + return new TableSchemaBuilder(); + } + + public static class TableSchemaBuilder { + + private TableId tableId; + private Map> columnMap; + private Map> orderColumnMap; + private List> columns; + private PrimaryKey primaryKey; + private List uniqueKeys; + private String comment; + + public TableSchemaBuilder() { + + } + + public TableSchemaBuilder withTableId(TableId tableId) { + this.tableId = tableId; + return this; + } + + public TableSchemaBuilder withColumns(Map> columnMap) { + this.columnMap = columnMap; + return this; + } + + public TableSchemaBuilder withColumns(List> columns) { + this.columns = columns; + return this; + } + + public TableSchemaBuilder withPrimaryKey(PrimaryKey primaryKey) { + this.primaryKey = primaryKey; + return this; + } + + public TableSchemaBuilder withUniqueKeys(List uniqueKeys) { + this.uniqueKeys = uniqueKeys; + return this; + } + + public TableSchemaBuilder withComment(String comment) { + this.comment = comment; + return this; + } + + public TableSchema build() { + return new TableSchema(tableId, columnMap, columns, orderColumnMap, primaryKey, uniqueKeys, comment); + } + + } + + public static MysqlTableSchemaBuilder newMysqlTableSchemaBuilder() { + return new MysqlTableSchemaBuilder(); + } + + public static class MysqlTableSchemaBuilder { + + private TableId tableId = new TableId(); + private Map columnMap; + private Map orderColumnMap; + private List columns; + private PrimaryKey primaryKey; + private List uniqueKeys; + private String comment; + private Options tableOptions = new Options(); + + public MysqlTableSchemaBuilder() { + + } + + public MysqlTableSchemaBuilder withName(String name) { + this.tableId.setTableName(name); + return this; + } + + public MysqlTableSchemaBuilder withTableId(TableId tableId) { + this.tableId = tableId; + return this; + } + + public MysqlTableSchemaBuilder withColumns(List columns) { + this.columns = columns; + this.columnMap = Optional.ofNullable(columns).orElse(new ArrayList<>(0)).stream() + .collect(Collectors.toMap(MysqlColumn::getName, Function.identity())); + this.orderColumnMap = Optional.ofNullable(columns).orElse(new ArrayList<>(0)).stream() + .collect(Collectors.toMap(MysqlColumn::getOrder, Function.identity())); + return this; + } + + public MysqlTableSchemaBuilder withPrimaryKey(PrimaryKey primaryKey) { + this.primaryKey = primaryKey; + return this; + } + + public MysqlTableSchemaBuilder withUniqueKeys(List uniqueKeys) { + this.uniqueKeys = uniqueKeys; + return this; + } + + public MysqlTableSchemaBuilder withComment(String comment) { + this.comment = comment; + return this; + } + + public MysqlTableSchemaBuilder withOption(String key, Object value) { + this.tableOptions.put(key, value); + return this; + } + + public MysqlTableSchemaBuilder withOptions(Options options) { + this.tableOptions.putAll(options); + return this; + } + + public MysqlTableSchema build() { + return new MysqlTableSchema(tableId, columnMap, columns, orderColumnMap, primaryKey, uniqueKeys, comment, tableOptions); + } + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/UniqueKey.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/UniqueKey.java new file mode 100644 index 0000000000..4677d43c62 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/UniqueKey.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import java.util.List; + +import lombok.Getter; +import lombok.Setter; + +/** + * Represents a unique key constraint for a database table. + *

A unique key ensures that the values in specified columns are unique across all rows in the table.

+ */ +@Setter +@Getter +public class UniqueKey extends Index { + + private static final String INDEX_TYPE = "UNIQUE"; + + public UniqueKey() { + } + + public UniqueKey(String name, List columnNames, String comment) { + super(name, columnNames, INDEX_TYPE, null, comment); + } + + public UniqueKey(String name, List columnNames) { + super(name, columnNames); + } + + public UniqueKey(List columnNames) { + super(columnNames); + } + + public UniqueKey copy() { + return new UniqueKey(getName(), getColumnNames(), getComment()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumn.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumn.java new file mode 100644 index 0000000000..424f70f3a6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumn.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.Options; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.sql.JDBCType; +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Represents a MySQL column in a database table. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MysqlColumn extends Column { + + public MysqlColumn(String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, boolean autoIncremented, boolean generated, String collationName, + String charsetName, List enumValues, String nativeType, Options options) { + super(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, 0, charsetName, + autoIncremented, generated, collationName, enumValues, nativeType, options); + } + + public MysqlColumn(String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, boolean autoIncremented, boolean generated, String collationName, + int order, String charsetName, List enumValues, String nativeType, Options options) { + super(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, order, charsetName, + autoIncremented, generated, collationName, enumValues, nativeType, options); + } + + public MysqlColumn() { + + } + + public static MysqlColumn of( + String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, + String comment, Object defaultValue, String defaultValueExpression, boolean autoIncremented, boolean generated, String collationName, + String charsetName, List enumValues, String nativeType, Options options) { + return new MysqlColumn(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, + autoIncremented, generated, collationName, charsetName, enumValues, nativeType, options); + } + + public static MysqlColumn of( + String name, EventMeshDataType dataType, JDBCType jdbcType, Long columnLength, Integer decimal, boolean notNull, String comment, + Object defaultValue, String defaultValueExpression, boolean autoIncremented, boolean generated, String collationName, int order, + String charsetName, List enumValues, String nativeType, Options options) { + return new MysqlColumn(name, dataType, jdbcType, columnLength, decimal, notNull, comment, defaultValue, defaultValueExpression, + autoIncremented, generated, collationName, order, charsetName, enumValues, nativeType, options); + } + + /** + * creates a clone of the Column + * + * @return clone of column + */ + @Override + public MysqlColumn clone() { + return null; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumnEditor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumnEditor.java new file mode 100644 index 0000000000..470e31affd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumnEditor.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.ColumnEditor; + +/** + * Interface for editing MySQL column properties. + */ +public interface MysqlColumnEditor extends ColumnEditor { + + /** + * Creates a new MySQL column editor with the specified name. + * + * @param name The name of the column. + * @return A new MySQL column editor instance. + */ + static MysqlColumnEditor ofEditor(String name) { + return new MysqlColumnEditorImpl(name); + } + + /** + * Creates a new MySQL column editor without specifying a name. + * + * @return A new MySQL column editor instance. + */ + static MysqlColumnEditor ofEditor() { + return new MysqlColumnEditorImpl(); + } + + /** + * Sets whether the column is auto-incremented. + * + * @param autoIncremented Whether the column is auto-incremented. + * @return The ColumnEditor instance. + */ + MysqlColumnEditor autoIncremented(boolean autoIncremented); + + /** + * Sets whether the column is generated. + * + * @param generated Whether the column is generated. + * @return The ColumnEditor instance. + */ + MysqlColumnEditor generated(boolean generated); + + /** + * Sets the collation (character set) for the column. + * + * @param collationName The name of the collation to set. + * @return The column editor with the collation set. + */ + MysqlColumnEditor collation(String collationName); + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumnEditorImpl.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumnEditorImpl.java new file mode 100644 index 0000000000..9f6ac950d0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlColumnEditorImpl.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.connector.jdbc.source.dialect.mysql.MysqlDataTypeConvertor; +import org.apache.eventmesh.connector.jdbc.table.catalog.AbstractColumnEditorImpl; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; + +import java.util.HashMap; +import java.util.Map; + +public class MysqlColumnEditorImpl extends AbstractColumnEditorImpl implements MysqlColumnEditor { + + private boolean autoIncremented; + + private boolean generated; + + private String collationName; + + private MysqlDataTypeConvertor convertor = new MysqlDataTypeConvertor(); + + public MysqlColumnEditorImpl(String name) { + super(name); + } + + public MysqlColumnEditorImpl() { + } + + /** + * Sets whether the column is auto-incremented. + * + * @param autoIncremented Whether the column is auto-incremented. + * @return The ColumnEditor instance. + */ + @Override + public MysqlColumnEditor autoIncremented(boolean autoIncremented) { + this.autoIncremented = autoIncremented; + return this; + } + + /** + * Sets whether the column is generated. + * + * @param generated Whether the column is generated. + * @return The ColumnEditor instance. + */ + @Override + public MysqlColumnEditor generated(boolean generated) { + this.generated = generated; + return this; + } + + /** + * Sets the collation (character set) for the column. + * + * @param collationName The name of the collation to set. + * @return The column editor with the collation set. + */ + @Override + public MysqlColumnEditor collation(String collationName) { + this.collationName = collationName; + return this; + } + + /** + * Builds and returns the configured column. + * + * @return The configured column. + */ + @Override + public MysqlColumn build() { + + Map dataTypeProperties = new HashMap<>(); + if (ofColumnLength() != null) { + dataTypeProperties.put(MysqlDataTypeConvertor.PRECISION, ofColumnLength().intValue()); + } + dataTypeProperties.put(MysqlDataTypeConvertor.SCALE, ofScale()); + EventMeshDataType eventMeshType = convertor.toEventMeshType(ofJdbcType(), dataTypeProperties); + withEventMeshType(eventMeshType); + + return MysqlColumn.of(ofName(), ofEventMeshDataType(), ofJdbcType(), ofColumnLength(), ofScale(), isNotNull(), ofComment(), ofDefaultValue(), + ofDefaultValueExpression(), autoIncremented, generated, collationName, ofOrder(), ofCharsetName(), ofEnumValues(), ofTypeName(), + ofOptions()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlDefaultValueConvertorImpl.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlDefaultValueConvertorImpl.java new file mode 100644 index 0000000000..1832f17d77 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlDefaultValueConvertorImpl.java @@ -0,0 +1,218 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.DefaultValueConvertor; +import org.apache.eventmesh.connector.jdbc.utils.ByteArrayUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.JDBCType; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MysqlDefaultValueConvertorImpl implements DefaultValueConvertor { + + private static final String EPOCH_DATE = "1970-01-01"; + + // Time The range is '-838:59:59.000000' to '838:59:59.000000' + private static final Pattern TIME_PATTERN = Pattern.compile("(\\-?[0-9]*):([0-9]*)(:([0-9]*))?(\\.([0-9]*))?"); + + private static final Set NUMBER_DATA_TYPES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(JDBCType.TINYINT, JDBCType.INTEGER, JDBCType.DATE, JDBCType.TIMESTAMP, JDBCType.TIMESTAMP_WITH_TIMEZONE, JDBCType.TIME, + JDBCType.BOOLEAN, JDBCType.BIT, JDBCType.NUMERIC, JDBCType.DECIMAL, JDBCType.FLOAT, JDBCType.DOUBLE, JDBCType.REAL))); + + private static final Set BINARY_DATA_TYPES = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(JDBCType.BINARY, JDBCType.VARBINARY))); + + @Override + public Object parseDefaultValue(Column column, String defaultValueExpression) { + if (defaultValueExpression == null) { + return null; + } + defaultValueExpression = defaultValueExpression.trim(); + + if (NUMBER_DATA_TYPES.contains(column.getJdbcType()) && StringUtils.equalsAnyIgnoreCase(defaultValueExpression, Boolean.TRUE.toString(), + Boolean.FALSE.toString())) { + /* + * These types are synonyms for DECIMAL: DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] + * [UNSIGNED] [ZEROFILL] + */ + if (column.getJdbcType() == JDBCType.DECIMAL || column.getJdbcType() == JDBCType.NUMERIC) { + return convert2Decimal(column, defaultValueExpression); + } + return StringUtils.equalsIgnoreCase(Boolean.TRUE.toString(), defaultValueExpression) ? 1 : 0; + } + + if (BINARY_DATA_TYPES.contains(column.getJdbcType()) && column.getDefaultValueExpression() != null) { + // https://dev.mysql.com/doc/refman/8.0/en/binary-varbinary.html + String cleanedDefaultValueExpression = StringUtils.replace(column.getDefaultValueExpression(), "\\0", ""); + return ByteArrayUtils.bytesToHexString(cleanedDefaultValueExpression.getBytes(Constants.DEFAULT_CHARSET)); + } + + switch (column.getDataType().getSQLType()) { + case DATE: + return convert2LocalDate(column, defaultValueExpression); + case TIMESTAMP: + return convertToLocalDateTime(column, defaultValueExpression); + case TIMESTAMP_WITH_TIMEZONE: + return convertToTimestamp(column, defaultValueExpression); + case TIME: + return convertToLocalTime(column, defaultValueExpression); + case BOOLEAN: + return convert2Boolean(column, defaultValueExpression); + case BIT: + return convertToBits(column, defaultValueExpression); + + case NUMERIC: + case DECIMAL: + return convert2Decimal(column, defaultValueExpression); + + case FLOAT: + case DOUBLE: + case REAL: + return Double.parseDouble(defaultValueExpression); + default: + } + return defaultValueExpression; + } + + private Object convert2Boolean(Column column, String value) { + // value maybe is numeric or string + if (StringUtils.isNumeric(value)) { + return Integer.parseInt(value) != 0; + } + return Boolean.parseBoolean(value); + } + + private Object convert2Decimal(Column column, String value) { + return Optional.ofNullable(column.getDecimal()).isPresent() ? new BigDecimal(value).setScale(column.getDecimal(), RoundingMode.HALF_UP) + : new BigDecimal(value); + } + + private Object convertToBits(Column column, String value) { + // value: '101010111' + if (column.getColumnLength() > 1) { + int nums = value.length() / Byte.SIZE + (value.length() % Byte.SIZE == 0 ? 0 : 1); + byte[] bytes = new byte[nums]; + int length = value.length(); + for (int i = 0; i < nums; i++) { + int size = value.length() - Byte.SIZE < 0 ? 0 : value.length() - Byte.SIZE; + bytes[nums - i - 1] = (byte) Integer.parseInt(value.substring(size, length), 2); + value = value.substring(0, size); + } + return bytes; + } + + // value: '1' or '0' parse to boolean + return Short.parseShort(value) != 0; + } + + private Object convertToLocalTime(Column column, String value) { + + Matcher matcher = TIME_PATTERN.matcher(value); + if (!matcher.matches()) { + throw new IllegalArgumentException("Unexpected format for TIME column: " + value); + } + + final int hours = Integer.parseInt(matcher.group(1)); + final int minutes = Integer.parseInt(matcher.group(2)); + final String secondsGroup = matcher.group(4); + int seconds = 0; + int nanoSeconds = 0; + + if (secondsGroup != null) { + seconds = Integer.parseInt(secondsGroup); + String microSecondsString = matcher.group(6); + if (microSecondsString != null) { + nanoSeconds = Integer.parseInt(microSecondsString) * 1000; + } + } + return LocalTime.of(hours, minutes, seconds, nanoSeconds); + } + + private Object convertToTimestamp(Column column, String value) { + // Mysql not support + return null; + } + + private Object convertToLocalDateTime(Column column, String value) { + if (StringUtils.containsAny(value, "CURRENT_TIMESTAMP", "current_timestamp")) { + return value; + } + // The TIMESTAMP data type is used for values that contain both date and time parts. + // TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC. + return LocalDateTime.from(timestampFormat(Optional.ofNullable(column.getColumnLength()).orElse(0L).intValue()).parse(value)); + } + + private Object convert2LocalDate(Column column, String value) { + // The DATE type is used for values with a date part but no time part. + // MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. + // The supported range is '1000-01-01' to '9999-12-31'. + + try { + if (StringUtils.contains(value, "-")) { + return LocalDate.parse(value); + } + // maybe is year, e.g. 2020 + if (StringUtils.isNumeric(value)) { + return LocalDate.parse(value + "-01-01"); + } + // format: 20200101 + return LocalDate.from(dateFormat().parse(value)); + } catch (Exception e) { + log.warn("Convert date error[value={}]", value); + return LocalDate.parse(EPOCH_DATE); + } + } + + private DateTimeFormatter timestampFormat(int length) { + final DateTimeFormatterBuilder dtf = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").optionalStart().appendLiteral(" ") + .append(DateTimeFormatter.ISO_LOCAL_TIME).optionalEnd().parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0).parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0); + if (length > 0) { + dtf.appendFraction(ChronoField.MICRO_OF_SECOND, 0, length, true); + } + return dtf.toFormatter(); + } + + private DateTimeFormatter dateFormat() { + final DateTimeFormatterBuilder dtf = new DateTimeFormatterBuilder().appendValue(ChronoField.YEAR, 4).appendValue(ChronoField.MONTH_OF_YEAR, 2) + .optionalStart().appendValue(ChronoField.DAY_OF_YEAR, 2); + return dtf.toFormatter(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlOptions.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlOptions.java new file mode 100644 index 0000000000..dc82e6ee51 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlOptions.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +/** + * The MysqlOptions class provides the constants for configuring options in MySQL tables and columns. + */ +public class MysqlOptions { + + public static final class MysqlTableOptions { + + public static String ENGINE = "ENGINE"; + + public static String AUTO_INCREMENT = "AUTO_INCREMENT"; + + public static String CHARSET = "CHARSET"; + + public static String COLLATE = "COLLATE"; + + public static String COMMENT = "COMMENT"; + } + + public static final class MysqlColumnOptions { + + public static String SIGNED = "SIGNED"; + + public static String UNSIGNED = "UNSIGNED"; + + public static String ZEROFILL = "ZEROFILL"; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableEditor.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableEditor.java new file mode 100644 index 0000000000..a62f7b7526 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableEditor.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableEditor; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +/** + * Interface for editing MySQL table schemas. + */ +public interface MysqlTableEditor extends TableEditor { + + /** + * Create a new instance of MysqlTableEditor for a specific table identified by its TableId. + * + * @param tableId The unique identifier for the table. + * @return A new MysqlTableEditor instance. + */ + static MysqlTableEditor ofCatalogTableEditor(TableId tableId) { + return new MysqlTableEditorImpl(tableId); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableEditorImpl.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableEditorImpl.java new file mode 100644 index 0000000000..852349b5bc --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableEditorImpl.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.AbstractTableEditorImpl; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableSchema; + +import java.util.ArrayList; + +public class MysqlTableEditorImpl extends AbstractTableEditorImpl implements MysqlTableEditor { + + public MysqlTableEditorImpl(TableId tableId) { + super(tableId); + } + + /** + * Builds and returns the table schema with the configured properties. + * + * @return The resulting table schema. + */ + @Override + public MysqlTableSchema build() { + return TableSchema.newMysqlTableSchemaBuilder() + .withTableId(ofTableId()) + .withColumns(new ArrayList<>(ofColumns().values())) + .withPrimaryKey(ofPrimaryKey()) + .withUniqueKeys(ofUniqueKeys()) + .withComment(ofComment()) + .withOptions(ofOptions()) + .build(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableSchema.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableSchema.java new file mode 100644 index 0000000000..4cddc03a65 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/catalog/mysql/MysqlTableSchema.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Options; +import org.apache.eventmesh.connector.jdbc.table.catalog.PrimaryKey; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; +import org.apache.eventmesh.connector.jdbc.table.catalog.TableSchema; +import org.apache.eventmesh.connector.jdbc.table.catalog.UniqueKey; + +import java.util.List; +import java.util.Map; + +import lombok.Getter; + +public class MysqlTableSchema extends TableSchema { + + @Getter + private Options tableOptions; + + public MysqlTableSchema(TableId tableId, Map columnMap, List columns, Map orderColumnMap, + PrimaryKey primaryKey, List uniqueKeys, String comment, Options tableOptions) { + super(tableId, columnMap, columns, orderColumnMap, primaryKey, uniqueKeys, comment); + this.tableOptions = tableOptions; + } + + public MysqlTableSchema() { + } + + public MysqlTableSchema(String name) { + super(name); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshDataType.java new file mode 100644 index 0000000000..110ef499df --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshDataType.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +import org.apache.eventmesh.connector.jdbc.type.Type; + +/** + * An interface representing a data type used in an EventMesh. + * + * @param The type of the data. + */ +public interface EventMeshDataType extends Type { + + /** + * Gets the class representing the type of the data. + * + * @return The class representing the type of the data. + */ + Class getTypeClass(); + + /** + * Gets the SQL type of the data. + * + * @return The SQL type of the data. + */ + SQLType getSQLType(); + + /** + * Gets the name of the data type. + * + * @return The name of the data type. + */ + String getName(); +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshRow.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshRow.java new file mode 100644 index 0000000000..81c24a3a08 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshRow.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import lombok.Getter; +import lombok.Setter; + +/** + * Represents a row in an event mesh. + */ +@Getter +@Setter +public class EventMeshRow implements Serializable { + + /** + * The mode for handling the row (e.g. INSERT, UPDATE, DELETE) {@link RowHandleMode} + */ + private RowHandleMode mode = RowHandleMode.INSERT; + + /** + * The ID of the table that the row belongs to + */ + private TableId tableId; + + /** + * The values of the fields in the row + */ + private final Object[] fieldValues; + + /** + * Any additional metadata associated with the row + */ + private Map ext = new HashMap<>(); + + public EventMeshRow(int fieldNum) { + this.fieldValues = new Object[fieldNum]; + } + + public EventMeshRow(int fieldNum, TableId tableId) { + this.tableId = tableId; + this.fieldValues = new Object[fieldNum]; + } + + public EventMeshRow(RowHandleMode mode, int fieldNum, TableId tableId) { + this.mode = mode; + this.tableId = tableId; + this.fieldValues = new Object[fieldNum]; + } + + /** + * Sets the values of the fields in the row. + * + * @param fieldValues the new field values + * @throws NullPointerException if fieldValues is null + * @throws IllegalArgumentException if fieldValues has a different length than the existing field values + */ + public void setFieldValues(Object[] fieldValues) { + Objects.requireNonNull(fieldValues, "Parameter fields can not be null"); + if (this.fieldValues.length != fieldValues.length) { + throw new IllegalArgumentException(); + } + System.arraycopy(fieldValues, 0, this.fieldValues, 0, this.fieldValues.length); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshTypeNameConverter.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshTypeNameConverter.java new file mode 100644 index 0000000000..f78386d37e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/EventMeshTypeNameConverter.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BooleanEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BytesEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DateEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DateTimeEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.DecimalEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Float32EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Float64EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int16EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int32EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int64EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.Int8EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.StringEventMeshDataType; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.TimeEventMeshDataType; + +import java.util.HashMap; +import java.util.Map; + +public final class EventMeshTypeNameConverter { + + private static Map PRIMITIVE_TYPE_MAP = new HashMap<>(32); + + static { + PRIMITIVE_TYPE_MAP.put(BooleanEventMeshDataType.INSTANCE.getName(), BooleanEventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(Float32EventMeshDataType.INSTANCE.getName(), Float32EventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(Float64EventMeshDataType.INSTANCE.getName(), Float64EventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(Int8EventMeshDataType.INSTANCE.getName(), Int8EventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(Int16EventMeshDataType.INSTANCE.getName(), Int16EventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(Int32EventMeshDataType.INSTANCE.getName(), Int32EventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(Int64EventMeshDataType.INSTANCE.getName(), Int64EventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(StringEventMeshDataType.INSTANCE.getName(), StringEventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(BytesEventMeshDataType.INSTANCE.getName(), BytesEventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(DateEventMeshDataType.INSTANCE.getName(), DateEventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(TimeEventMeshDataType.INSTANCE.getName(), TimeEventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(DateTimeEventMeshDataType.INSTANCE.getName(), DateTimeEventMeshDataType.INSTANCE); + PRIMITIVE_TYPE_MAP.put(DecimalEventMeshDataType.INSTANCE.getName(), DecimalEventMeshDataType.INSTANCE); + } + + public static EventMeshDataType ofEventMeshDataType(String dataType) { + return PRIMITIVE_TYPE_MAP.get(dataType); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/MapType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/MapType.java new file mode 100644 index 0000000000..f8a5fb530f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/MapType.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class MapType { + + private static final List SUPPORTED_KEY_TYPES = + Arrays.asList( + SQLType.NULL, + SQLType.BOOLEAN, + SQLType.TINYINT, + SQLType.SMALLINT, + SQLType.INTEGER, + SQLType.BIGINT, + SQLType.DATE, + SQLType.TIME, + SQLType.TIMESTAMP, + SQLType.FLOAT, + SQLType.DOUBLE, + SQLType.STRING, + SQLType.DECIMAL); + + private final EventMeshDataType keyType; + + private final EventMeshDataType valueType; + + public MapType(EventMeshDataType keyType, EventMeshDataType valueType) { + Objects.requireNonNull(keyType, "The key type is required."); + Objects.requireNonNull(valueType, "The value type is required."); + + if (!SUPPORTED_KEY_TYPES.contains(keyType.getSQLType())) { + throw new IllegalArgumentException(String.format("Not support type: %s", keyType.getSQLType())); + } + + this.keyType = keyType; + this.valueType = valueType; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MapType)) { + return false; + } + MapType mapType = (MapType) o; + return Objects.equals(keyType, mapType.keyType) && Objects.equals(valueType, mapType.valueType); + } + + @Override + public int hashCode() { + return Objects.hash(keyType, valueType); + } + + public EventMeshDataType keyType() { + return this.keyType; + } + + public EventMeshDataType valueType() { + return this.valueType; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/Pair.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/Pair.java new file mode 100644 index 0000000000..e5f0dd72ae --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/Pair.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pair { + + private Left left; + + private Right right; + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/RowHandleMode.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/RowHandleMode.java new file mode 100644 index 0000000000..d83cd48a31 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/RowHandleMode.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +/** + * An enum representing the different modes in which a row can be handled. + */ +public enum RowHandleMode { + + INSERT("+I", (byte) 1), + UPDATE_BEFORE("-UB", (byte) 2), + UPDATE_AFTER("+UA", (byte) 3), + DELETE("-D", (byte) 1), + ; + + private final String shortCut; + + private final byte value; + + /** + * Constructor for RowHandleMode. + * + * @param shortCut a string representing the shorthand for the row handle mode. + * @param value a byte representing the value of the row handle mode. + */ + RowHandleMode(String shortCut, byte value) { + this.shortCut = shortCut; + this.value = value; + } + + /** + * Returns the shorthand for the row handle mode. + * + * @return a string representing the shorthand for the row handle mode. + */ + public String toShortCut() { + return shortCut; + } + + /** + * Returns the value of the row handle mode. + * + * @return a byte representing the value of the row handle mode. + */ + public byte toValue() { + return value; + } + + /** + * Returns the row handle mode corresponding to the given byte value. + * + * @param value a byte representing the value of the row handle mode. + * @return the row handle mode corresponding to the given byte value. + * @throws UnsupportedOperationException if the byte value is not supported. + */ + public static RowHandleMode fromByteValue(byte value) { + switch (value) { + case 0: + return INSERT; + case 1: + return UPDATE_BEFORE; + case 2: + return UPDATE_AFTER; + case 3: + return DELETE; + default: + throw new UnsupportedOperationException( + "Unsupported byte value '" + value + "' for row handle mode."); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/SQLType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/SQLType.java new file mode 100644 index 0000000000..d8a397c700 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/table/type/SQLType.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.type; + +import java.sql.Types; + +/** + * see {@link java.sql.SQLType} + */ +public enum SQLType { + + BIT(Types.BIT), + + /** + * Identifies the generic SQL type {@code TINYINT}. + */ + TINYINT(Types.TINYINT), + /** + * Identifies the generic SQL type {@code SMALLINT}. + */ + SMALLINT(Types.SMALLINT), + /** + * Identifies the generic SQL type {@code INTEGER}. + */ + INTEGER(Types.INTEGER), + /** + * Identifies the generic SQL type {@code BIGINT}. + */ + BIGINT(Types.BIGINT), + /** + * Identifies the generic SQL type {@code FLOAT}. + */ + FLOAT(Types.FLOAT), + + /** + * Identifies the generic SQL type {@code DOUBLE}. + */ + DOUBLE(Types.DOUBLE), + + /** + * Identifies the generic SQL type {@code DECIMAL}. + */ + DECIMAL(Types.DECIMAL), + NUMERIC(Types.NUMERIC), + REAL(Types.REAL), + + /** + * Identifies the generic SQL type {@code DATE}. + */ + DATE(Types.DATE), + /** + * Identifies the generic SQL type {@code TIME}. + */ + TIME(Types.TIME), + /** + * Identifies the generic SQL type {@code TIMESTAMP}. + */ + TIMESTAMP(Types.TIMESTAMP), + + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE), + + /** + * Identifies the generic SQL type {@code BINARY}. + */ + BINARY(Types.BINARY), + + /** + * Identifies the generic SQL value {@code NULL}. + */ + NULL(Types.NULL), + + /** + * Identifies the generic SQL type {@code ARRAY}. + */ + ARRAY(Types.ARRAY), + + /** + * Identifies the generic SQL type {@code BOOLEAN}. + */ + BOOLEAN(Types.BOOLEAN), + + STRING(Types.VARCHAR); + + private int type; + + SQLType(int type) { + this.type = type; + } + + public int ofType() { + return type; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/AbstractType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/AbstractType.java new file mode 100644 index 0000000000..47b5c87896 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/AbstractType.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.EventMeshDataType; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; + +import java.util.Optional; + +import org.hibernate.dialect.Dialect; + +public abstract class AbstractType implements EventMeshDataType { + + protected Dialect hibernateDialect; + + protected DatabaseDialect eventMeshDialect; + + private final Class typeClass; + + private final SQLType sqlType; + + private final String name; + + public AbstractType(Class typeClass, SQLType sqlType, String name) { + this.typeClass = typeClass; + this.sqlType = sqlType; + this.name = name; + } + + @Override + public void configure(DatabaseDialect eventMeshDialect, Dialect hibernateDialect) { + this.hibernateDialect = hibernateDialect; + this.eventMeshDialect = eventMeshDialect; + } + + @Override + public String getTypeName(Column column) { + Long length = Optional.ofNullable(column.getColumnLength()).orElse(0L); + return hibernateDialect.getTypeName(column.getJdbcType().getVendorTypeNumber(), length, length.intValue(), + Optional.ofNullable(column.getDecimal()).orElse(0)); + } + + /** + * Returns the type class of the data. + * + * @return the type class of the data. + */ + @Override + public Class getTypeClass() { + return typeClass; + } + + /** + * Returns the SQL type of the data. + * + * @return the SQL type of the data. + */ + @Override + public SQLType getSQLType() { + return sqlType; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return column.getDefaultValue() == null ? "NULL" : column.getDefaultValue().toString(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/DatabaseTypeDialect.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/DatabaseTypeDialect.java new file mode 100644 index 0000000000..1496165dc8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/DatabaseTypeDialect.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.Table; + +import org.hibernate.dialect.Dialect; + +/** + * Interface for defining database type dialects. + */ +public interface DatabaseTypeDialect { + + String EMPTY_STRING = ""; + + /** + * Configures the given Hibernate dialect. + * + * @param hibernateDialect The Hibernate dialect to be configured. + */ + void configure(Dialect hibernateDialect); + + /** + * Gets type for the given column. + * + * @param column The column for which to get the type. + * @return The Hibernate type. + */ + Type getType(Column column); + + /** + * Gets the type name for the given column and Hibernate dialect. + * + * @param hibernateDialect The Hibernate dialect. + * @param column The column for which to get the type name. + * @return The type name. + */ + String getTypeName(Dialect hibernateDialect, Column column); + + /** + * Gets a formatted string for a boolean value. + * + * @param value The boolean value. + * @return The formatted string. + */ + default String getBooleanFormatted(boolean value) { + return value ? Boolean.TRUE.toString() : Boolean.FALSE.toString(); + } + + /** + * Gets a formatted string for an auto-incrementing column. + * + * @param column The auto-incrementing column. + * @return The formatted string. + */ + default String getAutoIncrementFormatted(Column column) { + return ""; + } + + /** + * Gets a formatted string for the default value of a column. + * + * @param column The column. + * @return The formatted string. + */ + default String getDefaultValueFormatted(Column column) { + return ""; + } + + /** + * Gets a formatted string for the character set or collation of a column. + * + * @param column The column. + * @return The formatted string. + */ + default String getCharsetOrCollateFormatted(Column column) { + return ""; + } + + /** + * Gets a formatted string for table options. + * + * @param table The table. + * @return The formatted string. + */ + default String getTableOptionsFormatted(Table table) { + return ""; + } + + /** + * Gets a formatted string for query binding with a value cast. + * + * @param column The column. + * @return The formatted string. + */ + default String getQueryBindingWithValueCast(Column column) { + return "?"; + } + + /** + * Gets a formatted string for the comment of a column. + * + * @param column The column. + * @return The formatted string. + */ + default String getCommentFormatted(Column column) { + return ""; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/Type.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/Type.java new file mode 100644 index 0000000000..6a903919c3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/Type.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.List; + +import org.hibernate.dialect.Dialect; +import org.hibernate.query.Query; + +/** + * top interface of jdbc type + */ +public interface Type { + + /** + * Configures the database dialects for the EventMesh and Hibernate. + * + * @param eventMeshDialect The database dialect for the EventMesh. + * @param hibernateDialect The database dialect for Hibernate. + */ + void configure(DatabaseDialect eventMeshDialect, Dialect hibernateDialect); + + /** + * Retrieves a list of registration keys. + * + * @return A list of registration keys as strings. + */ + List ofRegistrationKeys(); + + /** + * Retrieves the default value for a given database dialect and column. + * + * @param databaseDialect The specific database dialect. + * @param column The column for which to retrieve the default value. + * @return The default value for the specified database dialect and column. + */ + String getDefaultValue(DatabaseDialect databaseDialect, Column column); + + /** + * Returns the type name of the specified column. + * + * @param column the column object for which to retrieve the type name + * @return the type name of the column + */ + String getTypeName(Column column); + + /** + * Returns the query binding with value for the specified column and database dialect. + * + * @param databaseDialect the database dialect object to determine the query binding + * @param column the column object for which to retrieve the query binding with value + * @return the query binding with value for the column and database dialect + */ + default String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return databaseDialect.getQueryBindingWithValueCast(column); + } + + /** + * Converts the given value to the appropriate database type. + * + * @param value the value to be converted + * @return the converted value in the database type + */ + default Object convert2DatabaseTypeValue(Object value) { + return value; + } + + /** + * Binds the parameter value to the specified position in the query object and returns the number of bound parameters. + * + * @param startIndex The starting index for binding parameters + * @param value The value to bind + * @param query The query object to bind parameters to + * @return The number of bound parameters, Default is 1 + */ + default int bindValue(int startIndex, Object value, Query query) { + // Binds the parameter value to the specified index position in the query object + query.setParameter(startIndex, value); + // Returns the number of bound parameters, always 1 + return 1; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/BooleanEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/BooleanEventMeshDataType.java new file mode 100644 index 0000000000..a004dd2309 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/BooleanEventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class BooleanEventMeshDataType extends AbstractType { + + public static final BooleanEventMeshDataType INSTANCE = new BooleanEventMeshDataType(); + + private BooleanEventMeshDataType() { + super(Boolean.class, SQLType.BOOLEAN, "BOOLEAN"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("boolean", "bool", getName(), "BOOL"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/BytesEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/BytesEventMeshDataType.java new file mode 100644 index 0000000000..301d58d632 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/BytesEventMeshDataType.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + +public class BytesEventMeshDataType extends AbstractType { + + public static final BytesEventMeshDataType INSTANCE = new BytesEventMeshDataType(); + + public BytesEventMeshDataType() { + super(byte[].class, SQLType.BINARY, "BYTES"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("bytes", getName()); + } + + @Override + public Object convert2DatabaseTypeValue(Object value) { + // Jackson default serialize byte[] as base64 + String strValue = (String) value; + if (strValue == null) { + return null; + } + return Base64.getDecoder().decode(strValue); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DateEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DateEventMeshDataType.java new file mode 100644 index 0000000000..e2427c9348 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DateEventMeshDataType.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.List; + +public class DateEventMeshDataType extends AbstractType { + + public static final DateEventMeshDataType INSTANCE = new DateEventMeshDataType(); + + private DateEventMeshDataType() { + super(LocalDate.class, SQLType.DATE, "DATE"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName()); + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return column.getDefaultValue() == null ? "NULL" : "'" + column.getDefaultValue() + "'"; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DateTimeEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DateTimeEventMeshDataType.java new file mode 100644 index 0000000000..abb2eea520 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DateTimeEventMeshDataType.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class DateTimeEventMeshDataType extends AbstractType { + + public static final DateTimeEventMeshDataType INSTANCE = new DateTimeEventMeshDataType(); + + private DateTimeEventMeshDataType() { + super(LocalDateTime.class, SQLType.TIMESTAMP, "DATETIME"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName()); + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + if (column.getDefaultValue() == null) { + return "NULL"; + } + LocalDateTime localDateTime = LocalDateTime.parse(column.getDefaultValue().toString()); + if (Optional.ofNullable(column.getColumnLength()).orElse(0L) > 0) { + return "'" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S")) + "'"; + } + return "'" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "'"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DecimalEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DecimalEventMeshDataType.java new file mode 100644 index 0000000000..b7d40a33ae --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/DecimalEventMeshDataType.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; + +import lombok.Getter; +import lombok.Setter; + +public class DecimalEventMeshDataType extends AbstractType { + + public static final DecimalEventMeshDataType INSTANCE = new DecimalEventMeshDataType(); + + @Getter + @Setter + private Integer scale; + + @Getter + @Setter + private Integer precision; + + public DecimalEventMeshDataType(Integer precision, Integer scale) { + this(); + this.precision = precision; + this.scale = scale; + } + + public DecimalEventMeshDataType() { + super(BigDecimal.class, SQLType.DECIMAL, "DECIMAL"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "decimal"); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Float32EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Float32EventMeshDataType.java new file mode 100644 index 0000000000..6cfacdd700 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Float32EventMeshDataType.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class Float32EventMeshDataType extends AbstractType { + + public static final Float32EventMeshDataType INSTANCE = new Float32EventMeshDataType(); + + private Float32EventMeshDataType() { + super(Float.class, SQLType.FLOAT, "FLOAT"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "FLOAT32", "float32", "float"); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Float64EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Float64EventMeshDataType.java new file mode 100644 index 0000000000..938cb1f64a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Float64EventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class Float64EventMeshDataType extends AbstractType { + + public static final Float64EventMeshDataType INSTANCE = new Float64EventMeshDataType(); + + private Float64EventMeshDataType() { + super(Double.class, SQLType.DOUBLE, "FLOAT64"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "float64", "double"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int16EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int16EventMeshDataType.java new file mode 100644 index 0000000000..87b4d00716 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int16EventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class Int16EventMeshDataType extends AbstractType { + + public static final Int16EventMeshDataType INSTANCE = new Int16EventMeshDataType(); + + private Int16EventMeshDataType() { + super(Short.class, SQLType.SMALLINT, "INT16"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "int16", "shot", "SHORT", "Short", "smallint"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int32EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int32EventMeshDataType.java new file mode 100644 index 0000000000..e5c8f8146c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int32EventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class Int32EventMeshDataType extends AbstractType { + + public static final Int32EventMeshDataType INSTANCE = new Int32EventMeshDataType(); + + private Int32EventMeshDataType() { + super(Integer.class, SQLType.INTEGER, "INT32"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "int32", "Integer", "INTEGER", "integer"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int64EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int64EventMeshDataType.java new file mode 100644 index 0000000000..8b45479a0a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int64EventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class Int64EventMeshDataType extends AbstractType { + + public static final Int64EventMeshDataType INSTANCE = new Int64EventMeshDataType(); + + private Int64EventMeshDataType() { + super(Long.class, SQLType.BIGINT, "INT64"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "int64", "long", "Long", "LONG", "bigint", "BIGINT"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int8EventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int8EventMeshDataType.java new file mode 100644 index 0000000000..f59a8ed594 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/Int8EventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class Int8EventMeshDataType extends AbstractType { + + public static final Int8EventMeshDataType INSTANCE = new Int8EventMeshDataType(); + + private Int8EventMeshDataType() { + super(Byte.class, SQLType.TINYINT, "INT8"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("INT8, int8"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/NullEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/NullEventMeshDataType.java new file mode 100644 index 0000000000..21bdf7cf15 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/NullEventMeshDataType.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class NullEventMeshDataType extends AbstractType { + + public static final NullEventMeshDataType INSTANCE = new NullEventMeshDataType(); + + private NullEventMeshDataType() { + super(Void.class, SQLType.NULL, "NULL"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "null"); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/StringEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/StringEventMeshDataType.java new file mode 100644 index 0000000000..0b068d8f69 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/StringEventMeshDataType.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class StringEventMeshDataType extends AbstractType { + + public static final StringEventMeshDataType INSTANCE = new StringEventMeshDataType(); + + public StringEventMeshDataType() { + super(String.class, SQLType.STRING, "STRING"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("string", getName()); + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return column.getDefaultValue() == null ? "NULL" : "'" + column.getDefaultValue() + "'"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/TimeEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/TimeEventMeshDataType.java new file mode 100644 index 0000000000..876753d8cf --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/TimeEventMeshDataType.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.text.SimpleDateFormat; +import java.time.LocalTime; +import java.util.Arrays; +import java.util.List; + +public class TimeEventMeshDataType extends AbstractType { + + public static final TimeEventMeshDataType INSTANCE = new TimeEventMeshDataType(); + + private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + private TimeEventMeshDataType() { + super(LocalTime.class, SQLType.TIME, "TIME"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "time"); + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return column.getDefaultValue() == null ? "NULL" : "'" + column.getDefaultValue() + "'"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/YearEventMeshDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/YearEventMeshDataType.java new file mode 100644 index 0000000000..eac7fabf88 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/eventmesh/YearEventMeshDataType.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.eventmesh; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class YearEventMeshDataType extends AbstractType { + + public static final YearEventMeshDataType INSTANCE = new YearEventMeshDataType(); + + private YearEventMeshDataType() { + super(Integer.class, SQLType.INTEGER, "YEAR"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "year", "Year"); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BitType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BitType.java new file mode 100644 index 0000000000..ebe81152ae --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BitType.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.Base64; +import java.util.List; +import java.util.Optional; + +public class BitType extends AbstractType { + + public static final BitType INSTANCE = new BitType(); + + public BitType() { + super(byte[].class, SQLType.BIT, "BIT"); + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return column.getDefaultValue() == null ? " NULL " : String.format("b'%s'", column.getDefaultValue()); + } + + @Override + public String getTypeName(Column column) { + // https://dev.mysql.com/doc/refman/8.0/en/bit-type.html + Long columnLength = column.getColumnLength(); + return String.format("bit(%d)", Optional.ofNullable(columnLength).orElse(1L).intValue()); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("BIT", "bit"); + } + + @Override + public Object convert2DatabaseTypeValue(Object value) { + String strValue = (String) value; + return Base64.getDecoder().decode(strValue); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BooleanType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BooleanType.java new file mode 100644 index 0000000000..90dec2de0a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BooleanType.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; + +public class BooleanType extends AbstractType { + + public static final BooleanType INSTANCE = new BooleanType(); + + public BooleanType() { + super(Boolean.class, SQLType.BOOLEAN, "BOOLEAN"); + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return column.getDefaultValue() == null ? " NULL " : String.format("b'%s'", column.getDefaultValue()); + } + + @Override + public String getTypeName(Column column) { + return "bit(1)"; + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "bool", "boolean"); + } + + @Override + public Object convert2DatabaseTypeValue(Object value) { + if (value instanceof String) { + return StringUtils.equalsIgnoreCase("true", (String) value) ? 1 : 0; + } + return Long.parseLong(value.toString()) > 0 ? 1 : 0; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BytesType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BytesType.java new file mode 100644 index 0000000000..554e5aa6b3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/BytesType.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.BytesEventMeshDataType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class BytesType extends BytesEventMeshDataType { + + public static final BytesType INSTANCE = new BytesType(); + + private static final List BINARY_REGISTRATION_KEYS = Arrays.asList("BINARY", "binary", "VARBINARY", "varbinary"); + + private static final List BLOB_REGISTRATION_KEYS = Arrays.asList("TINYBLOB", "tinyblob", "BLOB", "blob", "MEDIUMBLOB", "mediumblob", + "LONGBLOB", "longblob"); + + @Override + public List ofRegistrationKeys() { + List registrationCodes = new ArrayList<>(); + registrationCodes.addAll(super.ofRegistrationKeys()); + registrationCodes.addAll(BINARY_REGISTRATION_KEYS); + registrationCodes.addAll(BLOB_REGISTRATION_KEYS); + return registrationCodes; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + // https://dev.mysql.com/doc/refman/8.0/en/blob.html + // BLOB and TEXT columns cannot have DEFAULT values + if (BLOB_REGISTRATION_KEYS.contains(column.getNativeType())) { + return ""; + } + // binary use hex string,e.g: 0x01020304 + return column.getDefaultValue() != null ? "0x" + column.getDefaultValue() : "NULL"; + } + + @Override + public String getTypeName(Column column) { + if (BLOB_REGISTRATION_KEYS.contains(column.getNativeType())) { + return column.getNativeType(); + } + if (BINARY_REGISTRATION_KEYS.contains(column.getNativeType())) { + final int lengthValue = Optional.ofNullable(column.getColumnLength()).orElse(1L).intValue(); + return String.format("%s(%d)", column.getNativeType(), lengthValue); + } + return "binary(1)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/DecimalType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/DecimalType.java new file mode 100644 index 0000000000..14f75d3130 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/DecimalType.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class DecimalType extends NumberType { + + public static final DecimalType INSTANCE = new DecimalType(); + + public DecimalType() { + super(Double.class, SQLType.DOUBLE, "DECIMAL"); + } + + @Override + public String getTypeName(Column column) { + // DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] + // A packed “exact” fixed-point number. M is the total number of digits (the precision) and D is the number of digits after the decimal point + // (the scale). The decimal point and (for negative numbers) the - sign are not counted in M. If D is 0, values have no decimal point or + // fractional part. The maximum number of digits (M) for DECIMAL is 65. + // The maximum number of supported decimals (D) is 30. If D is omitted, the default is 0. If M is omitted, the default is 10. + StringBuilder typeNameBuilder = new StringBuilder(); + Long length = Optional.ofNullable(column.getColumnLength()).orElse(10L); + if (column.getDecimal() == null) { + typeNameBuilder.append("DECIMAL(" + length + ")"); + } else { + String typeName = hibernateDialect.getTypeName(column.getJdbcType().getVendorTypeNumber(), length, length.intValue(), + Optional.ofNullable(column.getDecimal()).orElse(0)); + typeNameBuilder.append(typeName); + } + typeNameBuilder.append(convertOptions2Sql(column)); + return typeNameBuilder.toString(); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("decimal", getName()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/EnumType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/EnumType.java new file mode 100644 index 0000000000..4aa81fbb00 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/EnumType.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EnumType extends AbstractType { + + public static final EnumType INSTANCE = new EnumType(); + + private EnumType() { + super(byte[].class, SQLType.BIT, "ENUM"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("enum", "ENUM"); + } + + @Override + public String getTypeName(Column column) { + // https://dev.mysql.com/doc/refman/8.0/en/enum.html + List enumValues = column.getEnumValues(); + if (CollectionUtils.isNotEmpty(enumValues)) { + return "ENUM(" + enumValues.stream().map(val -> "'" + val + "'").collect(Collectors.joining(", ")) + ")"; + } + return "ENUM()"; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + if (column.getDefaultValue() == null) { + return "NULL"; + } + return "'" + column.getDefaultValue() + "'"; + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/GeometryCollectionType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/GeometryCollectionType.java new file mode 100644 index 0000000000..58ccb8630c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/GeometryCollectionType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class GeometryCollectionType extends SpatialDataType { + + public static final GeometryCollectionType INSTANCE = new GeometryCollectionType(); + + public GeometryCollectionType() { + super("GEOMETRYCOLLECTION"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "geometrycollection"); + } + + @Override + public String getTypeName(Column column) { + return "geometrycollection"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_GeomCollFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/GeometryType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/GeometryType.java new file mode 100644 index 0000000000..449b1adf94 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/GeometryType.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class GeometryType extends SpatialDataType { + + public static final GeometryType INSTANCE = new GeometryType(); + + public GeometryType() { + super("GEOMETRY"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "geometry"); + } + + @Override + public String getTypeName(Column column) { + return "geometry"; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + return ""; + } + + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_GeomFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/IntType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/IntType.java new file mode 100644 index 0000000000..d14cd75ba0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/IntType.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class IntType extends NumberType { + + public static final IntType INSTANCE = new IntType(); + + public IntType() { + super(Integer.class, SQLType.INTEGER, "INT"); + } + + @Override + public String getTypeName(Column column) { + Long length = Optional.ofNullable(column.getColumnLength()).orElse(0L); + String typeName = hibernateDialect.getTypeName(column.getJdbcType().getVendorTypeNumber(), length, length.intValue(), + Optional.ofNullable(column.getDecimal()).orElse(0)); + StringBuilder typeNameBuilder = new StringBuilder(length > 0 ? typeName + "(" + length + ")" : typeName); + typeNameBuilder.append(convertOptions2Sql(column)); + return typeNameBuilder.toString(); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("INT32", getName(), "int"); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/JsonType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/JsonType.java new file mode 100644 index 0000000000..e230a06741 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/JsonType.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; + +public class JsonType extends AbstractType { + + public static final JsonType INSTANCE = new JsonType(); + + public JsonType() { + super(String.class, SQLType.STRING, "JSON"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("json", getName(), "Json"); + } + + @Override + public String getTypeName(Column column) { + return "json"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "CAST(? AS JSON)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/LineStringType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/LineStringType.java new file mode 100644 index 0000000000..1c610fd449 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/LineStringType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class LineStringType extends SpatialDataType { + + public static final LineStringType INSTANCE = new LineStringType(); + + public LineStringType() { + super("LINESTRING"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "linestring"); + } + + @Override + public String getTypeName(Column column) { + return "linestring"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_LineFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MediumintType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MediumintType.java new file mode 100644 index 0000000000..0c51082f04 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MediumintType.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; + +import java.util.Arrays; +import java.util.List; + +public class MediumintType extends NumberType { + + public static final MediumintType INSTANCE = new MediumintType(); + + public MediumintType() { + super(Integer.class, SQLType.INTEGER, "MEDIUMINT"); + } + + @Override + public String getTypeName(Column column) { + StringBuilder typeNameBuilder = new StringBuilder(" mediumint "); + typeNameBuilder.append(convertOptions2Sql(column)); + return typeNameBuilder.toString(); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList("mediumint", getName()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiLineStringType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiLineStringType.java new file mode 100644 index 0000000000..00b7a2f6c4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiLineStringType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class MultiLineStringType extends SpatialDataType { + + public static final MultiLineStringType INSTANCE = new MultiLineStringType(); + + public MultiLineStringType() { + super("MULTILINESTRING"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "multilinestring"); + } + + @Override + public String getTypeName(Column column) { + return "multilinestring"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_MLineFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiPointType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiPointType.java new file mode 100644 index 0000000000..1b9c3c87c5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiPointType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class MultiPointType extends SpatialDataType { + + public static final MultiPointType INSTANCE = new MultiPointType(); + + public MultiPointType() { + super("MULTIPOINT"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "multipoint"); + } + + @Override + public String getTypeName(Column column) { + return "multipoint"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_MPointFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiPolygonType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiPolygonType.java new file mode 100644 index 0000000000..c35d167a03 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/MultiPolygonType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class MultiPolygonType extends SpatialDataType { + + public static final MultiPolygonType INSTANCE = new MultiPolygonType(); + + public MultiPolygonType() { + super("MULTIPOLYGON"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "multipolygon"); + } + + @Override + public String getTypeName(Column column) { + return "multipolygon"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_MPolyFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/NumberType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/NumberType.java new file mode 100644 index 0000000000..84c1dec4eb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/NumberType.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.catalog.mysql.MysqlOptions.MysqlColumnOptions; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import org.apache.commons.collections4.MapUtils; + +import java.util.Optional; + +public abstract class NumberType extends AbstractType { + + public NumberType(Class typeClass, SQLType sqlType, String name) { + super(typeClass, sqlType, name); + } + + @Override + public String getTypeName(Column column) { + Long length = Optional.ofNullable(column.getColumnLength()).orElse(0L); + String typeName = hibernateDialect.getTypeName(column.getJdbcType().getVendorTypeNumber(), length, length.intValue(), + Optional.ofNullable(column.getDecimal()).orElse(0)); + return typeName; + } + + protected String convertOptions2Sql(Column column) { + StringBuilder builder = new StringBuilder(); + if (MapUtils.isNotEmpty(column.getOptions())) { + String unsigned = (String) column.getOptions().get(MysqlColumnOptions.UNSIGNED); + if (unsigned != null) { + builder.append(" ").append(unsigned); + } + String zerofill = (String) column.getOptions().get(MysqlColumnOptions.ZEROFILL); + if (zerofill != null) { + builder.append(" ").append(zerofill); + } + } + return builder.toString(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/PointType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/PointType.java new file mode 100644 index 0000000000..839df9de82 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/PointType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class PointType extends SpatialDataType { + + public static final PointType INSTANCE = new PointType(); + + public PointType() { + super("POINT"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "point"); + } + + @Override + public String getTypeName(Column column) { + return "point"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_PointFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/PolygonType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/PolygonType.java new file mode 100644 index 0000000000..a26537580e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/PolygonType.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; + +import java.util.Arrays; +import java.util.List; + +public class PolygonType extends SpatialDataType { + + public static final PolygonType INSTANCE = new PolygonType(); + + public PolygonType() { + super("POLYGON"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "polygon"); + } + + @Override + public String getTypeName(Column column) { + return "polygon"; + } + + @Override + public String getQueryBindingWithValue(DatabaseDialect databaseDialect, Column column) { + return "ST_PolyFromWKB(?,?)"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/SetType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/SetType.java new file mode 100644 index 0000000000..402045cdf6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/SetType.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class SetType extends AbstractType { + + public static final SetType INSTANCE = new SetType(); + + private SetType() { + super(String.class, SQLType.STRING, "SET"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "set"); + } + + @Override + public String getTypeName(Column column) { + // https://dev.mysql.com/doc/refman/8.0/en/set.html + List enumValues = column.getEnumValues(); + if (CollectionUtils.isNotEmpty(enumValues)) { + return "SET(" + enumValues.stream().map(val -> "'" + val + "'").collect(Collectors.joining(", ")) + ")"; + } + return "SET()"; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + if (column.getDefaultValue() == null) { + return "NULL"; + } + return "'" + column.getDefaultValue() + "'"; + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/SpatialDataType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/SpatialDataType.java new file mode 100644 index 0000000000..dac75ab453 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/SpatialDataType.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Base64; + +import org.hibernate.query.Query; + +/** + * The SpatialDataType class is an abstract class that extends the AbstractType class. It represents a spatial data type for storing byte arrays. + * + *

+ * The SpatialDataType class provides constructors for specifying the type class, SQL type, and name of the spatial data type. + *

+ * mysql gis-wkb-functions + */ +public abstract class SpatialDataType extends AbstractType { + + public SpatialDataType(String name) { + super(byte[].class, SQLType.BINARY, name); + } + + @Override + public int bindValue(int startIndex, Object value, Query query) { + + if (value == null) { + query.setParameter(startIndex, null); + return 1; + } + + //doc:https://dev.mysql.com/doc/refman/8.0/en/gis-wkb-functions.html + //Different data types have different methods. For example, + // the `Point` type uses a method like this: `ST_PointFromWKB(wkb [, srid [, options]])`. + //Special handling is required when binding data like this. + if (value instanceof byte[]) { + + ByteBuffer buf = ByteBuffer.wrap((byte[]) value); + buf.order(ByteOrder.LITTLE_ENDIAN); + // The first 4 bytes represent the SRID. + Integer srid = buf.getInt(); + // The remainder is the WKB (Well-Known Binary) data. + byte[] wkb = new byte[buf.remaining()]; + buf.get(wkb); + query.setParameter(startIndex, wkb); + query.setParameter(startIndex + 1, srid); + return 2; + } + + throw new RuntimeException(); + } + + @Override + public Object convert2DatabaseTypeValue(Object value) { + // Jackson default serialize byte[] as base64 + String strValue = (String) value; + if (strValue == null) { + return null; + } + return Base64.getDecoder().decode(strValue); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/TextType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/TextType.java new file mode 100644 index 0000000000..8611c1beb6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/TextType.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.type.eventmesh.StringEventMeshDataType; + +import java.util.Arrays; +import java.util.List; + +public class TextType extends StringEventMeshDataType { + + public static final TextType INSTANCE = new TextType(); + + private static final List TEXT_REGISTRATION_KEYS = Arrays.asList("TEXT", "text", "MEDIUMTEXT", "mediumtext", "LONGTEXT", "longtext"); + + @Override + public List ofRegistrationKeys() { + return TEXT_REGISTRATION_KEYS; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + // https://dev.mysql.com/doc/refman/8.0/en/blob.html + // BLOB and TEXT columns cannot have DEFAULT values + return ""; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/TinyIntType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/TinyIntType.java new file mode 100644 index 0000000000..1c0b597d10 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/TinyIntType.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class TinyIntType extends AbstractType { + + public static final TinyIntType INSTANCE = new TinyIntType(); + + public TinyIntType() { + super(Byte.class, SQLType.TINYINT, "TINYINT"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "tinyint"); + } + + @Override + public String getTypeName(Column column) { + + final int size = Optional.ofNullable(column.getColumnLength()).orElse(0L).intValue(); + if (size > 0) { + return String.format("tinyint(%d)", size); + } + return "tinyint"; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/YearType.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/YearType.java new file mode 100644 index 0000000000..2b5ef3452d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/type/mysql/YearType.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.type.mysql; + +import org.apache.eventmesh.connector.jdbc.JdbcDriverMetaData; +import org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialect; +import org.apache.eventmesh.connector.jdbc.table.catalog.Column; +import org.apache.eventmesh.connector.jdbc.table.type.SQLType; +import org.apache.eventmesh.connector.jdbc.type.AbstractType; +import org.apache.eventmesh.connector.jdbc.utils.JdbcStringUtils; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.List; + +public class YearType extends AbstractType { + + public static final YearType INSTANCE = new YearType(); + + private YearType() { + super(Integer.class, SQLType.INTEGER, "YEAR"); + } + + @Override + public List ofRegistrationKeys() { + return Arrays.asList(getName(), "year", "Year"); + } + + @Override + public String getTypeName(Column column) { + JdbcDriverMetaData jdbcDriverMetaData = eventMeshDialect.getJdbcDriverMetaData(); + + // As of MySQL 8.0.19, the YEAR(4) data type with an explicit display width is deprecated; you should expect support for it to be removed in a + // future version of MySQL. + // Instead, use YEAR without a display width, which has the same meaning + if (JdbcStringUtils.compareVersion(jdbcDriverMetaData.getDatabaseProductVersion(), "8.0.19") >= 0) { + return "year"; + } + // MySQL 8.0 does not support the 2-digit YEAR(2) data type permitted in older versions of MySQL. For instructions on converting to 4-digit + // YEAR + if (column.getColumnLength() != null && column.getColumnLength() <= 2 + && JdbcStringUtils.compareVersion(jdbcDriverMetaData.getDatabaseProductVersion(), "8.0") >= 0) { + return "year(4)"; + } + return column.getColumnLength() == null ? "year" : "year(" + column.getColumnLength() + ")"; + } + + @Override + public String getDefaultValue(DatabaseDialect databaseDialect, Column column) { + + final Object defaultValue = column.getDefaultValue(); + if (defaultValue == null) { + return "NULL"; + } + return "'" + LocalDate.parse(defaultValue.toString()).getYear() + "'"; + } + + @Override + public Object convert2DatabaseTypeValue(Object value) { + if (value == null) { + return null; + } + return LocalDate.parse(value.toString()).getYear(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/Antlr4Utils.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/Antlr4Utils.java new file mode 100644 index 0000000000..6cee8cd01e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/Antlr4Utils.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.misc.Interval; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class Antlr4Utils { + + public static String getText(ParserRuleContext ctx) { + return getText(ctx, ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + } + + public static String getText(ParserRuleContext ctx, int start, int stop) { + Interval interval = new Interval(start, stop); + return ctx.getStart().getInputStream().getText(interval); + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/ByteArrayUtils.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/ByteArrayUtils.java new file mode 100644 index 0000000000..95f5d7a5e3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/ByteArrayUtils.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +public class ByteArrayUtils { + + private static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + /** + * Converts a byte array into a hexadecimal string. + * + * @param bytes the byte array to be converted + * @return the hexadecimal string representation of the byte array + * @throws NullPointerException if the byte array is null + */ + public static String bytesToHexString(byte[] bytes) { + if (bytes == null) { + throw new NullPointerException("Parameter to be converted can not be null"); + } + + char[] converted = new char[bytes.length * 2]; + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + converted[i * 2] = HEX_CHARS[b >> 4 & 0x0F]; + converted[i * 2 + 1] = HEX_CHARS[b & 0x0F]; + } + + return String.valueOf(converted); + } + + /** + * This method converts a hexadecimal string into an array of bytes. + * + * @param str the hexadecimal string to be converted + * @return the resulting byte array + * @throws IllegalArgumentException if the supplied character array contains an odd number of hex characters + */ + public static byte[] hexStringToBytes(String str) { + final char[] chars = str.toCharArray(); + if (chars.length % 2 != 0) { + throw new IllegalArgumentException("The supplied character array must contain an even number of hex chars."); + } + + byte[] response = new byte[chars.length / 2]; + + for (int i = 0; i < response.length; i++) { + int posOne = i * 2; + response[i] = (byte) (toByte(chars, posOne) << 4 | toByte(chars, posOne + 1)); + } + + return response; + } + + private static byte toByte(final char[] chars, final int pos) { + int response = Character.digit(chars[pos], 16); + if (response < 0 || response > 15) { + throw new IllegalArgumentException("Non-hex character '" + chars[pos] + "' at index=" + pos); + } + + return (byte) response; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/JdbcStringUtils.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/JdbcStringUtils.java new file mode 100644 index 0000000000..49f372214e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/JdbcStringUtils.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class JdbcStringUtils { + + /** + * Checks whether the given string is wrapped with a specific set of characters. + * + * @param possiblyWrapped the string to check + * @return true if the string is wrapped with characters '`', "'", or "\""; false otherwise + */ + public static boolean isWrapped(String possiblyWrapped) { + if (possiblyWrapped == null || possiblyWrapped.length() < 2) { + return false; + } + char firstChar = possiblyWrapped.charAt(0); + char lastChar = possiblyWrapped.charAt(possiblyWrapped.length() - 1); + return (firstChar == '`' && lastChar == '`') + || (firstChar == '\'' && lastChar == '\'') + || (firstChar == '\"' && lastChar == '\"'); + } + + public static boolean isWrapped(char c) { + return c == '\'' || c == '"' || c == '`'; + } + + public static String withoutWrapper(String possiblyWrapped) { + return isWrapped(possiblyWrapped) ? possiblyWrapped.substring(1, possiblyWrapped.length() - 1) : possiblyWrapped; + } + + /** + * Compares two version numbers and returns the result as an integer. + * + * @param versionX The first version number to compare. + * @param versionY The second version number to compare. + * @return An integer value representing the comparison result: -1 if versionX is less than versionY, 0 if versionX is equal to versionY, 1 if + * versionX is greater than versionY. + */ + public static int compareVersion(String versionX, String versionY) { + String[] firstVersionParts = versionX.split("\\."); + String[] secondVersionParts = versionY.split("\\."); + int maxLength = Math.max(firstVersionParts.length, secondVersionParts.length); + for (int i = 0; i < maxLength; i++) { + int firstVersionNumber = getPartAsNumber(firstVersionParts, i); + int secondVersionNumber = getPartAsNumber(secondVersionParts, i); + if (firstVersionNumber != secondVersionNumber) { + return Integer.signum(firstVersionNumber - secondVersionNumber); + } + } + return 0; + } + + private static int getPartAsNumber(String[] parts, int index) { + return index < parts.length ? Integer.parseInt(parts[index]) : 0; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/MysqlUtils.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/MysqlUtils.java new file mode 100644 index 0000000000..70cbb50705 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/java/org/apache/eventmesh/connector/jdbc/utils/MysqlUtils.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +public class MysqlUtils { + + /** + * Private constructor to prevent instantiation from outside the class. + */ + private MysqlUtils() { + + } + + /** + * Generates a wrapped name based on the TableId object. + * + * @param tableId The TableId object. + * @return The generated wrapped name. + */ + public static String wrapper(TableId tableId) { + return wrapper(tableId.getCatalogName()) + "." + wrapper(tableId.getTableName()); + } + + /** + * Generates a wrapped name based on the original string. + * + * @param original The original string. + * @return The generated wrapped name. + */ + public static String wrapper(String original) { + return "`" + original + "`"; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory new file mode 100644 index 0000000000..834b0bcf23 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.dialect.DatabaseDialectFactory @@ -0,0 +1,16 @@ +# 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. + +mysql=org.apache.eventmesh.connector.jdbc.dialect.mysql.MysqlDatabaseDialectFactory diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngineFactory b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngineFactory new file mode 100644 index 0000000000..06eb1b99e7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.source.dialect.cdc.CdcEngineFactory @@ -0,0 +1,16 @@ +# 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. + +mysql=org.apache.eventmesh.connector.jdbc.source.dialect.cdc.mysql.MysqlCdcEngineFactory diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngineFactory b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngineFactory new file mode 100644 index 0000000000..39075175e2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.SnapshotEngineFactory @@ -0,0 +1,16 @@ +# 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. + +mysql=org.apache.eventmesh.connector.jdbc.source.dialect.snapshot.mysql.MysqlSnapshotEngineFactory diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/log4j2.xml b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..cd699adad8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/log4j2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/server-config.yml new file mode 100644 index 0000000000..d9416e1ed2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: false +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..7896a08751 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/sink-config.yml @@ -0,0 +1,34 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10001 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: jdbcSourceUser + passWord: jdbcPassWord +sinkConnectorConfig: + connectorName: "EventMesh-sink" + jdbcConfig: + hostname: localhost + port: 3406 + user: root + password: xxxx + url: "jdbc:mysql://localhost:3406" diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/source-config.yml new file mode 100644 index 0000000000..9e2e4a3448 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/main/resources/source-config.yml @@ -0,0 +1,59 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10001 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: jdbcSourceUser + passWord: jdbcPassWord +sourceConnectorConfig: + maxTask: 10 #max task number + batchMaxRows: 100 + skipSnapshot: false + snapshotMaxThreads: 10 + snapshotSchema: true + snapshotData: true + snapshotFetchSize: 100 + databaseType: mysql + databaseIncludeList: + databaseExcludeList: + tableIncludeList: + tableExcludeList: + jdbcConfig: + hostname: localhost + port: 3306 + user: root + password: default + initialStatements: + connectTimeout: 10 + mysqlConfig: + serverId: 123 + keepAlive: true + keepAliveInterval: 6000 +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with topic + dataId: TopicTest, + #same with group + group: rocketmqSource + } diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableIdTest.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableIdTest.java new file mode 100644 index 0000000000..8a76906119 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/table/catalog/TableIdTest.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.table.catalog; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; + +public class TableIdTest { + + @Test + public void testConstructorWithMapper() { + TableId.TableIdToStringMapper customMapper = mock(TableId.TableIdToStringMapper.class); + when(customMapper.toString(any(TableId.class))).thenReturn("custom"); + + TableId tableId = new TableId("catalog", "schema", "table", customMapper); + assertEquals("custom", tableId.getId()); + } + + @Test + public void testConstructorWithDefaultMapper() { + TableId tableId = new TableId("catalog", "schema", "table"); + assertEquals("catalog.schema.table", tableId.getId()); + } + + @Test + public void testToStringMethod() { + TableId tableId = new TableId("catalog", "schema", "table"); + assertEquals("catalog.schema.table", tableId.toString()); + } + + @Test + public void testTablePathMethod() { + TableId tableId = new TableId("catalog", "schema", "table"); + assertEquals("catalog.schema.table", tableId.tablePath()); + } + + @Test + public void testEqualsMethod() { + TableId tableId1 = new TableId("catalog", "schema", "table"); + TableId tableId2 = new TableId("catalog", "schema", "table"); + assertTrue(tableId1.equals(tableId2)); + } + + @Test + public void testHashCodeMethod() { + TableId tableId1 = new TableId("catalog", "schema", "table"); + TableId tableId2 = new TableId("catalog", "schema", "table"); + assertEquals(tableId1.hashCode(), tableId2.hashCode()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/Antlr4UtilsTest.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/Antlr4UtilsTest.java new file mode 100644 index 0000000000..56d32ab57e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/Antlr4UtilsTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.junit.jupiter.api.Test; + +public class Antlr4UtilsTest { + + @Test + public void testGetTextWithContext() { + // Mock the ParserRuleContext and related objects + ParserRuleContext context = mock(ParserRuleContext.class); + Token startToken = mock(Token.class); + Token stopToken = mock(Token.class); + when(context.getStart()).thenReturn(startToken); + when(context.getStop()).thenReturn(stopToken); + when(startToken.getStartIndex()).thenReturn(0); + when(stopToken.getStopIndex()).thenReturn(11); + + // Mock the InputStream + CharStream inputStream = CharStreams.fromString("Hello, World!"); + when(startToken.getInputStream()).thenReturn(inputStream); + + // Call the method being tested + String result = Antlr4Utils.getText(context); + + // Assertions + assertEquals("Hello, World", result); + } + + @Test + public void testGetTextWithParameters() { + // Create a mock ParserRuleContext + ParserRuleContext context = mock(ParserRuleContext.class); + + // Mock the InputStream + String st = "Hello, Universe!"; + CharStream inputStream = CharStreams.fromString(st); + when(context.getStart()).thenReturn(mock(Token.class)); + when(context.getStop()).thenReturn(mock(Token.class)); + when(context.getStart().getInputStream()).thenReturn(inputStream); + + // Call the method being tested + String result = Antlr4Utils.getText(context, 0, st.length() - 2); + + // Assertions + assertEquals("Hello, Universe", result); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/ByteArrayUtilsTest.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/ByteArrayUtilsTest.java new file mode 100644 index 0000000000..51d30726aa --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/ByteArrayUtilsTest.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class ByteArrayUtilsTest { + + @Test + public void testBytesToHexString() { + byte[] bytes = {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE}; + String hexString = ByteArrayUtils.bytesToHexString(bytes); + assertEquals("cafebabe", hexString); + } + + @Test + public void testHexStringToBytes() { + String hexString = "cafebabe"; + byte[] bytes = ByteArrayUtils.hexStringToBytes(hexString); + assertArrayEquals(new byte[]{(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE}, bytes); + } + + @Test + public void testBytesToHexStringAndBack() { + byte[] originalBytes = {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE}; + String hexString = ByteArrayUtils.bytesToHexString(originalBytes); + byte[] convertedBytes = ByteArrayUtils.hexStringToBytes(hexString); + assertArrayEquals(originalBytes, convertedBytes); + } + + @Test + public void testHexStringToBytesWithOddLength() { + assertThrows(IllegalArgumentException.class, () -> { + ByteArrayUtils.hexStringToBytes("cafebabe1"); // Odd-length hex string + }); + } + + @Test + public void testHexStringToBytesWithInvalidCharacter() { + assertThrows(IllegalArgumentException.class, () -> { + ByteArrayUtils.hexStringToBytes("cafebabeG"); // Invalid hex character + }); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/JdbcStringUtilsTest.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/JdbcStringUtilsTest.java new file mode 100644 index 0000000000..5a97c21b10 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/JdbcStringUtilsTest.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +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 org.junit.jupiter.api.Test; + +public class JdbcStringUtilsTest { + + @Test + public void testIsWrapped() { + assertTrue(JdbcStringUtils.isWrapped("`Hello`")); + assertTrue(JdbcStringUtils.isWrapped("'World'")); + assertTrue(JdbcStringUtils.isWrapped("\"Java\"")); + assertFalse(JdbcStringUtils.isWrapped("NotWrapped")); + assertFalse(JdbcStringUtils.isWrapped("`NotClosed")); + assertFalse(JdbcStringUtils.isWrapped("NotOpened`")); + } + + @Test + public void testWithoutWrapper() { + assertEquals("Hello", JdbcStringUtils.withoutWrapper("`Hello`")); + assertEquals("World", JdbcStringUtils.withoutWrapper("'World'")); + assertEquals("Java", JdbcStringUtils.withoutWrapper("\"Java\"")); + assertEquals("NotWrapped", JdbcStringUtils.withoutWrapper("NotWrapped")); + assertEquals("`NotClosed", JdbcStringUtils.withoutWrapper("`NotClosed")); + assertEquals("NotOpened`", JdbcStringUtils.withoutWrapper("NotOpened`")); + } + + @Test + public void testIsWrappedWithChar() { + assertTrue(JdbcStringUtils.isWrapped('`')); + assertTrue(JdbcStringUtils.isWrapped('\'')); + assertTrue(JdbcStringUtils.isWrapped('\"')); + assertFalse(JdbcStringUtils.isWrapped('A')); + } + + @Test + public void testCompareVersion() { + // Test case 1: versionX is less than versionY + String versionX1 = "1.0.0"; + String versionY1 = "1.1.0"; + int expected1 = -1; + int result1 = JdbcStringUtils.compareVersion(versionX1, versionY1); + assertEquals(expected1, result1); + + // Test case 2: versionX is equal to versionY + String versionX2 = "1.2.3"; + String versionY2 = "1.2.3"; + int expected2 = 0; + int result2 = JdbcStringUtils.compareVersion(versionX2, versionY2); + assertEquals(expected2, result2); + + // Test case 3: versionX is greater than versionY + String versionX3 = "2.0.0"; + String versionY3 = "1.2.3"; + int expected3 = 1; + int result3 = JdbcStringUtils.compareVersion(versionX3, versionY3); + assertEquals(expected3, result3); + + assertEquals(0, JdbcStringUtils.compareVersion("1.0", "1.0")); + assertEquals(1, JdbcStringUtils.compareVersion("1.1", "1.0")); + assertEquals(-1, JdbcStringUtils.compareVersion("1.0", "1.1")); + assertEquals(1, JdbcStringUtils.compareVersion("1.10", "1.9")); + assertEquals(-1, JdbcStringUtils.compareVersion("1.9", "1.10")); + assertEquals(0, JdbcStringUtils.compareVersion("1.0.0", "1")); + assertEquals(0, JdbcStringUtils.compareVersion("1.0.0.0", "1.0")); + assertEquals(0, JdbcStringUtils.compareVersion("1.0.0.0", "1")); + assertEquals(-1, JdbcStringUtils.compareVersion("1.0.0.0", "1.1")); + assertEquals(1, JdbcStringUtils.compareVersion("1.1", "1.0.0.0")); + try { + assertEquals(0, JdbcStringUtils.compareVersion("1.1", "1.a")); + } catch (Exception e) { + assertTrue(e instanceof NumberFormatException); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/MysqlUtilsTest.java b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/MysqlUtilsTest.java new file mode 100644 index 0000000000..a84afd8570 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-jdbc/src/test/java/org/apache/eventmesh/connector/jdbc/utils/MysqlUtilsTest.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.jdbc.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.connector.jdbc.table.catalog.TableId; + +import org.junit.jupiter.api.Test; + +public class MysqlUtilsTest { + + @Test + public void testWrapperWithTableId() { + TableId mockTableId = mock(TableId.class); + when(mockTableId.getTableName()).thenReturn("test_table"); + when(mockTableId.getCatalogName()).thenReturn("test_table"); + + String wrapped = MysqlUtils.wrapper(mockTableId); + + assertEquals("`test_table`.`test_table`", wrapped); + } + + @Test + public void testWrapperWithString() { + String wrapped = MysqlUtils.wrapper("test_string"); + + assertEquals("`test_string`", wrapped); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-kafka/build.gradle b/eventmesh-connectors/eventmesh-connector-kafka/build.gradle new file mode 100644 index 0000000000..06e4fe97b3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/build.gradle @@ -0,0 +1,25 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation 'io.cloudevents:cloudevents-kafka:2.5.0' + implementation 'org.apache.kafka:kafka-clients:3.9.0' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-kafka/gradle.properties b/eventmesh-connectors/eventmesh-connector-kafka/gradle.properties new file mode 100644 index 0000000000..4486939e8d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=kafka \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/config/KafkaServerConfig.java b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/config/KafkaServerConfig.java new file mode 100644 index 0000000000..ccbabf2676 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/config/KafkaServerConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.kafka.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; + +@Data +public class KafkaServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/server/KafkaConnectServer.java b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/server/KafkaConnectServer.java new file mode 100644 index 0000000000..973424a18b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/server/KafkaConnectServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.kafka.server; + +import org.apache.eventmesh.connector.kafka.config.KafkaServerConfig; +import org.apache.eventmesh.connector.kafka.sink.connector.KafkaSinkConnector; +import org.apache.eventmesh.connector.kafka.source.connector.KafkaSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KafkaConnectServer { + + public static void main(String[] args) throws Exception { + + KafkaServerConfig serverConfig = ConfigUtil.parse(KafkaServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application kafkaSourceApp = new Application(); + kafkaSourceApp.run(KafkaSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application kafkaSinkApp = new Application(); + kafkaSinkApp.run(KafkaSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/sink/connector/KafkaSinkConnector.java b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/sink/connector/KafkaSinkConnector.java new file mode 100644 index 0000000000..0adafc1ce6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/sink/connector/KafkaSinkConnector.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.kafka.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.kafka.KafkaSinkConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.header.Header; +import org.apache.kafka.common.header.internals.RecordHeader; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KafkaSinkConnector implements Sink { + + private KafkaSinkConfig sinkConfig; + + private final Properties props = new Properties(); + Producer producer; + + @Override + public Class configClass() { + return KafkaSinkConfig.class; + } + + @Override + public void init(Config config) { + this.sinkConfig = (KafkaSinkConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (KafkaSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + private void doInit() { + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, sinkConfig.getConnectorConfig().getBootstrapServers()); + props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, sinkConfig.getConnectorConfig().getKeyConverter()); + props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, sinkConfig.getConnectorConfig().getValueConverter()); + props.put(ProducerConfig.ACKS_CONFIG, sinkConfig.getConnectorConfig().getAck()); + props.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, sinkConfig.getConnectorConfig().getMaxRequestSize()); + props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, sinkConfig.getConnectorConfig().getBufferMemory()); + props.put(ProducerConfig.BATCH_SIZE_CONFIG, sinkConfig.getConnectorConfig().getBatchSize()); + props.put(ProducerConfig.LINGER_MS_CONFIG, sinkConfig.getConnectorConfig().getLingerMs()); + props.put(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, sinkConfig.getConnectorConfig().getRequestTimeoutMs()); + props.put(ProducerConfig.MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION, sinkConfig.getConnectorConfig().getMaxInFightRequestsPerConnection()); + props.put(ProducerConfig.RETRIES_CONFIG, sinkConfig.getConnectorConfig().getRetries()); + props.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, sinkConfig.getConnectorConfig().getCompressionType()); + producer = new KafkaProducer<>(props); + } + + @Override + public void start() throws Exception { + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + producer.close(); + } + + @Override + public void put(List sinkRecords) { + try { + for (ConnectRecord connectRecord : sinkRecords) { + ProducerRecord message = convertRecordToMessage(connectRecord); + producer.send(message, (metadata, exception) -> { + if (exception == null) { + log.debug("Produced message to topic:{},partition:{},offset:{}", metadata.topic(), metadata.partition(), metadata.offset()); + } else { + log.error("Failed to produce message:{}", exception.getMessage()); + } + }); + } + } catch (Exception e) { + log.error("Failed to produce message:{}", e.getMessage()); + } + } + + public ProducerRecord convertRecordToMessage(ConnectRecord connectRecord) { + List
headers = new ArrayList<>(); + for (String key : connectRecord.getExtensions().keySet()) { + headers.add(new RecordHeader(key, connectRecord.getExtension(key).getBytes(StandardCharsets.UTF_8))); + } + ProducerRecord message = new ProducerRecord(this.sinkConfig.getConnectorConfig().getTopic(), null, "", + new String((byte[]) connectRecord.getData(), StandardCharsets.UTF_8), headers); + return message; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/source/connector/KafkaSourceConnector.java b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/source/connector/KafkaSourceConnector.java new file mode 100644 index 0000000000..f771e907cb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/java/org/apache/eventmesh/connector/kafka/source/connector/KafkaSourceConnector.java @@ -0,0 +1,137 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.kafka.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.kafka.KafkaSourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.kafka.KafkaRecordOffset; +import org.apache.eventmesh.common.remote.offset.kafka.KafkaRecordPartition; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +public class KafkaSourceConnector implements Source { + + private KafkaSourceConfig sourceConfig; + + private KafkaConsumer kafkaConsumer; + + private long maxPollWaitTime; + + @Override + public Class configClass() { + return KafkaSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.sourceConfig = (KafkaSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (KafkaSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, sourceConfig.getConnectorConfig().getBootstrapServers()); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, sourceConfig.getConnectorConfig().getKeyConverter()); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, sourceConfig.getConnectorConfig().getValueConverter()); + props.put(ConsumerConfig.GROUP_ID_CONFIG, sourceConfig.getConnectorConfig().getGroupID()); + props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, sourceConfig.getConnectorConfig().getEnableAutoCommit()); + props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, sourceConfig.getConnectorConfig().getMaxPollRecords()); + props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, sourceConfig.getConnectorConfig().getAutoCommitIntervalMS()); + props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, sourceConfig.getConnectorConfig().getSessionTimeoutMS()); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + this.kafkaConsumer = new KafkaConsumer<>(props); + } + + @Override + public void start() throws Exception { + kafkaConsumer.subscribe(Collections.singleton(sourceConfig.getConnectorConfig().getTopic())); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + kafkaConsumer.unsubscribe(); + } + + @Override + public List poll() { + ConsumerRecords records = kafkaConsumer.poll(Duration.ofMillis(maxPollWaitTime)); + List connectRecords = new ArrayList<>(records.count()); + for (ConsumerRecord record : records) { + Long timestamp = System.currentTimeMillis(); + String key = record.key(); + String value = record.value(); + RecordPartition recordPartition = convertToRecordPartition(record.topic(), record.partition()); + RecordOffset recordOffset = convertToRecordOffset(record.offset()); + ConnectRecord connectRecord = new ConnectRecord(recordPartition, recordOffset, timestamp, value); + connectRecord.addExtension("key", key); + connectRecords.add(connectRecord); + } + kafkaConsumer.commitAsync(); + return connectRecords; + } + + public static RecordOffset convertToRecordOffset(Long offset) { + KafkaRecordOffset recordOffset = new KafkaRecordOffset(); + recordOffset.setOffset(offset); + return recordOffset; + } + + public static RecordPartition convertToRecordPartition(String topic, int partition) { + KafkaRecordPartition recordPartition = new KafkaRecordPartition(); + recordPartition.setTopic(topic); + recordPartition.setPartition(partition); + return recordPartition; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/server-config.yml new file mode 100644 index 0000000000..0cd7b5b5ab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..b5c35b5434 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/sink-config.yml @@ -0,0 +1,33 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: kafkaSink + appId: 5031 + userName: kafkaSinkUser + passWord: kafkaPassWord +connectorConfig: + connectorName: kafkaSink + bootstrapServers: 127.0.0.1:9092 + topic: TopicTest + keyConverter: org.apache.kafka.common.serialization.StringSerializer + valueConverter: org.apache.kafka.common.serialization.StringSerializer + diff --git a/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/source-config.yml new file mode 100644 index 0000000000..4300c749f0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-kafka/src/main/resources/source-config.yml @@ -0,0 +1,33 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: kafkaSource + appId: 5032 + userName: kafkaSourceUser + passWord: kafkaPassWord +connectorConfig: + connectorName: kafkaSource + bootstrapServers: 127.0.0.1:9092 + topic: TopicTest + groupID: kafkaSource + sessionTimeoutMS: 10000 + maxPollRecords: 1000 diff --git a/eventmesh-connectors/eventmesh-connector-knative/build.gradle b/eventmesh-connectors/eventmesh-connector-knative/build.gradle new file mode 100644 index 0000000000..2380a6b192 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + +configurations { + implementation.exclude group: 'ch.qos.logback', module: 'logback-classic' + implementation.exclude group: 'log4j', module: 'log4j' +} + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + + implementation 'org.asynchttpclient:async-http-client' + + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/gradle.properties b/eventmesh-connectors/eventmesh-connector-knative/gradle.properties new file mode 100644 index 0000000000..27e6abf1c3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# +knative_version=1.5 +pluginType=connector +pluginName=knative \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/cloudevent/KnativeHeaders.java b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/cloudevent/KnativeHeaders.java new file mode 100644 index 0000000000..217023ddef --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/cloudevent/KnativeHeaders.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.knative.cloudevent; + +public class KnativeHeaders { + + public static final String CONTENT_TYPE = "Content-Type"; + + public static final String CE_ID = "Ce-Id"; + + public static final String CE_SPECVERSION = "Ce-Specversion"; + + public static final String CE_TYPE = "Ce-Type"; + + public static final String CE_SOURCE = "Ce-Source"; +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/cloudevent/KnativeMessageFactory.java b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/cloudevent/KnativeMessageFactory.java new file mode 100644 index 0000000000..d2d82e2033 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/cloudevent/KnativeMessageFactory.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.knative.cloudevent; + +import java.nio.charset.StandardCharsets; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public final class KnativeMessageFactory { + + private KnativeMessageFactory() { + // prevent instantiation + } + + public static String createReader(final CloudEvent message) { + if (message.getData() == null) { + log.warn("CloudEvent message's data is null."); + return ""; + } + return new String(message.getData().toBytes(), StandardCharsets.UTF_8); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/config/KnativeServerConfig.java b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/config/KnativeServerConfig.java new file mode 100644 index 0000000000..9469a5d4b5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/config/KnativeServerConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.knative.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class KnativeServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/server/KnativeConnectServer.java b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/server/KnativeConnectServer.java new file mode 100644 index 0000000000..1080261677 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/server/KnativeConnectServer.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.knative.server; + +import org.apache.eventmesh.connector.knative.config.KnativeServerConfig; +import org.apache.eventmesh.connector.knative.sink.connector.KnativeSinkConnector; +import org.apache.eventmesh.connector.knative.source.connector.KnativeSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KnativeConnectServer { + + public static void main(String[] args) throws Exception { + + KnativeServerConfig serverConfig = ConfigUtil.parse(KnativeServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application knativeSourceApp = new Application(); + knativeSourceApp.run(KnativeSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application knativeSinkApp = new Application(); + knativeSinkApp.run(KnativeSinkConnector.class); + } + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/sink/connector/KnativeSinkConnector.java b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/sink/connector/KnativeSinkConnector.java new file mode 100644 index 0000000000..b14f77ecd4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/sink/connector/KnativeSinkConnector.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.knative.sink.connector; + +import static org.asynchttpclient.Dsl.asyncHttpClient; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.knative.KnativeSinkConfig; +import org.apache.eventmesh.connector.knative.cloudevent.KnativeHeaders; +import org.apache.eventmesh.connector.knative.cloudevent.KnativeMessageFactory; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.ListenableFuture; +import org.asynchttpclient.Response; +import org.asynchttpclient.util.HttpConstants; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KnativeSinkConnector implements Sink { + + private KnativeSinkConfig sinkConfig; + + private transient AsyncHttpClient asyncHttpClient; + + private static final AtomicBoolean started = new AtomicBoolean(false); + + @Override + public Class configClass() { + return KnativeSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (KnativeSinkConfig) sinkConnectorContext.getSinkConfig(); + this.asyncHttpClient = asyncHttpClient(); + } + + @Override + public void start() throws Exception { + started.compareAndSet(false, true); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + started.compareAndSet(true, false); + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + CloudEvent cloudEvent = CloudEventUtil.convertRecordToEvent(connectRecord); + try { + ListenableFuture execute = asyncHttpClient.preparePost("http://" + sinkConfig.getConnectorConfig().getServiceAddr()) + .addHeader(KnativeHeaders.CONTENT_TYPE, cloudEvent.getDataContentType()) + .addHeader(KnativeHeaders.CE_ID, cloudEvent.getId()) + .addHeader(KnativeHeaders.CE_SPECVERSION, String.valueOf(cloudEvent.getSpecVersion())) + .addHeader(KnativeHeaders.CE_TYPE, cloudEvent.getType()) + .addHeader(KnativeHeaders.CE_SOURCE, String.valueOf(cloudEvent.getSource())) + .setBody(KnativeMessageFactory.createReader(cloudEvent)) + .execute(); + + Response response = execute.get(10, TimeUnit.SECONDS); + if (response.getStatusCode() != HttpConstants.ResponseStatusCodes.OK_200) { + log.error("[KnativeSinkConnector] sendResult fail : {}", response.getResponseBody());; + } + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[KnativeSinkConnector] Interrupting thread {} due to exception {}", currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } catch (Exception e) { + log.error("[KnativeSinkConnector] sendResult has error : ", e); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/source/connector/KnativeSourceConnector.java b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/source/connector/KnativeSourceConnector.java new file mode 100644 index 0000000000..1b0c033e8f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/java/org/apache/eventmesh/connector/knative/source/connector/KnativeSourceConnector.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.knative.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.knative.KnativeSourceConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KnativeSourceConnector implements Source { + + private KnativeSourceConfig sourceConfig; + + private static final AtomicBoolean started = new AtomicBoolean(false); + + @Override + public Class configClass() { + return KnativeSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (KnativeSourceConfig) sourceConnectorContext.getSourceConfig(); + } + + @Override + public void start() throws Exception { + started.compareAndSet(false, true); + } + + @Override + public void commit(ConnectRecord record) { + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + started.compareAndSet(true, false); + } + + @Override + public List poll() { + // todo: create a sink service and expose a public endpoint to Knative broker + // https://knative.dev/docs/eventing/sinks/ + return null; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..6340b667ec --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/sink-config.yml @@ -0,0 +1,31 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: knativeSink + appId: 5031 + userName: knativeSinkUser + passWord: knativePassWord +connectorConfig: + connectorName: knativeSink + emurl: 127.0.0.1 + serviceAddr: cloudevents-player.default.127.0.0.1.sslip.io + diff --git a/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/source-config.yml new file mode 100644 index 0000000000..dffc9cd020 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-knative/src/main/resources/source-config.yml @@ -0,0 +1,39 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: knativeSource + appId: 5032 + userName: knativeSourceUser + passWord: knativePassWord +connectorConfig: + connectorName: knativeSource + emurl: 127.0.0.1 + serviceAddr: cloudevents-player.default.127.0.0.1.sslip.io +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with connectorName + dataId: knativeSource, + #same with group + group: knativeSource + } diff --git a/eventmesh-connectors/eventmesh-connector-lark/build.gradle b/eventmesh-connectors/eventmesh-connector-lark/build.gradle new file mode 100644 index 0000000000..7cdd35b053 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + +List lark = [ + "com.larksuite.oapi:oapi-sdk:$lark_version", + "com.github.rholder:guava-retrying:$guava_retrying_version", + "org.apache.httpcomponents:httpclient", + project(":eventmesh-common") +] + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation lark + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-inline" + testImplementation "org.mockito:mockito-junit-jupiter" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-lark/gradle.properties b/eventmesh-connectors/eventmesh-connector-lark/gradle.properties new file mode 100644 index 0000000000..90f0d877f8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/gradle.properties @@ -0,0 +1,20 @@ +# +# 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. +# +lark_version=2.0.28 +guava_retrying_version=2.0.0 +pluginType=connector +pluginName=lark \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/ConfigUtils.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/ConfigUtils.java new file mode 100644 index 0000000000..f0017397e4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/ConfigUtils.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark; + +import org.apache.eventmesh.common.config.connector.lark.SinkConnectorConfig; + +import org.apache.commons.lang3.StringUtils; + +import com.lark.oapi.service.im.v1.enums.ReceiveIdTypeEnum; + +public class ConfigUtils { + + public static void validateSinkConfiguration(SinkConnectorConfig sinkConnectorConfig) { + // validate blank + if (StringUtils.isAnyBlank(sinkConnectorConfig.getAppId(), sinkConnectorConfig.getAppSecret(), sinkConnectorConfig.getReceiveId())) { + throw new IllegalArgumentException("appId or appSecret or receiveId is blank,please check it."); + } + + // validate receiveIdType + if (!StringUtils.containsAny(sinkConnectorConfig.getReceiveIdType(), ReceiveIdTypeEnum.CHAT_ID.getValue(), + ReceiveIdTypeEnum.EMAIL.getValue(), + ReceiveIdTypeEnum.OPEN_ID.getValue(), + ReceiveIdTypeEnum.USER_ID.getValue(), + ReceiveIdTypeEnum.UNION_ID.getValue())) { + throw new IllegalArgumentException( + String.format("sinkConnectorConfig.receiveIdType=[%s], Invalid.", sinkConnectorConfig.getReceiveIdType())); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/ConnectRecordExtensionKeys.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/ConnectRecordExtensionKeys.java new file mode 100644 index 0000000000..42274199e3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/ConnectRecordExtensionKeys.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark; + +/** + * Constants of record extension key. + */ +public interface ConnectRecordExtensionKeys { + + /** + * {@code text} or {@code markdown}, otherwise use {@code text} to replace. + */ + String TEMPLATE_TYPE_4_LARK = "templatetype4lark"; + + /** + * The value format is {@code id,name;id,name;}.Recommend to use {@code open_id} as {@code id}. + *

+ * To prevent bad situations, you should ensure that the {@code id} is valid + */ + String AT_USERS_4_LARK = "atusers4lark"; + + /** + * true or false + */ + String AT_ALL_4_LARK = "atall4lark"; + + String MARKDOWN_MESSAGE_TITLE_4_LARK = "markdownmessagetitle4lark"; +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/config/LarkConnectServerConfig.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/config/LarkConnectServerConfig.java new file mode 100644 index 0000000000..0106fa4a65 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/config/LarkConnectServerConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class LarkConnectServerConfig extends Config { + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/config/LarkMessageTemplateType.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/config/LarkMessageTemplateType.java new file mode 100644 index 0000000000..e99afcaa6b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/config/LarkMessageTemplateType.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.config; + +import java.util.Arrays; + +import lombok.Getter; + +@Getter +public enum LarkMessageTemplateType { + + PLAIN_TEXT("text"), + MARKDOWN("markdown"); + + private final String templateKey; + + LarkMessageTemplateType(String templateKey) { + this.templateKey = templateKey; + } + + public static LarkMessageTemplateType of(String templateKey) { + return Arrays.stream(values()) + .filter(v -> v.getTemplateKey().equals(templateKey)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("TemplateKey: " + templateKey + " not found.")); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/server/LarkConnectServer.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/server/LarkConnectServer.java new file mode 100644 index 0000000000..c6ec73c5a4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/server/LarkConnectServer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.server; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.lark.config.LarkConnectServerConfig; +import org.apache.eventmesh.connector.lark.sink.connector.LarkSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class LarkConnectServer { + + public static void main(String[] args) throws Exception { + + LarkConnectServerConfig larkConnectServerConfig = ConfigUtil.parse(LarkConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (larkConnectServerConfig.isSinkEnable()) { + Application application = new Application(); + application.run(LarkSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/sink/ImServiceHandler.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/sink/ImServiceHandler.java new file mode 100644 index 0000000000..ce5d4a3b85 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/sink/ImServiceHandler.java @@ -0,0 +1,346 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.sink; + +import static org.apache.eventmesh.connector.lark.sink.connector.LarkSinkConnector.getTenantAccessToken; + +import org.apache.eventmesh.common.config.connector.lark.SinkConnectorConfig; +import org.apache.eventmesh.connector.lark.ConnectRecordExtensionKeys; +import org.apache.eventmesh.connector.lark.config.LarkMessageTemplateType; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.text.StringEscapeUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.LongAdder; + +import com.github.rholder.retry.Attempt; +import com.github.rholder.retry.RetryException; +import com.github.rholder.retry.RetryListener; +import com.github.rholder.retry.Retryer; +import com.github.rholder.retry.RetryerBuilder; +import com.github.rholder.retry.StopStrategies; +import com.github.rholder.retry.WaitStrategies; +import com.lark.oapi.Client; +import com.lark.oapi.card.enums.MessageCardHeaderTemplateEnum; +import com.lark.oapi.card.model.MessageCard; +import com.lark.oapi.card.model.MessageCardConfig; +import com.lark.oapi.card.model.MessageCardElement; +import com.lark.oapi.card.model.MessageCardHeader; +import com.lark.oapi.card.model.MessageCardMarkdown; +import com.lark.oapi.card.model.MessageCardPlainText; +import com.lark.oapi.core.httpclient.OkHttpTransport; +import com.lark.oapi.core.request.RequestOptions; +import com.lark.oapi.core.utils.Lists; +import com.lark.oapi.okhttp.OkHttpClient; +import com.lark.oapi.service.im.v1.ImService; +import com.lark.oapi.service.im.v1.enums.MsgTypeEnum; +import com.lark.oapi.service.im.v1.model.CreateMessageReq; +import com.lark.oapi.service.im.v1.model.CreateMessageReqBody; +import com.lark.oapi.service.im.v1.model.CreateMessageResp; +import com.lark.oapi.service.im.v1.model.ext.MessageText; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ImServiceHandler { + + private SinkConnectorConfig sinkConnectorConfig; + + private ImService imService; + + private Retryer retryer; + + private ExecutorService sinkAsyncWorker; + private ExecutorService cleanerWorker; + private ScheduledExecutorService retryWorker; + + private static final LongAdder redoSinkNum = new LongAdder(); + + public ImServiceHandler() { + } + + public static ImServiceHandler create(SinkConnectorConfig sinkConnectorConfig) { + ImServiceHandler imServiceHandler = new ImServiceHandler(); + imServiceHandler.sinkConnectorConfig = sinkConnectorConfig; + imServiceHandler.imService = Client.newBuilder(sinkConnectorConfig.getAppId(), sinkConnectorConfig.getAppSecret()) + .httpTransport(new OkHttpTransport(new OkHttpClient().newBuilder() + .callTimeout(3L, TimeUnit.SECONDS) + .build())) + .disableTokenCache() + .requestTimeout(3, TimeUnit.SECONDS) + .build() + .im(); + + long fixedWait = Long.parseLong(sinkConnectorConfig.getRetryDelayInMills()); + int maxRetryTimes = Integer.parseInt(sinkConnectorConfig.getMaxRetryTimes()) + 1; + if (Boolean.parseBoolean(sinkConnectorConfig.getSinkAsync())) { + int availableProcessors = Runtime.getRuntime().availableProcessors(); + imServiceHandler.sinkAsyncWorker = Executors.newFixedThreadPool(availableProcessors, r -> { + Thread thread = new Thread(r); + thread.setDaemon(true); + thread.setName("eventmesh-connector-lark-sinkAsyncWorker"); + return thread; + }); + + imServiceHandler.cleanerWorker = Executors.newFixedThreadPool(availableProcessors, r -> { + Thread thread = new Thread(r); + thread.setDaemon(true); + thread.setName("eventmesh-connector-lark-cleanerWorker"); + return thread; + }); + + imServiceHandler.retryWorker = Executors.newScheduledThreadPool(availableProcessors, r -> { + Thread thread = new Thread(r); + thread.setDaemon(true); + thread.setName("eventmesh-connector-lark-retryWorker"); + return thread; + }); + } else { + imServiceHandler.retryer = RetryerBuilder.newBuilder() + .retryIfException() + .retryIfResult(Objects::nonNull) + .withWaitStrategy(WaitStrategies.fixedWait(fixedWait, TimeUnit.MILLISECONDS)) + .withStopStrategy(StopStrategies.stopAfterAttempt(maxRetryTimes)) + .withRetryListener(new RetryListener() { + + @SneakyThrows + @Override + public void onRetry(Attempt attempt) { + + long times = attempt.getAttemptNumber(); + if (times > 1) { + redoSinkNum.increment(); + log.info("Total redo sink task num : [{}]", redoSinkNum.sum()); + log.warn("Retry sink event to lark | times=[{}]", attempt.getAttemptNumber() - 1); + } + } + }) + .build(); + } + + return imServiceHandler; + } + + public void sink(ConnectRecord connectRecord) throws ExecutionException, RetryException { + Map> headers = new HashMap<>(); + headers.put("Content-Type", Lists.newArrayList("application/json; charset=utf-8")); + + RequestOptions requestOptions = RequestOptions.newBuilder() + .tenantAccessToken(getTenantAccessToken(sinkConnectorConfig.getAppId(), sinkConnectorConfig.getAppSecret())) + .headers(headers) + .build(); + + retryer.call(() -> { + CreateMessageReq createMessageReq = convertCreateMessageReq(connectRecord); + CreateMessageResp resp = imService.message().create(createMessageReq, requestOptions); + if (resp.getCode() != 0) { + log.warn("Sinking event to lark failure | code:[{}] | msg:[{}] | err:[{}]", resp.getCode(), resp.getMsg(), resp.getError()); + return connectRecord; + } + return null; + }); + } + + public void sinkAsync(ConnectRecord connectRecord) { + Map> headers = new HashMap<>(); + headers.put("Content-Type", Lists.newArrayList("application/json; charset=utf-8")); + + RequestOptions requestOptions = RequestOptions.newBuilder() + .tenantAccessToken(getTenantAccessToken(sinkConnectorConfig.getAppId(), sinkConnectorConfig.getAppSecret())) + .headers(headers) + .build(); + + CreateMessageReq createMessageReq = convertCreateMessageReq(connectRecord); + + long fixedWait = Long.parseLong(sinkConnectorConfig.getRetryDelayInMills()); + int maxRetryTimes = Integer.parseInt(sinkConnectorConfig.getMaxRetryTimes()) + 1; + LongAdder cnt = new LongAdder(); + AtomicBoolean isAck = new AtomicBoolean(false); + Runnable task = () -> CompletableFuture + .supplyAsync(() -> { + try { + cnt.increment(); + return imService.message().create(createMessageReq, requestOptions); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, sinkAsyncWorker) + .whenCompleteAsync((resp, e) -> { + if (cnt.sum() > 1) { + redoSinkNum.increment(); + log.info("Total redo sink task num : [{}]", redoSinkNum.sum()); + log.warn("Retry sink event to lark | times=[{}]", cnt.sum() - 1); + } + if (Objects.nonNull(e)) { + log.error("eventmesh-connector-lark internal exception.", e); + return; + } + if (resp.getCode() != 0) { + log.warn("Sinking event to lark failure | code:[{}] | msg:[{}] | err:[{}]", resp.getCode(), resp.getMsg(), resp.getError()); + return; + } + isAck.set(true); + }); + + ScheduledFuture future = retryWorker.scheduleAtFixedRate(task, 0L, fixedWait, TimeUnit.MILLISECONDS); + cleanerWorker.submit(() -> { + while (true) { + // complete task + if (isAck.get() || cnt.sum() >= maxRetryTimes) { + future.cancel(true); + return; + } + } + }); + } + + private CreateMessageReq convertCreateMessageReq(ConnectRecord connectRecord) { + CreateMessageReqBody.Builder bodyBuilder = CreateMessageReqBody.newBuilder() + .receiveId(sinkConnectorConfig.getReceiveId()) + .uuid(UUID.randomUUID().toString()); + + String templateTypeKey = connectRecord.getExtension(ConnectRecordExtensionKeys.TEMPLATE_TYPE_4_LARK); + if (templateTypeKey == null || "null".equals(templateTypeKey)) { + templateTypeKey = LarkMessageTemplateType.PLAIN_TEXT.getTemplateKey(); + } + LarkMessageTemplateType templateType = LarkMessageTemplateType.of(templateTypeKey); + if (LarkMessageTemplateType.PLAIN_TEXT == templateType) { + bodyBuilder.content(createTextContent(connectRecord)) + .msgType(MsgTypeEnum.MSG_TYPE_TEXT.getValue()); + } else if (LarkMessageTemplateType.MARKDOWN == templateType) { + String title = Optional.ofNullable(connectRecord.getExtension(ConnectRecordExtensionKeys.MARKDOWN_MESSAGE_TITLE_4_LARK)) + .orElse("EventMesh-Message"); + bodyBuilder.content(createInteractiveContent(connectRecord, title)) + .msgType(MsgTypeEnum.MSG_TYPE_INTERACTIVE.getValue()); + } + + return CreateMessageReq.newBuilder() + .receiveIdType(sinkConnectorConfig.getReceiveIdType()) + .createMessageReqBody(bodyBuilder.build()) + .build(); + } + + private String createTextContent(ConnectRecord connectRecord) { + MessageText.Builder msgBuilder = MessageText.newBuilder(); + + if (needAtAll(connectRecord)) { + msgBuilder.atAll(); + } + String atUsers = needAtUser(connectRecord); + if (!atUsers.isEmpty()) { + String[] users = atUsers.split(";"); + + for (String user : users) { + String[] kv = user.split(","); + msgBuilder.atUser(kv[0], kv[1]); + } + } + + String escapedString = StringEscapeUtils.escapeJava(new String((byte[]) connectRecord.getData())); + return msgBuilder.text(escapedString).build(); + } + + private String createInteractiveContent(ConnectRecord connectRecord, String title) { + StringBuilder sb = new StringBuilder(); + if (needAtAll(connectRecord)) { + atAll(sb); + } + String atUsers = needAtUser(connectRecord); + if (!atUsers.isEmpty()) { + String[] users = atUsers.split(";"); + + for (String user : users) { + String[] kv = user.split(","); + atUser(sb, kv[0]); + } + } + sb.append(new String((byte[]) connectRecord.getData())); + + MessageCardConfig config = MessageCardConfig.newBuilder() + .enableForward(true) + .wideScreenMode(true) + .updateMulti(true) + .build(); + + // header + MessageCardHeader header = MessageCardHeader.newBuilder() + .template(MessageCardHeaderTemplateEnum.BLUE) + .title(MessageCardPlainText.newBuilder() + .content(title) + .build()) + .build(); + + MessageCard content = MessageCard.newBuilder() + .config(config) + .header(header) + .elements(new MessageCardElement[]{ + MessageCardMarkdown.newBuilder().content(sb.toString()).build() + }) + .build(); + + return content.String(); + } + + private boolean needAtAll(ConnectRecord connectRecord) { + String atAll = connectRecord.getExtension(ConnectRecordExtensionKeys.AT_ALL_4_LARK); + return atAll != null && !"null".equals(atAll) && Boolean.parseBoolean(atAll); + } + + private String needAtUser(ConnectRecord connectRecord) { + String atUsers = connectRecord.getExtension(ConnectRecordExtensionKeys.AT_USERS_4_LARK); + return atUsers != null && !"null".equals(atUsers) ? atUsers : ""; + } + + /** + * For markdown template type. + * + * @param sb StringBuilder + */ + private void atAll(StringBuilder sb) { + sb.append("") + .append(""); + } + + /** + * For markdown template type + * + * @param sb StringBuilder + * @param userId open_id/union_id/user_id, recommend to use open_id. Custom robots can only be used open_id, + */ + private void atUser(StringBuilder sb, String userId) { + sb.append("") + .append(""); + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/sink/connector/LarkSinkConnector.java b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/sink/connector/LarkSinkConnector.java new file mode 100644 index 0000000000..9981322e8f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/java/org/apache/eventmesh/connector/lark/sink/connector/LarkSinkConnector.java @@ -0,0 +1,157 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.sink.connector; + +import static org.apache.eventmesh.connector.lark.sink.ImServiceHandler.create; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.lark.LarkSinkConfig; +import org.apache.eventmesh.common.config.connector.lark.SinkConnectorConfig; +import org.apache.eventmesh.connector.lark.ConfigUtils; +import org.apache.eventmesh.connector.lark.sink.ImServiceHandler; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.github.rholder.retry.RetryException; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.lark.oapi.Client; +import com.lark.oapi.core.enums.AppType; +import com.lark.oapi.core.request.SelfBuiltTenantAccessTokenReq; +import com.lark.oapi.core.response.TenantAccessTokenResp; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LarkSinkConnector implements Sink { + + public static final String TENANT_ACCESS_TOKEN = "tenant_access_token"; + + /** + * Global Access Credential Manager to replace lark build-in tokenCache. + *

+ * If you plan to extend the method of obtaining other credentials, + * you can refer to the implementation of {@link #getTenantAccessToken(String, String)} + *

+ * If the expiration mechanism provided by lark conflicts with the expiration time set in AUTH_CACHE, + * you can try to modify it. + */ + public static final Cache AUTH_CACHE = CacheBuilder.newBuilder() + .initialCapacity(12) + .maximumSize(10) + .concurrencyLevel(5) + .expireAfterWrite(30, TimeUnit.MINUTES) + .build(); + + private LarkSinkConfig sinkConfig; + + private ImServiceHandler imServiceHandler; + + private final AtomicBoolean started = new AtomicBoolean(false); + + @Override + public Class configClass() { + return LarkSinkConfig.class; + } + + @Override + public void init(Config config) { + } + + @Override + public void init(ConnectorContext connectorContext) { + // init config for lark sink connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (LarkSinkConfig) sinkConnectorContext.getSinkConfig(); + + SinkConnectorConfig sinkConnectorConfig = sinkConfig.getSinkConnectorConfig(); + ConfigUtils.validateSinkConfiguration(sinkConnectorConfig); + + imServiceHandler = create(sinkConnectorConfig); + } + + @Override + public void start() { + if (!started.compareAndSet(false, true)) { + log.info("LarkSinkConnector has been started."); + } + } + + @Override + public void commit(ConnectRecord record) { + // Sink does not need to implement + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + if (!started.compareAndSet(true, false)) { + log.info("LarkSinkConnector has not started yet."); + } + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + try { + if (Boolean.parseBoolean(sinkConfig.getSinkConnectorConfig().getSinkAsync())) { + imServiceHandler.sinkAsync(connectRecord); + } else { + imServiceHandler.sink(connectRecord); + } + } catch (ExecutionException | RetryException e) { + log.error("Failed to sink event to lark", e); + } + } + } + + @SneakyThrows + public static String getTenantAccessToken(String appId, String appSecret) { + return AUTH_CACHE.get(TENANT_ACCESS_TOKEN, () -> { + + Client client = Client.newBuilder(appId, appSecret) + .appType(AppType.SELF_BUILT) + .logReqAtDebug(true) + .build(); + + TenantAccessTokenResp resp = client.ext().getTenantAccessTokenBySelfBuiltApp( + SelfBuiltTenantAccessTokenReq.newBuilder() + .appSecret(appSecret) + .appId(appId) + .build()); + return resp.getTenantAccessToken(); + }); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-lark/src/main/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-lark/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..b5962fd99a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/main/resources/sink-config.yml @@ -0,0 +1,35 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-LARK + idc: FT + env: PRD + group: larkSink + appId: 5031 + userName: larkSinkUser + passWord: larkPassWord +sinkConnectorConfig: + connectorName: larkSink + appId: appId + appSecret: appSecret + receiveIdType: open_id + receiveId: receiveId + sinkAsync: true + maxRetryTimes: 3 + retryDelayInMills: 1000 diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/test/java/org/apache/eventmesh/connector/lark/sink/ImServiceHandlerTest.java b/eventmesh-connectors/eventmesh-connector-lark/src/test/java/org/apache/eventmesh/connector/lark/sink/ImServiceHandlerTest.java new file mode 100644 index 0000000000..9c54717fac --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/test/java/org/apache/eventmesh/connector/lark/sink/ImServiceHandlerTest.java @@ -0,0 +1,159 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.sink; + +import static org.apache.eventmesh.connector.lark.sink.ImServiceHandler.create; +import static org.apache.eventmesh.connector.lark.sink.connector.LarkSinkConnector.AUTH_CACHE; +import static org.apache.eventmesh.connector.lark.sink.connector.LarkSinkConnector.TENANT_ACCESS_TOKEN; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.common.config.connector.lark.LarkSinkConfig; +import org.apache.eventmesh.common.config.connector.lark.SinkConnectorConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; + +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 org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +import com.lark.oapi.service.im.v1.ImService; +import com.lark.oapi.service.im.v1.model.CreateMessageResp; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class ImServiceHandlerTest { + + private SinkConnectorConfig sinkConnectorConfig; + + private ImServiceHandler imServiceHandler; + + @Mock + private ImService imService; + + @Mock + private ImService.Message message; + + @BeforeEach + public void setup() throws Exception { + sinkConnectorConfig = ((LarkSinkConfig) ConfigUtil.parse(LarkSinkConfig.class)).getSinkConnectorConfig(); + } + + private void init() throws Exception { + // prevent rely on Lark's ExtService + AUTH_CACHE.put(TENANT_ACCESS_TOKEN, "test-TenantAccessToken"); + + imServiceHandler = create(sinkConnectorConfig); + + // prevent rely on Lark's ImService + when(message.create(any(), any())).thenReturn(new CreateMessageResp()); + when(imService.message()).thenReturn(message); + Field imServiceField = ReflectionSupport.findFields(imServiceHandler.getClass(), + (f) -> f.getName().equals("imService"), + HierarchyTraversalMode.BOTTOM_UP).get(0); + imServiceField.setAccessible(true); + imServiceField.set(imServiceHandler, imService); + } + + @Test + public void testRegularSink() throws Exception { + sinkConnectorConfig.setSinkAsync("false"); + init(); + regularSink(); + } + + @Test + public void testRegularSinkAsync() throws Exception { + sinkConnectorConfig.setSinkAsync("true"); + init(); + regularSink(); + } + + private void regularSink() throws Exception { + final int times = 3; + for (int i = 0; i < times; i++) { + + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "test-lark".getBytes(StandardCharsets.UTF_8)); + if (Boolean.parseBoolean(sinkConnectorConfig.getSinkAsync())) { + imServiceHandler.sinkAsync(connectRecord); + long retryDelayInMills = Long.parseLong(sinkConnectorConfig.getRetryDelayInMills()); + long duration = retryDelayInMills * times; + Thread.sleep(duration); + } else { + imServiceHandler.sink(connectRecord); + } + } + verify(message, times(times)).create(any(), any()); + } + + @Test + public void testRetrySink() throws Exception { + sinkConnectorConfig.setSinkAsync("false"); + init(); + retrySink(); + } + + @Test + public void testRetrySinkAsync() throws Exception { + sinkConnectorConfig.setSinkAsync("true"); + init(); + retrySink(); + } + + private void retrySink() throws Exception { + CreateMessageResp resp = new CreateMessageResp(); + resp.setCode(1); + doReturn(resp).when(message).create(any(), any()); + final int times = 3; + long retryDelayInMills = Long.parseLong(sinkConnectorConfig.getRetryDelayInMills()); + int maxRetryTimes = Integer.parseInt(sinkConnectorConfig.getMaxRetryTimes()); + // (maxRetryTimes + 1) event are actually sent + int sinkTimes = times * (maxRetryTimes + 1); + long duration = retryDelayInMills * sinkTimes; + + for (int i = 0; i < times; i++) { + + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "test-lark".getBytes(StandardCharsets.UTF_8)); + if (Boolean.parseBoolean(sinkConnectorConfig.getSinkAsync())) { + imServiceHandler.sinkAsync(connectRecord); + + Thread.sleep(duration); + } else { + Assertions.assertThrows(Exception.class, () -> imServiceHandler.sink(connectRecord)); + + } + } + verify(message, times(sinkTimes)).create(any(), any()); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/test/java/org/apache/eventmesh/connector/lark/sink/LarkSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-lark/src/test/java/org/apache/eventmesh/connector/lark/sink/LarkSinkConnectorTest.java new file mode 100644 index 0000000000..a02c845dc5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/test/java/org/apache/eventmesh/connector/lark/sink/LarkSinkConnectorTest.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.lark.sink; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.common.config.connector.lark.LarkSinkConfig; +import org.apache.eventmesh.connector.lark.sink.connector.LarkSinkConnector; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +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 org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class LarkSinkConnectorTest { + + private LarkSinkConnector larkSinkConnector; + + private LarkSinkConfig sinkConfig; + + /** + * more test see {@link ImServiceHandlerTest} + */ + @Mock + private ImServiceHandler imServiceHandler; + + private MockedStatic imServiceWrapperMockedStatic; + + @BeforeEach + public void setup() throws Exception { + imServiceWrapperMockedStatic = mockStatic(ImServiceHandler.class); + when(ImServiceHandler.create(any())).thenReturn(imServiceHandler); + doNothing().when(imServiceHandler).sink(any(ConnectRecord.class)); + doNothing().when(imServiceHandler).sinkAsync(any(ConnectRecord.class)); + + larkSinkConnector = new LarkSinkConnector(); + sinkConfig = (LarkSinkConfig) ConfigUtil.parse(larkSinkConnector.configClass()); + SinkConnectorContext sinkConnectorContext = new SinkConnectorContext(); + sinkConnectorContext.setSinkConfig(sinkConfig); + larkSinkConnector.init(sinkConnectorContext); + larkSinkConnector.start(); + } + + @Test + public void testPut() throws Exception { + final int times = 3; + List connectRecords = new ArrayList<>(); + for (int i = 0; i < times; i++) { + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "test-lark".getBytes(StandardCharsets.UTF_8)); + connectRecords.add(connectRecord); + } + larkSinkConnector.put(connectRecords); + if (Boolean.parseBoolean(sinkConfig.getSinkConnectorConfig().getSinkAsync())) { + verify(imServiceHandler, times(times)).sinkAsync(any(ConnectRecord.class)); + } else { + verify(imServiceHandler, times(times)).sink(any(ConnectRecord.class)); + } + } + + @AfterEach + public void tearDown() { + LarkSinkConnector.AUTH_CACHE.invalidate(LarkSinkConnector.TENANT_ACCESS_TOKEN); + larkSinkConnector.stop(); + imServiceWrapperMockedStatic.close(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-lark/src/test/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/test/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-lark/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-lark/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..b5962fd99a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-lark/src/test/resources/sink-config.yml @@ -0,0 +1,35 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-LARK + idc: FT + env: PRD + group: larkSink + appId: 5031 + userName: larkSinkUser + passWord: larkPassWord +sinkConnectorConfig: + connectorName: larkSink + appId: appId + appSecret: appSecret + receiveIdType: open_id + receiveId: receiveId + sinkAsync: true + maxRetryTimes: 3 + retryDelayInMills: 1000 diff --git a/eventmesh-connectors/eventmesh-connector-mcp/build.gradle b/eventmesh-connectors/eventmesh-connector-mcp/build.gradle new file mode 100644 index 0000000000..82072c2876 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/build.gradle @@ -0,0 +1,41 @@ +/* + * 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. + */ + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + implementation project(":eventmesh-connectors:eventmesh-connector-http") + implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-api") + implementation "io.cloudevents:cloudevents-core" + implementation "com.google.guava:guava" + implementation "io.cloudevents:cloudevents-json-jackson" + implementation ("io.grpc:grpc-protobuf:1.68.0") { + exclude group: "com.google.protobuf", module: "protobuf-java" + } + implementation 'io.cloudevents:cloudevents-http-vertx:3.0.0' + implementation 'io.vertx:vertx-web:4.5.8' + implementation 'io.vertx:vertx-web-client:4.5.9' + implementation 'dev.failsafe:failsafe:3.3.2' + + + testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.4' + testImplementation 'org.apache.httpcomponents.client5:httpclient5-fluent:5.4' + testImplementation 'org.mock-server:mockserver-netty:5.15.0' + implementation 'io.netty:netty-codec-http:4.1.114.Final' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/gradle.properties b/eventmesh-connectors/eventmesh-connector-mcp/gradle.properties new file mode 100644 index 0000000000..5e98eb968e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=mcp \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/config/McpServerConfig.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/config/McpServerConfig.java new file mode 100644 index 0000000000..33357b6a29 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/config/McpServerConfig.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + + +package org.apache.eventmesh.connector.mcp.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class McpServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/server/McpConnectServer.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/server/McpConnectServer.java new file mode 100644 index 0000000000..71ea9ae752 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/server/McpConnectServer.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.server; + +import org.apache.eventmesh.connector.mcp.config.McpServerConfig; +import org.apache.eventmesh.connector.mcp.sink.McpSinkConnector; +import org.apache.eventmesh.connector.mcp.source.McpSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class McpConnectServer { + public static void main(String[] args) throws Exception { + McpServerConfig serverConfig = ConfigUtil.parse(McpServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application mcpSourceApp = new Application(); + mcpSourceApp.run(McpSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application mcpSinkApp = new Application(); + mcpSinkApp.run(McpSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/McpSinkConnector.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/McpSinkConnector.java new file mode 100644 index 0000000000..3d65fb9b5d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/McpSinkConnector.java @@ -0,0 +1,189 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mcp.McpSinkConfig; +import org.apache.eventmesh.common.config.connector.mcp.SinkConnectorConfig; +import org.apache.eventmesh.connector.mcp.sink.handler.McpSinkHandler; +import org.apache.eventmesh.connector.mcp.sink.handler.impl.CommonMcpSinkHandler; +import org.apache.eventmesh.connector.mcp.sink.handler.impl.McpSinkHandlerRetryWrapper; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class McpSinkConnector implements Sink, ConnectorCreateService { + + private McpSinkConfig mcpSinkConfig; + + @Getter + private McpSinkHandler sinkHandler; + + private ThreadPoolExecutor executor; + + private final AtomicBoolean isStart = new AtomicBoolean(false); + + @Override + public Class configClass() { + return McpSinkConfig.class; + } + + @Override + public Sink create() { + return new McpSinkConnector(); + } + + @Override + public void init(Config config) throws Exception { + this.mcpSinkConfig = (McpSinkConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.mcpSinkConfig = (McpSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + @SneakyThrows + private void doInit() { + // Fill default values if absent + SinkConnectorConfig.populateFieldsWithDefaults(this.mcpSinkConfig.connectorConfig); + // Create different handlers for different configurations + McpSinkHandler nonRetryHandler; + + nonRetryHandler = new CommonMcpSinkHandler(this.mcpSinkConfig.connectorConfig); + + int maxRetries = this.mcpSinkConfig.connectorConfig.getRetryConfig().getMaxRetries(); + if (maxRetries == 0) { + // Use the original sink handler + this.sinkHandler = nonRetryHandler; + } else if (maxRetries > 0) { + // Wrap the sink handler with a retry handler + this.sinkHandler = new McpSinkHandlerRetryWrapper(this.mcpSinkConfig.connectorConfig, nonRetryHandler); + } else { + throw new IllegalArgumentException("Max retries must be greater than or equal to 0."); + } + + boolean isParallelized = this.mcpSinkConfig.connectorConfig.isParallelized(); + int parallelism = isParallelized ? this.mcpSinkConfig.connectorConfig.getParallelism() : 1; + + // Use the executor's built-in queue with a reasonable capacity + executor = new ThreadPoolExecutor( + parallelism, + parallelism, + 0L, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), // Built-in queue with capacity + new EventMeshThreadFactory("mcp-sink-handler") + ); + } + + @Override + public void start() throws Exception { + this.sinkHandler.start(); + isStart.set(true); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.mcpSinkConfig.connectorConfig.getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + isStart.set(false); + + log.info("Stopping mcp sink connector, shutting down executor..."); + executor.shutdown(); + + try { + // Wait for existing tasks to complete + if (!executor.awaitTermination(30, TimeUnit.SECONDS)) { + log.warn("Executor did not terminate gracefully, forcing shutdown"); + executor.shutdownNow(); + // Wait a bit more for tasks to respond to being cancelled + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + log.error("Executor did not terminate after forced shutdown"); + } + } + } catch (InterruptedException e) { + log.warn("Interrupted while waiting for executor termination"); + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + + this.sinkHandler.stop(); + } + + @Override + public void put(List sinkRecords) { + if (!isStart.get()) { + log.warn("Connector is not started, ignoring sink records"); + return; + } + + for (ConnectRecord sinkRecord : sinkRecords) { + if (Objects.isNull(sinkRecord)) { + log.warn("ConnectRecord data is null, ignore."); + continue; + } + log.info("McpSinkConnector put record: {}", sinkRecord); + + try { + // Use executor.submit() instead of custom queue + executor.submit(() -> { + try { + sinkHandler.handle(sinkRecord); + } catch (Exception e) { + log.error("Failed to handle sink record via mcp", e); + } + }); + } catch (Exception e) { + log.error("Failed to submit sink record to executor", e); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpAttemptEvent.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpAttemptEvent.java new file mode 100644 index 0000000000..451fc3523d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpAttemptEvent.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.data; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Single MCP attempt event + */ +public class McpAttemptEvent { + + public static final String PREFIX = "mcp-attempt-event-"; + + private final int maxAttempts; + + private final AtomicInteger attempts; + + private Throwable lastException; + + + public McpAttemptEvent(int maxAttempts) { + this.maxAttempts = maxAttempts; + this.attempts = new AtomicInteger(0); + } + + /** + * Increment the attempts + */ + public void incrementAttempts() { + attempts.incrementAndGet(); + } + + /** + * Update the event, incrementing the attempts and setting the last exception + * + * @param exception the exception to update, can be null + */ + public void updateEvent(Throwable exception) { + // increment the attempts + incrementAttempts(); + + // update the last exception + lastException = exception; + } + + /** + * Check if the attempts are less than the maximum attempts + * + * @return true if the attempts are less than the maximum attempts, false otherwise + */ + public boolean canAttempt() { + return attempts.get() < maxAttempts; + } + + public boolean isComplete() { + if (attempts.get() == 0) { + // No start yet + return false; + } + + // If no attempt can be made or the last exception is null, the event completed + return !canAttempt() || lastException == null; + } + + + public int getMaxAttempts() { + return maxAttempts; + } + + public int getAttempts() { + return attempts.get(); + } + + public Throwable getLastException() { + return lastException; + } + + /** + * Get the limited exception message with the default limit of 256 + * + * @return the limited exception message + */ + public String getLimitedExceptionMessage() { + return getLimitedExceptionMessage(256); + } + + /** + * Get the limited exception message with the specified limit + * + * @param maxLimit the maximum limit of the exception message + * @return the limited exception message + */ + public String getLimitedExceptionMessage(int maxLimit) { + if (lastException == null) { + return ""; + } + String message = lastException.getMessage(); + if (message == null) { + return ""; + } + if (message.length() > maxLimit) { + return message.substring(0, maxLimit); + } + return message; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpConnectRecord.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpConnectRecord.java new file mode 100644 index 0000000000..26f9c1e6fb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpConnectRecord.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.data; + +import org.apache.eventmesh.common.remote.offset.http.HttpRecordOffset; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.KeyValue; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import lombok.Builder; +import lombok.Getter; + +/** + * a special ConnectRecord for McpSinkConnector + */ +@Getter +@Builder +public class McpConnectRecord implements Serializable { + + private static final long serialVersionUID = 5271462532332251473L; + + /** + * The unique identifier for the McpConnectRecord + */ + private final String mcpRecordId = UUID.randomUUID().toString(); + + /** + * The time when the McpConnectRecord was created + */ + private LocalDateTime createTime; + + /** + * The type of the McpConnectRecord + */ + private String type; + + /** + * The event id of the McpConnectRecord + */ + private String eventId; + + private Object data; + + private KeyValue extensions; + + @Override + public String toString() { + return "McpConnectRecord{" + + "createTime=" + createTime + + ", mcpRecordId='" + mcpRecordId + + ", type='" + type + + ", eventId='" + eventId + + ", data=" + data + + ", extensions=" + extensions + + '}'; + } + + /** + * Convert ConnectRecord to McpConnectRecord + * + * @param record the ConnectRecord to convert + * @return the converted McpConnectRecord + */ + public static McpConnectRecord convertConnectRecord(ConnectRecord record, String type) { + Map offsetMap = new HashMap<>(); + if (record != null && record.getPosition() != null && record.getPosition().getRecordOffset() != null) { + if (HttpRecordOffset.class.equals(record.getPosition().getRecordOffsetClazz())) { + offsetMap = ((HttpRecordOffset) record.getPosition().getRecordOffset()).getOffsetMap(); + } + } + String offset = "0"; + if (!offsetMap.isEmpty()) { + offset = offsetMap.values().iterator().next().toString(); + } + if (record.getData() instanceof byte[]) { + String data = Base64.getEncoder().encodeToString((byte[]) record.getData()); + record.addExtension("isBase64", true); + return McpConnectRecord.builder() + .type(type) + .createTime(LocalDateTime.now()) + .eventId(type + "-" + offset) + .data(data) + .extensions(record.getExtensions()) + .build(); + } else { + record.addExtension("isBase64", false); + return McpConnectRecord.builder() + .type(type) + .createTime(LocalDateTime.now()) + .eventId(type + "-" + offset) + .data(record.getData()) + .extensions(record.getExtensions()) + .build(); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportMetadata.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportMetadata.java new file mode 100644 index 0000000000..72595b2637 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportMetadata.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +import lombok.Builder; +import lombok.Data; + +/** + * Metadata for an MCP export operation. + */ +@Data +@Builder +public class McpExportMetadata implements Serializable { + + private static final long serialVersionUID = 1121010466793041920L; + + private String url; + + private int code; + + private String message; + + private LocalDateTime receivedTime; + + private String recordId; + + private String retriedBy; + + private int retryNum; +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportRecord.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportRecord.java new file mode 100644 index 0000000000..c9a35c193b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportRecord.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.data; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Represents an MCP export record containing metadata and data to be exported. + */ +@Data +@AllArgsConstructor +public class McpExportRecord implements Serializable { + + private static final long serialVersionUID = 6010283911452947157L; + + private McpExportMetadata metadata; + + private Object data; +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportRecordPage.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportRecordPage.java new file mode 100644 index 0000000000..3e0e615523 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/McpExportRecordPage.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.data; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Represents a page of MCP export records. + */ +@Data +@AllArgsConstructor +public class McpExportRecordPage implements Serializable { + + private static final long serialVersionUID = 1143791658357035990L; + + private int pageNum; + + private int pageSize; + + private List pageItems; + +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/MultiMcpRequestContext.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/MultiMcpRequestContext.java new file mode 100644 index 0000000000..f24d0e3fd1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/data/MultiMcpRequestContext.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.data; + +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * Multi Mcp request context + */ +public class MultiMcpRequestContext { + + public static final String NAME = "multi-http-request-context"; + + /** + * The remaining requests to be processed. + */ + private final AtomicInteger remainingRequests; + + /** + * The last failed event. + * If retries occur but still fail, it will be logged, and only the last one will be retained. + */ + private McpAttemptEvent lastFailedEvent; + + public MultiMcpRequestContext(int remainingEvents) { + this.remainingRequests = new AtomicInteger(remainingEvents); + } + + /** + * Decrement the remaining requests by 1. + */ + public void decrementRemainingRequests() { + remainingRequests.decrementAndGet(); + } + + /** + * Check if all requests have been processed. + * + * @return true if all requests have been processed, false otherwise. + */ + public boolean isAllRequestsProcessed() { + return remainingRequests.get() == 0; + } + + public int getRemainingRequests() { + return remainingRequests.get(); + } + + public McpAttemptEvent getLastFailedEvent() { + return lastFailedEvent; + } + + public void setLastFailedEvent(McpAttemptEvent lastFailedEvent) { + this.lastFailedEvent = lastFailedEvent; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/AbstractMcpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/AbstractMcpSinkHandler.java new file mode 100644 index 0000000000..5c7435d037 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/AbstractMcpSinkHandler.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.handler; + +import org.apache.eventmesh.common.config.connector.mcp.SinkConnectorConfig; +import org.apache.eventmesh.connector.mcp.sink.data.McpAttemptEvent; +import org.apache.eventmesh.connector.mcp.sink.data.McpConnectRecord; +import org.apache.eventmesh.connector.mcp.sink.data.MultiMcpRequestContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import lombok.Getter; + +public abstract class AbstractMcpSinkHandler implements McpSinkHandler { + @Getter + private final SinkConnectorConfig sinkConnectorConfig; + + @Getter + private final List urls; + + private final McpDeliveryStrategy deliveryStrategy; + + private int roundRobinIndex = 0; + + protected AbstractMcpSinkHandler(SinkConnectorConfig sinkConnectorConfig) { + this.sinkConnectorConfig = sinkConnectorConfig; + this.deliveryStrategy = McpDeliveryStrategy.valueOf(sinkConnectorConfig.getDeliveryStrategy()); + // Initialize URLs + String[] urlStrings = sinkConnectorConfig.getUrls(); + this.urls = Arrays.stream(urlStrings) + .map(URI::create) + .collect(Collectors.toList()); + } + + /** + * Processes a ConnectRecord by sending it over HTTP or HTTPS. This method should be called for each ConnectRecord that needs to be processed. + * + * @param record the ConnectRecord to process + */ + @Override + public void handle(ConnectRecord record) { + // build attributes + Map attributes = new ConcurrentHashMap<>(); + + switch (deliveryStrategy) { + case ROUND_ROBIN: + attributes.put(MultiMcpRequestContext.NAME, new MultiMcpRequestContext(1)); + URI url = urls.get(roundRobinIndex); + roundRobinIndex = (roundRobinIndex + 1) % urls.size(); + sendRecordToUrl(record, attributes, url); + break; + case BROADCAST: + attributes.put(MultiMcpRequestContext.NAME, new MultiMcpRequestContext(urls.size())); + // send the record to all URLs + urls.forEach(url0 -> sendRecordToUrl(record, attributes, url0)); + break; + default: + throw new IllegalArgumentException("Unknown delivery strategy: " + deliveryStrategy); + } + } + + private void sendRecordToUrl(ConnectRecord record, Map attributes, URI url) { + // convert ConnectRecord to HttpConnectRecord + String type = String.format("%s.%s.%s", + this.sinkConnectorConfig.getConnectorName(), url.getScheme(), + "common"); + McpConnectRecord mcpConnectRecord = McpConnectRecord.convertConnectRecord(record, type); + + // add AttemptEvent to the attributes + McpAttemptEvent attemptEvent = new McpAttemptEvent(this.sinkConnectorConfig.getRetryConfig().getMaxRetries() + 1); + attributes.put(McpAttemptEvent.PREFIX + mcpConnectRecord.getMcpRecordId(), attemptEvent); + + // deliver the record + deliver(url, mcpConnectRecord, attributes, record); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/McpDeliveryStrategy.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/McpDeliveryStrategy.java new file mode 100644 index 0000000000..07cbbe3d46 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/McpDeliveryStrategy.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.handler; + +public enum McpDeliveryStrategy { + ROUND_ROBIN, + BROADCAST +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/McpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/McpSinkHandler.java new file mode 100644 index 0000000000..c10d96337b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/McpSinkHandler.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.handler; + +import org.apache.eventmesh.connector.mcp.sink.data.McpConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.util.Map; + +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.client.HttpResponse; + +/** + * Interface for handling ConnectRecords via HTTP or HTTPS. Classes implementing this interface are responsible for processing ConnectRecords by + * sending them over HTTP or HTTPS, with additional support for handling multiple requests and asynchronous processing. + * + *

Any class that needs to process ConnectRecords via HTTP or HTTPS should implement this interface. + * Implementing classes must provide implementations for the {@link #start()}, {@link #handle(ConnectRecord)}, + * {@link #deliver(URI, McpConnectRecord, Map, ConnectRecord)}, and {@link #stop()} methods.

+ * + *

Implementing classes should ensure thread safety and handle MCP communication efficiently. + * The {@link #start()} method initializes any necessary resources for MCP communication. The {@link #handle(ConnectRecord)} method processes a + * ConnectRecord by sending it over HTTP or HTTPS. The {@link #deliver(URI, McpConnectRecord, Map, ConnectRecord)} method processes HttpConnectRecord + * on specified URL while returning its own processing logic {@link #stop()} method releases any resources used for MCP communication.

+ * + *

It's recommended to handle exceptions gracefully within the {@link #deliver(URI, McpConnectRecord, Map, ConnectRecord)} method + * to prevent message loss or processing interruptions.

+ */ +public interface McpSinkHandler { + + /** + * Initializes the MCP handler. This method should be called before using the handler. + */ + void start(); + + /** + * Processes a ConnectRecord by sending it over HTTP or HTTPS. This method should be called for each ConnectRecord that needs to be processed. + * + * @param record the ConnectRecord to process + */ + void handle(ConnectRecord record); + + + /** + * Processes HttpConnectRecord on specified URL while returning its own processing logic + * + * @param url URI to which the HttpConnectRecord should be sent + * @param mcpConnectRecord HttpConnectRecord to process + * @param attributes additional attributes to be used in processing + * @return processing chain + */ + Future> deliver(URI url, McpConnectRecord mcpConnectRecord, Map attributes, ConnectRecord connectRecord); + + /** + * Cleans up and releases resources used by the MCP handler. This method should be called when the handler is no longer needed. + */ + void stop(); +} + diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/impl/CommonMcpSinkHandler.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/impl/CommonMcpSinkHandler.java new file mode 100644 index 0000000000..1d884f4a19 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/impl/CommonMcpSinkHandler.java @@ -0,0 +1,271 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.handler.impl; + +import org.apache.eventmesh.common.config.connector.mcp.SinkConnectorConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.http.util.HttpUtils; +import org.apache.eventmesh.connector.mcp.sink.data.McpAttemptEvent; +import org.apache.eventmesh.connector.mcp.sink.data.McpConnectRecord; +import org.apache.eventmesh.connector.mcp.sink.data.MultiMcpRequestContext; +import org.apache.eventmesh.connector.mcp.sink.handler.AbstractMcpSinkHandler; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.time.ZoneId; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import io.netty.handler.codec.http.HttpHeaderNames; +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + + +/** + * Common MCP Sink Handler implementation to handle ConnectRecords by sending them over MCP to configured URLs. + * + *

This handler initializes a WebClient for making HTTP requests based on the provided SinkConnectorConfig. + * It handles processing ConnectRecords by converting them to HttpConnectRecord and sending them asynchronously to each configured URL using the + * WebClient.

+ * + *

The handler uses Vert.x's WebClient to perform HTTP/HTTPS requests. It initializes the WebClient in the {@link #start()} + * method and closes it in the {@link #stop()} method to manage resources efficiently.

+ * + *

Each ConnectRecord is processed and sent to all configured URLs concurrently using asynchronous HTTP requests.

+ */ +@Slf4j +@Getter +public class CommonMcpSinkHandler extends AbstractMcpSinkHandler { + + private WebClient webClient; + + + public CommonMcpSinkHandler(SinkConnectorConfig sinkConnectorConfig) { + super(sinkConnectorConfig); + } + + /** + * Initializes the WebClient for making HTTP requests based on the provided SinkConnectorConfig. + */ + @Override + public void start() { + // Create WebClient + doInitWebClient(); + } + + /** + * Initializes the WebClient with the provided configuration options. + */ + private void doInitWebClient() { + SinkConnectorConfig sinkConnectorConfig = getSinkConnectorConfig(); + final Vertx vertx = Vertx.vertx(); + WebClientOptions options = new WebClientOptions() + .setKeepAlive(sinkConnectorConfig.isKeepAlive()) + .setKeepAliveTimeout(sinkConnectorConfig.getKeepAliveTimeout() / 1000) + .setIdleTimeout(sinkConnectorConfig.getIdleTimeout()) + .setIdleTimeoutUnit(TimeUnit.MILLISECONDS) + .setConnectTimeout(sinkConnectorConfig.getConnectionTimeout()) + .setMaxPoolSize(sinkConnectorConfig.getMaxConnectionPoolSize()) + .setPipelining(sinkConnectorConfig.isParallelized()); + this.webClient = WebClient.create(vertx, options); + } + + /** + * Processes HttpConnectRecord on specified URL while returning its own processing logic. This method sends the HttpConnectRecord to the specified + * URL using the WebClient. + * + * @param url URI to which the HttpConnectRecord should be sent + * @param mcpConnectRecord HttpConnectRecord to process + * @param attributes additional attributes to be used in processing + * @return processing chain + */ + @Override + public Future> deliver(URI url, McpConnectRecord mcpConnectRecord, Map attributes, + ConnectRecord connectRecord) { + // create headers + Map extensionMap = new HashMap<>(); + Set extensionKeySet = mcpConnectRecord.getExtensions().keySet(); + for (String extensionKey : extensionKeySet) { + Object v = mcpConnectRecord.getExtensions().getObject(extensionKey); + extensionMap.put(extensionKey, v); + } + + MultiMap headers = HttpHeaders.headers() + .set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8") + .set(HttpHeaderNames.ACCEPT, "application/json; charset=utf-8") + .set("extension", JsonUtils.toJSONString(extensionMap)); + // get timestamp and offset + Long timestamp = mcpConnectRecord.getCreateTime() + .atZone(ZoneId.systemDefault()) + .toInstant() + .toEpochMilli(); + + // send the request + return this.webClient.post(url.getPath()) + .host(url.getHost()) + .port(url.getPort() == -1 ? (Objects.equals(url.getScheme(), "https") ? 443 : 80) : url.getPort()) + .putHeaders(headers) + .ssl(Objects.equals(url.getScheme(), "https")) + .sendJson(mcpConnectRecord.getData()) + .onSuccess(res -> { + log.info("Request sent successfully. Record: timestamp={}", timestamp); + + Exception e = null; + + // log the response + if (HttpUtils.is2xxSuccessful(res.statusCode())) { + if (log.isDebugEnabled()) { + log.debug("Received successful response: statusCode={}. Record: timestamp={}, responseBody={}", + res.statusCode(), timestamp, res.bodyAsString()); + } else { + log.info("Received successful response: statusCode={}. Record: timestamp={}", res.statusCode(), timestamp); + } + } else { + if (log.isDebugEnabled()) { + log.warn("Received non-2xx response: statusCode={}. Record: timestamp={}, responseBody={}", + res.statusCode(), timestamp, res.bodyAsString()); + } else { + log.warn("Received non-2xx response: statusCode={}. Record: timestamp={}", res.statusCode(), timestamp); + } + + e = new RuntimeException("Unexpected HTTP response code: " + res.statusCode()); + } + + // try callback + tryCallback(mcpConnectRecord, e, attributes, connectRecord); + }).onFailure(err -> { + log.error("Request failed to send. Record: timestamp={}", timestamp, err); + + // try callback + tryCallback(mcpConnectRecord, err, attributes, connectRecord); + }); + } + + /** + * Tries to call the callback based on the result of the request. + * + * @param mcpConnectRecord the McpConnectRecord to use + * @param e the exception thrown during the request, may be null + * @param attributes additional attributes to be used in processing + */ + private void tryCallback(McpConnectRecord mcpConnectRecord, Throwable e, Map attributes, ConnectRecord record) { + // get and update the attempt event + McpAttemptEvent attemptEvent = (McpAttemptEvent) attributes.get(McpAttemptEvent.PREFIX + mcpConnectRecord.getMcpRecordId()); + attemptEvent.updateEvent(e); + + // get and update the multiHttpRequestContext + MultiMcpRequestContext multiMcpRequestContext = getAndUpdateMultiMcpRequestContext(attributes, attemptEvent); + + if (multiMcpRequestContext.isAllRequestsProcessed()) { + // do callback + if (record.getCallback() == null) { + if (log.isDebugEnabled()) { + log.warn("ConnectRecord callback is null. Ignoring callback. {}", record); + } else { + log.warn("ConnectRecord callback is null. Ignoring callback."); + } + return; + } + + // get the last failed event + McpAttemptEvent lastFailedEvent = multiMcpRequestContext.getLastFailedEvent(); + if (lastFailedEvent == null) { + // success + record.getCallback().onSuccess(convertToSendResult(record)); + } else { + // failure + record.getCallback().onException(buildSendExceptionContext(record, lastFailedEvent.getLastException())); + } + } else { + log.warn("still have requests to process, size {}|attempt num {}", + multiMcpRequestContext.getRemainingRequests(), attemptEvent.getAttempts()); + } + } + + + /** + * Gets and updates the multi mcp request context based on the provided attributes and HttpConnectRecord. + * + * @param attributes the attributes to use + * @param attemptEvent the McpAttemptEvent to use + * @return the updated multi mcp request context + */ + private MultiMcpRequestContext getAndUpdateMultiMcpRequestContext(Map attributes, McpAttemptEvent attemptEvent) { + // get the multi http request context + MultiMcpRequestContext multiMcpRequestContext = (MultiMcpRequestContext) attributes.get(MultiMcpRequestContext.NAME); + + // Check if the current attempted event has completed + if (attemptEvent.isComplete()) { + // decrement the counter + multiMcpRequestContext.decrementRemainingRequests(); + + if (attemptEvent.getLastException() != null) { + // if all attempts are exhausted, set the last failed event + multiMcpRequestContext.setLastFailedEvent(attemptEvent); + } + } + + return multiMcpRequestContext; + } + + private SendResult convertToSendResult(ConnectRecord record) { + SendResult result = new SendResult(); + result.setMessageId(record.getRecordId()); + if (org.apache.commons.lang3.StringUtils.isNotEmpty(record.getExtension("topic"))) { + result.setTopic(record.getExtension("topic")); + } + return result; + } + + private SendExceptionContext buildSendExceptionContext(ConnectRecord record, Throwable e) { + SendExceptionContext sendExceptionContext = new SendExceptionContext(); + sendExceptionContext.setMessageId(record.getRecordId()); + sendExceptionContext.setCause(e); + if (org.apache.commons.lang3.StringUtils.isNotEmpty(record.getExtension("topic"))) { + sendExceptionContext.setTopic(record.getExtension("topic")); + } + return sendExceptionContext; + } + + + /** + * Cleans up and releases resources used by the MCP handler. + */ + @Override + public void stop() { + if (this.webClient != null) { + this.webClient.close(); + } else { + log.warn("WebClient is null, ignore."); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/impl/McpSinkHandlerRetryWrapper.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/impl/McpSinkHandlerRetryWrapper.java new file mode 100644 index 0000000000..c2e990857e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/sink/handler/impl/McpSinkHandlerRetryWrapper.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.sink.handler.impl; + +import org.apache.eventmesh.common.config.connector.mcp.McpRetryConfig; +import org.apache.eventmesh.common.config.connector.mcp.SinkConnectorConfig; +import org.apache.eventmesh.connector.http.util.HttpUtils; +import org.apache.eventmesh.connector.mcp.sink.data.McpConnectRecord; +import org.apache.eventmesh.connector.mcp.sink.handler.AbstractMcpSinkHandler; +import org.apache.eventmesh.connector.mcp.sink.handler.McpSinkHandler; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.ConnectException; +import java.net.URI; +import java.time.Duration; +import java.util.Map; + +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.client.HttpResponse; + +import lombok.extern.slf4j.Slf4j; + +import dev.failsafe.Failsafe; +import dev.failsafe.RetryPolicy; + +/** + * McpSinkHandlerRetryWrapper is a wrapper class for the McpSinkHandler that provides retry functionality for failed Mcp requests. + */ +@Slf4j +public class McpSinkHandlerRetryWrapper extends AbstractMcpSinkHandler { + + private final McpRetryConfig mcpRetryConfig; + + private final McpSinkHandler sinkHandler; + + private final RetryPolicy> retryPolicy; + + public McpSinkHandlerRetryWrapper(SinkConnectorConfig sinkConnectorConfig, McpSinkHandler sinkHandler) { + super(sinkConnectorConfig); + this.sinkHandler = sinkHandler; + this.mcpRetryConfig = getSinkConnectorConfig().getRetryConfig(); + this.retryPolicy = buildRetryPolicy(); + } + + private RetryPolicy> buildRetryPolicy() { + return RetryPolicy.>builder() + .handleIf(e -> e instanceof ConnectException) + .handleResultIf(response -> mcpRetryConfig.isRetryOnNonSuccess() && !HttpUtils.is2xxSuccessful(response.statusCode())) + .withMaxRetries(mcpRetryConfig.getMaxRetries()) + .withDelay(Duration.ofMillis(mcpRetryConfig.getInterval())) + .onRetry(event -> { + if (log.isDebugEnabled()) { + log.warn("Failed to deliver message after {} attempts. Retrying in {} ms. Error: {}", + event.getAttemptCount(), mcpRetryConfig.getInterval(), event.getLastException()); + } else { + log.warn("Failed to deliver message after {} attempts. Retrying in {} ms.", + event.getAttemptCount(), mcpRetryConfig.getInterval()); + } + }).onFailure(event -> { + if (log.isDebugEnabled()) { + log.error("Failed to deliver message after {} attempts. Error: {}", + event.getAttemptCount(), event.getException()); + } else { + log.error("Failed to deliver message after {} attempts.", + event.getAttemptCount()); + } + }).build(); + } + + /** + * Initializes the WebClient for making Mcp requests based on the provided SinkConnectorConfig. + */ + @Override + public void start() { + sinkHandler.start(); + } + + + /** + * Processes McpConnectRecord on specified URL while returning its own processing logic This method provides the retry power to process the + * McpConnectRecord + * + * @param url URI to which the McpConnectRecord should be sent + * @param mcpConnectRecord McpConnectRecord to process + * @param attributes additional attributes to pass to the processing chain + * @return processing chain + */ + @Override + public Future> deliver(URI url, McpConnectRecord mcpConnectRecord, Map attributes, + ConnectRecord connectRecord) { + Failsafe.with(retryPolicy) + .getStageAsync(() -> sinkHandler.deliver(url, mcpConnectRecord, attributes, connectRecord).toCompletionStage()); + return null; + } + + + /** + * Cleans up and releases resources used by the Mcp handler. + */ + @Override + public void stop() { + sinkHandler.stop(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpSourceConnector.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpSourceConnector.java new file mode 100644 index 0000000000..e5fe258124 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpSourceConnector.java @@ -0,0 +1,659 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source; + +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CACHE_CONTROL_NO_CACHE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CONNECTION_KEEP_ALIVE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CONTENT_TYPE_JSON; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CONTENT_TYPE_JSON_PLAIN; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CONTENT_TYPE_SSE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CORS_ALLOWED_HEADERS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CORS_ALLOWED_METHODS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CORS_ALLOW_ALL; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.CORS_EXPOSED_HEADERS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_CONNECTOR_NAME; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_HEARTBEAT_INTERVAL_MS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_IDLE_TIMEOUT_MS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_NO_MESSAGE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_PROTOCOL_VERSION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_SERVER_NAME; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.DEFAULT_SERVER_VERSION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.ENDPOINT_HEALTH; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.ERROR_INTERNAL; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.ERROR_INVALID_PARAMS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.ERROR_METHOD_NOT_FOUND; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_ACCEPT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CACHE_CONTROL; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CONNECTION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CONTENT_TYPE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CORS_ALLOW_HEADERS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CORS_ALLOW_METHODS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CORS_ALLOW_ORIGIN; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_CORS_EXPOSE_HEADERS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HEADER_X_ACCEL_BUFFERING; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HTTP_METHOD_OPTIONS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HTTP_STATUS_INTERNAL_ERROR; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.HTTP_STATUS_NO_CONTENT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_CAPABILITIES; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_CONNECTOR; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_CONTENT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_DESCRIPTION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_ERROR; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_ERROR_CODE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_ERROR_MESSAGE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_ID; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_JSONRPC; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_METHOD; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_NAME; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_PARAMS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_PROPERTIES; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_PROTOCOL_VERSION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_REQUIRED; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_RESULT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_SERVER_INFO; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_STATUS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_TEXT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_TOOLS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_TYPE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.KEY_VERSION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.MAX_POLL_WAIT_TIME_MS; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.METHOD_INITIALIZE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.METHOD_NOTIFICATIONS_INITIALIZED; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.METHOD_PING; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.METHOD_TOOLS_CALL; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.METHOD_TOOLS_LIST; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.PARAM_DESC_MESSAGE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.PARAM_DESC_MESSAGE_CONTENT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.PARAM_DESC_TOPIC; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.PARAM_MESSAGE; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.PARAM_TOPIC; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.SSE_DATA_OPEN; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.SSE_EVENT_OPEN; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.SSE_HEARTBEAT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.VALUE_JSONRPC_VERSION; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.VALUE_STATUS_UP; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.VALUE_TYPE_OBJECT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.VALUE_TYPE_STRING; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.VALUE_TYPE_TEXT; +import static org.apache.eventmesh.connector.mcp.source.McpSourceConstants.X_ACCEL_BUFFERING_NO; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mcp.McpSourceConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.connector.mcp.source.protocol.Protocol; +import org.apache.eventmesh.connector.mcp.source.protocol.ProtocolFactory; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.handler.BodyHandler; +import io.vertx.ext.web.handler.LoggerHandler; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * MCP Source Connector for EventMesh Implements MCP protocol server allowing AI clients to interact with EventMesh via MCP protocol + */ +@Slf4j +public class McpSourceConnector implements Source, ConnectorCreateService { + + private McpSourceConfig sourceConfig; + + private BlockingQueue queue; + + private int batchSize; + + private String forwardPath; + + private Route route; + + private Protocol protocol; + + private HttpServer server; + + private Vertx vertx; + + private WebClient webClient; + + private McpToolRegistry toolRegistry; + + @Getter + private volatile boolean started = false; + + @Getter + private volatile boolean destroyed = false; + + @Override + public Class configClass() { + return McpSourceConfig.class; + } + + @Override + public Source create() { + return new McpSourceConnector(); + } + + @Override + public void init(Config config) { + this.sourceConfig = (McpSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (McpSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + /** + * Initialize the connector + */ + private void doInit() { + log.info("Initializing MCP Source Connector..."); + + // Initialize queue + int maxQueueSize = this.sourceConfig.getConnectorConfig().getMaxStorageSize(); + this.queue = new LinkedBlockingQueue<>(maxQueueSize); + + // Initialize batch size + this.batchSize = this.sourceConfig.getConnectorConfig().getBatchSize(); + + String protocolName = this.sourceConfig.getConnectorConfig().getProtocol(); + this.protocol = ProtocolFactory.getInstance(this.sourceConfig.connectorConfig, protocolName); + + // Initialize tool registry + this.toolRegistry = new McpToolRegistry(); + registerDefaultTools(); + + // Initialize Vertx and router + this.vertx = Vertx.vertx(); + final Router router = Router.router(vertx); + this.webClient = WebClient.create(vertx); + + final String basePath = this.sourceConfig.connectorConfig.getPath(); + this.forwardPath = this.sourceConfig.connectorConfig.getForwardPath(); + + // Configure CORS (must be before all routes) + router.route().handler(ctx -> { + ctx.response() + .putHeader(HEADER_CORS_ALLOW_ORIGIN, CORS_ALLOW_ALL) + .putHeader(HEADER_CORS_ALLOW_METHODS, CORS_ALLOWED_METHODS) + .putHeader(HEADER_CORS_ALLOW_HEADERS, CORS_ALLOWED_HEADERS) + .putHeader(HEADER_CORS_EXPOSE_HEADERS, CORS_EXPOSED_HEADERS); + + if (HTTP_METHOD_OPTIONS.equals(ctx.request().method().name())) { + ctx.response().setStatusCode(HTTP_STATUS_NO_CONTENT).end(); + } else { + ctx.next(); + } + }); + + // Body handler + router.route().handler(BodyHandler.create()); + + // Main endpoint - handles both JSON-RPC and SSE requests + router.post(basePath) + .handler(LoggerHandler.create()) + .handler(ctx -> { + String contentType = ctx.request().getHeader(HEADER_CONTENT_TYPE); + String accept = ctx.request().getHeader(HEADER_ACCEPT); + + // Determine if it's an SSE request or JSON-RPC request + if (CONTENT_TYPE_SSE.startsWith(accept != null ? accept : "")) { + handleSseRequest(ctx); + } else { + handleJsonRpcRequest(ctx); + } + }); + + // GET request for SSE support + router.get(basePath) + .handler(this::handleSseRequest); + + // Health check endpoint + router.get(basePath + ENDPOINT_HEALTH).handler(ctx -> { + JsonObject health = new JsonObject() + .put(KEY_STATUS, VALUE_STATUS_UP) + .put(KEY_CONNECTOR, DEFAULT_CONNECTOR_NAME) + .put(KEY_TOOLS, toolRegistry.getToolCount()); + ctx.response() + .putHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON) + .end(health.encode()); + }); + + Route forwardRoute = router.route().path(forwardPath).handler(LoggerHandler.create()); + + this.route = router.route() + .path(this.sourceConfig.connectorConfig.getPath()) + .handler(LoggerHandler.create()); + + // set protocol handler + this.protocol.setHandler(route, queue); + this.protocol.setHandler(forwardRoute, queue); + + // Create server + this.server = vertx.createHttpServer(new HttpServerOptions() + .setPort(this.sourceConfig.connectorConfig.getPort()) + .setHandle100ContinueAutomatically(true) + .setIdleTimeout(DEFAULT_IDLE_TIMEOUT_MS) + .setIdleTimeoutUnit(TimeUnit.MILLISECONDS)) + .requestHandler(router); + + log.info("MCP Source Connector initialized on http://127.0.0.1:{}{}", + this.sourceConfig.connectorConfig.getPort(), basePath); + } + + /** + * Register default MCP tools + */ + private void registerDefaultTools() { + // Echo tool + toolRegistry.registerTool( + "echo", + "Echo back the input message", + createEchoSchema(), + args -> { + String message = args.getString(PARAM_MESSAGE, DEFAULT_NO_MESSAGE); + return createTextContent("Echo: " + message); + } + ); + + // EventMesh message sending tool + toolRegistry.registerTool( + "sendEventMeshMessage", + "Send a message to EventMesh", + createSendMessageSchema(), + args -> { + String topic = args.getString(PARAM_TOPIC); + Object message = args.getString(PARAM_MESSAGE); + + webClient.post(this.sourceConfig.connectorConfig.getPort(), "127.0.0.1", this.forwardPath) + .putHeader(CORS_EXPOSED_HEADERS, CONTENT_TYPE_JSON_PLAIN) + .sendBuffer(Buffer.buffer( + new JsonObject() + .put("type", "mcp.tools.call") + .put("tool", "sendEventMeshMessage") + .put("arguments", new JsonObject().put("message", message).put("topic", topic)) + .encode() + ), ar -> { + if (ar.succeeded()) { + log.info("forwarded tools/call to {} OK, status={}", forwardPath, ar.result().statusCode()); + } else { + log.warn("forward tools/call failed: {}", ar.cause().toString()); + } + }); + + return createTextContent( + String.format("Message sent to topic '%s': %s", topic, message) + ); + } + ); + + log.info("Registered {} MCP tools", toolRegistry.getToolCount()); + } + + /** + * Handle JSON-RPC request (HTTP mode) + * + * @param ctx Routing context + */ + private void handleJsonRpcRequest(RoutingContext ctx) { + String body = ctx.body().asString(); + + try { + JsonObject request = new JsonObject(body); + JsonObject response = handleMcpRequest(request); + + if (response != null) { + ctx.response() + .putHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON) + .end(response.encode()); + } else { + // Notification messages don't need response + ctx.response().setStatusCode(HTTP_STATUS_NO_CONTENT).end(); + } + + } catch (Exception e) { + JsonObject error = createErrorResponse(null, ERROR_INTERNAL, + "Internal error: " + e.getMessage()); + ctx.response() + .putHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON) + .setStatusCode(HTTP_STATUS_INTERNAL_ERROR) + .end(error.encode()); + } + } + + /** + * Handle SSE request (Server-Sent Events mode) + * + * @param ctx Routing context + */ + private void handleSseRequest(RoutingContext ctx) { + ctx.response() + .putHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_SSE) + .putHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE) + .putHeader(HEADER_CONNECTION, CONNECTION_KEEP_ALIVE) + .putHeader(HEADER_X_ACCEL_BUFFERING, X_ACCEL_BUFFERING_NO) + .setChunked(true); + + // Send connection established event + ctx.response().write(SSE_EVENT_OPEN); + ctx.response().write(SSE_DATA_OPEN); + + // Heartbeat (optional) + long timerId = vertx.setPeriodic(DEFAULT_HEARTBEAT_INTERVAL_MS, id -> { + if (!ctx.response().closed()) { + ctx.response().write(SSE_HEARTBEAT); + } else { + vertx.cancelTimer(id); + } + }); + + ctx.request().connection().closeHandler(v -> { + vertx.cancelTimer(timerId); + }); + } + + /** + * Handle MCP JSON-RPC request + * + * @param request JSON-RPC request object + * @return JSON-RPC response object, or null for notifications + */ + private JsonObject handleMcpRequest(JsonObject request) { + String method = request.getString(KEY_METHOD, ""); + Object id = request.getValue(KEY_ID); + JsonObject params = request.getJsonObject(KEY_PARAMS); + + switch (method) { + case METHOD_INITIALIZE: + return handleInitialize(id, params); + case METHOD_NOTIFICATIONS_INITIALIZED: + return null; // Notifications don't need response + case METHOD_TOOLS_LIST: + return handleToolsList(id); + case METHOD_TOOLS_CALL: + return handleToolsCall(id, params); + case METHOD_PING: + return createSuccessResponse(id, new JsonObject()); + default: + return createErrorResponse(id, ERROR_METHOD_NOT_FOUND, + "Method not found: " + method); + } + } + + /** + * Handle initialize method + * + * @param id Request ID + * @param params Request parameters + * @return Initialize response + */ + private JsonObject handleInitialize(Object id, JsonObject params) { + String clientVersion = params != null + ? params.getString(KEY_PROTOCOL_VERSION, DEFAULT_PROTOCOL_VERSION) + : DEFAULT_PROTOCOL_VERSION; + + JsonObject result = new JsonObject() + .put(KEY_PROTOCOL_VERSION, clientVersion) + .put(KEY_SERVER_INFO, new JsonObject() + .put(KEY_NAME, DEFAULT_SERVER_NAME) + .put(KEY_VERSION, DEFAULT_SERVER_VERSION)) + .put(KEY_CAPABILITIES, new JsonObject() + .put(KEY_TOOLS, new JsonObject())); + + return createSuccessResponse(id, result); + } + + /** + * Handle tools/list method + * + * @param id Request ID + * @return Tools list response + */ + private JsonObject handleToolsList(Object id) { + JsonArray tools = toolRegistry.getToolsArray(); + JsonObject result = new JsonObject().put(KEY_TOOLS, tools); + return createSuccessResponse(id, result); + } + + /** + * Handle tools/call method + * + * @param id Request ID + * @param params Tool call parameters + * @return Tool execution result + */ + private JsonObject handleToolsCall(Object id, JsonObject params) { + if (params == null) { + return createErrorResponse(id, ERROR_INVALID_PARAMS, "Invalid params"); + } + + String toolName = params.getString(KEY_NAME); + JsonObject arguments = params.getJsonObject("arguments", new JsonObject()); + + log.info("Calling tool: {} with arguments: {}", toolName, arguments); + + try { + JsonObject content = toolRegistry.executeTool(toolName, arguments); + JsonObject result = new JsonObject() + .put(KEY_CONTENT, new JsonArray().add(content)); + + return createSuccessResponse(id, result); + + } catch (IllegalArgumentException e) { + return createErrorResponse(id, ERROR_INVALID_PARAMS, e.getMessage()); + } catch (Exception e) { + log.error("Tool execution error", e); + return createErrorResponse(id, ERROR_INTERNAL, + "Tool execution failed: " + e.getMessage()); + } + } + + // ========== JSON-RPC Response Builders ========== + + /** + * Create a success response + * + * @param id Request ID + * @param result Result object + * @return JSON-RPC success response + */ + private JsonObject createSuccessResponse(Object id, JsonObject result) { + return new JsonObject() + .put(KEY_JSONRPC, VALUE_JSONRPC_VERSION) + .put(KEY_ID, id) + .put(KEY_RESULT, result); + } + + /** + * Create an error response + * + * @param id Request ID + * @param code Error code + * @param message Error message + * @return JSON-RPC error response + */ + private JsonObject createErrorResponse(Object id, int code, String message) { + return new JsonObject() + .put(KEY_JSONRPC, VALUE_JSONRPC_VERSION) + .put(KEY_ID, id) + .put(KEY_ERROR, new JsonObject() + .put(KEY_ERROR_CODE, code) + .put(KEY_ERROR_MESSAGE, message)); + } + + // ========== Schema Creation Helpers ========== + + /** + * Create JSON schema for echo tool + * + * @return Echo tool input schema + */ + private JsonObject createEchoSchema() { + return new JsonObject() + .put(KEY_TYPE, VALUE_TYPE_OBJECT) + .put(KEY_PROPERTIES, new JsonObject() + .put(PARAM_MESSAGE, new JsonObject() + .put(KEY_TYPE, VALUE_TYPE_STRING) + .put(KEY_DESCRIPTION, PARAM_DESC_MESSAGE))) + .put(KEY_REQUIRED, new JsonArray().add(PARAM_MESSAGE)); + } + + /** + * Create JSON schema for send message tool + * + * @return Send message tool input schema + */ + private JsonObject createSendMessageSchema() { + return new JsonObject() + .put(KEY_TYPE, VALUE_TYPE_OBJECT) + .put(KEY_PROPERTIES, new JsonObject() + .put(PARAM_TOPIC, new JsonObject() + .put(KEY_TYPE, VALUE_TYPE_STRING) + .put(KEY_DESCRIPTION, PARAM_DESC_TOPIC)) + .put(PARAM_MESSAGE, new JsonObject() + .put(KEY_TYPE, VALUE_TYPE_STRING) + .put(KEY_DESCRIPTION, PARAM_DESC_MESSAGE_CONTENT))) + .put(KEY_REQUIRED, new JsonArray().add(PARAM_TOPIC).add(PARAM_MESSAGE)); + } + + /** + * Create text content object + * + * @param text Text content + * @return MCP text content object + */ + private JsonObject createTextContent(String text) { + return new JsonObject() + .put(KEY_TYPE, VALUE_TYPE_TEXT) + .put(KEY_TEXT, text); + } + + // ========== Source Interface Implementation ========== + + @Override + public void start() { + this.server.listen(res -> { + if (res.succeeded()) { + this.started = true; + log.info("McpSourceConnector started on port: {}", + this.sourceConfig.getConnectorConfig().getPort()); + log.info("MCP endpoints available at:"); + log.info(" - POST {} (JSON-RPC)", this.sourceConfig.connectorConfig.getPath()); + log.info(" - GET {} (SSE)", this.sourceConfig.connectorConfig.getPath()); + log.info(" - GET {}{} (Health check)", + this.sourceConfig.connectorConfig.getPath(), ENDPOINT_HEALTH); + } else { + log.error("McpSourceConnector failed to start on port: {}", + this.sourceConfig.getConnectorConfig().getPort()); + throw new EventMeshException("failed to start Vertx server", res.cause()); + } + }); + } + + @Override + public void commit(ConnectRecord record) { + if (sourceConfig.getConnectorConfig().isDataConsistencyEnabled()) { + log.debug("McpSourceConnector commit record: {}", record.getRecordId()); + // MCP protocol processing doesn't require additional commit logic + } + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + log.error("Exception occurred for record: {}", record.getRecordId()); + // MCP errors are already handled via JSON-RPC error responses + } + + @Override + public void stop() { + if (this.server != null) { + this.server.close(res -> { + if (res.succeeded()) { + this.destroyed = true; + log.info("McpSourceConnector stopped on port: {}", + this.sourceConfig.getConnectorConfig().getPort()); + } else { + log.error("McpSourceConnector failed to stop on port: {}", + this.sourceConfig.getConnectorConfig().getPort()); + throw new EventMeshException("failed to stop Vertx server", res.cause()); + } + }); + } else { + log.warn("McpSourceConnector server is null, ignore."); + } + + if (this.vertx != null) { + this.vertx.close(); + } + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = MAX_POLL_WAIT_TIME_MS; + + List connectRecords = new ArrayList<>(batchSize); + for (int i = 0; i < batchSize; i++) { + try { + Object obj = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (obj == null) { + break; + } + + // Convert MCP tool calls to ConnectRecord + ConnectRecord connectRecord = protocol.convertToConnectRecord(obj); + connectRecords.add(connectRecord); + + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = MAX_POLL_WAIT_TIME_MS > elapsedTime + ? MAX_POLL_WAIT_TIME_MS - elapsedTime : 0; + } catch (Exception e) { + log.error("Failed to poll from queue.", e); + throw new RuntimeException(e); + } + } + return connectRecords; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpSourceConstants.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpSourceConstants.java new file mode 100644 index 0000000000..423cbbc2c7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpSourceConstants.java @@ -0,0 +1,433 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source; + +/** + * Constants for MCP Source Connector + */ +public final class McpSourceConstants { + + private McpSourceConstants() { + // Utility class, no instantiation + } + + // ========== Server Configuration ========== + + /** + * Default connector name + */ + public static final String DEFAULT_CONNECTOR_NAME = "mcp-source"; + + /** + * Default server name for MCP protocol + */ + public static final String DEFAULT_SERVER_NAME = "eventmesh-mcp-connector"; + + /** + * Default server version + */ + public static final String DEFAULT_SERVER_VERSION = "1.0.0"; + + /** + * Default MCP protocol version + */ + public static final String DEFAULT_PROTOCOL_VERSION = "2024-11-05"; + + /** + * Default idle timeout in milliseconds (60 seconds) + */ + public static final int DEFAULT_IDLE_TIMEOUT_MS = 60000; + + /** + * Default heartbeat interval in milliseconds (30 seconds) + */ + public static final long DEFAULT_HEARTBEAT_INTERVAL_MS = 30000; + + /** + * Maximum poll wait time in milliseconds (5 seconds) + */ + public static final long MAX_POLL_WAIT_TIME_MS = 5000; + + // ========== HTTP Headers ========== + + /** + * Content-Type header name + */ + public static final String HEADER_CONTENT_TYPE = "Content-Type"; + + /** + * Accept header name + */ + public static final String HEADER_ACCEPT = "Accept"; + + /** + * Access-Control-Allow-Origin header + */ + public static final String HEADER_CORS_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; + + /** + * Access-Control-Allow-Methods header + */ + public static final String HEADER_CORS_ALLOW_METHODS = "Access-Control-Allow-Methods"; + + /** + * Access-Control-Allow-Headers header + */ + public static final String HEADER_CORS_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + + /** + * Access-Control-Expose-Headers header + */ + public static final String HEADER_CORS_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; + + /** + * Cache-Control header + */ + public static final String HEADER_CACHE_CONTROL = "Cache-Control"; + + /** + * Connection header + */ + public static final String HEADER_CONNECTION = "Connection"; + + /** + * X-Accel-Buffering header + */ + public static final String HEADER_X_ACCEL_BUFFERING = "X-Accel-Buffering"; + + // ========== CORS Values ========== + + /** + * CORS allow all origins + */ + public static final String CORS_ALLOW_ALL = "*"; + + /** + * CORS allowed methods + */ + public static final String CORS_ALLOWED_METHODS = "GET, POST, OPTIONS"; + + /** + * CORS allowed headers + */ + public static final String CORS_ALLOWED_HEADERS = "Content-Type, Authorization, Accept"; + + /** + * CORS exposed headers + */ + public static final String CORS_EXPOSED_HEADERS = "Content-Type"; + + // ========== Content Types ========== + + /** + * JSON content type with UTF-8 charset + */ + public static final String CONTENT_TYPE_JSON = "application/json; charset=utf-8"; + + /** + * Server-Sent Events content type + */ + public static final String CONTENT_TYPE_SSE = "text/event-stream; charset=utf-8"; + + /** + * Plain JSON content type (for matching) + */ + public static final String CONTENT_TYPE_JSON_PLAIN = "application/json"; + + // ========== HTTP Status Codes ========== + + /** + * HTTP 204 No Content + */ + public static final int HTTP_STATUS_NO_CONTENT = 204; + + /** + * HTTP 500 Internal Server Error + */ + public static final int HTTP_STATUS_INTERNAL_ERROR = 500; + + // ========== JSON-RPC Methods ========== + + /** + * Initialize method + */ + public static final String METHOD_INITIALIZE = "initialize"; + + /** + * Notifications initialized method + */ + public static final String METHOD_NOTIFICATIONS_INITIALIZED = "notifications/initialized"; + + /** + * Tools list method + */ + public static final String METHOD_TOOLS_LIST = "tools/list"; + + /** + * Tools call method + */ + public static final String METHOD_TOOLS_CALL = "tools/call"; + + /** + * Ping method + */ + public static final String METHOD_PING = "ping"; + + // ========== JSON-RPC Error Codes ========== + + /** + * Invalid params error code + */ + public static final int ERROR_INVALID_PARAMS = -32602; + + /** + * Method not found error code + */ + public static final int ERROR_METHOD_NOT_FOUND = -32601; + + /** + * Internal error code + */ + public static final int ERROR_INTERNAL = -32603; + + // ========== JSON Keys ========== + + /** + * JSON-RPC version key + */ + public static final String KEY_JSONRPC = "jsonrpc"; + + /** + * JSON-RPC version value + */ + public static final String VALUE_JSONRPC_VERSION = "2.0"; + + /** + * Method key + */ + public static final String KEY_METHOD = "method"; + + /** + * ID key + */ + public static final String KEY_ID = "id"; + + /** + * Params key + */ + public static final String KEY_PARAMS = "params"; + + /** + * Result key + */ + public static final String KEY_RESULT = "result"; + + /** + * Error key + */ + public static final String KEY_ERROR = "error"; + + /** + * Error code key + */ + public static final String KEY_ERROR_CODE = "code"; + + /** + * Error message key + */ + public static final String KEY_ERROR_MESSAGE = "message"; + + /** + * Protocol version key + */ + public static final String KEY_PROTOCOL_VERSION = "protocolVersion"; + + /** + * Server info key + */ + public static final String KEY_SERVER_INFO = "serverInfo"; + + /** + * Capabilities key + */ + public static final String KEY_CAPABILITIES = "capabilities"; + + /** + * Tools key + */ + public static final String KEY_TOOLS = "tools"; + + /** + * Name key + */ + public static final String KEY_NAME = "name"; + + /** + * Version key + */ + public static final String KEY_VERSION = "version"; + + /** + * Content key + */ + public static final String KEY_CONTENT = "content"; + + /** + * Type key + */ + public static final String KEY_TYPE = "type"; + + /** + * Text key + */ + public static final String KEY_TEXT = "text"; + + /** + * Description key + */ + public static final String KEY_DESCRIPTION = "description"; + + /** + * Input schema key + */ + public static final String KEY_INPUT_SCHEMA = "inputSchema"; + + /** + * Properties key + */ + public static final String KEY_PROPERTIES = "properties"; + + /** + * Required key + */ + public static final String KEY_REQUIRED = "required"; + + /** + * Status key + */ + public static final String KEY_STATUS = "status"; + + /** + * Connector key + */ + public static final String KEY_CONNECTOR = "connector"; + + // ========== JSON Values ========== + + /** + * Object type value + */ + public static final String VALUE_TYPE_OBJECT = "object"; + + /** + * String type value + */ + public static final String VALUE_TYPE_STRING = "string"; + + /** + * Text type value + */ + public static final String VALUE_TYPE_TEXT = "text"; + + /** + * Status UP value + */ + public static final String VALUE_STATUS_UP = "UP"; + + // ========== HTTP Methods ========== + + /** + * OPTIONS HTTP method + */ + public static final String HTTP_METHOD_OPTIONS = "OPTIONS"; + + // ========== SSE Events ========== + + /** + * SSE event: open + */ + public static final String SSE_EVENT_OPEN = "event: open\n"; + + /** + * SSE data for open event + */ + public static final String SSE_DATA_OPEN = "data: {\"type\":\"open\"}\n\n"; + + /** + * SSE heartbeat comment + */ + public static final String SSE_HEARTBEAT = ": heartbeat\n\n"; + + /** + * Cache control: no-cache + */ + public static final String CACHE_CONTROL_NO_CACHE = "no-cache"; + + /** + * Connection: keep-alive + */ + public static final String CONNECTION_KEEP_ALIVE = "keep-alive"; + + /** + * X-Accel-Buffering: no + */ + public static final String X_ACCEL_BUFFERING_NO = "no"; + + // ========== Tool Parameter Names ========== + + /** + * Message parameter name + */ + public static final String PARAM_MESSAGE = "message"; + + /** + * Topic parameter name + */ + public static final String PARAM_TOPIC = "topic"; + + // ========== Tool Parameter Descriptions ========== + + /** + * Message parameter description + */ + public static final String PARAM_DESC_MESSAGE = "Message to echo"; + + /** + * Topic parameter description + */ + public static final String PARAM_DESC_TOPIC = "EventMesh topic"; + + /** + * Message content parameter description + */ + public static final String PARAM_DESC_MESSAGE_CONTENT = "Message content"; + + // ========== Default Values ========== + + /** + * Default message when no message provided + */ + public static final String DEFAULT_NO_MESSAGE = "No message"; + + // ========== Endpoint Paths ========== + + /** + * Health check endpoint suffix + */ + public static final String ENDPOINT_HEALTH = "/health"; +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpToolRegistry.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpToolRegistry.java new file mode 100644 index 0000000000..a59d93f0b6 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/McpToolRegistry.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; + +import lombok.extern.slf4j.Slf4j; + +/** + * MCP Tool Registry + * Manages all available MCP tools + */ +@Slf4j +public class McpToolRegistry { + + private final Map tools = new ConcurrentHashMap<>(); + + /** + * Register an MCP tool + * @param name Tool name + * @param description Tool description + * @param inputSchema JSON schema for tool input parameters + * @param executor Tool execution logic + */ + public void registerTool(String name, String description, + JsonObject inputSchema, ToolExecutor executor) { + McpTool tool = new McpTool(name, description, inputSchema, executor); + tools.put(name, tool); + log.info("Registered MCP tool: {}", name); + } + + /** + * Execute a specified tool + * @param name Tool name + * @param arguments Tool arguments as JSON object + * @return Tool execution result as MCP content object + * @throws IllegalArgumentException if tool not found + * @throws RuntimeException if tool execution fails + */ + public JsonObject executeTool(String name, JsonObject arguments) { + McpTool tool = tools.get(name); + if (tool == null) { + throw new IllegalArgumentException("Unknown tool: " + name); + } + + try { + return tool.executor.execute(arguments); + } catch (Exception e) { + log.error("Tool execution failed: {}", name, e); + throw new RuntimeException("Tool execution failed: " + e.getMessage(), e); + } + } + + /** + * Get all tools as a JSON array + * @return JSON array containing all registered tools with their metadata + */ + public JsonArray getToolsArray() { + JsonArray array = new JsonArray(); + for (McpTool tool : tools.values()) { + JsonObject toolObj = new JsonObject() + .put("name", tool.name) + .put("description", tool.description) + .put("inputSchema", tool.inputSchema); + array.add(toolObj); + } + return array; + } + + /** + * Get the number of registered tools + * @return Total count of registered tools + */ + public int getToolCount() { + return tools.size(); + } + + /** + * Check if a tool exists + * @param name Tool name to check + * @return true if tool is registered, false otherwise + */ + public boolean hasTool(String name) { + return tools.containsKey(name); + } + + /** + * Tool Executor Interface + * Functional interface for defining tool execution logic + */ + @FunctionalInterface + public interface ToolExecutor { + /** + * Execute tool logic + * @param arguments Tool input arguments as JSON object + * @return MCP content object (must contain 'type' and 'text' fields) + * @throws Exception if execution fails + */ + JsonObject execute(JsonObject arguments) throws Exception; + } + + /** + * MCP Tool Definition + * Internal class representing a registered MCP tool + */ + private static class McpTool { + final String name; + final String description; + final JsonObject inputSchema; + final ToolExecutor executor; + + McpTool(String name, String description, JsonObject inputSchema, ToolExecutor executor) { + this.name = name; + this.description = description; + this.inputSchema = inputSchema; + this.executor = executor; + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/data/McpRequest.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/data/McpRequest.java new file mode 100644 index 0000000000..38b9be8b53 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/data/McpRequest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source.data; + +import java.io.Serializable; + +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * MCP Protocol Request + * Represents a request in the MCP (Model Context Protocol) format + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class McpRequest implements Serializable { + + private static final long serialVersionUID = -483500600756490500L; + + /** + * Protocol name + */ + private String protocolName; + + /** + * Session ID for tracking the request + */ + private String sessionId; + + /** + * MCP method name + */ + private String method; + + /** + * Tool name + */ + private String toolName; + + /** + * Tool arguments + */ + private JsonObject arguments; + + /** + * Tool execution result + */ + private JsonObject result; + + /** + * Request timestamp + */ + private long timestamp; + + /** + * Whether the tool execution succeeded + */ + private boolean success; + + /** + * Error message if execution failed + */ + private String errorMessage; + + /** + * Vert.x routing context for HTTP response handling + */ + private transient RoutingContext routingContext; +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/data/McpResponse.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/data/McpResponse.java new file mode 100644 index 0000000000..93e1cbcfab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/data/McpResponse.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source.data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONWriter.Feature; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * MCP Response + * Represents a response message for MCP protocol operations + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class McpResponse implements Serializable { + + private static final long serialVersionUID = 8616938575207104455L; + + /** + * Response status: "success", "error", etc. + */ + private String status; + + /** + * Response message + */ + private String msg; + + /** + * Response timestamp + */ + private LocalDateTime handleTime; + + /** + * Additional error code for error responses + */ + private Integer errorCode; + + /** + * Additional data payload + */ + private Object data; + + /** + * Convert to JSON string + * + * @return JSON string representation + */ + public String toJsonStr() { + return JSON.toJSONString(this, Feature.WriteMapNullValue); + } + + /** + * Create a success response + * + * @return Success response + */ + public static McpResponse success() { + return new McpResponse("success", "Operation completed successfully", + LocalDateTime.now(), null, null); + } + + /** + * Create a success response with message + * + * @param msg Success message + * @return Success response + */ + public static McpResponse success(String msg) { + return new McpResponse("success", msg, LocalDateTime.now(), null, null); + } + + /** + * Create a success response with data + * + * @param msg Success message + * @param data Response data + * @return Success response with data + */ + public static McpResponse success(String msg, Object data) { + return new McpResponse("success", msg, LocalDateTime.now(), null, data); + } + + /** + * Create an error response + * + * @param msg Error message + * @return Error response + */ + public static McpResponse error(String msg) { + return new McpResponse("error", msg, LocalDateTime.now(), null, null); + } + + /** + * Create an error response with error code + * + * @param msg Error message + * @param errorCode Error code + * @return Error response with code + */ + public static McpResponse error(String msg, Integer errorCode) { + return new McpResponse("error", msg, LocalDateTime.now(), errorCode, null); + } + + /** + * Create a base response + * + * @param msg Message + * @return Base response + */ + public static McpResponse base(String msg) { + return new McpResponse("info", msg, LocalDateTime.now(), null, null); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/Protocol.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/Protocol.java new file mode 100644 index 0000000000..f18397a6c3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/Protocol.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source.protocol; + +import org.apache.eventmesh.common.config.connector.mcp.SourceConnectorConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.concurrent.BlockingQueue; + +import io.vertx.ext.web.Route; + +/** + * Protocol Interface. + * All protocols should implement this interface. + */ +public interface Protocol { + + /** + * Initialize the protocol. + * + * @param sourceConnectorConfig source connector config + */ + void initialize(SourceConnectorConfig sourceConnectorConfig); + + + /** + * Handle the protocol message. + * + * @param route route + * @param queue queue info + */ + void setHandler(Route route, BlockingQueue queue); + + + /** + * Convert the message to ConnectRecord. + * + * @param message message + * @return ConnectRecord + */ + ConnectRecord convertToConnectRecord(Object message); +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/ProtocolFactory.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/ProtocolFactory.java new file mode 100644 index 0000000000..1c30d4e43e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/ProtocolFactory.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source.protocol; + +import org.apache.eventmesh.common.config.connector.mcp.SourceConnectorConfig; +import org.apache.eventmesh.connector.mcp.source.protocol.impl.McpStandardProtocol; + +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Protocol factory. This class is responsible for storing and creating instances of {@link Protocol} classes. + */ +public class ProtocolFactory { + // protocol name -> protocol class + private static final ConcurrentHashMap> protocols = new ConcurrentHashMap<>(); + + static { + // register all protocols + registerProtocol(McpStandardProtocol.PROTOCOL_NAME, McpStandardProtocol.class); + } + + + /** + * Register a protocol + * + * @param name name of the protocol + * @param clazz class of the protocol + */ + public static void registerProtocol(String name, Class clazz) { + if (Protocol.class.isAssignableFrom(clazz)) { + // put the class into the map(case insensitive) + protocols.put(name.toLowerCase(), clazz); + } else { + throw new IllegalArgumentException("Class " + clazz.getName() + " does not implement Protocol interface"); + } + } + + /** + * Get an instance of a protocol, if it is not already created, create a new instance + * + * @param name name of the protocol + * @return instance of the protocol + */ + public static Protocol getInstance(SourceConnectorConfig sourceConnectorConfig, String name) { + // get the class by name(case insensitive) + Class clazz = Optional.ofNullable(protocols.get(name.toLowerCase())) + .orElseThrow(() -> new IllegalArgumentException("Protocol " + name + " is not registered")); + try { + // create a new instance + Protocol protocol = (Protocol) clazz.newInstance(); + // initialize the protocol + protocol.initialize(sourceConnectorConfig); + return protocol; + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException("Failed to instantiate protocol " + name, e); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/impl/McpStandardProtocol.java b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/impl/McpStandardProtocol.java new file mode 100644 index 0000000000..737dae82de --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/java/org/apache/eventmesh/connector/mcp/source/protocol/impl/McpStandardProtocol.java @@ -0,0 +1,339 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mcp.source.protocol.impl; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.connector.mcp.SourceConnectorConfig; +import org.apache.eventmesh.connector.mcp.source.data.McpRequest; +import org.apache.eventmesh.connector.mcp.source.data.McpResponse; +import org.apache.eventmesh.connector.mcp.source.protocol.Protocol; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.Base64; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.handler.BodyHandler; + +import lombok.extern.slf4j.Slf4j; + +/** + * MCP Standard Protocol Implementation + * Handles MCP (Model Context Protocol) requests and converts them to EventMesh ConnectRecords + */ +@Slf4j +public class McpStandardProtocol implements Protocol { + + /** + * Protocol name constant + */ + public static final String PROTOCOL_NAME = "MCP"; + + // Extension keys + private static final String EXTENSION_PROTOCOL = "protocol"; + private static final String EXTENSION_SESSION_ID = "sessionid"; + private static final String EXTENSION_TOOL_NAME = "toolname"; + private static final String EXTENSION_METHOD = "method"; // ok + private static final String EXTENSION_REQUEST_ID = "requestid"; + private static final String EXTENSION_SUCCESS = "success"; // ok + private static final String EXTENSION_ERROR_MESSAGE = "errormessage"; + private static final String EXTENSION_ROUTING_CONTEXT = "routingcontext"; + private static final String EXTENSION_IS_BASE64 = "isbase64"; + private static final String METADATA_EXTENSION_KEY = "extension"; + + private SourceConnectorConfig sourceConnectorConfig; + + /** + * Initialize the protocol + * + * @param sourceConnectorConfig Source connector configuration + */ + @Override + public void initialize(SourceConnectorConfig sourceConnectorConfig) { + this.sourceConnectorConfig = sourceConnectorConfig; + log.info("Initialized MCP Standard Protocol"); + } + + /** + * Set the handler for the route + * This method is called when using the protocol in a generic HTTP connector context + * + * @param route Vert.x route to configure + * @param queue Queue for storing requests + */ + @Override + public void setHandler(Route route, BlockingQueue queue) { + route.method(HttpMethod.POST) + .handler(BodyHandler.create()) + .handler(ctx -> { + try { + // Parse the request body + String bodyString = ctx.body().asString(Constants.DEFAULT_CHARSET.toString()); + + // Try to parse as JSON + JsonObject requestJson; + try { + requestJson = new JsonObject(bodyString); + } catch (Exception e) { + log.error("Failed to parse request as JSON: {}", bodyString, e); + ctx.response() + .setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) + .putHeader("Content-Type", "application/json") + .end(McpResponse.error("Invalid JSON format").toJsonStr()); + return; + } + + // Extract JSON-RPC fields + String method = requestJson.getString("type", ""); + String toolName = requestJson.getString("tool", ""); + JsonObject params = requestJson.getJsonObject("arguments"); + + // Generate session ID if not present + String sessionId = ctx.request().getHeader("Mcp-Session-Id"); + if (sessionId == null || sessionId.isEmpty()) { + sessionId = generateSessionId(); + } + + // Create MCP request based on method type + McpRequest mcpRequest = createMcpRequest( + method, + params, + sessionId, + toolName, + ctx + ); + + // Queue the request + if (!queue.offer(mcpRequest)) { + log.error("Failed to queue MCP request: queue is full"); + ctx.response() + .setStatusCode(HttpResponseStatus.SERVICE_UNAVAILABLE.code()) + .putHeader("Content-Type", "application/json") + .end(McpResponse.error("Service temporarily unavailable").toJsonStr()); + return; + } + + // If data consistency is not enabled, return immediate response + if (!sourceConnectorConfig.isDataConsistencyEnabled()) { + ctx.response() + .setStatusCode(HttpResponseStatus.OK.code()) + .putHeader("Content-Type", "application/json") + .end(McpResponse.success().toJsonStr()); + } + // Otherwise, response will be sent after processing (via commit) + + } catch (Exception e) { + log.error("Error handling MCP request", e); + ctx.response() + .setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()) + .putHeader("Content-Type", "application/json") + .end(McpResponse.error("Internal server error: " + e.getMessage()).toJsonStr()); + } + }) + .failureHandler(ctx -> { + log.error("Failed to handle MCP request", ctx.failure()); + + // Return error response + ctx.response() + .setStatusCode(ctx.statusCode() > 0 ? ctx.statusCode() : 500) + .putHeader("Content-Type", "application/json") + .end(McpResponse.error(ctx.failure().getMessage()).toJsonStr()); + }); + } + + /** + * Create MCP request from parsed JSON-RPC data + * + * @param method JSON-RPC method name + * @param params JSON-RPC params + * @param sessionId Session identifier + * @param tool Tool name + * @param ctx Routing context + * @return Constructed McpRequest + */ + private McpRequest createMcpRequest( + String method, + JsonObject params, + String sessionId, + String tool, + io.vertx.ext.web.RoutingContext ctx) { + + McpRequest.McpRequestBuilder builder = McpRequest.builder() + .protocolName(PROTOCOL_NAME) + .sessionId(sessionId) + .method(method) + .toolName(tool) + .timestamp(System.currentTimeMillis()) + .routingContext(ctx); + + + // Handle different method types + if ("mcp.tools.call".equals(method) && params != null) { + // Tool call request + String toolName = params.getString("name"); + JsonObject arguments = params.getJsonObject("arguments", new JsonObject()); + + builder.toolName(toolName) + .arguments(arguments) + .success(false); // Will be set to true after execution + + + } else if ("initialize".equals(method)) { + // Initialize request + builder.success(true); + + } else { + // Other methods + builder.success(true); + } + + return builder.build(); + } + + /** + * Convert MCP request to ConnectRecord + * Simple and direct conversion following the existing pattern + * + * @param message MCP request message + * @return ConnectRecord representation + */ + @Override + public ConnectRecord convertToConnectRecord(Object message) { + // Validate input + if (message == null) { + throw new IllegalArgumentException("Message cannot be null"); + } + + if (!(message instanceof McpRequest)) { + throw new IllegalArgumentException( + String.format("Expected McpRequest but got %s", message.getClass().getName()) + ); + } + + McpRequest request = (McpRequest) message; + + // Get timestamp + long timestamp = request.getTimestamp() > 0 + ? request.getTimestamp() + : System.currentTimeMillis(); + + // Get data (priority: result > arguments > inputs) + Object data = extractData(request); + + // Create ConnectRecord + ConnectRecord connectRecord = new ConnectRecord(null, null, timestamp, data); + + // Add protocol extension + connectRecord.addExtension(EXTENSION_PROTOCOL, PROTOCOL_NAME); + + // Add session ID + if (request.getSessionId() != null) { + connectRecord.addExtension(EXTENSION_SESSION_ID, request.getSessionId()); + } + + // Add method + if (request.getMethod() != null) { + connectRecord.addExtension(EXTENSION_METHOD, request.getMethod()); + } + + // Add tool name (for tool calls) + if (request.getToolName() != null) { + connectRecord.addExtension(EXTENSION_TOOL_NAME, request.getToolName()); + } + + // Add success status + connectRecord.addExtension(EXTENSION_SUCCESS, String.valueOf(request.isSuccess())); + + // Add error message if failed + if (!request.isSuccess() && request.getErrorMessage() != null) { + connectRecord.addExtension(EXTENSION_ERROR_MESSAGE, request.getErrorMessage()); + } + + // Handle Base64 decoding if needed + handleBase64Decoding(connectRecord); + + // Add routing context for response handling + if (request.getRoutingContext() != null) { + connectRecord.addExtension(EXTENSION_ROUTING_CONTEXT, request.getRoutingContext()); + } + + return connectRecord; + } + + /** + * Extract data from MCP request + * Priority: result > arguments > inputs + */ + private Object extractData(McpRequest request) { + if (request.isSuccess() && request.getResult() != null) { + return request.getResult().encode(); + } + + if (request.getArguments() != null) { + return request.getArguments().encode(); + } + + return String.format("{\"tool\":\"%s\",\"timestamp\":%d}", + request.getToolName(), request.getTimestamp()); + } + + /** + * Handle Base64 decoding if isBase64 flag is set + */ + private void handleBase64Decoding(ConnectRecord connectRecord) { + Object isBase64Obj = connectRecord.getExtensionObj(EXTENSION_IS_BASE64); + + if (isBase64Obj == null) { + return; + } + + // Parse boolean value + boolean isBase64; + if (isBase64Obj instanceof Boolean) { + isBase64 = (Boolean) isBase64Obj; + } else { + isBase64 = Boolean.parseBoolean(String.valueOf(isBase64Obj)); + } + + // Decode if needed + if (isBase64 && connectRecord.getData() != null) { + try { + String dataStr = connectRecord.getData().toString(); + byte[] decodedData = Base64.getDecoder().decode(dataStr); + connectRecord.setData(decodedData); + log.debug("Decoded Base64 data: {} bytes", decodedData.length); + } catch (IllegalArgumentException e) { + log.error("Failed to decode Base64 data: {}", e.getMessage()); + // Keep original data if decoding fails + } + } + } + + /** + * Generate a unique session ID + * + * @return Generated session ID + */ + private String generateSessionId() { + return "mcp-session-" + UUID.randomUUID(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/META-INF.eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/META-INF.eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService new file mode 100644 index 0000000000..01a46e9de0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/META-INF.eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService @@ -0,0 +1,20 @@ +# +# 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. +# + + +MCP-Source=org.apache.eventmesh.connector.mcp.source.McpSourceConnector +MCP-Sink=org.apache.eventmesh.connector.mcp.sink.McpSinkConnector \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/server-config.yml new file mode 100644 index 0000000000..8009f5c76a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..c04f886699 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/sink-config.yml @@ -0,0 +1,56 @@ +# +# 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. +# + +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: mcpSink + appId: 5032 + userName: mcpSourceUser + passWord: mcpPassWord +connectorConfig: + connectorName: mcpSink + urls: + - http://127.0.0.1:7092/test + keepAlive: true + keepAliveTimeout: 60000 + idleTimeout: 5000 # timeunit: ms, recommended scope: common(5s - 10s), webhook(15s - 60s) + connectionTimeout: 5000 # timeunit: ms, recommended scope: 5 - 10s + maxConnectionPoolSize: 5 + retryConfig: + maxRetries: 2 + interval: 1000 + retryOnNonSuccess: false diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/source-config.yml new file mode 100644 index 0000000000..66ad75d37b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/main/resources/source-config.yml @@ -0,0 +1,38 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: mcpSource + appId: 5032 + userName: mcpSourceUser + passWord: mcpPassWord +connectorConfig: + connectorName: mcpSource + path: /test + port: 7091 + idleTimeout: 5000 # timeunit: ms + maxFormAttributeSize: 1048576 # timeunit: byte, default: 1048576(1MB). This applies only when handling form data submissions. + protocol: MCP # Case insensitive, default: CloudEvent, options: CloudEvent, GitHub, Common + extraConfig: # extra config for different protocol, e.g. GitHub secret + streamType: chunked + contentType: application/json + reconnection: true + forwardPath: /forward \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-mcp/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-mcp/src/test/resources/server-config.yml new file mode 100644 index 0000000000..0cd7b5b5ab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mcp/src/test/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/build.gradle b/eventmesh-connectors/eventmesh-connector-mongodb/build.gradle new file mode 100644 index 0000000000..0c5602eb7f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/build.gradle @@ -0,0 +1,28 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + + implementation 'org.mongodb:mongodb-driver:3.12.14' + + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/gradle.properties b/eventmesh-connectors/eventmesh-connector-mongodb/gradle.properties new file mode 100644 index 0000000000..440c926cd3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=mongodb \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/config/MongodbServerConfig.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/config/MongodbServerConfig.java new file mode 100644 index 0000000000..fa5618d4a8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/config/MongodbServerConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; + +@Data +public class MongodbServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/constant/MongodbConstants.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/constant/MongodbConstants.java new file mode 100644 index 0000000000..13dfbf530c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/constant/MongodbConstants.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.constant; + +public class MongodbConstants { + + public static final String TOPIC = "flag"; + public static final String CAPPED_COL_TOPIC_FN = "topic"; + public static final String CAPPED_COL_CURSOR_FN = "ts"; + public static final String SEQUENCE_COLLECTION_NAME = "pub_sub_seq"; + public static final String SEQUENCE_KEY_FN = "topic"; + public static final String SEQUENCE_VALUE_FN = "value"; + public static final String CLOUD_EVENT_DOC_VERSION = "version"; + public static final String CLOUD_EVENT_DOC_DATA = "data"; + public static final String CLOUD_EVENT_DOC_ID = "id"; + public static final String CLOUD_EVENT_DOC_SOURCE = "source"; + public static final String CLOUD_EVENT_DOC_TYPE = "type"; + public static final String CLOUD_EVENT_DOC_DATACONTENTTYPE = "datacontenttype"; + public static final String CLOUD_EVENT_DOC_SUBJECT = "subject"; +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/server/MongodbConnectServer.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/server/MongodbConnectServer.java new file mode 100644 index 0000000000..4d58a35e16 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/server/MongodbConnectServer.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.server; + +import org.apache.eventmesh.connector.mongodb.config.MongodbServerConfig; +import org.apache.eventmesh.connector.mongodb.sink.connector.MongodbSinkConnector; +import org.apache.eventmesh.connector.mongodb.source.connector.MongodbSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class MongodbConnectServer { + + public static void main(String[] args) throws Exception { + + MongodbServerConfig serverConfig = ConfigUtil.parse(MongodbServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application mongodbSourceApp = new Application(); + mongodbSourceApp.run(MongodbSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application mongodbSinkApp = new Application(); + mongodbSinkApp.run(MongodbSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/Impl/MongodbSinkClient.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/Impl/MongodbSinkClient.java new file mode 100644 index 0000000000..dcc3bbe7b4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/Impl/MongodbSinkClient.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.sink.client.Impl; + +import io.cloudevents.CloudEvent; + +/** + * MongodbSinkClient + */ +public interface MongodbSinkClient { + + void init(); + + void start(); + + void publish(CloudEvent cloudEvent); + + void stop(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/MongodbReplicaSetSinkClient.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/MongodbReplicaSetSinkClient.java new file mode 100644 index 0000000000..0afae2b8de --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/MongodbReplicaSetSinkClient.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.sink.client; + +import org.apache.eventmesh.common.config.connector.rdb.mongodb.SinkConnectorConfig; +import org.apache.eventmesh.connector.mongodb.sink.client.Impl.MongodbSinkClient; +import org.apache.eventmesh.connector.mongodb.utils.MongodbCloudEventUtil; + +import org.bson.Document; + +import io.cloudevents.CloudEvent; + +import com.mongodb.ConnectionString; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; + +public class MongodbReplicaSetSinkClient implements MongodbSinkClient { + + private final SinkConnectorConfig connectorConfig; + + private volatile boolean started = false; + + private MongoClient client; + + public MongodbReplicaSetSinkClient(SinkConnectorConfig connectorConfig) { + this.connectorConfig = connectorConfig; + } + + @Override + public void init() { + this.client = MongoClients.create(new ConnectionString(connectorConfig.getUrl())); + } + + @Override + public void start() { + if (!started) { + started = true; + } + } + + @Override + public void publish(CloudEvent cloudEvent) { + Document document = MongodbCloudEventUtil.convertToDocument(cloudEvent); + MongoCollection collection = client + .getDatabase(connectorConfig.getDatabase()).getCollection(connectorConfig.getCollection()); + collection.insertOne(document); + } + + @Override + public void stop() { + if (started) { + try { + this.client.close(); + } finally { + started = false; + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/MongodbStandaloneSinkClient.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/MongodbStandaloneSinkClient.java new file mode 100644 index 0000000000..4a87a4320f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/client/MongodbStandaloneSinkClient.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.sink.client; + +import org.apache.eventmesh.common.config.connector.rdb.mongodb.SinkConnectorConfig; +import org.apache.eventmesh.connector.mongodb.constant.MongodbConstants; +import org.apache.eventmesh.connector.mongodb.sink.client.Impl.MongodbSinkClient; +import org.apache.eventmesh.connector.mongodb.utils.MongodbCloudEventUtil; + +import org.bson.Document; + +import io.cloudevents.CloudEvent; + +import com.mongodb.BasicDBObject; +import com.mongodb.ConnectionString; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.ReturnDocument; + +public class MongodbStandaloneSinkClient implements MongodbSinkClient { + + private final SinkConnectorConfig connectorConfig; + + private volatile boolean started = false; + + private MongoClient client; + + private MongoCollection cappedCol; + + private MongoCollection seqCol; + + public MongodbStandaloneSinkClient(SinkConnectorConfig connectorConfig) { + this.connectorConfig = connectorConfig; + } + + @Override + public void init() { + this.client = MongoClients.create(new ConnectionString(connectorConfig.getUrl())); + MongoDatabase db = client.getDatabase(connectorConfig.getDatabase()); + this.cappedCol = db.getCollection(connectorConfig.getCollection()); + this.seqCol = db.getCollection(MongodbConstants.SEQUENCE_COLLECTION_NAME); + } + + @Override + public void start() { + if (!started) { + started = true; + } + } + + @Override + public void publish(CloudEvent cloudEvent) { + Document doc = MongodbCloudEventUtil.convertToDocument(cloudEvent); + int i = getNextSeq(MongodbConstants.TOPIC); + doc.append(MongodbConstants.CAPPED_COL_TOPIC_FN, MongodbConstants.TOPIC) + .append(MongodbConstants.CAPPED_COL_CURSOR_FN, i); + cappedCol.insertOne(doc); + } + + @Override + public void stop() { + if (started) { + try { + this.client.close(); + } finally { + started = false; + } + } + } + + public int getNextSeq(String topic) { + Document query = new Document(MongodbConstants.SEQUENCE_KEY_FN, topic); + Document update = new Document("$inc", new BasicDBObject(MongodbConstants.SEQUENCE_VALUE_FN, 1)); + FindOneAndUpdateOptions options = new FindOneAndUpdateOptions(); + options.upsert(true); + options.returnDocument(ReturnDocument.AFTER); + Document result = seqCol.findOneAndUpdate(query, update, options); + return (int) (Integer) result.get(MongodbConstants.SEQUENCE_VALUE_FN); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/connector/MongodbSinkConnector.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/connector/MongodbSinkConnector.java new file mode 100644 index 0000000000..1001ffa584 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/sink/connector/MongodbSinkConnector.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.mongodb.MongodbSinkConfig; +import org.apache.eventmesh.connector.mongodb.sink.client.Impl.MongodbSinkClient; +import org.apache.eventmesh.connector.mongodb.sink.client.MongodbReplicaSetSinkClient; +import org.apache.eventmesh.connector.mongodb.sink.client.MongodbStandaloneSinkClient; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.List; + +import io.cloudevents.CloudEvent; + +import com.mongodb.connection.ClusterType; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MongodbSinkConnector implements Sink { + + private MongodbSinkConfig sinkConfig; + + private MongodbSinkClient client; + + @Override + public Class configClass() { + return MongodbSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.sinkConfig = (MongodbSinkConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (MongodbSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + private void doInit() { + String connectorType = sinkConfig.getConnectorConfig().getConnectorType(); + if (connectorType.equals(ClusterType.STANDALONE.name())) { + this.client = new MongodbStandaloneSinkClient(sinkConfig.getConnectorConfig()); + } + if (connectorType.equals(ClusterType.REPLICA_SET.name())) { + this.client = new MongodbReplicaSetSinkClient(sinkConfig.getConnectorConfig()); + } + client.init(); + } + + @Override + public void start() throws Exception { + this.client.start(); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + this.client.stop(); + } + + @Override + public void put(List sinkRecords) { + try { + for (ConnectRecord connectRecord : sinkRecords) { + CloudEvent event = CloudEventUtil.convertRecordToEvent(connectRecord); + client.publish(event); + log.debug("Produced message to event:{}}", event); + } + } catch (Exception e) { + log.error("Failed to produce message:{}", e.getMessage()); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/Impl/MongodbSourceClient.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/Impl/MongodbSourceClient.java new file mode 100644 index 0000000000..f3dfd198a4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/Impl/MongodbSourceClient.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.source.client.Impl; + +/** + * MongodbSourceClient + */ +public interface MongodbSourceClient { + + void init(); + + void start(); + + void stop(); + +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/MongodbReplicaSetSourceClient.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/MongodbReplicaSetSourceClient.java new file mode 100644 index 0000000000..b389c0db9c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/MongodbReplicaSetSourceClient.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.source.client; + +import org.apache.eventmesh.common.config.connector.rdb.mongodb.SourceConnectorConfig; +import org.apache.eventmesh.connector.mongodb.source.client.Impl.MongodbSourceClient; +import org.apache.eventmesh.connector.mongodb.utils.MongodbCloudEventUtil; + +import java.util.concurrent.BlockingQueue; + +import org.bson.Document; + +import io.cloudevents.CloudEvent; + +import com.mongodb.ConnectionString; +import com.mongodb.client.ChangeStreamIterable; +import com.mongodb.client.MongoChangeStreamCursor; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.changestream.ChangeStreamDocument; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MongodbReplicaSetSourceClient implements MongodbSourceClient { + + private final SourceConnectorConfig connectorConfig; + + private volatile boolean started = false; + + private MongoClient client; + + private MongoChangeStreamCursor> cursor; + + private final BlockingQueue queue; + + public MongodbReplicaSetSourceClient(SourceConnectorConfig connectorConfig, BlockingQueue queue) { + this.queue = queue; + this.connectorConfig = connectorConfig; + } + + @Override + public void init() { + this.client = MongoClients.create(new ConnectionString(connectorConfig.getUrl())); + } + + @Override + public void start() { + if (!started) { + MongoCollection collection = client + .getDatabase(connectorConfig.getDatabase()).getCollection(connectorConfig.getCollection()); + ChangeStreamIterable changeStreamDocuments = collection.watch(); + this.cursor = changeStreamDocuments.cursor(); + this.handle(); + started = true; + } + } + + @Override + public void stop() { + if (started) { + try { + this.client.close(); + this.cursor.close(); + } finally { + started = false; + } + } + } + + private void handle() { + while (this.cursor.hasNext()) { + ChangeStreamDocument next = cursor.next(); + Document fullDocument = next.getFullDocument(); + if (fullDocument != null) { + try { + CloudEvent cloudEvent = MongodbCloudEventUtil.convertToCloudEvent(fullDocument); + queue.add(cloudEvent); + } catch (Exception e) { + log.error("[MongodbReplicaSetSourceClient] happen exception.", e); + } + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/MongodbStandaloneSourceClient.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/MongodbStandaloneSourceClient.java new file mode 100644 index 0000000000..ce7452e0ae --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/client/MongodbStandaloneSourceClient.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.source.client; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.connector.rdb.mongodb.SourceConnectorConfig; +import org.apache.eventmesh.connector.mongodb.constant.MongodbConstants; +import org.apache.eventmesh.connector.mongodb.source.client.Impl.MongodbSourceClient; +import org.apache.eventmesh.connector.mongodb.utils.MongodbCloudEventUtil; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.bson.Document; + +import io.cloudevents.CloudEvent; + +import com.mongodb.ConnectionString; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MongodbStandaloneSourceClient implements MongodbSourceClient { + + private final SourceConnectorConfig connectorConfig; + + private volatile boolean started = false; + + private MongoClient client; + + private MongoCollection cappedCol; + + private final BlockingQueue queue; + + private final SubTask task = new SubTask(); + + private final ThreadPoolExecutor executor = ThreadPoolFactory.createThreadPoolExecutor( + Runtime.getRuntime().availableProcessors() * 2, + Runtime.getRuntime().availableProcessors() * 2, + "EventMesh-MongodbStandaloneSourceClient-"); + + public MongodbStandaloneSourceClient(SourceConnectorConfig connectorConfig, BlockingQueue queue) { + this.queue = queue; + this.connectorConfig = connectorConfig; + } + + @Override + public void init() { + this.client = MongoClients.create(new ConnectionString(connectorConfig.getUrl())); + MongoDatabase db = client.getDatabase(connectorConfig.getDatabase()); + this.cappedCol = db.getCollection(connectorConfig.getCollection()); + // create index + Document index = new Document(MongodbConstants.CAPPED_COL_CURSOR_FN, 1) + .append(MongodbConstants.CAPPED_COL_TOPIC_FN, 1); + this.cappedCol.createIndex(index); + } + + @Override + public void start() { + if (!started) { + executor.execute(task); + started = true; + } + } + + @Override + public void stop() { + if (started) { + try { + this.task.stop(); + this.client.close(); + } finally { + started = false; + } + } + } + + private FindIterable getCursor(MongoCollection collection, String topic, int lastId) { + Document index = new Document("$gt", lastId); + Document ts = new Document(MongodbConstants.CAPPED_COL_CURSOR_FN, index); + + Document spec = ts.append(MongodbConstants.CAPPED_COL_TOPIC_FN, topic); + return collection.find(spec); + } + + private class SubTask implements Runnable { + + private final AtomicBoolean stop = new AtomicBoolean(false); + + public void run() { + int lastId = -1; + while (!stop.get()) { + try { + FindIterable cur = getCursor(cappedCol, MongodbConstants.TOPIC, lastId); + for (Document obj : cur) { + CloudEvent cloudEvent = MongodbCloudEventUtil.convertToCloudEvent(obj); + queue.add(cloudEvent); + try { + lastId = (int) ((Double) obj.get(MongodbConstants.CAPPED_COL_CURSOR_FN)).doubleValue(); + } catch (ClassCastException ce) { + lastId = (Integer) obj.get(MongodbConstants.CAPPED_COL_CURSOR_FN); + } + } + } catch (Exception ex) { + log.error("[MongodbStandaloneSourceClient] thread run happen exception.", ex); + } + Thread.yield(); + } + } + + public void stop() { + stop.set(true); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/connector/MongodbSourceConnector.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/connector/MongodbSourceConnector.java new file mode 100644 index 0000000000..1d1dcc1843 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/source/connector/MongodbSourceConnector.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.rdb.mongodb.MongodbSourceConfig; +import org.apache.eventmesh.connector.mongodb.source.client.Impl.MongodbSourceClient; +import org.apache.eventmesh.connector.mongodb.source.client.MongodbReplicaSetSourceClient; +import org.apache.eventmesh.connector.mongodb.source.client.MongodbStandaloneSourceClient; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; + +import com.mongodb.connection.ClusterType; + +public class MongodbSourceConnector implements Source { + + private MongodbSourceConfig sourceConfig; + + private BlockingQueue queue; + + private int maxBatchSize; + + private long maxPollWaitTime; + + private MongodbSourceClient client; + + @Override + public Class configClass() { + return MongodbSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.sourceConfig = (MongodbSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (MongodbSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + String connectorType = sourceConfig.getConnectorConfig().getConnectorType(); + if (connectorType.equals(ClusterType.STANDALONE.name())) { + this.client = new MongodbStandaloneSourceClient(sourceConfig.getConnectorConfig(), queue); + } + if (connectorType.equals(ClusterType.REPLICA_SET.name())) { + this.client = new MongodbReplicaSetSourceClient(sourceConfig.getConnectorConfig(), queue); + } + client.init(); + } + + @Override + public void start() throws Exception { + this.client.start(); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.connectorConfig.getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + this.client.stop(); + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int count = 0; count < maxBatchSize; ++count) { + try { + CloudEvent event = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (event == null) { + break; + } + connectRecords.add(CloudEventUtil.convertEventToRecord(event)); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + break; + } + } + return connectRecords; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/utils/MongodbCloudEventUtil.java b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/utils/MongodbCloudEventUtil.java new file mode 100644 index 0000000000..ef2f34e6f4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/java/org/apache/eventmesh/connector/mongodb/utils/MongodbCloudEventUtil.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.mongodb.utils; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.mongodb.constant.MongodbConstants; + +import java.net.URI; +import java.nio.charset.StandardCharsets; + +import org.bson.Document; + +import io.cloudevents.CloudEvent; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class MongodbCloudEventUtil { + + public static CloudEvent convertToCloudEvent(Document document) throws Exception { + document.remove("_id"); + String versionStr = document.getString(MongodbConstants.CLOUD_EVENT_DOC_VERSION); + SpecVersion version = SpecVersion.valueOf(versionStr); + CloudEventBuilder builder; + switch (version) { + case V03: + builder = CloudEventBuilder.v03(); + break; + case V1: + builder = CloudEventBuilder.v1(); + break; + default: + throw new Exception(String.format("CloudEvent version %s does not support.", version)); + } + builder.withData(document.remove(MongodbConstants.CLOUD_EVENT_DOC_DATA).toString().getBytes(Constants.DEFAULT_CHARSET)) + .withId(document.remove(MongodbConstants.CLOUD_EVENT_DOC_ID).toString()) + .withSource(URI.create(document.remove(MongodbConstants.CLOUD_EVENT_DOC_SOURCE).toString())) + .withType(document.remove(MongodbConstants.CLOUD_EVENT_DOC_TYPE).toString()) + .withDataContentType(document.remove(MongodbConstants.CLOUD_EVENT_DOC_DATACONTENTTYPE).toString()) + .withSubject(document.remove(MongodbConstants.CLOUD_EVENT_DOC_SUBJECT).toString()); + document.forEach((key, value) -> builder.withExtension(key, value.toString())); + + return builder.build(); + } + + public static Document convertToDocument(CloudEvent cloudEvent) { + Document document = new Document(); + document.put(MongodbConstants.CLOUD_EVENT_DOC_VERSION, cloudEvent.getSpecVersion().name()); + document.put(MongodbConstants.CLOUD_EVENT_DOC_DATA, cloudEvent.getData() == null + ? null + : new String(cloudEvent.getData().toBytes(), StandardCharsets.UTF_8)); + document.put(MongodbConstants.CLOUD_EVENT_DOC_ID, cloudEvent.getId()); + document.put(MongodbConstants.CLOUD_EVENT_DOC_SOURCE, cloudEvent.getSource().toString()); + document.put(MongodbConstants.CLOUD_EVENT_DOC_TYPE, cloudEvent.getType()); + document.put(MongodbConstants.CLOUD_EVENT_DOC_DATACONTENTTYPE, cloudEvent.getDataContentType()); + document.put(MongodbConstants.CLOUD_EVENT_DOC_SUBJECT, cloudEvent.getSubject()); + cloudEvent.getExtensionNames().forEach(key -> document.put(key, cloudEvent.getExtension(key))); + + return document; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..0f2ee2449b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/sink-config.yml @@ -0,0 +1,34 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: mongodbSink + appId: 5031 + userName: mongodbSinkUser + passWord: mongodbPassWord +connectorConfig: + connectorName: mongodbSink + connectorType: STANDALONE + #mongodb://root:root@127.0.0.1:27018,127.0.0.1:27019 + url: mongodb://127.0.0.1:27018 + database: db + collection: col + diff --git a/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/source-config.yml new file mode 100644 index 0000000000..b4d264a058 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-mongodb/src/main/resources/source-config.yml @@ -0,0 +1,42 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: mongodbSource + appId: 5032 + userName: mongodbSourceUser + passWord: mongodbPassWord +connectorConfig: + connectorName: mongodbSource + connectorType: STANDALONE + #mongodb://root:root@127.0.0.1:27018,127.0.0.1:27019 + url: mongodb://127.0.0.1:27018 + database: db + collection: col +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with connectorName + dataId: rocketmqSource, + #same with group + group: rocketmqSource + } \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/build.gradle b/eventmesh-connectors/eventmesh-connector-openfunction/build.gradle new file mode 100644 index 0000000000..5fc19090a7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/build.gradle @@ -0,0 +1,37 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + + implementation "io.grpc:grpc-core" + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty" + implementation "io.grpc:grpc-netty-shaded" + + api "com.fasterxml.jackson.core:jackson-databind" + api "com.fasterxml.jackson.core:jackson-core" + api "com.fasterxml.jackson.core:jackson-annotations" + + implementation "javax.annotation:javax.annotation-api:1.3.2" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/gradle.properties b/eventmesh-connectors/eventmesh-connector-openfunction/gradle.properties new file mode 100644 index 0000000000..cdcf52e5a8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=openfunction \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CallbackService.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CallbackService.java new file mode 100644 index 0000000000..2fda7c3293 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CallbackService.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.client; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; + +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Timestamp; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CallbackService extends CallbackServiceGrpc.CallbackServiceImplBase { + + @Override + public void onTopicEvent(CloudEvent cloudEvent, StreamObserver responseObserver) { + log.info("cloudevents: {}|data: {}", cloudEvent, cloudEvent.getTextData()); + + Instant instant = now(); + CloudEvent.Builder builder = CloudEvent.newBuilder(); + builder.putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, + CloudEventAttributeValue.newBuilder().setCeString(StatusCode.SUCCESS.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, + CloudEventAttributeValue.newBuilder().setCeString(StatusCode.SUCCESS.getErrMsg()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + responseObserver.onNext(builder.build()); + responseObserver.onCompleted(); + } + + private static Instant now() { + return OffsetDateTime.of(LocalDateTime.now(ZoneId.systemDefault()), ZoneOffset.UTC).toInstant(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CallbackServiceGrpc.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CallbackServiceGrpc.java new file mode 100644 index 0000000000..ddb2e650c2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CallbackServiceGrpc.java @@ -0,0 +1,270 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.client; + +import static io.grpc.MethodDescriptor.generateFullMethodName; +import static io.grpc.stub.ClientCalls.asyncUnaryCall; +import static io.grpc.stub.ClientCalls.blockingUnaryCall; +import static io.grpc.stub.ClientCalls.futureUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; + +/** + * + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.4.0)", + comments = "Source: callback-service.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class CallbackServiceGrpc { + + private CallbackServiceGrpc() { + } + + public static final String SERVICE_NAME = "org.apache.eventmesh.cloudevents.v1.CallbackService"; + + // Static method descriptors that strictly reflect the proto. + @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901") + public static final io.grpc.MethodDescriptor METHOD_ON_TOPIC_EVENT = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName( + "org.apache.eventmesh.cloudevents.v1.CallbackService", "OnTopicEvent")) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + CloudEvent.getDefaultInstance())) + .build(); + + /** + * Creates a new async stub that supports all call types for the service + */ + public static CallbackServiceStub newStub(io.grpc.Channel channel) { + return new CallbackServiceStub(channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static CallbackServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + return new CallbackServiceBlockingStub(channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static CallbackServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + return new CallbackServiceFutureStub(channel); + } + + /** + * + */ + public static abstract class CallbackServiceImplBase implements io.grpc.BindableService { + + /** + *
+         * Subscribes events
+         * 
+ */ + public void onTopicEvent(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(METHOD_ON_TOPIC_EVENT, responseObserver); + } + + @Override + public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + METHOD_ON_TOPIC_EVENT, + asyncUnaryCall( + new MethodHandlers< + CloudEvent, + CloudEvent>( + this, METHODID_ON_TOPIC_EVENT))) + .build(); + } + } + + /** + * + */ + public static final class CallbackServiceStub extends io.grpc.stub.AbstractStub { + + private CallbackServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private CallbackServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected CallbackServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { + return new CallbackServiceStub(channel, callOptions); + } + + /** + *
+         * Subscribes events
+         * 
+ */ + public void onTopicEvent(CloudEvent request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(METHOD_ON_TOPIC_EVENT, getCallOptions()), request, responseObserver); + } + } + + /** + * + */ + public static final class CallbackServiceBlockingStub extends io.grpc.stub.AbstractStub { + + private CallbackServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private CallbackServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected CallbackServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { + return new CallbackServiceBlockingStub(channel, callOptions); + } + + /** + *
+         * Subscribes events
+         * 
+ */ + public CloudEvent onTopicEvent( + CloudEvent request) { + return blockingUnaryCall( + getChannel(), METHOD_ON_TOPIC_EVENT, getCallOptions(), request); + } + } + + /** + * + */ + public static final class CallbackServiceFutureStub extends io.grpc.stub.AbstractStub { + + private CallbackServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private CallbackServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @Override + protected CallbackServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { + return new CallbackServiceFutureStub(channel, callOptions); + } + + /** + *
+         * Subscribes events
+         * 
+ */ + public com.google.common.util.concurrent.ListenableFuture onTopicEvent( + CloudEvent request) { + return futureUnaryCall( + getChannel().newCall(METHOD_ON_TOPIC_EVENT, getCallOptions()), request); + } + } + + private static final int METHODID_ON_TOPIC_EVENT = 0; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + + private final CallbackServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(CallbackServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @Override + @SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_ON_TOPIC_EVENT: + serviceImpl.onTopicEvent((CloudEvent) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + private static final class CallbackServiceDescriptorSupplier implements io.grpc.protobuf.ProtoFileDescriptorSupplier { + + @Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return EventMeshGrpcService.getDescriptor(); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (CallbackServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new CallbackServiceDescriptorSupplier()) + .addMethod(METHOD_ON_TOPIC_EVENT) + .build(); + } + } + } + return result; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CloudEventsPublishInstance.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CloudEventsPublishInstance.java new file mode 100644 index 0000000000..578fd53397 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CloudEventsPublishInstance.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.client; + +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventsPublishInstance { + + // This messageSize is also used in SubService.java (Subscriber) + public static final int MESSAGE_SIZE = 5; + + public static void main(String[] args) throws Exception { + + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig("FUNCTION_PRODUCER_GROUP"))) { + + final Map content = new HashMap<>(); + content.put("content", "testAsyncMessage"); + + for (int i = 0; i < MESSAGE_SIZE; i++) { + eventMeshGrpcProducer.publish(buildCloudEvent(content)); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + + ThreadUtils.sleep(30, TimeUnit.SECONDS); + } + } + + protected static EventMeshGrpcClientConfig initEventMeshGrpcClientConfig(final String groupName) throws IOException { + final String eventMeshIp = "127.0.0.1"; + final String eventMeshGrpcPort = "10110"; + + return EventMeshGrpcClientConfig.builder() + .serverAddr(eventMeshIp) + .serverPort(Integer.parseInt(eventMeshGrpcPort)) + .producerGroup(groupName) + .env("env") + .idc("idc") + .sys("1234") + .build(); + } + + protected static CloudEvent buildCloudEvent(final Map content) { + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSubject("TEST-TOPIC-FUNCTION") + .withSource(URI.create("/")) + .withDataContentType("application/cloudevents+json") + .withType(CLOUD_EVENTS_PROTOCOL_NAME) + .withData(JsonUtils.toJSONString(content).getBytes(StandardCharsets.UTF_8)) + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) + .build(); + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CloudEventsSubscribeInstance.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CloudEventsSubscribeInstance.java new file mode 100644 index 0000000000..d1e5c5affd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/CloudEventsSubscribeInstance.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.client; + +import io.grpc.Server; +import io.grpc.ServerBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventsSubscribeInstance { + + public static void main(String[] args) throws Exception { + Server server = ServerBuilder.forPort(10115).addService(new CallbackService()).build(); + server.start(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + server.shutdown(); + } catch (Exception e) { + log.error("exception when shutdown.", e); + } + })); + server.awaitTermination(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/EventMeshGrpcService.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/EventMeshGrpcService.java new file mode 100644 index 0000000000..b4c766e050 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/client/EventMeshGrpcService.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: callback-service.proto + +package org.apache.eventmesh.connector.openfunction.client; + +public final class EventMeshGrpcService { + + private EventMeshGrpcService() { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + + static { + String[] descriptorData = { + "\n\026callback-service.proto\022#org.apache.eve" + + "ntmesh.cloudevents.v1\032\033eventmesh-cloudev" + + "ents.proto\032\031google/protobuf/any.proto\032\037g" + + "oogle/protobuf/timestamp.proto2\203\001\n\017Callb" + + "ackService\022p\n\014OnTopicEvent\022/.org.apache." + + "eventmesh.cloudevents.v1.CloudEvent\032/.or" + + "g.apache.eventmesh.cloudevents.v1.CloudE" + + "ventBA\n)org.apache.eventmesh.connect.ope" + + "nfunctionB\024EventMeshGrpcServiceb\006proto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + org.apache.eventmesh.common.protocol.grpc.cloudevents.EventMeshCloudEvents.getDescriptor(), + com.google.protobuf.AnyProto.getDescriptor(), + com.google.protobuf.TimestampProto.getDescriptor(), + }, assigner); + org.apache.eventmesh.common.protocol.grpc.cloudevents.EventMeshCloudEvents.getDescriptor(); + com.google.protobuf.AnyProto.getDescriptor(); + com.google.protobuf.TimestampProto.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/config/OpenFunctionServerConfig.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/config/OpenFunctionServerConfig.java new file mode 100644 index 0000000000..b4ae607d5b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/config/OpenFunctionServerConfig.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class OpenFunctionServerConfig extends Config { + + private int serverPort; + + private boolean sourceEnable; + + private boolean sinkEnable; + + private String targetAddress; + + private int targetPort; + +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/server/OpenFunctionConnectServer.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/server/OpenFunctionConnectServer.java new file mode 100644 index 0000000000..18f5b604cc --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/server/OpenFunctionConnectServer.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.server; + +import org.apache.eventmesh.connector.openfunction.config.OpenFunctionServerConfig; +import org.apache.eventmesh.connector.openfunction.service.ConsumerService; +import org.apache.eventmesh.connector.openfunction.service.ProducerService; +import org.apache.eventmesh.connector.openfunction.sink.connector.OpenFunctionSinkConnector; +import org.apache.eventmesh.connector.openfunction.source.connector.OpenFunctionSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.api.connector.Connector; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.util.Map; + +import io.grpc.Server; +import io.grpc.ServerBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OpenFunctionConnectServer { + + private static Server server; + + public static void main(String[] args) throws Exception { + + OpenFunctionServerConfig serverConfig = ConfigUtil.parse(OpenFunctionServerConfig.class, "server-config.yml"); + + int serverPort = serverConfig.getServerPort(); + + ServerBuilder grpcServerBuilder = ServerBuilder.forPort(serverPort); + + if (serverConfig.isSourceEnable()) { + Application openFunctionSourceApp = new Application(); + openFunctionSourceApp.run(OpenFunctionSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application openFunctionSinkApp = new Application(); + openFunctionSinkApp.run(OpenFunctionSinkConnector.class); + } + + Map connectorMap = Application.CONNECTOR_MAP; + + for (Map.Entry entry : connectorMap.entrySet()) { + if (Application.isSource(entry.getValue().getClass())) { + grpcServerBuilder.addService(new ProducerService((OpenFunctionSourceConnector) entry.getValue(), serverConfig)); + } else if (Application.isSink(entry.getValue().getClass())) { + grpcServerBuilder.addService(new ConsumerService((OpenFunctionSinkConnector) entry.getValue(), serverConfig)); + } + } + server = grpcServerBuilder.build(); + server.start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + server.shutdown(); + } catch (Exception e) { + log.error("exception when shutdown.", e); + } + })); + server.awaitTermination(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/service/ConsumerService.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/service/ConsumerService.java new file mode 100644 index 0000000000..8ed8a65b46 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/service/ConsumerService.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.service; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.Builder; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc; +import org.apache.eventmesh.connector.openfunction.client.CallbackServiceGrpc; +import org.apache.eventmesh.connector.openfunction.client.CallbackServiceGrpc.CallbackServiceBlockingStub; +import org.apache.eventmesh.connector.openfunction.config.OpenFunctionServerConfig; +import org.apache.eventmesh.connector.openfunction.sink.connector.OpenFunctionSinkConnector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.StringUtils; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import io.cloudevents.SpecVersion; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ConsumerService extends ConsumerServiceGrpc.ConsumerServiceImplBase { + + private final OpenFunctionSinkConnector openFunctionSinkConnector; + + private final BlockingQueue queue; + + private final CallbackServiceBlockingStub publisherClient; + + public ConsumerService(OpenFunctionSinkConnector openFunctionSinkConnector, OpenFunctionServerConfig serverConfig) { + this.openFunctionSinkConnector = openFunctionSinkConnector; + this.queue = openFunctionSinkConnector.queue(); + ManagedChannel channel = ManagedChannelBuilder.forAddress(serverConfig.getTargetAddress(), + serverConfig.getTargetPort()).usePlaintext().build(); + this.publisherClient = CallbackServiceGrpc.newBlockingStub(channel); + ExecutorService handleService = Executors.newSingleThreadExecutor(); + handleService.execute(this::startHandleConsumeEvents); + } + + private void startHandleConsumeEvents() { + while (openFunctionSinkConnector.isRunning()) { + ConnectRecord connectRecord = queue.poll(); + if (connectRecord != null) { + CloudEvent response = publisherClient.onTopicEvent(convertRecordToEvent(connectRecord)); + } + } + + } + + private CloudEvent convertRecordToEvent(ConnectRecord connectRecord) { + Builder cloudEventBuilder = CloudEvent.newBuilder(); + cloudEventBuilder.setId(connectRecord.getExtension("id")); + cloudEventBuilder.setSource(connectRecord.getExtension("source")); + cloudEventBuilder.setSpecVersion(SpecVersion.V1.toString()); + cloudEventBuilder.setType(connectRecord.getExtension("type")); + cloudEventBuilder.setTextData(new String((byte[]) connectRecord.getData())); + for (String extensionKey : connectRecord.getExtensions().keySet()) { + if (!StringUtils.equalsAny(extensionKey, "id", "source", "type")) { + cloudEventBuilder.putAttributes(extensionKey, + CloudEventAttributeValue.newBuilder().setCeString(connectRecord.getExtension(extensionKey)).build()); + } + } + return cloudEventBuilder.build(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/service/ProducerService.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/service/ProducerService.java new file mode 100644 index 0000000000..df746e2ff8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/service/ProducerService.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.service; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.connector.openfunction.config.OpenFunctionServerConfig; +import org.apache.eventmesh.connector.openfunction.source.connector.OpenFunctionSourceConnector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.Objects; +import java.util.concurrent.BlockingQueue; + +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Timestamp; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ProducerService extends PublisherServiceGrpc.PublisherServiceImplBase { + + private final OpenFunctionSourceConnector openFunctionSourceConnector; + + private final BlockingQueue queue; + + private final OpenFunctionServerConfig config; + + public ProducerService(OpenFunctionSourceConnector openFunctionSourceConnector, OpenFunctionServerConfig serverConfig) { + this.openFunctionSourceConnector = openFunctionSourceConnector; + this.queue = openFunctionSourceConnector.queue(); + this.config = serverConfig; + } + + /** + * publish event to eventmesh + * + * @param event + * @param responseObserver + */ + @Override + public void publish(CloudEvent event, StreamObserver responseObserver) { + log.info("receive cloudevents {}", event); + Instant instant = now(); + CloudEvent.Builder builder = CloudEvent.newBuilder(); + ConnectRecord connectRecord = convertCloudEventToConnectorRecord(event); + try { + // put record to source connector + queue.put(connectRecord); + builder.putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, + CloudEventAttributeValue.newBuilder().setCeString(StatusCode.SUCCESS.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, + CloudEventAttributeValue.newBuilder().setCeString(StatusCode.SUCCESS.getErrMsg()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + } catch (InterruptedException e) { + log.error("publish event error {}", e.getMessage()); + builder.putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, + CloudEventAttributeValue.newBuilder().setCeString(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, + CloudEventAttributeValue.newBuilder().setCeString(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + Thread.currentThread().interrupt(); + } + + responseObserver.onNext(builder.build()); + responseObserver.onCompleted(); + + } + + private ConnectRecord convertCloudEventToConnectorRecord(CloudEvent event) { + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), event.getTextData()); + for (String extensionName : event.getAttributesMap().keySet()) { + connectRecord.addExtension(extensionName, Objects.requireNonNull(event.getAttributesOrThrow(extensionName)).getCeString()); + } + connectRecord.addExtension("id", event.getId()); + connectRecord.addExtension("source", event.getSource()); + connectRecord.addExtension("type", event.getType()); + return connectRecord; + } + + /** + * publish eventBatch to eventmesh + * + * @param eventBatch + * @param responseObserver + */ + @Override + public void batchPublish(CloudEventBatch eventBatch, StreamObserver responseObserver) { + + } + + private static Instant now() { + return OffsetDateTime.of(LocalDateTime.now(ZoneId.systemDefault()), ZoneOffset.UTC).toInstant(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/sink/connector/OpenFunctionSinkConnector.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/sink/connector/OpenFunctionSinkConnector.java new file mode 100644 index 0000000000..0f00a7e381 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/sink/connector/OpenFunctionSinkConnector.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.openfunction.OpenFunctionSinkConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OpenFunctionSinkConnector implements Sink { + + private OpenFunctionSinkConfig sinkConfig; + + private BlockingQueue queue; + + private volatile boolean isRunning = false; + + @Override + public Class configClass() { + return OpenFunctionSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for openfunction source connector + this.sinkConfig = (OpenFunctionSinkConfig) config; + this.queue = new LinkedBlockingQueue<>(1000); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for openfunction source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (OpenFunctionSinkConfig) sinkConnectorContext.getSinkConfig(); + this.queue = new LinkedBlockingQueue<>(1000); + } + + @Override + public void start() throws Exception { + isRunning = true; + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + try { + queue.put(connectRecord); + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[OpenFunctionSinkConnector] Interrupting thread {} due to exception {}", + currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } + } + } + + public BlockingQueue queue() { + return queue; + } + + public boolean isRunning() { + return isRunning; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/source/connector/OpenFunctionSourceConnector.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/source/connector/OpenFunctionSourceConnector.java new file mode 100644 index 0000000000..e40c451ff8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/java/org/apache/eventmesh/connector/openfunction/source/connector/OpenFunctionSourceConnector.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.openfunction.OpenFunctionSourceConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OpenFunctionSourceConnector implements Source { + + private OpenFunctionSourceConfig sourceConfig; + + private BlockingQueue queue; + + private int maxBatchSize; + + private long maxPollWaitTime; + + @Override + public Class configClass() { + return OpenFunctionSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for openfunction source connector + this.sourceConfig = (OpenFunctionSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + // init config for openfunction source connector + this.sourceConfig = (OpenFunctionSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + // init config for openfunction source connector + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + } + + @Override + public void start() throws Exception { + + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getSourceConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + + } + + public BlockingQueue queue() { + return queue; + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int count = 0; count < maxBatchSize; ++count) { + try { + ConnectRecord connectRecord = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (connectRecord == null) { + break; + } + connectRecords.add(connectRecord); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[OpenFunctionSourceConnector] Interrupting thread {} due to exception {}", + currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } + } + return connectRecords; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/callback-service.proto b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/callback-service.proto new file mode 100644 index 0000000000..b7e21d054f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/callback-service.proto @@ -0,0 +1,37 @@ +/* + * 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. + */ + +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "eventmesh-cloudevents.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option java_outer_classname = "EventMeshGrpcService"; +option java_package = "org.apache.eventmesh.connect.openfunction"; + +service CallbackService { + + // Subscribes events + rpc OnTopicEvent(CloudEvent) returns (CloudEvent); + +} + + + diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/eventmesh-cloudevents.proto b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/eventmesh-cloudevents.proto new file mode 100644 index 0000000000..37e07a0b40 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/eventmesh-cloudevents.proto @@ -0,0 +1,86 @@ +/* + * 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. + */ + + + +/** + * CloudEvent Protobuf Format + * + * - Required context attributes are explicitly represented. + * - Optional and Extension context attributes are carried in a map structure. + * - Data may be represented as binary, text, or protobuf messages. + */ + +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option java_package = "org.apache.eventmesh.common.protocol.grpc.cloudevents"; +option java_multiple_files = true; +option java_outer_classname = "EventMeshCloudEvents"; + + +message CloudEvent { + + // -- CloudEvent Context Attributes + + // Required Attributes + string id = 1; + string source = 2; // URI-reference + string spec_version = 3; + string type = 4; + + // Optional & Extension Attributes + map attributes = 5; + + // -- CloudEvent Data (Bytes, Text, or Proto) + oneof data { + bytes binary_data = 6; + string text_data = 7; + google.protobuf.Any proto_data = 8; + } + + /** + * The CloudEvent specification defines + * seven attribute value types... + */ + + message CloudEventAttributeValue { + + oneof attr { + bool ce_boolean = 1; + int32 ce_integer = 2; + string ce_string = 3; + bytes ce_bytes = 4; + string ce_uri = 5; + string ce_uri_ref = 6; + google.protobuf.Timestamp ce_timestamp = 7; + } + } +} + +/** + * CloudEvent Protobuf Batch Format + * + */ + +message CloudEventBatch { + repeated CloudEvent events = 1; +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/eventmesh-service.proto b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/eventmesh-service.proto new file mode 100644 index 0000000000..99d57bc514 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/proto/eventmesh-service.proto @@ -0,0 +1,58 @@ +/* + * 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. + */ +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "google/protobuf/empty.proto"; +import "eventmesh-cloudevents.proto"; + +option java_package = "org.apache.eventmesh.common.protocol.grpc.cloudevents"; +option java_multiple_files = true; +option java_outer_classname = "EventMeshGrpcService"; + + +service PublisherService { + //publish event + rpc publish(CloudEvent) returns (CloudEvent); + + //publish event with reply + rpc requestReply(CloudEvent) returns (CloudEvent); + + //publish event one way + rpc publishOneWay(CloudEvent) returns (google.protobuf.Empty); + + // publish batch event + rpc batchPublish(CloudEventBatch) returns (CloudEvent); + + //publish batch event one way + rpc batchPublishOneWay(CloudEventBatch) returns (google.protobuf.Empty); +} + +service ConsumerService { + // The subscribed event will be delivered by invoking the webhook url in the Subscription + rpc subscribe(CloudEvent) returns (CloudEvent); + + // The subscribed event will be delivered through stream of Message + rpc subscribeStream(stream CloudEvent) returns (stream CloudEvent); + + rpc unsubscribe(CloudEvent) returns (CloudEvent); +} + +service HeartbeatService { + rpc heartbeat(CloudEvent) returns (CloudEvent); +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/server-config.yml new file mode 100644 index 0000000000..83c94d164b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/server-config.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +serverPort: 10110 +sourceEnable: true +sinkEnable: true +targetAddress: 127.0.0.1 +targetPort: 10115 diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..659ed04920 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/sink-config.yml @@ -0,0 +1,29 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-FUNCTION + idc: FT + env: PRD + group: openFunctionSink + appId: 5031 + userName: openFunctionSinkUser + passWord: openFunctionPassWord +sinkConnectorConfig: + connectorName: openFunctionSink + target: 127.0.0.1:8080/openfunction diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/source-config.yml new file mode 100644 index 0000000000..1b75dcab42 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/main/resources/source-config.yml @@ -0,0 +1,28 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-FUNCTION + idc: FT + env: PRD + group: openFunctionSource + appId: 5031 + userName: openFunctionSourceUser + passWord: openFunctionPassWord +sourceConnectorConfig: + connectorName: openFunctionSource diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/test/java/org/apache/eventmesh/connector/openfunction/sink/connector/OpenFunctionSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/test/java/org/apache/eventmesh/connector/openfunction/sink/connector/OpenFunctionSinkConnectorTest.java new file mode 100644 index 0000000000..6751c0ec17 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/test/java/org/apache/eventmesh/connector/openfunction/sink/connector/OpenFunctionSinkConnectorTest.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.sink.connector; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.apache.eventmesh.common.config.connector.openfunction.OpenFunctionSinkConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class OpenFunctionSinkConnectorTest { + + private final OpenFunctionSinkConnector connector = new OpenFunctionSinkConnector(); + + @BeforeEach + public void setUp() throws Exception { + OpenFunctionSinkConfig sinkConfig = new OpenFunctionSinkConfig(); + connector.init(sinkConfig); + connector.start(); + } + + @Test + public void testSinkConnectorRunning() { + Assertions.assertTrue(connector.isRunning()); + } + + @Test + public void testOpenFunctionSinkConnector() throws Exception { + final int count = 5; + final String message = "testMessage"; + writeMockedRecords(count, message); + BlockingQueue queue = connector.queue(); + Assertions.assertEquals(count, queue.size()); + for (int i = 0; i < count; i++) { + ConnectRecord poll = queue.poll(); + assertNotNull(poll); + String expectedMessage = message + i; + Assertions.assertEquals(poll.getData(), expectedMessage); + } + } + + @AfterEach + public void shutdownConnector() { + connector.stop(); + } + + private void writeMockedRecords(int count, String message) throws Exception { + List records = new ArrayList<>(); + for (int i = 0; i < count; i++) { + records.add(new ConnectRecord(null, null, System.currentTimeMillis(), message + i)); + } + connector.put(records); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-openfunction/src/test/java/org/apache/eventmesh/connector/openfunction/source/connector/OpenFunctionSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-openfunction/src/test/java/org/apache/eventmesh/connector/openfunction/source/connector/OpenFunctionSourceConnectorTest.java new file mode 100644 index 0000000000..880ee701dc --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-openfunction/src/test/java/org/apache/eventmesh/connector/openfunction/source/connector/OpenFunctionSourceConnectorTest.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.openfunction.source.connector; + +import org.apache.eventmesh.common.config.connector.openfunction.OpenFunctionSourceConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.concurrent.BlockingQueue; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class OpenFunctionSourceConnectorTest { + + private final OpenFunctionSourceConnector connector = new OpenFunctionSourceConnector(); + + @Test + public void testSpringSourceConnector() throws Exception { + OpenFunctionSourceConfig sourceConfig = new OpenFunctionSourceConfig(); + connector.init(sourceConfig); + connector.start(); + final int count = 5; + final String message = "testMessage"; + writeMockedRecords(count, message); + List connectRecords = connector.poll(); + Assertions.assertEquals(count, connectRecords.size()); + for (int i = 0; i < connectRecords.size(); i++) { + Object actualMessage = String.valueOf(connectRecords.get(i).getData()); + String expectedMessage = "testMessage" + i; + Assertions.assertEquals(expectedMessage, actualMessage); + } + connector.stop(); + } + + private void writeMockedRecords(int count, String message) { + BlockingQueue queue = connector.queue(); + for (int i = 0; i < count; i++) { + ConnectRecord record = new ConnectRecord(null, null, System.currentTimeMillis(), message + i); + queue.offer(record); + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/build.gradle b/eventmesh-connectors/eventmesh-connector-pravega/build.gradle new file mode 100644 index 0000000000..24876409f1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/build.gradle @@ -0,0 +1,28 @@ +/* + * 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. + */ + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + + implementation("io.pravega:pravega-client:$pravega_version") + + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/gradle.properties b/eventmesh-connectors/eventmesh-connector-pravega/gradle.properties new file mode 100644 index 0000000000..a5ea881f6f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/gradle.properties @@ -0,0 +1,20 @@ +# 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. +# + +pravega_version=0.11.0 + +pluginType=connector +pluginName=pravega \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/client/PravegaCloudEventWriter.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/client/PravegaCloudEventWriter.java new file mode 100644 index 0000000000..e8f6e5cba5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/client/PravegaCloudEventWriter.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.client; + +import java.nio.charset.StandardCharsets; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import io.cloudevents.CloudEventData; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.message.MessageWriter; +import io.cloudevents.rw.CloudEventContextWriter; +import io.cloudevents.rw.CloudEventRWException; +import io.cloudevents.rw.CloudEventWriter; + +public class PravegaCloudEventWriter + implements MessageWriter, PravegaEvent>, CloudEventWriter { + + private final PravegaEvent pravegaEvent; + + public PravegaCloudEventWriter(String topic) { + pravegaEvent = new PravegaEvent(); + pravegaEvent.setTopic(topic); + pravegaEvent.setCreateTimestamp(System.currentTimeMillis()); + } + + @Override + public PravegaEvent setEvent(@Nullable EventFormat format, @Nonnull byte[] value) throws CloudEventRWException { + pravegaEvent.setData(new String(value, StandardCharsets.UTF_8)); + return pravegaEvent; + } + + @Override + public PravegaEvent end(CloudEventData data) throws CloudEventRWException { + pravegaEvent.setData(new String(data.toBytes(), StandardCharsets.UTF_8)); + return pravegaEvent; + } + + @Override + public PravegaEvent end() throws CloudEventRWException { + pravegaEvent.setData(""); + return pravegaEvent; + } + + @Override + public CloudEventContextWriter withContextAttribute(@Nonnull String name, @Nonnull String value) throws CloudEventRWException { + pravegaEvent.getExtensions().put(name, value); + return this; + } + + @Override + public CloudEventWriter create(SpecVersion version) throws CloudEventRWException { + pravegaEvent.setVersion(version); + return this; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/client/PravegaEvent.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/client/PravegaEvent.java new file mode 100644 index 0000000000..ce06e482e7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/client/PravegaEvent.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.client; + +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.io.Serializable; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import io.cloudevents.CloudEvent; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class PravegaEvent implements Serializable { + + private static final long serialVersionUID = 0L; + + private SpecVersion version; + private String topic; + private String data; + private Map extensions = new HashMap<>(); + private long createTimestamp; + + public static byte[] toByteArray(PravegaEvent pravegaEvent) { + return JsonUtils.toJSONString(pravegaEvent).getBytes(StandardCharsets.UTF_8); + } + + public static PravegaEvent getFromByteArray(byte[] body) { + return JsonUtils.parseObject(new String(body, StandardCharsets.UTF_8), PravegaEvent.class); + } + + public CloudEvent convertToCloudEvent() { + CloudEventBuilder builder = CloudEventBuilder.fromSpecVersion(version); + builder.withData(data.getBytes(StandardCharsets.UTF_8)) + .withId(extensions.remove("id")) + .withSource(URI.create(extensions.remove("source"))) + .withType(extensions.remove("type")) + .withDataContentType(extensions.remove("datacontenttype")) + .withSubject(extensions.remove("subject")); + extensions.forEach(builder::withExtension); + return builder.build(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/config/PravegaServerConfig.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/config/PravegaServerConfig.java new file mode 100644 index 0000000000..5945b4a7ae --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/config/PravegaServerConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PravegaServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/exception/PravegaConnectorException.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/exception/PravegaConnectorException.java new file mode 100644 index 0000000000..5a94f3a871 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/exception/PravegaConnectorException.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.exception; + +public class PravegaConnectorException extends Exception { + + public PravegaConnectorException(String message) { + super(message); + } + + public PravegaConnectorException(Throwable throwable) { + super(throwable); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/server/PravegaConnectServer.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/server/PravegaConnectServer.java new file mode 100644 index 0000000000..7501396162 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/server/PravegaConnectServer.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.server; + +import org.apache.eventmesh.connector.pravega.config.PravegaServerConfig; +import org.apache.eventmesh.connector.pravega.sink.connector.PravegaSinkConnector; +import org.apache.eventmesh.connector.pravega.source.connector.PravegaSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PravegaConnectServer { + + public static void main(String[] args) throws Exception { + + PravegaServerConfig serverConfig = ConfigUtil.parse(PravegaServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application pravegaSourceApp = new Application(); + pravegaSourceApp.run(PravegaSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application pravegaSinkApp = new Application(); + pravegaSinkApp.run(PravegaSinkConnector.class); + } + + } +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/sink/connector/PravegaSinkConnector.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/sink/connector/PravegaSinkConnector.java new file mode 100644 index 0000000000..e089ef6760 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/sink/connector/PravegaSinkConnector.java @@ -0,0 +1,163 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.pravega.PravegaSinkConfig; +import org.apache.eventmesh.connector.pravega.client.PravegaCloudEventWriter; +import org.apache.eventmesh.connector.pravega.client.PravegaEvent; +import org.apache.eventmesh.connector.pravega.exception.PravegaConnectorException; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; +import io.pravega.client.ClientConfig; +import io.pravega.client.EventStreamClientFactory; +import io.pravega.client.admin.StreamManager; +import io.pravega.client.stream.EventStreamWriter; +import io.pravega.client.stream.EventWriterConfig; +import io.pravega.client.stream.StreamConfiguration; +import io.pravega.client.stream.impl.ByteArraySerializer; +import io.pravega.shared.security.auth.DefaultCredentials; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PravegaSinkConnector implements Sink { + + private PravegaSinkConfig sinkConfig; + private StreamManager streamManager; + private EventStreamClientFactory clientFactory; + private final Map> writerMap = new ConcurrentHashMap<>(); + + private static final AtomicBoolean started = new AtomicBoolean(false); + + @Override + public Class configClass() { + return PravegaSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (PravegaSinkConfig) sinkConnectorContext.getSinkConfig(); + + streamManager = StreamManager.create(sinkConfig.getConnectorConfig().getControllerURI()); + + if (!streamManager.checkScopeExists(sinkConfig.getConnectorConfig().getScope())) { + streamManager.createScope(sinkConfig.getConnectorConfig().getScope()); + log.debug("scope[{}] is just created.", sinkConfig.getConnectorConfig().getScope()); + } + + ClientConfig.ClientConfigBuilder clientConfigBuilder = + ClientConfig.builder().controllerURI(sinkConfig.getConnectorConfig().getControllerURI()); + if (sinkConfig.getConnectorConfig().isAuthEnabled()) { + clientConfigBuilder.credentials( + new DefaultCredentials( + sinkConfig.getConnectorConfig().getPassword(), + sinkConfig.getConnectorConfig().getUsername())); + } + if (sinkConfig.getConnectorConfig().isTlsEnable()) { + clientConfigBuilder.trustStore(sinkConfig.getConnectorConfig().getTruststore()).validateHostName(false); + } + ClientConfig clientConfig = clientConfigBuilder.build(); + clientFactory = EventStreamClientFactory.withScope(sinkConfig.getConnectorConfig().getScope(), clientConfig); + } + + @Override + public void start() throws Exception { + started.compareAndSet(false, true); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + writerMap.forEach((topic, writer) -> writer.close()); + writerMap.clear(); + clientFactory.close(); + streamManager.close(); + started.compareAndSet(true, false); + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + CloudEvent cloudEvent = CloudEventUtil.convertRecordToEvent(connectRecord); + try { + publish(cloudEvent.getSubject(), cloudEvent); + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[PravegaSinkConnector] Interrupting thread {} due to exception {}", currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } catch (Exception e) { + log.error("[PravegaSinkConnector] sendResult has error : ", e); + } + } + } + + private void publish(String topic, CloudEvent cloudEvent) throws Exception { + if (!createStream(topic)) { + log.debug("stream[{}] has already been created.", topic); + } + + try (EventStreamWriter writer = writerMap.computeIfAbsent(topic, + k -> clientFactory.createEventWriter(topic, new ByteArraySerializer(), EventWriterConfig.builder().build()))) { + PravegaCloudEventWriter cloudEventWriter = new PravegaCloudEventWriter(topic); + PravegaEvent pravegaEvent = cloudEventWriter.writeBinary(cloudEvent); + writer.writeEvent(PravegaEvent.toByteArray(pravegaEvent)).get(5, TimeUnit.SECONDS); + } catch (ExecutionException | InterruptedException | TimeoutException e) { + log.error(String.format("Write topic[%s] fail.", topic), e); + throw new PravegaConnectorException(String.format("Write topic[%s] fail.", topic)); + } + } + + private boolean createStream(String topic) { + StreamConfiguration streamConfiguration = StreamConfiguration.builder().build(); + return streamManager.createStream(sinkConfig.getConnectorConfig().getScope(), topic, streamConfiguration); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/source/connector/PravegaSourceConnector.java b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/source/connector/PravegaSourceConnector.java new file mode 100644 index 0000000000..4b5e4751b3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/java/org/apache/eventmesh/connector/pravega/source/connector/PravegaSourceConnector.java @@ -0,0 +1,230 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pravega.source.connector; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.pravega.PravegaSourceConfig; +import org.apache.eventmesh.connector.pravega.client.PravegaEvent; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; +import io.pravega.client.ClientConfig; +import io.pravega.client.EventStreamClientFactory; +import io.pravega.client.admin.ReaderGroupManager; +import io.pravega.client.admin.StreamManager; +import io.pravega.client.stream.EventRead; +import io.pravega.client.stream.EventStreamReader; +import io.pravega.client.stream.ReaderConfig; +import io.pravega.client.stream.ReaderGroupConfig; +import io.pravega.client.stream.impl.ByteArraySerializer; +import io.pravega.shared.NameUtils; +import io.pravega.shared.security.auth.DefaultCredentials; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PravegaSourceConnector implements Source { + + private static final AtomicBoolean started = new AtomicBoolean(false); + + private PravegaSourceConfig sourceConfig; + + private StreamManager streamManager; + + private EventStreamClientFactory clientFactory; + + private ReaderGroupManager readerGroupManager; + + private final Map sourceHandlerMap = new ConcurrentHashMap<>(); + + private BlockingQueue queue; + + private int maxBatchSize; + + private long maxPollWaitTime; + + private final ThreadPoolExecutor executor = ThreadPoolFactory.createThreadPoolExecutor( + Runtime.getRuntime().availableProcessors() * 2, + Runtime.getRuntime().availableProcessors() * 2, + "EventMesh-RabbitMQSourceConnector-"); + + @Override + public Class configClass() { + return PravegaSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (PravegaSourceConfig) sourceConnectorContext.getSourceConfig(); + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + + streamManager = StreamManager.create(sourceConfig.getConnectorConfig().getControllerURI()); + ClientConfig.ClientConfigBuilder clientConfigBuilder = + ClientConfig.builder().controllerURI(sourceConfig.getConnectorConfig().getControllerURI()); + if (sourceConfig.getConnectorConfig().isAuthEnabled()) { + clientConfigBuilder.credentials( + new DefaultCredentials( + sourceConfig.getConnectorConfig().getPassword(), + sourceConfig.getConnectorConfig().getUsername())); + } + if (sourceConfig.getConnectorConfig().isTlsEnable()) { + clientConfigBuilder.trustStore(sourceConfig.getConnectorConfig().getTruststore()).validateHostName(false); + } + ClientConfig clientConfig = clientConfigBuilder.build(); + clientFactory = EventStreamClientFactory.withScope(sourceConfig.getConnectorConfig().getScope(), clientConfig); + readerGroupManager = ReaderGroupManager.withScope(sourceConfig.getConnectorConfig().getScope(), clientConfig); + + initReaders(); + } + + private void initReaders() { + streamManager.listStreams(sourceConfig.getConnectorConfig().getScope()) + .forEachRemaining(stream -> { + if (stream.getStreamName().startsWith("_")) { + return; + } + ReaderGroupConfig readerGroupConfig = + ReaderGroupConfig.builder() + .stream(NameUtils.getScopedStreamName(sourceConfig.getConnectorConfig().getScope(), stream.getStreamName())) + .retentionType(ReaderGroupConfig.StreamDataRetention.AUTOMATIC_RELEASE_AT_LAST_CHECKPOINT) + .build(); + readerGroupManager.createReaderGroup(stream.getStreamName(), readerGroupConfig); + + EventStreamReader reader = clientFactory.createReader( + "PravegaSourceConnector-reader", + stream.getStreamName(), + new ByteArraySerializer(), + ReaderConfig.builder().build()); + this.sourceHandlerMap.put(stream.getStreamName(), new PravegaSourceHandler(reader)); + }); + + } + + @Override + public void start() throws Exception { + sourceHandlerMap.forEach((topic, handler) -> executor.execute(handler)); + started.compareAndSet(false, true); + } + + @Override + public void commit(ConnectRecord record) { + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + sourceHandlerMap.forEach((topic, handler) -> { + readerGroupManager.deleteReaderGroup(topic); + handler.stop(); + }); + sourceHandlerMap.clear(); + readerGroupManager.close(); + clientFactory.close(); + streamManager.close(); + started.compareAndSet(true, false); + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int count = 0; count < maxBatchSize; ++count) { + try { + CloudEvent event = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (event == null) { + break; + } + connectRecords.add(CloudEventUtil.convertEventToRecord(event)); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + break; + } + } + return connectRecords; + } + + public class PravegaSourceHandler implements Runnable { + + private final EventStreamReader reader; + + private final AtomicBoolean running = new AtomicBoolean(true); + + public PravegaSourceHandler(EventStreamReader reader) { + this.reader = reader; + } + + @Override + public void run() { + while (running.get()) { + try { + EventRead event = reader.readNextEvent(2000); + + byte[] eventByteArray = event.getEvent(); + if (eventByteArray == null) { + continue; + } + PravegaEvent pravegaEvent = PravegaEvent.getFromByteArray(eventByteArray); + CloudEvent cloudEvent = pravegaEvent.convertToCloudEvent(); + queue.add(cloudEvent); + } catch (Exception ex) { + log.error("[PravegaSourceHandler] thread run happen exception.", ex); + } + } + } + + public void stop() { + running.compareAndSet(true, false); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..99bad33863 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/sink-config.yml @@ -0,0 +1,37 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: pravegaSink + appId: 5031 + userName: pravegaSinkUser + passWord: pravegaPassWord +connectorConfig: + connectorName: pravegaSink + controllerURI: tcp://127.0.0.1:9090 + scope: eventmesh-pravega + authEnabled: false + username: + password: + tlsEnabled: false + truststore: + clientPoolSize: 8 + queueSize: 512 diff --git a/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/source-config.yml new file mode 100644 index 0000000000..fe9fb81dcd --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pravega/src/main/resources/source-config.yml @@ -0,0 +1,46 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: pravegaSource + appId: 5032 + userName: pravegaSourceUser + passWord: pravegaPassWord +connectorConfig: + connectorName: pravegaSource + controllerURI: tcp://127.0.0.1:9090 + scope: eventmesh-pravega + authEnabled: false + username: + password: + tlsEnabled: false + truststore: + clientPoolSize: 8 + queueSize: 512 +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with connectorName + dataId: pravegaSource, + #same with group + group: pravegaSource + } diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/build.gradle b/eventmesh-connectors/eventmesh-connector-prometheus/build.gradle new file mode 100644 index 0000000000..97e4ed12f3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/build.gradle @@ -0,0 +1,26 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation 'org.apache.httpcomponents:httpclient' + implementation 'com.github.rholder:guava-retrying' + implementation 'com.alibaba.fastjson2:fastjson2' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/gradle.properties b/eventmesh-connectors/eventmesh-connector-prometheus/gradle.properties new file mode 100644 index 0000000000..d3e3811f5f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=prometheus \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/config/PrometheusServerConfig.java b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/config/PrometheusServerConfig.java new file mode 100644 index 0000000000..a238109c72 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/config/PrometheusServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.prometheus.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PrometheusServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/QueryPrometheusReq.java b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/QueryPrometheusReq.java new file mode 100644 index 0000000000..cdc1190afc --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/QueryPrometheusReq.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.prometheus.model; + +import lombok.Data; + +@Data +public class QueryPrometheusReq { + + private String query; + + private Long start; + + private Long end; + + private String step; +} diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/QueryPrometheusRsp.java b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/QueryPrometheusRsp.java new file mode 100644 index 0000000000..25a114767a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/QueryPrometheusRsp.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.prometheus.model; + +import lombok.Data; + +@Data +public class QueryPrometheusRsp { + + private String status; + + private ResponseData data; + +} diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/ResponseData.java b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/ResponseData.java new file mode 100644 index 0000000000..73e7a45b78 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/model/ResponseData.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.prometheus.model; + +import java.util.List; + +import lombok.Data; + +@Data +public class ResponseData { + + private String resultType; + + private List result; + +} diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/server/PrometheusConnectServer.java b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/server/PrometheusConnectServer.java new file mode 100644 index 0000000000..88f6c55725 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/server/PrometheusConnectServer.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.prometheus.server; + +import org.apache.eventmesh.connector.prometheus.config.PrometheusServerConfig; +import org.apache.eventmesh.connector.prometheus.source.connector.PrometheusSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PrometheusConnectServer { + + public static void main(String[] args) throws Exception { + + PrometheusServerConfig serverConfig = ConfigUtil.parse(PrometheusServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application prometheusSourceApp = new Application(); + prometheusSourceApp.run(PrometheusSourceConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/source/connector/PrometheusSourceConnector.java b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/source/connector/PrometheusSourceConnector.java new file mode 100644 index 0000000000..0cafed73f3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/java/org/apache/eventmesh/connector/prometheus/source/connector/PrometheusSourceConnector.java @@ -0,0 +1,200 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.prometheus.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.prometheus.PrometheusSourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.prometheus.PrometheusRecordOffset; +import org.apache.eventmesh.common.remote.offset.prometheus.PrometheusRecordPartition; +import org.apache.eventmesh.connector.prometheus.model.QueryPrometheusReq; +import org.apache.eventmesh.connector.prometheus.model.QueryPrometheusRsp; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; + +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.github.rholder.retry.Attempt; +import com.github.rholder.retry.RetryListener; +import com.github.rholder.retry.Retryer; +import com.github.rholder.retry.RetryerBuilder; +import com.github.rholder.retry.StopStrategies; +import com.github.rholder.retry.WaitStrategies; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PrometheusSourceConnector implements Source { + + private static final int MAX_RETRY_TIME = 3; + + private static final int FIXED_WAIT_SECOND = 1; + + private final Retryer retryer = + RetryerBuilder.newBuilder() + .retryIfException() + .retryIfResult(res -> !res) + .withWaitStrategy(WaitStrategies.fixedWait(FIXED_WAIT_SECOND, TimeUnit.SECONDS)) + .withStopStrategy(StopStrategies.stopAfterAttempt(MAX_RETRY_TIME)) + .withRetryListener( + new RetryListener() { + + @Override + public void onRetry(Attempt attempt) { + long times = attempt.getAttemptNumber(); + log.warn("retry invoke http,times={}", times); + } + }) + .build(); + + private PrometheusSourceConfig sourceConfig; + + private CloseableHttpClient httpClient; + + private QueryPrometheusReq queryPrometheusReq; + + private Long initTime; + + private Long startTime; + + private Integer interval; + + private String url; + + @Override + public Class configClass() { + return PrometheusSourceConfig.class; + } + + @Override + public void init(Config config) { + this.sourceConfig = (PrometheusSourceConfig) config; + + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (PrometheusSourceConfig) sourceConnectorContext.getSourceConfig(); + + doInit(); + } + + private void doInit() { + queryPrometheusReq = new QueryPrometheusReq(); + queryPrometheusReq.setQuery(sourceConfig.getConnectorConfig().getQuery()); + queryPrometheusReq.setStep(sourceConfig.getConnectorConfig().getStep()); + + interval = sourceConfig.getConnectorConfig().getInterval(); + initTime = sourceConfig.getConnectorConfig().getInitTime(); + + url = MessageFormat.format("{0}/{1}", sourceConfig.getConnectorConfig().getAddress(), sourceConfig.getConnectorConfig().getApi()); + + // TODO: replace with feature #4481 + httpClient = HttpClientBuilder.create().build(); + } + + @Override + public void start() { + log.info("prometheus source connector start."); + startTime = initTime != null ? initTime : System.currentTimeMillis() / 1000; + } + + @Override + public void commit(ConnectRecord record) { + startTime += interval; + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + log.info("prometheus source connector stop."); + } + + @Override + public List poll() { + try { + if (startTime > System.currentTimeMillis() / 1000 - interval) { + Thread.sleep(interval * 1000); + } + + AtomicReference response = null; + retryer.call(() -> { + try { + queryPrometheusReq.setStart(startTime); + queryPrometheusReq.setEnd(startTime + interval); + + HttpPost httpPost = new HttpPost(url); + httpPost.setEntity(new StringEntity(JSON.toJSONString(queryPrometheusReq), ContentType.APPLICATION_JSON)); + response.set(httpClient.execute(httpPost)); + return response.get().getStatusLine().getStatusCode() == HttpStatus.SC_OK; + } catch (Exception e) { + log.error("invoke http failed", e); + return false; + } + }); + + String result = EntityUtils.toString(response.get().getEntity(), StandardCharsets.UTF_8); + QueryPrometheusRsp responseData = JSONObject.parseObject(result, QueryPrometheusRsp.class); + List connectRecords = + responseData.getData().getResult().stream().map(this::assembleRecord).collect(Collectors.toList()); + + return connectRecords; + } catch (Exception e) { + log.error("failed to poll message from prometheus", e); + return null; + } + } + + private ConnectRecord assembleRecord(String data) { + Long timestamp = System.currentTimeMillis(); + RecordPartition recordPartition = new PrometheusRecordPartition(); + RecordOffset recordOffset = new PrometheusRecordOffset(); + + return new ConnectRecord(recordPartition, recordOffset, timestamp, data); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/resources/server-config.yml new file mode 100644 index 0000000000..0cd7b5b5ab --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: false diff --git a/eventmesh-connectors/eventmesh-connector-prometheus/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/resources/source-config.yml new file mode 100644 index 0000000000..5ad5e9bcc9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-prometheus/src/main/resources/source-config.yml @@ -0,0 +1,35 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: prometheusSource + appId: 5032 + userName: prometheusSourceUser + passWord: prometheusPassWord +connectorConfig: + connectorName: prometheusSource + connectorId: prometheusSourceId + address: https://127.0.0.1:9090 + api: /api/v1/query_range + initTime: 1237507200 + query: up + interval: 60 + step: 1s \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/build.gradle b/eventmesh-connectors/eventmesh-connector-pulsar/build.gradle new file mode 100644 index 0000000000..62ab590d89 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/build.gradle @@ -0,0 +1,42 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + + /* + * TODO: This is a shaded artifact that contains 20 MiB of external libraries. It could probably be replaced by: + * + * implementation "org.apache.pulsar:pulsar-client-api:$pulsar_version" + * runtimeOnly "org.apache.pulsar:pulsar-client-original:$pulsar_version" + * + * The exclusions can be removed after an upgrade of the transitive: + * + * "org.apache.bookkeeper:bookkeeper" + * + * dependency to 4.15.4 or higher (used by Pulsar 2.11.2 or higher). + */ + implementation("org.apache.pulsar:pulsar-client:$pulsar_version") { + // Remove logging backend implementations + exclude group: 'org.apache.logging.log4j', module: 'log4j-core' + exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' + } + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/gradle.properties b/eventmesh-connectors/eventmesh-connector-pulsar/gradle.properties new file mode 100644 index 0000000000..01e274d5fb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# +pulsar_version=2.11.1 +pluginType=connector +pluginName=pulsar \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/config/PulsarServerConfig.java b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/config/PulsarServerConfig.java new file mode 100644 index 0000000000..2c7e939259 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/config/PulsarServerConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pulsar.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; + +@Data +public class PulsarServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/server/PulsarConnectServer.java b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/server/PulsarConnectServer.java new file mode 100644 index 0000000000..c54e085900 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/server/PulsarConnectServer.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pulsar.server; + +import org.apache.eventmesh.connector.pulsar.config.PulsarServerConfig; +import org.apache.eventmesh.connector.pulsar.sink.connector.PulsarSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PulsarConnectServer { + + public static void main(String[] args) throws Exception { + + PulsarServerConfig serverConfig = ConfigUtil.parse(PulsarServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application rocketmqSourceApp = new Application(); + rocketmqSourceApp.run(PulsarSinkConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application rocketmqSinkApp = new Application(); + rocketmqSinkApp.run(PulsarSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/sink/connector/PulsarSinkConnector.java b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/sink/connector/PulsarSinkConnector.java new file mode 100644 index 0000000000..3f90c6c1be --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/sink/connector/PulsarSinkConnector.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pulsar.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.pulsar.PulsarSinkConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.pulsar.client.api.MessageId; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PulsarSinkConnector implements Sink { + + private PulsarSinkConfig sinkConfig; + + private Producer producer; + + @Override + public Class configClass() { + return PulsarSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for pulsar source connector + this.sinkConfig = (PulsarSinkConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for pulsar source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (PulsarSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + private void doInit() throws Exception { + PulsarClient client = PulsarClient.builder() + .serviceUrl(sinkConfig.getConnectorConfig().getServiceUrl()) + .build(); + producer = client.newProducer() + .topic(sinkConfig.getConnectorConfig().getTopic()) + .create(); + } + + @Override + public void start() throws Exception { + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + try { + producer.close(); + } catch (PulsarClientException e) { + log.error("close pulsar producer failed", e); + } + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + try { + Map props = new HashMap(); + for (String key : connectRecord.getExtensions().keySet()) { + props.put(key, connectRecord.getExtension(key)); + } + MessageId messageId = producer.newMessage() + .value((byte[]) connectRecord.getData()) + .properties(props) + .send(); + } catch (Exception e) { + log.error("put records to pulsar failed", e); + } + } + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/source/connector/PulsarSourceConnector.java b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/source/connector/PulsarSourceConnector.java new file mode 100644 index 0000000000..0bc576221e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/java/org/apache/eventmesh/connector/pulsar/source/connector/PulsarSourceConnector.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.pulsar.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.pulsar.PulsarSourceConfig; +import org.apache.eventmesh.common.remote.offset.pulsar.PulsarRecordPartition; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.client.api.Message; +import org.apache.pulsar.client.api.Messages; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PulsarSourceConnector implements Source { + + private PulsarSourceConfig sourceConfig; + + private Consumer consumer; + + @Override + public Class configClass() { + return PulsarSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for rocketmq source connector + this.sourceConfig = (PulsarSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (PulsarSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() throws Exception { + PulsarClient client = PulsarClient.builder() + .serviceUrl(sourceConfig.getConnectorConfig().getServiceUrl()) + .build(); + consumer = client.newConsumer() + .topic(sourceConfig.connectorConfig.getTopic()) + .subscriptionName(sourceConfig.getPubSubConfig().getGroup()) + .subscribe(); + } + + @Override + public void start() throws Exception { + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + try { + consumer.close(); + } catch (PulsarClientException e) { + log.error("close pulsar consumer failed", e); + } + } + + @Override + public List poll() { + List connectRecords = new ArrayList<>(); + try { + Messages messages = consumer.batchReceive(); + for (Object msg : messages) { + Long timestamp = System.currentTimeMillis(); + Message message = (Message) msg; + byte[] body = message.getData(); + String bodyStr = new String(body, StandardCharsets.UTF_8); + PulsarRecordPartition partition = new PulsarRecordPartition(); + partition.setTopic(consumer.getTopic()); + partition.setQueueId(message.getSequenceId()); + ConnectRecord connectRecord = new ConnectRecord(partition, null, timestamp, bodyStr); + connectRecord.addExtension("topic", consumer.getTopic()); + connectRecords.add(connectRecord); + } + consumer.acknowledge(messages); + } catch (PulsarClientException e) { + log.error("consumer msg from pulsar failed", e); + } + return connectRecords; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..e716e496da --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: pulsarSink + appId: 5031 + userName: pulsarSinkUser + passWord: pulsarPassWord +sinkConnectorConfig: + connectorName: pulsarSink + serviceUrl: 127.0.0.1:6650 + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/source-config.yml new file mode 100644 index 0000000000..c4bd62595d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-pulsar/src/main/resources/source-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: pulsarSource + appId: 5032 + userName: rocketmqSourceUser + passWord: rocketmqPassWord +sourceConnectorConfig: + connectorName: pulsarSource + serviceUrl: 127.0.0.1:6650 + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/build.gradle b/eventmesh-connectors/eventmesh-connector-rabbitmq/build.gradle new file mode 100644 index 0000000000..2693b681d0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/build.gradle @@ -0,0 +1,29 @@ +/* + * 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. + */ + + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + // rabbitmq + implementation 'com.rabbitmq:amqp-client:5.22.0' + + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/gradle.properties b/eventmesh-connectors/eventmesh-connector-rabbitmq/gradle.properties new file mode 100644 index 0000000000..b9fedf465a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=rabbitmq \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/client/RabbitmqClient.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/client/RabbitmqClient.java new file mode 100644 index 0000000000..1f324b5847 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/client/RabbitmqClient.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.client; + +import org.apache.commons.lang3.StringUtils; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RabbitmqClient { + + private final RabbitmqConnectionFactory rabbitmqConnectionFactory; + + public RabbitmqClient(RabbitmqConnectionFactory rabbitmqConnectionFactory) { + this.rabbitmqConnectionFactory = rabbitmqConnectionFactory; + } + + /** + * get rabbitmq connection + * + * @param host host + * @param username username + * @param passwd password + * @param port port + * @param virtualHost virtual host + * @return connection + * @throws Exception Exception + */ + public Connection getConnection(String host, String username, + String passwd, int port, + String virtualHost) throws Exception { + ConnectionFactory factory = rabbitmqConnectionFactory.createConnectionFactory(); + factory.setHost(host.trim()); + factory.setPort(port); + if (StringUtils.isNotEmpty(virtualHost)) { + factory.setVirtualHost(virtualHost.trim()); + } + factory.setUsername(username); + factory.setPassword(passwd.trim()); + + return rabbitmqConnectionFactory.createConnection(factory); + } + + /** + * send message + * + * @param channel channel + * @param exchangeName exchange name + * @param routingKey routing key + * @param message message + * @throws Exception Exception + */ + public void publish(Channel channel, String exchangeName, + String routingKey, byte[] message) throws Exception { + channel.basicPublish(exchangeName, routingKey, null, message); + } + + /** + * binding queue + * + * @param channel channel + * @param builtinExchangeType exchange type + * @param exchangeName exchange name + * @param routingKey routing key + * @param queueName queue name + */ + public void binding(Channel channel, BuiltinExchangeType builtinExchangeType, + String exchangeName, String routingKey, String queueName) { + try { + channel.exchangeDeclare(exchangeName, builtinExchangeType.getType(), true, + false, false, null); + channel.queueDeclare(queueName, false, false, + false, null); + routingKey = builtinExchangeType.getType().equals(BuiltinExchangeType.FANOUT.getType()) ? "" : routingKey; + channel.queueBind(queueName, exchangeName, routingKey); + } catch (Exception ex) { + log.error("[RabbitmqClient] binding happen exception.", ex); + } + } + + /** + * unbinding queue + * + * @param channel channel + * @param exchangeName exchange name + * @param routingKey routing key + * @param queueName queue name + */ + public void unbinding(Channel channel, String exchangeName, String routingKey, String queueName) { + try { + channel.queueUnbind(queueName, exchangeName, routingKey); + } catch (Exception ex) { + log.error("[RabbitmqClient] unbinding happen exception.", ex); + } + } + + /** + * close connection + * + * @param connection connection + */ + public void closeConnection(Connection connection) { + if (connection != null) { + try { + connection.close(); + } catch (Exception ex) { + log.error("[RabbitmqClient] connection close happen exception.", ex); + } + } + } + + /** + * close channel + * + * @param channel channel + */ + public void closeChannel(Channel channel) { + if (channel != null) { + try { + channel.close(); + } catch (Exception ex) { + log.error("[RabbitmqClient] channel close happen exception.", ex); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/client/RabbitmqConnectionFactory.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/client/RabbitmqConnectionFactory.java new file mode 100644 index 0000000000..82f6b929e3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/client/RabbitmqConnectionFactory.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.client; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class RabbitmqConnectionFactory { + + public ConnectionFactory createConnectionFactory() { + return new ConnectionFactory(); + } + + public Connection createConnection(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + return connectionFactory.newConnection(); + } + + public Channel createChannel(Connection connection) throws IOException { + return connection.createChannel(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/cloudevent/RabbitmqCloudEvent.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/cloudevent/RabbitmqCloudEvent.java new file mode 100644 index 0000000000..06eced2ae5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/cloudevent/RabbitmqCloudEvent.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.cloudevent; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.rabbitmq.exception.RabbitmqConnectorException; +import org.apache.eventmesh.connector.rabbitmq.utils.ByteArrayUtils; + +import java.io.Serializable; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import io.cloudevents.CloudEvent; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class RabbitmqCloudEvent implements Serializable { + + private SpecVersion version; + private String data; + private Map extensions = new HashMap<>(); + + public CloudEvent convertToCloudEvent() throws Exception { + CloudEventBuilder builder; + switch (version) { + case V03: + builder = CloudEventBuilder.v03(); + break; + case V1: + builder = CloudEventBuilder.v1(); + break; + default: + throw new RabbitmqConnectorException(String.format("CloudEvent version %s does not support.", version)); + } + builder.withData(data.getBytes(StandardCharsets.UTF_8)) + .withId(extensions.remove("id")) + .withSource(URI.create(extensions.remove("source"))) + .withType(extensions.remove("type")) + .withDataContentType(extensions.remove("datacontenttype")) + .withSubject(extensions.remove("subject")); + extensions.forEach(builder::withExtension); + + return builder.build(); + } + + public static byte[] toByteArray(RabbitmqCloudEvent rabbitmqCloudEvent) throws Exception { + Optional optionalBytes = ByteArrayUtils.objectToBytes(rabbitmqCloudEvent); + return optionalBytes.orElseGet(() -> new byte[]{}); + } + + public static RabbitmqCloudEvent getFromByteArray(byte[] body) { + return JsonUtils.parseTypeReferenceObject(new String(body, Constants.DEFAULT_CHARSET), new TypeReference() { + }); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/cloudevent/RabbitmqCloudEventWriter.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/cloudevent/RabbitmqCloudEventWriter.java new file mode 100644 index 0000000000..a82cbc9e3c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/cloudevent/RabbitmqCloudEventWriter.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.cloudevent; + +import java.nio.charset.StandardCharsets; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import io.cloudevents.CloudEventData; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.message.MessageWriter; +import io.cloudevents.rw.CloudEventContextWriter; +import io.cloudevents.rw.CloudEventRWException; +import io.cloudevents.rw.CloudEventWriter; + +public class RabbitmqCloudEventWriter + implements MessageWriter, RabbitmqCloudEvent>, CloudEventWriter { + + private final RabbitmqCloudEvent rabbitmqCloudEvent; + + public RabbitmqCloudEventWriter() { + rabbitmqCloudEvent = new RabbitmqCloudEvent(); + } + + @Override + public RabbitmqCloudEvent setEvent(@Nullable EventFormat format, @Nonnull byte[] value) throws CloudEventRWException { + rabbitmqCloudEvent.setData(new String(value, StandardCharsets.UTF_8)); + return rabbitmqCloudEvent; + } + + @Override + public RabbitmqCloudEvent end(CloudEventData data) throws CloudEventRWException { + rabbitmqCloudEvent.setData(new String(data.toBytes(), StandardCharsets.UTF_8)); + return rabbitmqCloudEvent; + } + + @Override + public RabbitmqCloudEvent end() throws CloudEventRWException { + rabbitmqCloudEvent.setData(""); + return rabbitmqCloudEvent; + } + + @Override + public CloudEventContextWriter withContextAttribute(@Nonnull String name, @Nonnull String value) throws CloudEventRWException { + rabbitmqCloudEvent.getExtensions().put(name, value); + return this; + } + + @Override + public CloudEventWriter create(SpecVersion version) throws CloudEventRWException { + rabbitmqCloudEvent.setVersion(version); + return this; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/config/RabbitMQServerConfig.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/config/RabbitMQServerConfig.java new file mode 100644 index 0000000000..27b89c62e5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/config/RabbitMQServerConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RabbitMQServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/exception/RabbitmqConnectorException.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/exception/RabbitmqConnectorException.java new file mode 100644 index 0000000000..c107277a2c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/exception/RabbitmqConnectorException.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.exception; + +public class RabbitmqConnectorException extends Exception { + + public RabbitmqConnectorException(String message) { + super(message); + } + + public RabbitmqConnectorException(Throwable throwable) { + super(throwable); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/server/RabbitMQConnectorServer.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/server/RabbitMQConnectorServer.java new file mode 100644 index 0000000000..529392c327 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/server/RabbitMQConnectorServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.server; + +import org.apache.eventmesh.connector.rabbitmq.config.RabbitMQServerConfig; +import org.apache.eventmesh.connector.rabbitmq.sink.connector.RabbitMQSinkConnector; +import org.apache.eventmesh.connector.rabbitmq.source.connector.RabbitMQSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RabbitMQConnectorServer { + + public static void main(String[] args) throws Exception { + + RabbitMQServerConfig serverConfig = ConfigUtil.parse(RabbitMQServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application rabbitmqSourceApp = new Application(); + rabbitmqSourceApp.run(RabbitMQSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application rabbitmqSinkApp = new Application(); + rabbitmqSinkApp.run(RabbitMQSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/sink/connector/RabbitMQSinkConnector.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/sink/connector/RabbitMQSinkConnector.java new file mode 100644 index 0000000000..08d1cefbac --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/sink/connector/RabbitMQSinkConnector.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.rabbitmq.RabbitMQSinkConfig; +import org.apache.eventmesh.connector.rabbitmq.client.RabbitmqClient; +import org.apache.eventmesh.connector.rabbitmq.client.RabbitmqConnectionFactory; +import org.apache.eventmesh.connector.rabbitmq.cloudevent.RabbitmqCloudEvent; +import org.apache.eventmesh.connector.rabbitmq.cloudevent.RabbitmqCloudEventWriter; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.List; + +import io.cloudevents.CloudEvent; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RabbitMQSinkConnector implements Sink { + + private RabbitMQSinkConfig sinkConfig; + + private final RabbitmqConnectionFactory rabbitmqConnectionFactory = new RabbitmqConnectionFactory(); + + private RabbitmqClient rabbitmqClient; + + private Connection connection; + + private Channel channel; + + private volatile boolean started = false; + + @Override + public Class configClass() { + return RabbitMQSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + this.sinkConfig = (RabbitMQSinkConfig) ((SinkConnectorContext) connectorContext).getSinkConfig(); + this.rabbitmqClient = new RabbitmqClient(rabbitmqConnectionFactory); + this.connection = rabbitmqClient.getConnection(sinkConfig.getConnectorConfig().getHost(), + sinkConfig.getConnectorConfig().getUsername(), + sinkConfig.getConnectorConfig().getPasswd(), + sinkConfig.getConnectorConfig().getPort(), + sinkConfig.getConnectorConfig().getVirtualHost()); + this.channel = rabbitmqConnectionFactory.createChannel(connection); + } + + @Override + public void start() throws Exception { + if (!started) { + BuiltinExchangeType builtinExchangeType = BuiltinExchangeType.valueOf(sinkConfig.getConnectorConfig().getExchangeType()); + rabbitmqClient.binding(channel, builtinExchangeType, sinkConfig.getConnectorConfig().getExchangeName(), + sinkConfig.getConnectorConfig().getRoutingKey(), sinkConfig.getConnectorConfig().getQueueName()); + started = true; + } + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + if (started) { + try { + rabbitmqClient.closeConnection(connection); + rabbitmqClient.closeChannel(channel); + } finally { + started = false; + } + } + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + CloudEvent event = CloudEventUtil.convertRecordToEvent(connectRecord); + try { + RabbitmqCloudEventWriter writer = new RabbitmqCloudEventWriter(); + RabbitmqCloudEvent rabbitmqCloudEvent = writer.writeBinary(event); + byte[] data = RabbitmqCloudEvent.toByteArray(rabbitmqCloudEvent); + rabbitmqClient.publish(channel, sinkConfig.getConnectorConfig().getExchangeName(), + sinkConfig.getConnectorConfig().getRoutingKey(), data); + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[RabbitMQSinkConnector] Interrupting thread {} due to exception {}", + currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } catch (Exception e) { + log.error("[RabbitMQSinkConnector] sendResult has error : ", e); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/source/connector/RabbitMQSourceConnector.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/source/connector/RabbitMQSourceConnector.java new file mode 100644 index 0000000000..a19b159c1c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/source/connector/RabbitMQSourceConnector.java @@ -0,0 +1,204 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.source.connector; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.rabbitmq.RabbitMQSourceConfig; +import org.apache.eventmesh.common.config.connector.mq.rabbitmq.SourceConnectorConfig; +import org.apache.eventmesh.connector.rabbitmq.client.RabbitmqClient; +import org.apache.eventmesh.connector.rabbitmq.client.RabbitmqConnectionFactory; +import org.apache.eventmesh.connector.rabbitmq.cloudevent.RabbitmqCloudEvent; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.GetResponse; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RabbitMQSourceConnector implements Source { + + private RabbitMQSourceConfig sourceConfig; + + private volatile boolean started = false; + + private BlockingQueue queue; + + private int maxBatchSize; + + private long maxPollWaitTime; + + private final RabbitmqConnectionFactory rabbitmqConnectionFactory = new RabbitmqConnectionFactory(); + + private RabbitMQSourceHandler rabbitMQSourceHandler; + + private RabbitmqClient rabbitmqClient; + + private Connection connection; + + private Channel channel; + + private final ThreadPoolExecutor executor = ThreadPoolFactory.createThreadPoolExecutor( + Runtime.getRuntime().availableProcessors() * 2, + Runtime.getRuntime().availableProcessors() * 2, + "EventMesh-RabbitMQSourceConnector-"); + + @Override + public Class configClass() { + return RabbitMQSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + this.sourceConfig = (RabbitMQSourceConfig) ((SourceConnectorContext) connectorContext).getSourceConfig(); + this.rabbitmqClient = new RabbitmqClient(rabbitmqConnectionFactory); + this.connection = rabbitmqClient.getConnection(sourceConfig.getConnectorConfig().getHost(), + sourceConfig.getConnectorConfig().getUsername(), + sourceConfig.getConnectorConfig().getPasswd(), + sourceConfig.getConnectorConfig().getPort(), + sourceConfig.getConnectorConfig().getVirtualHost()); + this.channel = rabbitmqConnectionFactory.createChannel(connection); + this.rabbitMQSourceHandler = new RabbitMQSourceHandler(channel, sourceConfig.getConnectorConfig()); + } + + @Override + public void start() throws Exception { + if (!started) { + BuiltinExchangeType builtinExchangeType = BuiltinExchangeType.valueOf(sourceConfig.getConnectorConfig().getExchangeType()); + rabbitmqClient.binding(channel, builtinExchangeType, sourceConfig.getConnectorConfig().getExchangeName(), + sourceConfig.getConnectorConfig().getRoutingKey(), sourceConfig.getConnectorConfig().getQueueName()); + executor.execute(this.rabbitMQSourceHandler); + started = true; + } + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + if (started) { + try { + rabbitmqClient.unbinding(channel, sourceConfig.getConnectorConfig().getExchangeName(), + sourceConfig.getConnectorConfig().getRoutingKey(), sourceConfig.getConnectorConfig().getQueueName()); + rabbitmqClient.closeConnection(connection); + rabbitmqClient.closeChannel(channel); + rabbitMQSourceHandler.stop(); + } finally { + started = false; + } + } + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int count = 0; count < maxBatchSize; ++count) { + try { + CloudEvent event = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (event == null) { + break; + } + connectRecords.add(CloudEventUtil.convertEventToRecord(event)); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + break; + } + } + return connectRecords; + } + + public class RabbitMQSourceHandler implements Runnable { + + private final Channel channel; + private final SourceConnectorConfig connectorConfig; + private final AtomicBoolean stop = new AtomicBoolean(false); + + public RabbitMQSourceHandler(Channel channel, SourceConnectorConfig connectorConfig) { + this.channel = channel; + this.connectorConfig = connectorConfig; + } + + @Override + public void run() { + while (!stop.get()) { + try { + GetResponse response = channel.basicGet(connectorConfig.getQueueName(), connectorConfig.isAutoAck()); + if (response != null) { + RabbitmqCloudEvent rabbitmqCloudEvent = RabbitmqCloudEvent.getFromByteArray(response.getBody()); + CloudEvent event = rabbitmqCloudEvent.convertToCloudEvent(); + if (event != null) { + queue.add(event); + } + if (!connectorConfig.isAutoAck()) { + channel.basicAck(response.getEnvelope().getDeliveryTag(), false); + } + } + } catch (Exception ex) { + log.error("[RabbitMQSourceHandler] thread run happen exception.", ex); + } + } + } + + public void stop() { + stop.compareAndSet(false, true); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/utils/ByteArrayUtils.java b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/utils/ByteArrayUtils.java new file mode 100644 index 0000000000..57f9423258 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/java/org/apache/eventmesh/connector/rabbitmq/utils/ByteArrayUtils.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rabbitmq.utils; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.io.IOException; +import java.util.Optional; + +import com.fasterxml.jackson.core.type.TypeReference; + +@SuppressWarnings("all") +public class ByteArrayUtils { + + public static Optional objectToBytes(T obj) throws IOException { + String s = JsonUtils.toJSONString(obj); + byte[] bytes = s.getBytes(Constants.DEFAULT_CHARSET); + return Optional.ofNullable(bytes); + } + + public static Optional bytesToObject(byte[] bytes) throws IOException, ClassNotFoundException { + T t = JsonUtils.parseTypeReferenceObject(new String(bytes, Constants.DEFAULT_CHARSET), new TypeReference() { + }); + return Optional.ofNullable(t); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..f4eea14c79 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/sink-config.yml @@ -0,0 +1,38 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rabbitmqSink + appId: 5031 + userName: rabbitmqSinkUser + passWord: rabbitmqPassWord +connectorConfig: + connectorName: rabbitmqSink + host: + port: + username: + passwd: + virtualHost: + exchangeType: TOPIC + exchangeName: + routingKey: + queueName: + autoAck: true diff --git a/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/source-config.yml new file mode 100644 index 0000000000..bc0fdfeda5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rabbitmq/src/main/resources/source-config.yml @@ -0,0 +1,47 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rabbitmqSource + appId: 5032 + userName: rabbitmqSourceUser + passWord: rabbitmqPassWord +connectorConfig: + connectorName: rabbitmqSource + host: + port: + username: + passwd: + virtualHost: + exchangeType: TOPIC + exchangeName: + routingKey: + queueName: + autoAck: true +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with connectorName + dataId: rabbitmqSource, + #same with group + group: rabbitmqSource + } diff --git a/eventmesh-connectors/eventmesh-connector-redis/build.gradle b/eventmesh-connectors/eventmesh-connector-redis/build.gradle new file mode 100644 index 0000000000..fabfe1c983 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/build.gradle @@ -0,0 +1,31 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + + implementation 'org.redisson:redisson:3.38.1' + + api 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'ai.grakn:redis-mock:0.1.6' + testImplementation project(":eventmesh-common") +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-redis/gradle.properties b/eventmesh-connectors/eventmesh-connector-redis/gradle.properties new file mode 100644 index 0000000000..88d5964c29 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=redis \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/cloudevent/CloudEventCodec.java b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/cloudevent/CloudEventCodec.java new file mode 100644 index 0000000000..8fb347354d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/cloudevent/CloudEventCodec.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.cloudevent; + +import org.redisson.client.codec.BaseCodec; +import org.redisson.client.protocol.Decoder; +import org.redisson.client.protocol.Encoder; + +import io.cloudevents.CloudEvent; +import io.cloudevents.jackson.JsonFormat; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +/** + * TODO: Duplicate with org.apache.eventmesh.storage.redis.cloudevent.CloudEventCodec + */ +public class CloudEventCodec extends BaseCodec { + + private static final CloudEventCodec INSTANCE = new CloudEventCodec(); + + private static final JsonFormat jsonFormat = new JsonFormat(false, true); + + private CloudEventCodec() { + // To prevent class instantiation + } + + public static CloudEventCodec getInstance() { + return INSTANCE; + } + + private static final Encoder encoder = in -> { + ByteBuf out = ByteBufAllocator.DEFAULT.buffer(); + if (in instanceof CloudEvent) { + out.writeBytes(jsonFormat.serialize((CloudEvent) in)); + return out; + } + throw new IllegalStateException("Illegal object type: " + in.getClass().getSimpleName()); + }; + + private static final Decoder decoder = (buf, state) -> { + final byte[] bytes = new byte[buf.readableBytes()]; + buf.getBytes(buf.readerIndex(), bytes); + return jsonFormat.deserialize(bytes); + }; + + @Override + public Decoder getValueDecoder() { + return decoder; + } + + @Override + public Encoder getValueEncoder() { + return encoder; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/config/RedisServerConfig.java b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/config/RedisServerConfig.java new file mode 100644 index 0000000000..d4aaee292a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/config/RedisServerConfig.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; + +@Data +public class RedisServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/server/RedisConnectServer.java b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/server/RedisConnectServer.java new file mode 100644 index 0000000000..c9abdb5ee7 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/server/RedisConnectServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.server; + +import org.apache.eventmesh.connector.redis.config.RedisServerConfig; +import org.apache.eventmesh.connector.redis.sink.connector.RedisSinkConnector; +import org.apache.eventmesh.connector.redis.source.connector.RedisSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RedisConnectServer { + + public static void main(String[] args) throws Exception { + + RedisServerConfig serverConfig = ConfigUtil.parse(RedisServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application redisSourceApp = new Application(); + redisSourceApp.run(RedisSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application redisSinkApp = new Application(); + redisSinkApp.run(RedisSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/sink/connector/RedisSinkConnector.java b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/sink/connector/RedisSinkConnector.java new file mode 100644 index 0000000000..5b7d27c3ba --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/sink/connector/RedisSinkConnector.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.redis.RedisSinkConfig; +import org.apache.eventmesh.connector.redis.cloudevent.CloudEventCodec; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.List; + +import org.redisson.Redisson; +import org.redisson.api.RTopic; +import org.redisson.api.RedissonClient; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RedisSinkConnector implements Sink { + + private RTopic topic; + + private RedisSinkConfig sinkConfig; + + private RedissonClient redissonClient; + + @Override + public Class configClass() { + return RedisSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.sinkConfig = (RedisSinkConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (RedisSinkConfig) sinkConnectorContext.getSinkConfig(); + doInit(); + } + + private void doInit() { + org.redisson.config.Config redisConfig = new org.redisson.config.Config(); + redisConfig.useSingleServer().setAddress(sinkConfig.connectorConfig.getServer()); + redisConfig.setCodec(CloudEventCodec.getInstance()); + this.redissonClient = Redisson.create(redisConfig); + } + + @Override + public void start() throws Exception { + this.topic = redissonClient.getTopic(sinkConfig.connectorConfig.getTopic()); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + this.redissonClient.shutdown(); + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + CloudEvent event = CloudEventUtil.convertRecordToEvent(connectRecord); + try { + long publish = topic.publish(event); + } catch (Exception e) { + log.error("[RedisSinkConnector] sendResult has error : ", e); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/source/connector/RedisSourceConnector.java b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/source/connector/RedisSourceConnector.java new file mode 100644 index 0000000000..5b858afa30 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/java/org/apache/eventmesh/connector/redis/source/connector/RedisSourceConnector.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.redis.RedisSourceConfig; +import org.apache.eventmesh.connector.redis.cloudevent.CloudEventCodec; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.redisson.Redisson; +import org.redisson.api.RTopic; +import org.redisson.api.RedissonClient; + +import io.cloudevents.CloudEvent; + +public class RedisSourceConnector implements Source { + + private RTopic topic; + + private RedisSourceConfig sourceConfig; + + private RedissonClient redissonClient; + + private BlockingQueue queue; + + private int maxBatchSize; + + private long maxPollWaitTime; + + @Override + public Class configClass() { + return RedisSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + this.sourceConfig = (RedisSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (RedisSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + org.redisson.config.Config redisConfig = new org.redisson.config.Config(); + redisConfig.useSingleServer().setAddress(sourceConfig.connectorConfig.getServer()); + redisConfig.setCodec(CloudEventCodec.getInstance()); + this.redissonClient = Redisson.create(redisConfig); + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + } + + @Override + public void start() throws Exception { + this.topic = redissonClient.getTopic(sourceConfig.connectorConfig.getTopic()); + this.topic.addListener(CloudEvent.class, (channel, msg) -> { + queue.add(msg); + }); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + this.topic.removeAllListeners(); + this.redissonClient.shutdown(); + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int count = 0; count < maxBatchSize; ++count) { + try { + CloudEvent event = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (event == null) { + break; + } + connectRecords.add(CloudEventUtil.convertEventToRecord(event)); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + break; + } + } + return connectRecords; + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..596006a2a1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/sink-config.yml @@ -0,0 +1,31 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: redisSink + appId: 5031 + userName: redisSinkUser + passWord: redisPassWord +connectorConfig: + connectorName: redisSink + server: redis://127.0.0.1:6379 + topic: SinkTopic + diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/source-config.yml new file mode 100644 index 0000000000..5d31ad0fcb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/main/resources/source-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: redisSource + appId: 5032 + userName: redisSourceUser + passWord: redisPassWord +connectorConfig: + connectorName: redisSource + server: redis://127.0.0.1:6379 + topic: SourceTopic diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/AbstractRedisServer.java b/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/AbstractRedisServer.java new file mode 100644 index 0000000000..46272496f4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/AbstractRedisServer.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis; + +import ai.grakn.redismock.RedisServer; + +public abstract class AbstractRedisServer { + + protected RedisServer redisServer; + + public void setupRedisServer(int port) throws Exception { + redisServer = RedisServer.newRedisServer(port); + redisServer.start(); + } + + public void shutdownRedisServer() { + if (redisServer != null) { + redisServer.stop(); + } + } + + public static int getPortFromUrl(String url) { + return Integer.parseInt(url.substring(url.lastIndexOf(":") + 1)); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/sink/connector/RedisSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/sink/connector/RedisSinkConnectorTest.java new file mode 100644 index 0000000000..c4d153bd25 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/sink/connector/RedisSinkConnectorTest.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.sink.connector; + +import org.apache.eventmesh.common.config.connector.redis.RedisSinkConfig; +import org.apache.eventmesh.connector.redis.AbstractRedisServer; +import org.apache.eventmesh.connector.redis.cloudevent.CloudEventCodec; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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.redisson.Redisson; +import org.redisson.api.RTopic; +import org.redisson.config.Config; + +import io.cloudevents.CloudEvent; + +public class RedisSinkConnectorTest extends AbstractRedisServer { + + private RedisSinkConnector connector; + + private Redisson redisson; + + private RedisSinkConfig sinkConfig; + + @BeforeEach + public void setUp() throws Exception { + connector = new RedisSinkConnector(); + sinkConfig = (RedisSinkConfig) ConfigUtil.parse(connector.configClass()); + setupRedisServer(getPortFromUrl(sinkConfig.getConnectorConfig().getServer())); + connector.init(sinkConfig); + connector.start(); + Config config = new Config(); + config.setCodec(CloudEventCodec.getInstance()); + config.useSingleServer() + .setAddress(sinkConfig.getConnectorConfig().getServer()); + redisson = (Redisson) Redisson.create(config); + } + + @Test + public void testPutConnectRecords() throws InterruptedException { + RTopic topic = redisson.getTopic(sinkConfig.connectorConfig.getTopic()); + + final String expectedMessage = "\"testRedisMessage\""; + final int expectedCount = 5; + final CountDownLatch downLatch = new CountDownLatch(expectedCount); + topic.addListener(CloudEvent.class, (channel, msg) -> { + downLatch.countDown(); + Assertions.assertNotNull(msg.getData()); + Assertions.assertEquals(expectedMessage, new String(msg.getData().toBytes())); + }); + + List records = new ArrayList<>(); + for (int i = 0; i < expectedCount; i++) { + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), + expectedMessage.getBytes(StandardCharsets.UTF_8)); + connectRecord.addExtension("id", String.valueOf(UUID.randomUUID())); + connectRecord.addExtension("source", "testSource"); + connectRecord.addExtension("type", "testType"); + records.add(connectRecord); + } + connector.put(records); + Assertions.assertTrue(downLatch.await(10, TimeUnit.SECONDS)); + } + + @AfterEach + public void tearDown() throws Exception { + connector.stop(); + redisson.shutdown(); + shutdownRedisServer(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/source/connector/RedisSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/source/connector/RedisSourceConnectorTest.java new file mode 100644 index 0000000000..326798d64a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/test/java/org/apache/eventmesh/connector/redis/source/connector/RedisSourceConnectorTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.redis.source.connector; + +import org.apache.eventmesh.common.config.connector.redis.RedisSourceConfig; +import org.apache.eventmesh.connector.redis.AbstractRedisServer; +import org.apache.eventmesh.connector.redis.cloudevent.CloudEventCodec; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; + +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.redisson.Redisson; +import org.redisson.api.RTopic; +import org.redisson.config.Config; + +public class RedisSourceConnectorTest extends AbstractRedisServer { + + private RedisSourceConnector connector; + + private final String expectedMessage = "testRedisMessage"; + + private RTopic topic; + + private Redisson redisson; + + @BeforeEach + public void setUp() throws Exception { + connector = new RedisSourceConnector(); + RedisSourceConfig sourceConfig = (RedisSourceConfig) ConfigUtil.parse(connector.configClass()); + setupRedisServer(getPortFromUrl(sourceConfig.getConnectorConfig().getServer())); + connector.init(sourceConfig); + connector.start(); + Config config = new Config(); + config.setCodec(CloudEventCodec.getInstance()); + config.useSingleServer() + .setAddress(sourceConfig.getConnectorConfig().getServer()); + redisson = (Redisson) Redisson.create(config); + topic = redisson.getTopic(sourceConfig.connectorConfig.getTopic()); + } + + @Test + public void testPollConnectRecords() throws Exception { + publishMockEvents(); + List connectRecords = connector.poll(); + for (ConnectRecord connectRecord : connectRecords) { + String actualMessage = new String((byte[]) connectRecord.getData()); + Assertions.assertEquals(expectedMessage, actualMessage); + } + } + + private void publishMockEvents() { + int mockCount = 5; + for (int i = 0; i < mockCount; i++) { + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), + ("\"" + expectedMessage + "\"").getBytes(StandardCharsets.UTF_8)); + connectRecord.addExtension("id", String.valueOf(UUID.randomUUID())); + connectRecord.addExtension("source", "testSource"); + connectRecord.addExtension("topic", "testTopic"); + connectRecord.addExtension("type", "testType"); + connectRecord.addExtension("datacontenttype", "testdatacontenttype"); + topic.publish(CloudEventUtil.convertRecordToEvent(connectRecord)); + } + } + + @AfterEach + public void tearDown() throws Exception { + connector.stop(); + redisson.shutdown(); + shutdownRedisServer(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-redis/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..596006a2a1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/test/resources/sink-config.yml @@ -0,0 +1,31 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: redisSink + appId: 5031 + userName: redisSinkUser + passWord: redisPassWord +connectorConfig: + connectorName: redisSink + server: redis://127.0.0.1:6379 + topic: SinkTopic + diff --git a/eventmesh-connectors/eventmesh-connector-redis/src/test/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-redis/src/test/resources/source-config.yml new file mode 100644 index 0000000000..5d31ad0fcb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-redis/src/test/resources/source-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: redisSource + appId: 5032 + userName: redisSourceUser + passWord: redisPassWord +connectorConfig: + connectorName: redisSource + server: redis://127.0.0.1:6379 + topic: SourceTopic diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/build.gradle b/eventmesh-connectors/eventmesh-connector-rocketmq/build.gradle new file mode 100644 index 0000000000..64c43e29d5 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/build.gradle @@ -0,0 +1,51 @@ +/* + * 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. + */ + +List rocketmq = [ + "org.apache.rocketmq:rocketmq-client:$rocketmq_version", + "org.apache.rocketmq:rocketmq-broker:$rocketmq_version", + "org.apache.rocketmq:rocketmq-common:$rocketmq_version", + "org.apache.rocketmq:rocketmq-store:$rocketmq_version", + "org.apache.rocketmq:rocketmq-namesrv:$rocketmq_version", + "org.apache.rocketmq:rocketmq-tools:$rocketmq_version", + "org.apache.rocketmq:rocketmq-remoting:$rocketmq_version", + "org.apache.rocketmq:rocketmq-logging:$rocketmq_version", + "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", + "org.apache.rocketmq:rocketmq-filter:$rocketmq_version", + "org.apache.rocketmq:rocketmq-acl:$rocketmq_version", + "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", + +] + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + /* + * The exclusions can be removed after this issue is fixed: + * https://github.com/apache/rocketmq/issues/5347 + */ + rocketmq.each { + implementation(it) { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } + } + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/gradle.properties b/eventmesh-connectors/eventmesh-connector-rocketmq/gradle.properties new file mode 100644 index 0000000000..8545888587 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# +rocketmq_version=4.9.5 +pluginType=connector +pluginName=rocketmq \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/RocketMQServerConfig.java b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/RocketMQServerConfig.java new file mode 100644 index 0000000000..842094e07f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/config/RocketMQServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rocketmq.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RocketMQServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/server/RocketMQConnectServer.java b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/server/RocketMQConnectServer.java new file mode 100644 index 0000000000..98fd225ba8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/server/RocketMQConnectServer.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rocketmq.server; + +import org.apache.eventmesh.connector.rocketmq.config.RocketMQServerConfig; +import org.apache.eventmesh.connector.rocketmq.sink.connector.RocketMQSinkConnector; +import org.apache.eventmesh.connector.rocketmq.source.connector.RocketMQSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RocketMQConnectServer { + + public static void main(String[] args) throws Exception { + + RocketMQServerConfig serverConfig = ConfigUtil.parse(RocketMQServerConfig.class, "server-config.yml"); + + if (serverConfig.isSourceEnable()) { + Application rocketmqSourceApp = new Application(); + rocketmqSourceApp.run(RocketMQSourceConnector.class); + } + + if (serverConfig.isSinkEnable()) { + Application rocketmqSinkApp = new Application(); + rocketmqSinkApp.run(RocketMQSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/sink/connector/RocketMQSinkConnector.java b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/sink/connector/RocketMQSinkConnector.java new file mode 100644 index 0000000000..31d45a28f4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/sink/connector/RocketMQSinkConnector.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rocketmq.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.rocketmq.RocketMQSinkConfig; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageAccessor; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RocketMQSinkConnector implements Sink, ConnectorCreateService { + + private RocketMQSinkConfig sinkConfig; + + private final DefaultMQProducer producer = new DefaultMQProducer(); + + @Override + public Class configClass() { + return RocketMQSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for rocketmq source connector + this.sinkConfig = (RocketMQSinkConfig) config; + producer.setProducerGroup(sinkConfig.getPubSubConfig().getGroup()); + producer.setNamesrvAddr(sinkConfig.getConnectorConfig().getNameServer()); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for rocketmq source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (RocketMQSinkConfig) sinkConnectorContext.getSinkConfig(); + producer.setProducerGroup(sinkConfig.getPubSubConfig().getGroup()); + producer.setNamesrvAddr(sinkConfig.getConnectorConfig().getNameServer()); + } + + @Override + public void start() throws Exception { + producer.start(); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + producer.shutdown(); + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + Message message = convertRecordToMessage(connectRecord); + try { + SendResult sendResult = producer.send(message); + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[RocketMQSinkConnector] Interrupting thread {} due to exception {}", + currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } catch (Exception e) { + log.error("[RocketMQSinkConnector] sendResult has error : ", e); + } + } + } + + public Message convertRecordToMessage(ConnectRecord connectRecord) { + Message message = new Message(); + message.setTopic(this.sinkConfig.getConnectorConfig().getTopic()); + message.setBody((byte[]) connectRecord.getData()); + for (String key : connectRecord.getExtensions().keySet()) { + MessageAccessor.putProperty(message, key, connectRecord.getExtension(key)); + } + return message; + } + + @Override + public Sink create() { + return new RocketMQSinkConnector(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/source/connector/RocketMQSourceConnector.java b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/source/connector/RocketMQSourceConnector.java new file mode 100644 index 0000000000..410f927d75 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/source/connector/RocketMQSourceConnector.java @@ -0,0 +1,317 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rocketmq.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.mq.rocketmq.RocketMQSourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.rocketmq.RocketMQRecordOffset; +import org.apache.eventmesh.common.remote.offset.rocketmq.RocketMQRecordPartition; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetStorageReader; + +import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy; +import org.apache.rocketmq.client.consumer.DefaultLitePullConsumer; +import org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.Connection; +import org.apache.rocketmq.common.protocol.body.ConsumerConnection; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RocketMQSourceConnector implements Source, ConnectorCreateService { + + private RocketMQSourceConfig sourceConfig; + + private OffsetStorageReader offsetStorageReader; + + private DefaultMQAdminExt srcMQAdminExt; + + // message queue divided strategy + private final AllocateMessageQueueStrategy allocateMessageQueueStrategy = new AllocateMessageQueueAveragely(); + + private final DefaultLitePullConsumer consumer = new DefaultLitePullConsumer(); + + private final ScheduledExecutorService commitOffsetScheduleService = Executors.newSingleThreadScheduledExecutor(); + + private final ConcurrentHashMap> prepareCommitOffset = new ConcurrentHashMap<>(); + + private final ConcurrentHashMap> queue2Offsets = new ConcurrentHashMap<>(); + + private final AtomicInteger unAckCounter = new AtomicInteger(); + + @Override + public Class configClass() { + return RocketMQSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for rocketmq source connector + this.sourceConfig = (RocketMQSourceConfig) config; + consumer.setConsumerGroup(sourceConfig.getPubSubConfig().getGroup()); + consumer.setNamesrvAddr(sourceConfig.getConnectorConfig().getNameserver()); + consumer.setAutoCommit(false); + consumer.setPullBatchSize(32); + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + initAdmin(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (RocketMQSourceConfig) sourceConnectorContext.getSourceConfig(); + this.offsetStorageReader = sourceConnectorContext.getOffsetStorageReader(); + consumer.setConsumerGroup(sourceConfig.getPubSubConfig().getGroup()); + consumer.setNamesrvAddr(sourceConfig.getConnectorConfig().getNameserver()); + consumer.setAutoCommit(false); + consumer.setPullBatchSize(32); + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + consumer.setAllocateMessageQueueStrategy(allocateMessageQueueStrategy); + initAdmin(); + } + + private synchronized void initAdmin() throws MQClientException { + if (srcMQAdminExt == null) { + srcMQAdminExt = new DefaultMQAdminExt(); + srcMQAdminExt.setNamesrvAddr(sourceConfig.getConnectorConfig().getNameserver()); + srcMQAdminExt.setAdminExtGroup("RocketMQ-Admin"); + } + } + + @Override + public void start() throws Exception { + + consumer.start(); + srcMQAdminExt.start(); + + // commit offset with schedule task + execScheduleTask(); + // todo: we need more elegant way instead of sleep + // for rocketmq client, will delay 1 second to send heartbeat to broker, so here sleep few seconds + Thread.sleep(1500); + + List allocated = getAllocatedMessageQueue(sourceConfig.getConnectorConfig().getTopic(), + sourceConfig.getPubSubConfig().getGroup()); + + consumer.assign(allocated); + + consumer.setMessageQueueListener((topic, mqAll, mqDivided) -> { + + for (MessageQueue messageQueue : mqDivided) { + try { + RocketMQRecordPartition recordPartition = new RocketMQRecordPartition(); + recordPartition.setBroker(messageQueue.getBrokerName()); + recordPartition.setTopic(messageQueue.getTopic()); + recordPartition.setQueueId(messageQueue.getQueueId() + ""); + RecordOffset recordOffset = offsetStorageReader.readOffset(recordPartition); + log.info("assigned messageQueue {}, recordOffset {}", messageQueue, recordOffset); + if (recordOffset != null) { + long pollOffset = ((RocketMQRecordOffset) recordOffset).getQueueOffset(); + if (pollOffset != 0) { + consumer.seek(messageQueue, pollOffset); + } + } + } catch (MQClientException e) { + throw new RuntimeException(e); + } + } + }); + } + + private List getAllocatedMessageQueue(String topic, String group) + throws MQBrokerException, RemotingException, InterruptedException, MQClientException { + List mqAll = getMessageQueueList(topic); + List cidAll = getCidList(group); + if (cidAll != null) { + Collections.sort(mqAll); + Collections.sort(cidAll); + return allocateMessageQueueStrategy.allocate(group, consumer.buildMQClientId(), mqAll, cidAll); + } + return new ArrayList<>(); + } + + private List getCidList(String group) throws MQBrokerException, RemotingException, InterruptedException, MQClientException { + ConsumerConnection consumerConnection = srcMQAdminExt.examineConsumerConnectionInfo(group); + return consumerConnection.getConnectionSet().stream().map(Connection::getClientId).collect(Collectors.toList()); + } + + private List getMessageQueueList(String topic) throws MQClientException { + Collection messageQueueCollection = consumer.fetchMessageQueues(topic); + return new ArrayList<>(messageQueueCollection); + } + + @Override + public void commit(ConnectRecord record) { + // send success, commit offset + RocketMQRecordPartition rocketMQRecordPartition = (RocketMQRecordPartition) (record.getPosition().getRecordPartition()); + String brokerName = rocketMQRecordPartition.getBroker(); + String topic = rocketMQRecordPartition.getTopic(); + int queueId = Integer.parseInt(rocketMQRecordPartition.getQueueId()); + MessageQueue mq = new MessageQueue(topic, brokerName, queueId); + RocketMQRecordOffset rocketMQRecordOffset = (RocketMQRecordOffset) record.getPosition().getRecordOffset(); + long offset = rocketMQRecordOffset.getQueueOffset(); + long canCommitOffset = removeMessage(mq, offset); + log.info("commit record {}|mq {}|canCommitOffset {}", record, mq, canCommitOffset); + // commit offset to prepareCommitOffset + commitOffset(mq, canCommitOffset); + } + + @Override + public String name() { + return this.sourceConfig.getConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + consumer.unsubscribe(sourceConfig.getConnectorConfig().getTopic()); + consumer.shutdown(); + } + + @Override + public List poll() { + List messageExts = consumer.poll(); + List connectRecords = new ArrayList<>(messageExts.size()); + for (MessageExt messageExt : messageExts) { + log.info("poll message {} from mq", messageExt); + Long timestamp = System.currentTimeMillis(); + byte[] body = messageExt.getBody(); + String bodyStr = new String(body, StandardCharsets.UTF_8); + RecordPartition recordPartition = convertToRecordPartition(messageExt.getTopic(), + messageExt.getBrokerName(), messageExt.getQueueId()); + RecordOffset recordOffset = convertToRecordOffset(messageExt.getQueueOffset()); + ConnectRecord connectRecord = new ConnectRecord(recordPartition, recordOffset, timestamp, bodyStr); + connectRecord.addExtension("topic", messageExt.getTopic()); + connectRecords.add(connectRecord); + // put to unAckMessage Map + putPulledQueueOffset(messageExt); + } + return connectRecords; + } + + public static RecordOffset convertToRecordOffset(Long offset) { + RocketMQRecordOffset rocketMQRecordOffset = new RocketMQRecordOffset(); + rocketMQRecordOffset.setQueueOffset(offset); + return rocketMQRecordOffset; + } + + public static RecordPartition convertToRecordPartition(String topic, String brokerName, int queueId) { + RocketMQRecordPartition rocketMQRecordPartition = new RocketMQRecordPartition(); + rocketMQRecordPartition.setBroker(brokerName); + rocketMQRecordPartition.setTopic(topic); + rocketMQRecordPartition.setQueueId(queueId + ""); + + return rocketMQRecordPartition; + } + + private void putPulledQueueOffset(MessageExt messageExt) { + MessageQueue mq = new MessageQueue(messageExt.getTopic(), messageExt.getBrokerName(), messageExt.getQueueId()); + TreeMap offsets = queue2Offsets.get(mq); + if (offsets == null) { + TreeMap newOffsets = new TreeMap<>(); + offsets = queue2Offsets.putIfAbsent(mq, newOffsets); + if (offsets == null) { + offsets = newOffsets; + } + } + // add to unAckMessage + offsets.put(messageExt.getQueueOffset(), messageExt); + unAckCounter.incrementAndGet(); + } + + private long removeMessage(MessageQueue mq, long offset) { + TreeMap offsets = queue2Offsets.get(mq); + if (offsets != null && !offsets.isEmpty()) { + MessageExt prev = offsets.remove(offset); + if (prev != null) { + unAckCounter.decrementAndGet(); + } + } + return offset; + } + + private void execScheduleTask() { + commitOffsetScheduleService.scheduleAtFixedRate(this::commitOffsetSchedule, sourceConfig.connectorConfig.getCommitOffsetIntervalMs(), + sourceConfig.connectorConfig.getCommitOffsetIntervalMs(), TimeUnit.MILLISECONDS); + } + + private void commitOffsetSchedule() { + + prepareCommitOffset.forEach((messageQueue, list) -> { + Iterator offsetIterator = list.iterator(); + while (offsetIterator.hasNext()) { + Map commitOffsetTable = new HashMap<>(); + commitOffsetTable.put(messageQueue, offsetIterator.next().get()); + consumer.commitSync(commitOffsetTable, false); + offsetIterator.remove(); + } + }); + } + + public void commitOffset(MessageQueue mq, long canCommitOffset) { + if (canCommitOffset == -1) { + return; + } + long nextBeginOffset = canCommitOffset + 1; + List commitOffset = prepareCommitOffset.get(mq); + if (commitOffset == null || commitOffset.isEmpty()) { + commitOffset = new ArrayList<>(); + } + commitOffset.add(new AtomicLong(nextBeginOffset)); + prepareCommitOffset.put(mq, commitOffset); + } + + @Override + public Source create() { + return new RocketMQSourceConnector(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..210361dc28 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSink + appId: 5031 + userName: rocketmqSinkUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSink + nameServer: 127.0.0.1:9876 + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/source-config.yml new file mode 100644 index 0000000000..7a7880b877 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/main/resources/source-config.yml @@ -0,0 +1,40 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: rocketmqSourceUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSource + nameserver: 127.0.0.1:9876 + topic: TopicTest + commitOffsetIntervalMs: 5000 +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with topic + dataId: TopicTest, + #same with group + group: rocketmqSource + } diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/sink/connector/RocketMQSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/sink/connector/RocketMQSinkConnectorTest.java new file mode 100644 index 0000000000..51d77182a0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/sink/connector/RocketMQSinkConnectorTest.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rocketmq.sink.connector; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.apache.eventmesh.common.config.connector.mq.rocketmq.RocketMQSinkConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.message.Message; + +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class RocketMQSinkConnectorTest { + + @InjectMocks + private RocketMQSinkConnector sinkConnector; + + @Mock + private DefaultMQProducer producer; + + private static final String EXPECTED_MESSAGE = "\"testMessage\""; + + @BeforeEach + public void setUp() throws Exception { + Mockito.doNothing().when(producer).start(); + Mockito.doReturn(null).when(producer).send(Mockito.any(Message.class)); + Field field = ReflectionSupport.findFields(sinkConnector.getClass(), + (f) -> f.getName().equals("producer"), HierarchyTraversalMode.BOTTOM_UP).get(0); + field.setAccessible(true); + field.set(sinkConnector, producer); + producer.start(); + RocketMQSinkConfig sinkConfig = (RocketMQSinkConfig) ConfigUtil.parse(sinkConnector.configClass()); + sinkConnector.init(sinkConfig); + sinkConnector.start(); + } + + @Test + public void testRocketMQSinkConnector() throws Exception { + final int messageCount = 5; + sinkConnector.put(generateMockedRecords(messageCount)); + verify(producer, times(messageCount)).send(any(Message.class)); + } + + private List generateMockedRecords(final int messageCount) { + List records = new ArrayList<>(); + for (int i = 0; i < messageCount; i++) { + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), + EXPECTED_MESSAGE.getBytes(StandardCharsets.UTF_8)); + connectRecord.addExtension("id", String.valueOf(UUID.randomUUID())); + records.add(connectRecord); + } + return records; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/source/connector/RocketMQSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/source/connector/RocketMQSourceConnectorTest.java new file mode 100644 index 0000000000..78510e2e4f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/java/org/apache/eventmesh/connector/rocketmq/source/connector/RocketMQSourceConnectorTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.rocketmq.source.connector; + +import org.apache.eventmesh.common.config.connector.mq.rocketmq.RocketMQSourceConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.rocketmq.client.consumer.DefaultLitePullConsumer; +import org.apache.rocketmq.common.message.MessageExt; + +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +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 org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class RocketMQSourceConnectorTest { + + @InjectMocks + private RocketMQSourceConnector sourceConnector; + + @Mock + private DefaultLitePullConsumer consumer; + + private RocketMQSourceConfig sourceConfig; + + private static final String EXPECTED_MESSAGE = "testMessage"; + + @BeforeEach + public void setUp() throws Exception { + sourceConfig = (RocketMQSourceConfig) ConfigUtil.parse(sourceConnector.configClass()); + Mockito.doReturn(generateMockedMessages()).when(consumer).poll(); + Field field = ReflectionSupport.findFields(sourceConnector.getClass(), + (f) -> f.getName().equals("consumer"), HierarchyTraversalMode.BOTTOM_UP).get(0); + field.setAccessible(true); + field.set(sourceConnector, consumer); + } + + @Test + public void testRocketMQSourceConnectorPoll() { + List poll = sourceConnector.poll(); + poll.forEach(connectRecord -> { + Assertions.assertNotNull(connectRecord); + Assertions.assertEquals(EXPECTED_MESSAGE, connectRecord.getData()); + Assertions.assertNotNull(connectRecord.getExtension("topic")); + Assertions.assertNotNull(connectRecord.getPosition()); + Assertions.assertEquals(connectRecord.getExtension("topic"), sourceConfig.getConnectorConfig().getTopic()); + }); + } + + private List generateMockedMessages() { + final int mockCount = 5; + List messageExts = new ArrayList<>(); + for (int i = 0; i < mockCount; i++) { + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(sourceConfig.getConnectorConfig().getTopic()); + messageExt.setBody(EXPECTED_MESSAGE.getBytes(StandardCharsets.UTF_8)); + messageExt.setQueueOffset(1L); + messageExt.setQueueId(2); + messageExt.setBrokerName("testBroker"); + messageExts.add(messageExt); + } + return messageExts; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..210361dc28 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSink + appId: 5031 + userName: rocketmqSinkUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSink + nameServer: 127.0.0.1:9876 + topic: TopicTest diff --git a/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/resources/source-config.yml new file mode 100644 index 0000000000..7a7880b877 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-rocketmq/src/test/resources/source-config.yml @@ -0,0 +1,40 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: rocketmqSourceUser + passWord: rocketmqPassWord +connectorConfig: + connectorName: rocketmqSource + nameserver: 127.0.0.1:9876 + topic: TopicTest + commitOffsetIntervalMs: 5000 +offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with topic + dataId: TopicTest, + #same with group + group: rocketmqSource + } diff --git a/eventmesh-connectors/eventmesh-connector-s3/build.gradle b/eventmesh-connectors/eventmesh-connector-s3/build.gradle new file mode 100644 index 0000000000..af2867917e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-s3/build.gradle @@ -0,0 +1,24 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation 'software.amazon.awssdk:s3' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-s3/gradle.properties b/eventmesh-connectors/eventmesh-connector-s3/gradle.properties new file mode 100644 index 0000000000..4697f2bdc2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-s3/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=s3 \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/config/S3ServerConfig.java b/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/config/S3ServerConfig.java new file mode 100644 index 0000000000..a422c0468c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/config/S3ServerConfig.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.s3.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class S3ServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; + +} diff --git a/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/server/S3ConnectServer.java b/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/server/S3ConnectServer.java new file mode 100644 index 0000000000..e1b485801f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/server/S3ConnectServer.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.s3.server; + +import org.apache.eventmesh.connector.s3.config.S3ServerConfig; +import org.apache.eventmesh.connector.s3.source.connector.S3SourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class S3ConnectServer { + + public static void main(String[] args) throws Exception { + S3ServerConfig s3ServerConfig = ConfigUtil.parse(S3ServerConfig.class, "server-config.yml"); + if (s3ServerConfig.isSourceEnable()) { + Application application = new Application(); + application.run(S3SourceConnector.class); + } + + if (s3ServerConfig.isSinkEnable()) { + log.error("S3 sink is not supported yet."); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/source/connector/S3SourceConnector.java b/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/source/connector/S3SourceConnector.java new file mode 100644 index 0000000000..078ed7691a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-s3/src/main/java/org/apache/eventmesh/connector/s3/source/connector/S3SourceConnector.java @@ -0,0 +1,177 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.s3.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.s3.S3SourceConfig; +import org.apache.eventmesh.common.config.connector.s3.SourceConnectorConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.S3.S3RecordOffset; +import org.apache.eventmesh.common.remote.offset.S3.S3RecordPartition; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.async.AsyncResponseTransformer; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.HeadObjectResponse; + +@Slf4j +public class S3SourceConnector implements Source { + + public static final String REGION = "region"; + + public static final String BUCKET = "bucket"; + + public static final String FILE_NAME = "fileName"; + + public static final String POSITION = "position"; + + private S3SourceConfig sourceConfig; + + private SourceConnectorConfig sourceConnectorConfig; + + private int eachRecordSize; + + private long fileSize; + + private S3AsyncClient s3Client; + + private long position; + + @Override + public Class configClass() { + return S3SourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for s3 source connector + this.sourceConfig = (S3SourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + this.sourceConfig = (S3SourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + this.sourceConnectorConfig = this.sourceConfig.getSourceConnectorConfig(); + this.eachRecordSize = calculateEachRecordSize(); + AwsBasicCredentials basicCredentials = AwsBasicCredentials.create(this.sourceConnectorConfig.getAccessKey(), + this.sourceConnectorConfig.getSecretKey()); + this.s3Client = S3AsyncClient.builder().credentialsProvider(() -> basicCredentials) + .region(Region.of(this.sourceConnectorConfig.getRegion())).build(); + } + + private int calculateEachRecordSize() { + Optional sum = this.sourceConnectorConfig.getSchema().values().stream().reduce((x, y) -> x + y); + return sum.orElse(0); + } + + @Override + public void start() throws Exception { + CompletableFuture headObjectResponseCompletableFuture = this.s3Client.headObject( + builder -> builder.bucket(this.sourceConnectorConfig.getBucket()).key(this.sourceConnectorConfig.getFileName())); + headObjectResponseCompletableFuture.get(this.sourceConnectorConfig.getTimeout(), TimeUnit.MILLISECONDS); + this.fileSize = headObjectResponseCompletableFuture.get().contentLength(); + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getSourceConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + + } + + @Override + public List poll() { + if (this.position >= this.fileSize) { + return Collections.EMPTY_LIST; + } + long startPosition = this.position; + long endPosition = Math.min(this.fileSize, this.position + this.eachRecordSize * this.sourceConnectorConfig.getBatchSize()) - 1; + GetObjectRequest request = GetObjectRequest.builder().bucket(this.sourceConnectorConfig.getBucket()) + .key(this.sourceConnectorConfig.getFileName()) + .range("bytes=" + startPosition + "-" + endPosition).build(); + ResponseBytes resp; + try { + resp = this.s3Client.getObject(request, AsyncResponseTransformer.toBytes()) + .get(this.sourceConnectorConfig.getTimeout(), TimeUnit.MILLISECONDS); + } catch (Exception e) { + log.error("poll records from S3 file, poll range {}-{}, but failed", startPosition, endPosition, e); + return Collections.EMPTY_LIST; + } + byte[] bytes = resp.asByteArray(); + List records = new ArrayList<>(bytes.length / this.eachRecordSize); + for (int i = 0; i < bytes.length; i += this.eachRecordSize) { + byte[] body = new byte[this.eachRecordSize]; + System.arraycopy(bytes, i, body, 0, this.eachRecordSize); + this.position += this.eachRecordSize; + ConnectRecord record = new ConnectRecord(getRecordPartition(), getRecordOffset(), System.currentTimeMillis(), body); + records.add(record); + } + return records; + } + + private RecordPartition getRecordPartition() { + S3RecordPartition s3RecordPartition = new S3RecordPartition(); + s3RecordPartition.setRegion(this.sourceConnectorConfig.getRegion()); + s3RecordPartition.setBucket(this.sourceConnectorConfig.getBucket()); + s3RecordPartition.setFileName(this.sourceConnectorConfig.getFileName()); + return s3RecordPartition; + } + + private RecordOffset getRecordOffset() { + S3RecordOffset s3RecordOffset = new S3RecordOffset(); + s3RecordOffset.setOffset(this.position); + return s3RecordOffset; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-s3/src/test/java/org/apache/eventmesh/connector/s3/source/S3SourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-s3/src/test/java/org/apache/eventmesh/connector/s3/source/S3SourceConnectorTest.java new file mode 100644 index 0000000000..4d5d41093b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-s3/src/test/java/org/apache/eventmesh/connector/s3/source/S3SourceConnectorTest.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.s3.source; + +import org.apache.eventmesh.common.config.connector.s3.S3SourceConfig; +import org.apache.eventmesh.common.config.connector.s3.SourceConnectorConfig; +import org.apache.eventmesh.connector.s3.source.connector.S3SourceConnector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; + +@Disabled +public class S3SourceConnectorTest { + + private static final S3SourceConfig sourceConfig; + + private static final SourceConnectorConfig SOURCE_CONNECTOR_CONFIG; + + private static final Map schema; + + private static final int eachRecordSize; + + static { + sourceConfig = new S3SourceConfig(); + SOURCE_CONNECTOR_CONFIG = new SourceConnectorConfig(); + SOURCE_CONNECTOR_CONFIG.setConnectorName("S3SourceConnector"); + SOURCE_CONNECTOR_CONFIG.setRegion("ap-southeast-1"); + SOURCE_CONNECTOR_CONFIG.setBucket("event-mesh-bucket"); + SOURCE_CONNECTOR_CONFIG.setAccessKey("access-key"); + SOURCE_CONNECTOR_CONFIG.setSecretKey("secret-key"); + + SOURCE_CONNECTOR_CONFIG.setFileName("test-file"); + + schema = new HashMap<>(); + schema.put("id", 4); + schema.put("body", 16); + schema.put("time", 8); + + eachRecordSize = schema.values().stream().reduce((x, y) -> x + y).orElse(0); + SOURCE_CONNECTOR_CONFIG.setSchema(schema); + sourceConfig.setSourceConnectorConfig(SOURCE_CONNECTOR_CONFIG); + } + + private S3AsyncClient s3Client; + + @BeforeEach + public void setUp() throws Exception { + AwsBasicCredentials basicCredentials = AwsBasicCredentials.create(this.SOURCE_CONNECTOR_CONFIG.getAccessKey(), + this.SOURCE_CONNECTOR_CONFIG.getSecretKey()); + this.s3Client = S3AsyncClient.builder().credentialsProvider(() -> basicCredentials) + .region(Region.of(this.SOURCE_CONNECTOR_CONFIG.getRegion())).build(); + + // write mocked data + this.writeMockedRecords(200); + } + + @AfterEach + public void tearDown() throws Exception { + // clear file + this.s3Client.deleteObject(builder -> builder.bucket(this.SOURCE_CONNECTOR_CONFIG.getBucket()) + .key(this.SOURCE_CONNECTOR_CONFIG.getFileName()).build()).get(); + } + + @Test + public void testS3SourceConnector() throws Exception { + S3SourceConnector s3SourceConnector = new S3SourceConnector(); + s3SourceConnector.init(sourceConfig); + s3SourceConnector.start(); + int expectedId = 0; + while (true) { + List connectRecords = s3SourceConnector.poll(); + if (connectRecords.isEmpty()) { + break; + } + Assertions.assertEquals(20, connectRecords.size()); + for (ConnectRecord connectRecord : connectRecords) { + byte[] data = (byte[]) connectRecord.getData(); + Assertions.assertEquals(eachRecordSize, data.length); + ByteBuffer byteBuffer = ByteBuffer.wrap(data); + int id = byteBuffer.getInt(); + Assertions.assertEquals(expectedId++, id); + } + } + + } + + private void writeMockedRecords(int count) throws Exception { + ByteBuffer bytes = ByteBuffer.allocate(count * eachRecordSize); + ByteBuffer body = ByteBuffer.allocate(16); + body.putLong(13L); + body.putLong(13L); + body.flip(); + for (int i = 0; i < count; i++) { + bytes.putInt(i); + bytes.put(body); + body.flip(); + bytes.putLong(System.currentTimeMillis()); + } + PutObjectRequest putObjectRequest = PutObjectRequest.builder() + .bucket(SOURCE_CONNECTOR_CONFIG.getBucket()).key(SOURCE_CONNECTOR_CONFIG.getFileName()).build(); + AsyncRequestBody requestBody = AsyncRequestBody.fromBytes(bytes.array()); + this.s3Client.putObject(putObjectRequest, requestBody).get(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-slack/build.gradle b/eventmesh-connectors/eventmesh-connector-slack/build.gradle new file mode 100644 index 0000000000..665f748b5f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/build.gradle @@ -0,0 +1,31 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + + implementation "com.slack.api:bolt:1.42.+" + implementation 'com.google.guava:guava' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-slack/gradle.properties b/eventmesh-connectors/eventmesh-connector-slack/gradle.properties new file mode 100644 index 0000000000..c6c4b2e224 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=slack \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/config/SlackConnectServerConfig.java b/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/config/SlackConnectServerConfig.java new file mode 100644 index 0000000000..97479cb87a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/config/SlackConnectServerConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.slack.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class SlackConnectServerConfig extends Config { + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/server/SlackConnectServer.java b/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/server/SlackConnectServer.java new file mode 100644 index 0000000000..b59f0657ac --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/server/SlackConnectServer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.slack.server; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.slack.config.SlackConnectServerConfig; +import org.apache.eventmesh.connector.slack.sink.connector.SlackSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class SlackConnectServer { + + public static void main(String[] args) throws Exception { + + SlackConnectServerConfig slackConnectServerConfig = ConfigUtil.parse(SlackConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (slackConnectServerConfig.isSinkEnable()) { + Application application = new Application(); + application.run(SlackSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/sink/connector/SlackSinkConnector.java b/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/sink/connector/SlackSinkConnector.java new file mode 100644 index 0000000000..836409af71 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/main/java/org/apache/eventmesh/connector/slack/sink/connector/SlackSinkConnector.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.slack.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.slack.SlackSinkConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.Objects; + +import com.slack.api.Slack; +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +/** + * Slack sink connector. + * Slack doc: ... + */ +@Slf4j +public class SlackSinkConnector implements Sink { + + private SlackSinkConfig sinkConfig; + + private volatile boolean isRunning = false; + + private MethodsClient client; + + @Override + public Class configClass() { + return SlackSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for dingding sink connector + this.sinkConfig = (SlackSinkConfig) config; + this.client = Slack.getInstance().methods(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for dingding source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (SlackSinkConfig) sinkConnectorContext.getSinkConfig(); + this.client = Slack.getInstance().methods(); + } + + @Override + public void start() { + isRunning = true; + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() { + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + + @SneakyThrows + @Override + public void put(List sinkRecords) { + for (ConnectRecord record : sinkRecords) { + publishMessage(record); + } + } + + private void publishMessage(ConnectRecord record) { + try { + ChatPostMessageResponse response = client.chatPostMessage(r -> r + .token(sinkConfig.getSinkConnectorConfig().getAppToken()) + .channel(sinkConfig.getSinkConnectorConfig().getChannelId()) + .text(new String((byte[]) record.getData()))); + if (Objects.nonNull(response) && StringUtils.isNotBlank(response.getError())) { + throw new IllegalAccessException(response.getError()); + } + } catch (Exception e) { + log.error("Send message to slack error.", e); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-slack/src/main/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/main/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-slack/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..062eaf3495 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/main/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-SLACK + idc: FT + env: PRD + group: slackSink + appId: 5034 + userName: slackSinkUser + passWord: slackPassWord +sinkConnectorConfig: + connectorName: slackSink + appToken: slackAppToken + channelId: slackChannelId diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/test/java/org/apache/eventmesh/connector/slack/sink/connector/SlackSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-slack/src/test/java/org/apache/eventmesh/connector/slack/sink/connector/SlackSinkConnectorTest.java new file mode 100644 index 0000000000..fc5f04c7e1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/test/java/org/apache/eventmesh/connector/slack/sink/connector/SlackSinkConnectorTest.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.slack.sink.connector; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.apache.eventmesh.common.config.connector.slack.SlackSinkConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +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 org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.slack.api.RequestConfigurator; +import com.slack.api.methods.MethodsClient; +import com.slack.api.methods.response.chat.ChatPostMessageResponse; + +@ExtendWith(MockitoExtension.class) +public class SlackSinkConnectorTest { + + private SlackSinkConnector sinkConnector; + + @Mock + private MethodsClient client; + + @BeforeEach + public void setUp() throws Exception { + sinkConnector = new SlackSinkConnector(); + SlackSinkConfig sinkConfig = (SlackSinkConfig) ConfigUtil.parse(sinkConnector.configClass()); + sinkConnector.init(sinkConfig); + doReturn(new ChatPostMessageResponse()) + .when(client).chatPostMessage(any(RequestConfigurator.class)); + Field clientField = ReflectionSupport.findFields(sinkConnector.getClass(), + (f) -> f.getName().equals("client"), + HierarchyTraversalMode.BOTTOM_UP).get(0); + clientField.setAccessible(true); + clientField.set(sinkConnector, client); + sinkConnector.start(); + } + + @Test + public void testSendMessageToSlack() throws Exception { + final int times = 3; + List records = new ArrayList<>(); + for (int i = 0; i < times; i++) { + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "Hello, EventMesh!".getBytes(StandardCharsets.UTF_8)); + records.add(connectRecord); + } + sinkConnector.put(records); + verify(client, times(times)).chatPostMessage(any(RequestConfigurator.class)); + } + + @AfterEach + public void tearDown() { + sinkConnector.stop(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-slack/src/test/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/test/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-slack/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-slack/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..062eaf3495 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-slack/src/test/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-SLACK + idc: FT + env: PRD + group: slackSink + appId: 5034 + userName: slackSinkUser + passWord: slackPassWord +sinkConnectorConfig: + connectorName: slackSink + appToken: slackAppToken + channelId: slackChannelId diff --git a/eventmesh-connectors/eventmesh-connector-spring/build.gradle b/eventmesh-connectors/eventmesh-connector-spring/build.gradle new file mode 100644 index 0000000000..e0680d2bf2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/build.gradle @@ -0,0 +1,40 @@ +/* + * 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. + */ + +dependencies { + api project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + + /* + * TODO: Are these dependencies necessary? The source code only requires these two dependencies + * that do not propagate logging backends: + * + * api "org.springframework:spring-context:$spring_version" + * implementation "org.springframework.boot:spring-boot-autoconfigure:$spring_boot_version" + */ + implementation("org.springframework.boot:spring-boot-starter-validation:$spring_boot_version") { + exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' + } + implementation "org.springframework:spring-messaging:$spring_version" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-spring/gradle.properties b/eventmesh-connectors/eventmesh-connector-spring/gradle.properties new file mode 100644 index 0000000000..3ff99a1c80 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/gradle.properties @@ -0,0 +1,20 @@ +# +# 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. +# +spring_boot_version=2.5.9 +spring_version=5.3.20 +pluginType=connector +pluginName=spring \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/common/SpringApplicationContextHolder.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/common/SpringApplicationContextHolder.java new file mode 100644 index 0000000000..bb07baa94f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/common/SpringApplicationContextHolder.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.common; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +public class SpringApplicationContextHolder implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + public static boolean isStarted() { + return applicationContext != null; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringApplicationContextHolder.applicationContext = applicationContext; + } + + public static T getBean(Class clazz) { + return applicationContext.getBean(clazz); + } + + public static Object getBean(String beanName) { + return applicationContext.getBean(beanName); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/config/EventMeshAutoConfiguration.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/config/EventMeshAutoConfiguration.java new file mode 100644 index 0000000000..12f56a501e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/config/EventMeshAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.config; + +import org.apache.eventmesh.connector.spring.common.SpringApplicationContextHolder; +import org.apache.eventmesh.connector.spring.server.SpringConnectServer; +import org.apache.eventmesh.connector.spring.sink.EventMeshListenerBeanPostProcessor; +import org.apache.eventmesh.connector.spring.sink.connector.SpringSinkConnector; +import org.apache.eventmesh.connector.spring.source.connector.SpringSourceConnector; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Spring auto configuration. + */ +@Configuration +public class EventMeshAutoConfiguration { + + public static final String SPRING_SOURCE_CONNECTOR_BEAN_NAME = "springSourceConnector"; + public static final String SPRING_SINK_CONNECTOR_BEAN_NAME = "springSinkConnector"; + public static final String SPRING_CONNECT_SERVER_BEAN_NAME = "springConnectServer"; + public static final String SPRING_APPLICATION_CONTEXT_HOLDER = "springApplicationContextHolder"; + public static final String EVENTMESH_LISTENER_BEAN_POST_PROCESSOR = "eventMeshListenerBeanPostProcessor"; + + @Bean(name = SPRING_SOURCE_CONNECTOR_BEAN_NAME) + @ConditionalOnMissingBean(name = SPRING_SOURCE_CONNECTOR_BEAN_NAME) + public SpringSourceConnector springSourceConnector() { + return new SpringSourceConnector(); + } + + @Bean(name = SPRING_SINK_CONNECTOR_BEAN_NAME) + @ConditionalOnMissingBean(name = SPRING_SINK_CONNECTOR_BEAN_NAME) + public SpringSinkConnector springSinkConnector() { + return new SpringSinkConnector(); + } + + @Bean(name = SPRING_CONNECT_SERVER_BEAN_NAME) + @ConditionalOnMissingBean(name = SPRING_CONNECT_SERVER_BEAN_NAME) + public SpringConnectServer springConnectServer() { + return new SpringConnectServer(); + } + + @Bean(name = SPRING_APPLICATION_CONTEXT_HOLDER) + @ConditionalOnMissingBean(name = SPRING_APPLICATION_CONTEXT_HOLDER) + public SpringApplicationContextHolder springApplicationContextHolder() { + return new SpringApplicationContextHolder(); + } + + @Bean(name = EVENTMESH_LISTENER_BEAN_POST_PROCESSOR) + @ConditionalOnMissingBean(name = EVENTMESH_LISTENER_BEAN_POST_PROCESSOR) + public EventMeshListenerBeanPostProcessor eventMeshListenerBeanPostProcessor() { + return new EventMeshListenerBeanPostProcessor(); + } + +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/config/SpringConnectServerConfig.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/config/SpringConnectServerConfig.java new file mode 100644 index 0000000000..88cf8156a8 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/config/SpringConnectServerConfig.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class SpringConnectServerConfig extends Config { + + private boolean sourceEnable; + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/server/SpringConnectServer.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/server/SpringConnectServer.java new file mode 100644 index 0000000000..f176200ae4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/server/SpringConnectServer.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.server; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.spring.config.SpringConnectServerConfig; +import org.apache.eventmesh.connector.spring.source.connector.SpringSourceConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.CommandLineRunner; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SpringConnectServer implements CommandLineRunner { + + private static final String SPRING_SOURCE = "springSource"; + + @Override + public void run(String... args) throws Exception { + SpringConnectServerConfig springConnectServerConfig = ConfigUtil.parse(SpringConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (springConnectServerConfig.isSourceEnable()) { + Map extensions = new HashMap<>(); + extensions.put(Application.CREATE_EXTENSION_KEY, SPRING_SOURCE); + Application application = new Application(extensions); + application.run(SpringSourceConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshConsumerMetadata.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshConsumerMetadata.java new file mode 100644 index 0000000000..1585480c8d --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshConsumerMetadata.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.sink; + +import java.lang.reflect.Method; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class EventMeshConsumerMetadata { + + private Object bean; + + private Method method; + + private EventMeshListener annotation; + +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshListener.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshListener.java new file mode 100644 index 0000000000..e2a850a219 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshListener.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.sink; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface EventMeshListener { + + /** + * The requestTimeout of client,it is 5s by default. + */ + int requestTimeout() default 5; +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshListenerBeanPostProcessor.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshListenerBeanPostProcessor.java new file mode 100644 index 0000000000..f6c9605f6e --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/EventMeshListenerBeanPostProcessor.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.sink; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.spring.config.SpringConnectServerConfig; +import org.apache.eventmesh.connector.spring.sink.connector.SpringSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.util.ReflectionUtils; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshListenerBeanPostProcessor implements ApplicationContextAware, + CommandLineRunner, BeanPostProcessor { + + private static final String SPRING_SINK = "springSink"; + + private static final ThreadPoolExecutor executor = ThreadPoolFactory.createThreadPoolExecutor( + Runtime.getRuntime().availableProcessors() * 2, + Runtime.getRuntime().availableProcessors() * 2, + "EventMesh-MessageListenerBeanPostProcessor-"); + + private ApplicationContext applicationContext; + + private List metadataList = new ArrayList<>(); + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + Class targetClass = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass(); + ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() { + + @Override + public void doWith(final Method method) throws IllegalArgumentException, IllegalAccessException { + EventMeshListener annotation = AnnotatedElementUtils.findMergedAnnotation(method, EventMeshListener.class); + if (annotation == null || method.isBridge()) { + return; + } + metadataList.add(new EventMeshConsumerMetadata(bean, method, annotation)); + } + }); + return bean; + } + + @Override + public void run(String... args) throws Exception { + runSinkConnector(); + metadataList.forEach(metadata -> { + Object bean = metadata.getBean(); + Method method = metadata.getMethod(); + EventMeshListener annotation = metadata.getAnnotation(); + SpringSinkConnector sinkConnector = applicationContext.getBean(SpringSinkConnector.class); + executor.execute(() -> { + ConnectRecord poll; + while (sinkConnector.isRunning()) { + try { + poll = sinkConnector.getQueue().poll(annotation.requestTimeout(), TimeUnit.SECONDS); + if (poll == null || poll.getData() == null) { + continue; + } + String messageBody = new String((byte[]) poll.getData()); + Type[] parameterizedTypes = method.getGenericParameterTypes(); + if (parameterizedTypes.length == 0) { + throw new IllegalStateException("There has not any arguments for consumer method."); + } + if (parameterizedTypes.length > 1) { + throw new IllegalStateException("There has more than one arguments for consumer method."); + } + Class rawType; + if (parameterizedTypes[0] instanceof Class) { + rawType = (Class) parameterizedTypes[0]; + } else { + throw new IllegalStateException( + "The arguments type for consumer method can't cast to be Class and ParameterizedTypeImpl"); + } + if (rawType == String.class) { + metadata.getMethod().invoke(bean, messageBody); + } else { + metadata.getMethod().invoke(bean, JsonUtils.parseObject(messageBody, parameterizedTypes[0])); + } + } catch (Exception e) { + log.warn("Consume snapshot event error", e); + } + } + }); + }); + } + + @SneakyThrows + public void runSinkConnector() { + SpringConnectServerConfig springConnectServerConfig = ConfigUtil.parse(SpringConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (springConnectServerConfig.isSinkEnable()) { + Map extensions = new HashMap<>(); + extensions.put(Application.CREATE_EXTENSION_KEY, SPRING_SINK); + Application application = new Application(extensions); + application.run(SpringSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnector.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnector.java new file mode 100644 index 0000000000..9ba99cd547 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnector.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.spring.SpringSinkConfig; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import lombok.extern.slf4j.Slf4j; + +/** + * Spring sink connector + */ +@Slf4j +public class SpringSinkConnector implements Sink { + + private SpringSinkConfig sinkConfig; + + private BlockingQueue queue; + + private volatile boolean isRunning = false; + + @Override + public Class configClass() { + return SpringSinkConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for spring sink connector + this.sinkConfig = (SpringSinkConfig) config; + this.queue = new LinkedBlockingQueue<>(1000); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + // init config for openfunction source connector + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (SpringSinkConfig) sinkConnectorContext.getSinkConfig(); + this.queue = new LinkedBlockingQueue<>(1000); + } + + @Override + public void start() throws Exception { + isRunning = true; + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + + } + + public boolean isRunning() { + return isRunning; + } + + public BlockingQueue getQueue() { + return queue; + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord connectRecord : sinkRecords) { + try { + queue.put(connectRecord); + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[SpringSinkConnector] Interrupting thread {} due to exception {}", + currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnectorCreateServiceImpl.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnectorCreateServiceImpl.java new file mode 100644 index 0000000000..e7e7b2554a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnectorCreateServiceImpl.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.sink.connector; + +import org.apache.eventmesh.connector.spring.common.SpringApplicationContextHolder; +import org.apache.eventmesh.connector.spring.config.EventMeshAutoConfiguration; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.sink.Sink; + +public class SpringSinkConnectorCreateServiceImpl implements ConnectorCreateService { + + @Override + public Sink create() { + if (SpringApplicationContextHolder.isStarted()) { + return (Sink) SpringApplicationContextHolder.getBean(EventMeshAutoConfiguration.SPRING_SINK_CONNECTOR_BEAN_NAME); + } + return null; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/MessageSendingOperations.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/MessageSendingOperations.java new file mode 100644 index 0000000000..5f38914bb1 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/MessageSendingOperations.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.source; + +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendMessageCallback; + +/** + * Operations for sending messages. + */ +public interface MessageSendingOperations { + + void send(Object message); + + void send(Object message, SendMessageCallback sendCallback); + +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnector.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnector.java new file mode 100644 index 0000000000..6efed2db3c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnector.java @@ -0,0 +1,205 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.source.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.spring.SpringSourceConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.spring.SpringRecordOffset; +import org.apache.eventmesh.common.remote.offset.spring.SpringRecordPartition; +import org.apache.eventmesh.connector.spring.source.MessageSendingOperations; +import org.apache.eventmesh.openconnect.SourceWorker; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendMessageCallback; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.BeansException; +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SpringSourceConnector implements Source, MessageSendingOperations, ApplicationContextAware { + + private static final String CONNECTOR_PROPERTY_PREFIX = "eventmesh.connector."; + + private ApplicationContext applicationContext; + + private SpringSourceConfig sourceConfig; + + private BlockingQueue queue; + + private int maxBatchSize; + + private long maxPollWaitTime; + + @Override + public Class configClass() { + return SpringSourceConfig.class; + } + + @Override + public void init(Config config) throws Exception { + // init config for spring source connector + this.sourceConfig = (SpringSourceConfig) config; + doInit(); + } + + @Override + public void init(ConnectorContext connectorContext) throws Exception { + SourceConnectorContext sourceConnectorContext = (SourceConnectorContext) connectorContext; + // init config for spring source connector + this.sourceConfig = (SpringSourceConfig) sourceConnectorContext.getSourceConfig(); + doInit(); + } + + private void doInit() { + this.queue = new LinkedBlockingQueue<>(sourceConfig.getPollConfig().getCapacity()); + this.maxBatchSize = sourceConfig.getPollConfig().getMaxBatchSize(); + this.maxPollWaitTime = sourceConfig.getPollConfig().getMaxWaitTime(); + } + + @Override + public void start() throws Exception { + + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sourceConfig.getSourceConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws Exception { + + } + + @Override + public List poll() { + long startTime = System.currentTimeMillis(); + long remainingTime = maxPollWaitTime; + + List connectRecords = new ArrayList<>(maxBatchSize); + for (int count = 0; count < maxBatchSize; ++count) { + try { + ConnectRecord connectRecord = queue.poll(remainingTime, TimeUnit.MILLISECONDS); + if (connectRecord == null) { + break; + } + connectRecords.add(connectRecord); + + // calculate elapsed time and update remaining time for next poll + long elapsedTime = System.currentTimeMillis() - startTime; + remainingTime = maxPollWaitTime > elapsedTime ? maxPollWaitTime - elapsedTime : 0; + } catch (InterruptedException e) { + Thread currentThread = Thread.currentThread(); + log.warn("[SpringSourceConnector] Interrupting thread {} due to exception {}", + currentThread.getName(), e.getMessage()); + currentThread.interrupt(); + } + } + return connectRecords; + } + + /** + * Send message. + * + * @param message message to send + */ + @Override + public void send(Object message) { + RecordPartition partition = new SpringRecordPartition(); + RecordOffset offset = new SpringRecordOffset(); + ConnectRecord record = new ConnectRecord(partition, offset, System.currentTimeMillis(), message); + addSpringEnvironmentPropertyExtensions(record); + queue.offer(record); + } + + /** + * Send message with a callback. + * + * @param message message to send. + * @param workerCallback After the user sends the message to the Connector, the SourceWorker will fetch message and invoke. + */ + @Override + public void send(Object message, SendMessageCallback workerCallback) { + RecordPartition partition = new SpringRecordPartition(); + RecordOffset offset = new SpringRecordOffset(); + ConnectRecord record = new ConnectRecord(partition, offset, System.currentTimeMillis(), message); + record.addExtension(SourceWorker.CALLBACK_EXTENSION, workerCallback); + addSpringEnvironmentPropertyExtensions(record); + queue.offer(record); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + private void addSpringEnvironmentPropertyExtensions(ConnectRecord connectRecord) { + ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext; + MutablePropertySources propertySources = context.getEnvironment().getPropertySources(); + for (PropertySource propertySource : propertySources) { + if (!(propertySource instanceof OriginTrackedMapPropertySource)) { + continue; + } + OriginTrackedMapPropertySource originTrackedMapPropertySource = + (OriginTrackedMapPropertySource) propertySource; + String[] keys = originTrackedMapPropertySource.getPropertyNames(); + for (String key : keys) { + if (!key.startsWith(CONNECTOR_PROPERTY_PREFIX)) { + continue; + } + Object value = null; + try { + value = originTrackedMapPropertySource.getProperty(key); + if (value != null) { + connectRecord.addExtension(key.replaceAll(CONNECTOR_PROPERTY_PREFIX, "").toLowerCase(), + String.valueOf(value)); + } + } catch (Throwable e) { + log.error("Put spring environment property to extension failed, key=[{}], value=[{}]", key, value); + } + } + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnectorCreateServiceImpl.java b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnectorCreateServiceImpl.java new file mode 100644 index 0000000000..573ff9ed76 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnectorCreateServiceImpl.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.source.connector; + +import org.apache.eventmesh.connector.spring.common.SpringApplicationContextHolder; +import org.apache.eventmesh.connector.spring.config.EventMeshAutoConfiguration; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.source.Source; + +public class SpringSourceConnectorCreateServiceImpl implements ConnectorCreateService { + + @Override + public Source create() { + if (SpringApplicationContextHolder.isStarted()) { + return (Source) SpringApplicationContextHolder.getBean(EventMeshAutoConfiguration.SPRING_SOURCE_CONNECTOR_BEAN_NAME); + } + return null; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService new file mode 100644 index 0000000000..1daf7796fb --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.api.ConnectorCreateService @@ -0,0 +1,19 @@ +# +# 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. +# + +springSink=org.apache.eventmesh.connector.spring.sink.connector.SpringSinkConnectorCreateServiceImpl +springSource=org.apache.eventmesh.connector.spring.source.connector.SpringSourceConnectorCreateServiceImpl \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/META-INF/spring.factories b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..8cc07dc970 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/META-INF/spring.factories @@ -0,0 +1,19 @@ +# +# 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. +# + +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.apache.eventmesh.connector.spring.config.EventMeshAutoConfiguration \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..dd5c081afa --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/sink-config.yml @@ -0,0 +1,28 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-SPRING + idc: FT + env: PRD + group: springSink + appId: 5033 + userName: springSinkUser + passWord: springPassWord +connectorConfig: + connectorName: springSink \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/source-config.yml b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/source-config.yml new file mode 100644 index 0000000000..4559cd6708 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/main/resources/source-config.yml @@ -0,0 +1,28 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-SPRING + idc: FT + env: PRD + group: springSource + appId: 5033 + userName: springSourceUser + passWord: springPassWord +connectorConfig: + connectorName: springSource diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/test/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-spring/src/test/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnectorTest.java new file mode 100644 index 0000000000..767c8803de --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/test/java/org/apache/eventmesh/connector/spring/sink/connector/SpringSinkConnectorTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.sink.connector; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.apache.eventmesh.common.config.connector.spring.SpringSinkConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; + +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 org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class SpringSinkConnectorTest { + + @Spy + private SpringSinkConnector connector; + + @BeforeEach + public void setUp() throws Exception { + SpringSinkConfig sinkConfig = new SpringSinkConfig(); + connector.init(sinkConfig); + connector.start(); + } + + @Test + public void testSinkConnectorRunning() { + Assertions.assertTrue(connector.isRunning()); + } + + @Test + public void testProcessRecordsInSinkConnectorQueue() throws Exception { + final int count = 5; + final String message = "testMessage"; + writeMockedRecords(count, message); + BlockingQueue queue = connector.getQueue(); + Assertions.assertEquals(count, queue.size()); + for (int i = 0; i < count; i++) { + ConnectRecord poll = queue.poll(); + assertNotNull(poll); + String expectedMessage = message + i; + Assertions.assertEquals(poll.getData(), expectedMessage); + } + } + + private void writeMockedRecords(int count, String message) throws Exception { + List records = new ArrayList<>(); + for (int i = 0; i < count; i++) { + records.add(new ConnectRecord(null, null, System.currentTimeMillis(), message + i)); + } + connector.put(records); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-spring/src/test/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnectorTest.java b/eventmesh-connectors/eventmesh-connector-spring/src/test/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnectorTest.java new file mode 100644 index 0000000000..c4c59f0e5f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-spring/src/test/java/org/apache/eventmesh/connector/spring/source/connector/SpringSourceConnectorTest.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.spring.source.connector; + +import static org.mockito.Mockito.doReturn; + +import org.apache.eventmesh.common.config.connector.spring.SpringSourceConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MutablePropertySources; + +@ExtendWith(MockitoExtension.class) +public class SpringSourceConnectorTest { + + private SpringSourceConnector connector; + + @Test + public void testSpringSourceConnector() throws Exception { + ConfigurableApplicationContext context = Mockito.mock(ConfigurableApplicationContext.class); + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + doReturn(new MutablePropertySources()).when(environment).getPropertySources(); + doReturn(environment).when(context).getEnvironment(); + connector = new SpringSourceConnector(); + connector.setApplicationContext(context); + SpringSourceConfig sourceConfig = new SpringSourceConfig(); + connector.init(sourceConfig); + connector.start(); + final int count = 5; + final String message = "testMessage"; + writeMockedRecords(count, message); + List connectRecords = connector.poll(); + Assertions.assertEquals(count, connectRecords.size()); + for (int i = 0; i < connectRecords.size(); i++) { + Object actualMessage = String.valueOf(connectRecords.get(i).getData()); + String expectedMessage = "testMessage" + i; + Assertions.assertEquals(expectedMessage, actualMessage); + } + } + + private void writeMockedRecords(int count, String message) { + for (int i = 0; i < count; i++) { + connector.send(message + i); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wechat/build.gradle b/eventmesh-connectors/eventmesh-connector-wechat/build.gradle new file mode 100644 index 0000000000..afd4e115c0 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/build.gradle @@ -0,0 +1,36 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + + implementation 'com.alibaba.fastjson2:fastjson2' + implementation 'com.google.guava:guava' + implementation 'com.squareup.okhttp3:okhttp' + + implementation "io.netty:netty-all" + + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + testImplementation "org.mockito:mockito-inline" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wechat/gradle.properties b/eventmesh-connectors/eventmesh-connector-wechat/gradle.properties new file mode 100644 index 0000000000..3b209c14b4 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=wechat \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/config/WeChatConnectServerConfig.java b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/config/WeChatConnectServerConfig.java new file mode 100644 index 0000000000..2555041c02 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/config/WeChatConnectServerConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wechat.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class WeChatConnectServerConfig extends Config { + + private boolean sinkEnable; +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/server/WeChatConnectServer.java b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/server/WeChatConnectServer.java new file mode 100644 index 0000000000..0ea1927c18 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/server/WeChatConnectServer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wechat.server; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.wechat.config.WeChatConnectServerConfig; +import org.apache.eventmesh.connector.wechat.sink.connector.WeChatSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class WeChatConnectServer { + + public static void main(String[] args) throws Exception { + + WeChatConnectServerConfig weChatConnectServerConfig = ConfigUtil.parse(WeChatConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (weChatConnectServerConfig.isSinkEnable()) { + Application application = new Application(); + application.run(WeChatSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/sink/connector/TemplateMessageResponse.java b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/sink/connector/TemplateMessageResponse.java new file mode 100644 index 0000000000..231b01c164 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/sink/connector/TemplateMessageResponse.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wechat.sink.connector; + +import lombok.Data; + +@Data +public class TemplateMessageResponse { + + private int errcode; + + private String errmsg; + + private String msgid; +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/sink/connector/WeChatSinkConnector.java b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/sink/connector/WeChatSinkConnector.java new file mode 100644 index 0000000000..6908d119b9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/main/java/org/apache/eventmesh/connector/wechat/sink/connector/WeChatSinkConnector.java @@ -0,0 +1,207 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wechat.sink.connector; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.wechat.WeChatSinkConfig; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +/** + * WeChat sink connector. WeChat doc: ... + */ +@Slf4j +public class WeChatSinkConnector implements Sink { + + public static final Cache ACCESS_TOKEN_CACHE = CacheBuilder.newBuilder() + .initialCapacity(12) + .maximumSize(10) + .concurrencyLevel(5) + .expireAfterWrite(120, TimeUnit.MINUTES) + .build(); + + public static final String ACCESS_TOKEN_CACHE_KEY = "access_token"; + + private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + + private static final String MESSAGE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"; + + private OkHttpClient okHttpClient; + + private WeChatSinkConfig sinkConfig; + + private volatile boolean isRunning = false; + + @Override + public Class configClass() { + return WeChatSinkConfig.class; + } + + @Override + public void init(Config config) { + this.sinkConfig = (WeChatSinkConfig) config; + okHttpClient = new OkHttpClient.Builder() + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .build(); + } + + @Override + public void init(ConnectorContext connectorContext) { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (WeChatSinkConfig) sinkConnectorContext.getSinkConfig(); + okHttpClient = new OkHttpClient.Builder() + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .build(); + } + + @Override + public void start() { + isRunning = true; + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws IOException { + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord record : sinkRecords) { + try { + if (Objects.isNull(record.getData())) { + log.warn("ConnectRecord data is null, ignore."); + continue; + } + sendMessage(record); + } catch (Exception e) { + log.error("Failed to sink message to WeChat.", e); + } + } + } + + @SneakyThrows + private void sendMessage(ConnectRecord record) { + // get access token + String accessToken = getAccessToken(); + MediaType mediaType = MediaType.parse("application/json; charset=utf-8"); + RequestBody body = RequestBody.create(mediaType, new String((byte[]) record.getData())); + Request request = new Request.Builder() + .url(String.format(MESSAGE_SEND_URL, accessToken)) + .post(body) + .build(); + try (Response response = okHttpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + log.error("server response: {}", ToStringBuilder.reflectionToString(response)); + throw new IOException("Unexpected code " + response); + } + + ResponseBody responseBody = response.body(); + if (responseBody == null) { + throw new IOException("Response body is null."); + } + + String jsonStr = responseBody.string(); + TemplateMessageResponse messageResponse = JsonUtils.parseObject(jsonStr, TemplateMessageResponse.class); + if (messageResponse == null) { + throw new IOException("message response is null."); + } + + if (messageResponse.getErrcode() != 0) { + throw new IllegalAccessException(String.format("Send message to WeChat error! errorCode=%s, errorMessage=%s", + messageResponse.getErrcode(), messageResponse.getErrmsg())); + } + } + + } + + @SneakyThrows + private String getAccessToken() { + return ACCESS_TOKEN_CACHE.get(ACCESS_TOKEN_CACHE_KEY, + () -> { + Request tokenRequest = new Request.Builder() + .url(String.format(ACCESS_TOKEN_URL, sinkConfig.getSinkConnectorConfig().getAppId(), + sinkConfig.getSinkConnectorConfig().getAppSecret())) + .get() + .build(); + String accessToken; + try (Response response = okHttpClient.newCall(tokenRequest).execute()) { + if (!response.isSuccessful()) { + log.error("server response: {}", ToStringBuilder.reflectionToString(response)); + throw new IOException("Unexpected code " + response); + } + + String json = Objects.requireNonNull(response.body()).string(); + JSONObject jsonObject = JSON.parseObject(json); + accessToken = Objects.requireNonNull(jsonObject).getString(ACCESS_TOKEN_CACHE_KEY); + ACCESS_TOKEN_CACHE.put(ACCESS_TOKEN_CACHE_KEY, accessToken); + } + + return accessToken; + }); + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-wechat/src/main/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/main/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-wechat/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..6f8face365 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/main/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-WECHAT + idc: FT + env: PRD + group: weChatSink + appId: 5034 + userName: weChatSinkUser + passWord: weChatPassWord +sinkConnectorConfig: + connectorName: weChatSink + appId: weChatAppId + appSecret: weChatAppSecret diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/test/java/org/apache/eventmesh/connector/wechat/sink/connector/WeChatSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-wechat/src/test/java/org/apache/eventmesh/connector/wechat/sink/connector/WeChatSinkConnectorTest.java new file mode 100644 index 0000000000..00432a4e2c --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/test/java/org/apache/eventmesh/connector/wechat/sink/connector/WeChatSinkConnectorTest.java @@ -0,0 +1,152 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wechat.sink.connector; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.apache.eventmesh.common.config.connector.wechat.WeChatSinkConfig; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +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 org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +@ExtendWith(MockitoExtension.class) +public class WeChatSinkConnectorTest { + + private WeChatSinkConnector weChatSinkConnector; + + @Mock + private OkHttpClient okHttpClient; + + @BeforeEach + public void setUp() throws Exception { + Request tokenRequest = new Request.Builder().url("https://api.weixin.qq.com/cgi-bin/token").build(); + String tokenResponseJson = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}"; + ResponseBody responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), tokenResponseJson); + Response tokenResponse = new Response.Builder() + .request(tokenRequest) + .protocol(Protocol.HTTP_1_0) + .message("ok") + .code(200) + .body(responseBody) + .build(); + ArgumentMatcher tokenMatcher = (anyRequest) -> tokenRequest.url().encodedPath().startsWith(anyRequest.url().encodedPath()); + Call tokenCall = Mockito.mock(Call.class); + Mockito.doReturn(tokenCall).when(okHttpClient).newCall(Mockito.argThat(tokenMatcher)); + Mockito.doReturn(tokenResponse).when(tokenCall).execute(); + + weChatSinkConnector = new WeChatSinkConnector(); + WeChatSinkConfig weChatSinkConfig = (WeChatSinkConfig) ConfigUtil.parse(weChatSinkConnector.configClass()); + weChatSinkConnector.init(weChatSinkConfig); + Field clientField = ReflectionSupport.findFields(weChatSinkConnector.getClass(), + (f) -> f.getName().equals("okHttpClient"), + HierarchyTraversalMode.BOTTOM_UP).get(0); + clientField.setAccessible(true); + clientField.set(weChatSinkConnector, okHttpClient); + weChatSinkConnector.start(); + } + + @Test + public void testSendMessageToWeChat() throws Exception { + + Request sendMessageRequest = new Request.Builder().url("https://api.weixin.qq.com/cgi-bin/message/template/send").build(); + String sendMessageResponseJson = "{\"errcode\":0,\"errmsg\":\"ok\",\"msgid\":200228332}"; + ResponseBody sendMessageBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), sendMessageResponseJson); + Response sendMessageResponse = new Response.Builder() + .code(200) + .protocol(Protocol.HTTP_1_0) + .request(sendMessageRequest) + .body(sendMessageBody) + .message("ok") + .build(); + ArgumentMatcher sendMessageMatcher = + (anyRequest) -> sendMessageRequest.url().encodedPath().startsWith(anyRequest.url().encodedPath()); + Call sendMessageRequestCall = Mockito.mock(Call.class); + Mockito.doReturn(sendMessageRequestCall).when(okHttpClient).newCall(Mockito.argThat(sendMessageMatcher)); + Mockito.doReturn(sendMessageResponse).when(sendMessageRequestCall).execute(); + + List records = new ArrayList<>(); + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "Hello, EventMesh!".getBytes(StandardCharsets.UTF_8)); + records.add(connectRecord); + + weChatSinkConnector.put(records); + verify(okHttpClient, times(2)).newCall(any(Request.class)); + + WeChatSinkConnector.ACCESS_TOKEN_CACHE.invalidate(WeChatSinkConnector.ACCESS_TOKEN_CACHE_KEY); + } + + @Test + public void testSendMessageToWeChatAbnormally() throws Exception { + Request sendMessageRequest = new Request.Builder().url("https://api.weixin.qq.com/cgi-bin/message/template/send").build(); + String sendMessageResponseJson = "{\"errcode\":42001,\"errmsg\":\"access_token expired rid: 656e8793-061949b5-738cb8f4\"}"; + ResponseBody sendMessageBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), sendMessageResponseJson); + Response sendMessageResponse = new Response.Builder() + .code(200) + .protocol(Protocol.HTTP_1_0) + .request(sendMessageRequest) + .body(sendMessageBody) + .message("ok") + .build(); + ArgumentMatcher sendMessageMatcher = + (anyRequest) -> sendMessageRequest.url().encodedPath().startsWith(anyRequest.url().encodedPath()); + Call sendMessageRequestCall = Mockito.mock(Call.class); + Mockito.doReturn(sendMessageRequestCall).when(okHttpClient).newCall(Mockito.argThat(sendMessageMatcher)); + Mockito.doReturn(sendMessageResponse).when(sendMessageRequestCall).execute(); + + ConnectRecord connectRecord = new ConnectRecord(null, null, + System.currentTimeMillis(), "Hello, EventMesh!".getBytes(StandardCharsets.UTF_8)); + Method sendMessageMethod = WeChatSinkConnector.class.getDeclaredMethod("sendMessage", ConnectRecord.class); + sendMessageMethod.setAccessible(true); + Assertions.assertThrows(InvocationTargetException.class, () -> sendMessageMethod.invoke(weChatSinkConnector, connectRecord)); + } + + @AfterEach + public void tearDown() throws IOException { + weChatSinkConnector.stop(); + } + +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-wechat/src/test/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/test/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-wechat/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-wechat/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..6f8face365 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wechat/src/test/resources/sink-config.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-WECHAT + idc: FT + env: PRD + group: weChatSink + appId: 5034 + userName: weChatSinkUser + passWord: weChatPassWord +sinkConnectorConfig: + connectorName: weChatSink + appId: weChatAppId + appSecret: weChatAppSecret diff --git a/eventmesh-connectors/eventmesh-connector-wecom/build.gradle b/eventmesh-connectors/eventmesh-connector-wecom/build.gradle new file mode 100644 index 0000000000..e89567c6f9 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + + implementation 'com.google.guava:guava' + implementation "io.netty:netty-all" + implementation 'org.apache.httpcomponents:httpclient' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + testImplementation "org.mockito:mockito-inline" +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wecom/gradle.properties b/eventmesh-connectors/eventmesh-connector-wecom/gradle.properties new file mode 100644 index 0000000000..c91eb40394 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=connector +pluginName=wecom \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/config/WeComConnectServerConfig.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/config/WeComConnectServerConfig.java new file mode 100644 index 0000000000..38235b3d3b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/config/WeComConnectServerConfig.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.config; + +import org.apache.eventmesh.common.config.connector.Config; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class WeComConnectServerConfig extends Config { + + private boolean sinkEnable; +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/config/WeComMessageTemplateType.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/config/WeComMessageTemplateType.java new file mode 100644 index 0000000000..a166022731 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/config/WeComMessageTemplateType.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.config; + +import java.util.Arrays; + +public enum WeComMessageTemplateType { + + PLAIN_TEXT("text", "text"), + MARKDOWN("markdown", "markdown"); + + private final String templateType; + + private final String templateKey; + + WeComMessageTemplateType(String templateType, String templateKey) { + this.templateType = templateType; + this.templateKey = templateKey; + } + + public String getTemplateType() { + return templateType; + } + + public String getTemplateKey() { + return templateKey; + } + + public static WeComMessageTemplateType of(String templateType) { + return Arrays.stream(values()) + .filter(v -> v.getTemplateType().equals(templateType)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("TemplateType: " + templateType + " not found.")); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/constants/ConnectRecordExtensionKeys.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/constants/ConnectRecordExtensionKeys.java new file mode 100644 index 0000000000..3c1a9dfa8b --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/constants/ConnectRecordExtensionKeys.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.constants; + +/** + * Constants of record extension key. + */ +public interface ConnectRecordExtensionKeys { + + String WECOM_MESSAGE_TEMPLATE_TYPE = "wecomtemplatetype"; + +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/server/WeComConnectServer.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/server/WeComConnectServer.java new file mode 100644 index 0000000000..f9c4861684 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/server/WeComConnectServer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.server; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.connector.wecom.config.WeComConnectServerConfig; +import org.apache.eventmesh.connector.wecom.sink.connector.WeComSinkConnector; +import org.apache.eventmesh.openconnect.Application; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +public class WeComConnectServer { + + public static void main(String[] args) throws Exception { + + WeComConnectServerConfig weComConnectServerConfig = ConfigUtil.parse(WeComConnectServerConfig.class, + Constants.CONNECT_SERVER_CONFIG_FILE_NAME); + + if (weComConnectServerConfig.isSinkEnable()) { + Application application = new Application(); + application.run(WeComSinkConnector.class); + } + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/SendMessageRequest.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/SendMessageRequest.java new file mode 100644 index 0000000000..43f1f1657a --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/SendMessageRequest.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.sink.connector; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class SendMessageRequest { + + @JsonProperty("msgtype") + private String messageType; + + @JsonProperty("text") + private Map textContent; + + @JsonProperty("markdown") + private Map markdownContent; +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/SendMessageResponse.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/SendMessageResponse.java new file mode 100644 index 0000000000..0a64f326d2 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/SendMessageResponse.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.sink.connector; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class SendMessageResponse { + + @JsonProperty("errcode") + private int errorCode; + + @JsonProperty("errmsg") + private String errorMessage; +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/WeComSinkConnector.java b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/WeComSinkConnector.java new file mode 100644 index 0000000000..ca628fa590 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/java/org/apache/eventmesh/connector/wecom/sink/connector/WeComSinkConnector.java @@ -0,0 +1,155 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.sink.connector; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.wecom.WeComSinkConfig; +import org.apache.eventmesh.common.enums.EventMeshDataContentType; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.wecom.config.WeComMessageTemplateType; +import org.apache.eventmesh.connector.wecom.constants.ConnectRecordExtensionKeys; +import org.apache.eventmesh.openconnect.api.connector.ConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +/** + * WeCom sink connector. + * WeCom doc: ... + */ +@Slf4j +public class WeComSinkConnector implements Sink { + + private static final String ROBOT_WEBHOOK_URL_PREFIX = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key="; + + private CloseableHttpClient httpClient; + + private WeComSinkConfig sinkConfig; + + private volatile boolean isRunning = false; + + @Override + public Class configClass() { + return WeComSinkConfig.class; + } + + @Override + public void init(Config config) { + this.sinkConfig = (WeComSinkConfig) config; + httpClient = HttpClientBuilder.create().build(); + } + + @Override + public void init(ConnectorContext connectorContext) { + SinkConnectorContext sinkConnectorContext = (SinkConnectorContext) connectorContext; + this.sinkConfig = (WeComSinkConfig) sinkConnectorContext.getSinkConfig(); + httpClient = HttpClientBuilder.create().build(); + } + + @Override + public void start() { + isRunning = true; + } + + @Override + public void commit(ConnectRecord record) { + + } + + @Override + public String name() { + return this.sinkConfig.getSinkConnectorConfig().getConnectorName(); + } + + @Override + public void onException(ConnectRecord record) { + + } + + @Override + public void stop() throws IOException { + isRunning = false; + httpClient.close(); + } + + public boolean isRunning() { + return isRunning; + } + + @Override + public void put(List sinkRecords) { + for (ConnectRecord record : sinkRecords) { + try { + if (Objects.isNull(record.getData())) { + log.warn("ConnectRecord data is null, ignore."); + continue; + } + sendMessage(record); + } catch (Exception e) { + log.error("Failed to sink message to WeCom.", e); + } + } + } + + @SneakyThrows + private void sendMessage(ConnectRecord record) { + final String target = ROBOT_WEBHOOK_URL_PREFIX + sinkConfig.getSinkConnectorConfig().getRobotWebhookKey(); + SendMessageRequest request = new SendMessageRequest(); + HttpPost httpPost = new HttpPost(target); + httpPost.addHeader("Content-Type", EventMeshDataContentType.JSON.getCode()); + WeComMessageTemplateType templateType = WeComMessageTemplateType.of( + Optional.ofNullable(record.getExtension(ConnectRecordExtensionKeys.WECOM_MESSAGE_TEMPLATE_TYPE)) + .orElse(WeComMessageTemplateType.PLAIN_TEXT.getTemplateType())); + Map contentMap = new HashMap<>(); + if (WeComMessageTemplateType.PLAIN_TEXT == templateType) { + contentMap.put("content", new String((byte[]) record.getData())); + request.setTextContent(contentMap); + } else if (WeComMessageTemplateType.MARKDOWN == templateType) { + contentMap.put("content", new String((byte[]) record.getData())); + request.setMarkdownContent(contentMap); + } + request.setMessageType(templateType.getTemplateKey()); + httpPost.setEntity(new StringEntity(Objects.requireNonNull(JsonUtils.toJSONString(request)), ContentType.APPLICATION_JSON)); + CloseableHttpResponse httpResponse = httpClient.execute(httpPost); + String resultStr = EntityUtils.toString(httpResponse.getEntity(), Constants.DEFAULT_CHARSET); + SendMessageResponse sendMessageResponse = Objects.requireNonNull(JsonUtils.parseObject(resultStr, SendMessageResponse.class)); + if (sendMessageResponse.getErrorCode() != 0) { + throw new IllegalAccessException(String.format("Send message to weCom error! errorCode=%s, errorMessage=%s", + sendMessageResponse.getErrorCode(), sendMessageResponse.getErrorMessage())); + } + } +} \ No newline at end of file diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-wecom/src/main/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/main/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-wecom/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..c21d5db0dc --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/main/resources/sink-config.yml @@ -0,0 +1,29 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-WECOM + idc: FT + env: PRD + group: weComSink + appId: 5034 + userName: weComSinkUser + passWord: weComPassWord +sinkConnectorConfig: + connectorName: weComSink + robotWebhookKey: weComRobotWebhookKey diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/MockRecordOffset.java b/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/MockRecordOffset.java new file mode 100644 index 0000000000..066fe3f667 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/MockRecordOffset.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.connector; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; + +public class MockRecordOffset extends RecordOffset { + @Override + public Class getRecordOffsetClass() { + return MockRecordOffset.class; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/MockRecordPartition.java b/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/MockRecordPartition.java new file mode 100644 index 0000000000..aae552891f --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/MockRecordPartition.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.connector; + +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +public class MockRecordPartition extends RecordPartition { + @Override + public Class getRecordPartitionClass() { + return MockRecordPartition.class; + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/WeComSinkConnectorTest.java b/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/WeComSinkConnectorTest.java new file mode 100644 index 0000000000..64b4e19aa3 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/test/java/org/apache/eventmesh/connector/wecom/connector/WeComSinkConnectorTest.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.eventmesh.connector.wecom.connector; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.apache.eventmesh.common.config.connector.wecom.WeComSinkConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.wecom.config.WeComMessageTemplateType; +import org.apache.eventmesh.connector.wecom.constants.ConnectRecordExtensionKeys; +import org.apache.eventmesh.connector.wecom.sink.connector.SendMessageResponse; +import org.apache.eventmesh.connector.wecom.sink.connector.WeComSinkConnector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +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 org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class WeComSinkConnectorTest { + + private WeComSinkConnector connector; + + @Mock + private CloseableHttpClient httpClient; + + @BeforeEach + public void setUp() throws Exception { + connector = new WeComSinkConnector(); + CloseableHttpResponse mockedResponse = Mockito.mock(CloseableHttpResponse.class); + HttpEntity httpEntity = Mockito.mock(HttpEntity.class); + Mockito.doReturn(mockedResponse).when(httpClient).execute(any(HttpPost.class)); + Mockito.doReturn(httpEntity).when(mockedResponse).getEntity(); + WeComSinkConfig sinkConfig = (WeComSinkConfig) ConfigUtil.parse(connector.configClass()); + connector.init(sinkConfig); + Field httpClientField = + ReflectionSupport.findFields(connector.getClass(), (f) -> f.getName().equals("httpClient"), HierarchyTraversalMode.BOTTOM_UP).get(0); + httpClientField.setAccessible(true); + httpClientField.set(connector, httpClient); + connector.start(); + } + + @Test + public void testSendMessageToWeCom() throws IOException { + try (MockedStatic entityUtilsMockedStatic = Mockito.mockStatic(EntityUtils.class)) { + entityUtilsMockedStatic.when(() -> EntityUtils.toString(any(HttpEntity.class), any(Charset.class))) + .thenReturn(JsonUtils.toJSONString(new SendMessageResponse())); + final int times = 3; + List records = new ArrayList<>(); + for (int i = 0; i < times; i++) { + RecordPartition partition = new MockRecordPartition(); + RecordOffset offset = new MockRecordOffset(); + ConnectRecord connectRecord = + new ConnectRecord(partition, offset, System.currentTimeMillis(), "Hello, EventMesh!".getBytes(StandardCharsets.UTF_8)); + connectRecord.addExtension(ConnectRecordExtensionKeys.WECOM_MESSAGE_TEMPLATE_TYPE, + WeComMessageTemplateType.PLAIN_TEXT.getTemplateType()); + records.add(connectRecord); + } + connector.put(records); + verify(httpClient, times(times)).execute(any(HttpPost.class)); + } + } + + @AfterEach + public void tearDown() throws IOException { + connector.stop(); + httpClient.close(); + } +} diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/test/resources/server-config.yml b/eventmesh-connectors/eventmesh-connector-wecom/src/test/resources/server-config.yml new file mode 100644 index 0000000000..20d6e6d592 --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/test/resources/server-config.yml @@ -0,0 +1,18 @@ +# +# 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. +# + +sinkEnable: true diff --git a/eventmesh-connectors/eventmesh-connector-wecom/src/test/resources/sink-config.yml b/eventmesh-connectors/eventmesh-connector-wecom/src/test/resources/sink-config.yml new file mode 100644 index 0000000000..c21d5db0dc --- /dev/null +++ b/eventmesh-connectors/eventmesh-connector-wecom/src/test/resources/sink-config.yml @@ -0,0 +1,29 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-WECOM + idc: FT + env: PRD + group: weComSink + appId: 5034 + userName: weComSinkUser + passWord: weComPassWord +sinkConnectorConfig: + connectorName: weComSink + robotWebhookKey: weComRobotWebhookKey diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/gradle.properties b/eventmesh-connectors/gradle.properties similarity index 100% rename from eventmesh-connector-plugin/eventmesh-connector-api/gradle.properties rename to eventmesh-connectors/gradle.properties diff --git a/eventmesh-examples/build.gradle b/eventmesh-examples/build.gradle index ed3d38f02b..5815a1b9b7 100644 --- a/eventmesh-examples/build.gradle +++ b/eventmesh-examples/build.gradle @@ -15,30 +15,31 @@ * limitations under the License. */ -def grpcVersion = '1.17.1' - -configurations { - implementation.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' -} +def grpcVersion = '1.68.0' dependencies { - implementation project(":eventmesh-sdk-java") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") implementation project(":eventmesh-common") - implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") - implementation 'org.springframework.boot:spring-boot-starter-web' + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-a2a") + implementation project(":eventmesh-connectors:eventmesh-connector-spring") + implementation('org.springframework.boot:spring-boot-starter-web') { + exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' + } implementation 'io.netty:netty-all' implementation "io.cloudevents:cloudevents-core" implementation "io.cloudevents:cloudevents-json-jackson" implementation "io.openmessaging:openmessaging-api" + implementation 'com.alibaba.nacos:nacos-client' implementation "io.grpc:grpc-protobuf:${grpcVersion}" implementation "io.grpc:grpc-stub:${grpcVersion}" implementation "io.grpc:grpc-netty:${grpcVersion}" implementation "io.grpc:grpc-netty-shaded:${grpcVersion}" - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' -} \ No newline at end of file + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/A2AAbstractDemo.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/A2AAbstractDemo.java new file mode 100644 index 0000000000..e0d2cdabf1 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/A2AAbstractDemo.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.util.Utils; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.util.Properties; + +public class A2AAbstractDemo { + + protected static EventMeshHttpClientConfig initEventMeshHttpClientConfig(final String groupName) + throws IOException { + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); + final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); + + String eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; + if (StringUtils.isNotBlank(eventMeshIp) || StringUtils.isNotBlank(eventMeshHttpPort)) { + eventMeshIPPort = eventMeshIp + ":" + eventMeshHttpPort; + } + + return EventMeshHttpClientConfig.builder() + .liteEventMeshAddr(eventMeshIPPort) + .producerGroup(groupName) + .env("env") + .idc("idc") + .ip(IPUtils.getLocalAddress()) + .sys("1234") + .pid(String.valueOf(ThreadUtils.getPID())) + .userName("eventmesh") + .password("pass") + .build(); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/AgentCardDemo.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/AgentCardDemo.java new file mode 100644 index 0000000000..c3418dc190 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/AgentCardDemo.java @@ -0,0 +1,199 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.protocol.a2a.A2AProtocolConstants; +import org.apache.eventmesh.protocol.a2a.model.AgentCapabilities; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; +import org.apache.eventmesh.protocol.a2a.model.AgentInterface; +import org.apache.eventmesh.protocol.a2a.model.AgentProvider; +import org.apache.eventmesh.protocol.a2a.model.AgentSkill; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.extern.slf4j.Slf4j; + +/** + * Demo showing A2A Agent Card registration, discovery, and deletion via EventMesh. + */ +@Slf4j +public class AgentCardDemo extends A2AAbstractDemo { + + public static void main(String[] args) throws Exception { + EventMeshHttpClientConfig config = initEventMeshHttpClientConfig("a2a-agent-card-demo"); + try (EventMeshHttpProducer producer = new EventMeshHttpProducer(config)) { + + // 1. Register an Agent Card + registerAgentCard(producer, "my.org", "my.unit", "weather-agent"); + + // 2. List Agent Cards + listAgentCards(producer); + + // 3. Get specific Agent Card + getAgentCard(producer, "my.org", "my.unit", "weather-agent"); + + // 4. Delete Agent Card + deleteAgentCard(producer, "my.org", "my.unit", "weather-agent"); + + log.info("AgentCardDemo completed."); + } + } + + private static void registerAgentCard(EventMeshHttpProducer producer, + String orgId, String unitId, String agentId) throws Exception { + AgentCard card = buildSampleCard(agentId); + + Map params = new HashMap<>(); + params.put("org_id", orgId); + params.put("unit_id", unitId); + params.put("agent_id", agentId); + params.put("card", card); + + Map request = new HashMap<>(); + request.put("jsonrpc", "2.0"); + request.put("method", A2AProtocolConstants.OP_REGISTER_AGENT_CARD); + request.put("params", params); + request.put("id", UUID.randomUUID().toString()); + + CloudEvent event = buildA2ACardEvent(request); + producer.publish(event); + log.info("Registered agent card: {}/{}/{}", orgId, unitId, agentId); + } + + private static void listAgentCards(EventMeshHttpProducer producer) throws Exception { + Map params = new HashMap<>(); + params.put("org_id", "my.org"); + + Map request = new HashMap<>(); + request.put("jsonrpc", "2.0"); + request.put("method", A2AProtocolConstants.OP_LIST_AGENT_CARDS); + request.put("params", params); + request.put("id", UUID.randomUUID().toString()); + + CloudEvent event = buildA2ACardEvent(request); + producer.publish(event); + log.info("Listed agent cards for org: my.org"); + } + + private static void getAgentCard(EventMeshHttpProducer producer, + String orgId, String unitId, String agentId) throws Exception { + Map params = new HashMap<>(); + params.put("org_id", orgId); + params.put("unit_id", unitId); + params.put("agent_id", agentId); + + Map request = new HashMap<>(); + request.put("jsonrpc", "2.0"); + request.put("method", A2AProtocolConstants.OP_GET_AGENT_CARD); + request.put("params", params); + request.put("id", UUID.randomUUID().toString()); + + CloudEvent event = buildA2ACardEvent(request); + producer.publish(event); + log.info("Got agent card: {}/{}/{}", orgId, unitId, agentId); + } + + private static void deleteAgentCard(EventMeshHttpProducer producer, + String orgId, String unitId, String agentId) throws Exception { + Map params = new HashMap<>(); + params.put("org_id", orgId); + params.put("unit_id", unitId); + params.put("agent_id", agentId); + + Map request = new HashMap<>(); + request.put("jsonrpc", "2.0"); + request.put("method", A2AProtocolConstants.OP_DELETE_AGENT_CARD); + request.put("params", params); + request.put("id", UUID.randomUUID().toString()); + + CloudEvent event = buildA2ACardEvent(request); + producer.publish(event); + log.info("Deleted agent card: {}/{}/{}", orgId, unitId, agentId); + } + + private static AgentCard buildSampleCard(String agentId) { + AgentInterface iface = AgentInterface.builder() + .url("http://localhost:8080/a2a") + .protocolBinding("JSONRPC") + .protocolVersion(A2AProtocolConstants.PROTOCOL_VERSION) + .build(); + + AgentProvider provider = AgentProvider.builder() + .url("https://example.org") + .organization("Example Org") + .build(); + + AgentCapabilities capabilities = AgentCapabilities.builder() + .streaming(true) + .pushNotifications(true) + .build(); + + AgentSkill skill = AgentSkill.builder() + .id("weather-query") + .name("Weather Query") + .description("Queries weather information for a given location") + .tags(Arrays.asList("weather", "query")) + .examples(Arrays.asList("What's the weather in Beijing?")) + .build(); + + return AgentCard.builder() + .name(agentId) + .description("A weather query agent") + .version("1.0.0") + .supportedInterfaces(Collections.singletonList(iface)) + .provider(provider) + .capabilities(capabilities) + .skills(Collections.singletonList(skill)) + .defaultInputModes(Collections.singletonList("text/plain")) + .defaultOutputModes(Collections.singletonList("text/plain")) + .build(); + } + + private static CloudEvent buildA2ACardEvent(Map jsonRpcBody) { + String content = JsonUtils.toJSONString(jsonRpcBody); + String method = (String) jsonRpcBody.get("method"); + String ceType = A2AProtocolConstants.CE_TYPE_PREFIX + method.replace("/", ".") + ".req"; + + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("a2a-agent-card-demo")) + .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) + .withType(ceType) + .withData(content.getBytes(StandardCharsets.UTF_8)) + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL, "A2A") + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL_VERSION, "2.0") + .withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, method) + .withExtension(A2AProtocolConstants.CE_EXTENSION_MCP_TYPE, "request") + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)) + .build(); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/README.md b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/README.md new file mode 100644 index 0000000000..0e4ea34de3 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/README.md @@ -0,0 +1,151 @@ +# EventMesh A2A Gateway Demo + +## 架构 + +``` + protocol-a2a 模块 runtime 模块 examples 模块 + ┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐ + │ A2AMessageTransport(接口) │ A2AGatewayServer │ │ A2AGatewayDemo│ + │ A2AClient (SDK) │<──HTTP──>│ (main, Netty HTTP)│<──HTTP──>│ (纯客户端) │ + │ AgentCard/Topic │ │ InMemoryTransport │ └──────────────┘ + └─────────────────┘ │ GatewayService │ + │ TaskRegistry │ + └──────────────────┘ +``` + +## 快速开始 + +### 1. 编译 + +```bash +cd eventmesh +./gradlew :eventmesh-protocol-plugin:eventmesh-protocol-a2a:compileJava \ + :eventmesh-runtime:compileJava \ + :eventmesh-examples:compileJava +``` + +### 2. 启动服务端 + +```bash +# 方式一:Gradle +./gradlew :eventmesh-runtime:run -PmainClass=org.apache.eventmesh.runtime.a2a.A2AGatewayServer + +# 方式二:Java 命令行 +java -cp org.apache.eventmesh.runtime.a2a.A2AGatewayServer [port] +# 默认端口 10105 +``` + +服务端启动后: +- Netty HTTP server 监听指定端口 +- 预注册 mock `weather-agent`,自动响应 task 请求 +- TTL 清理:已完成的 task 5 分钟后自动清理,agent card 60 秒无心跳自动过期 + +### 3. 运行客户端 + +```bash +# 方式一:Gradle +./gradlew :eventmesh-examples:run -PmainClass=org.apache.eventmesh.a2a.demo.gateway.A2AGatewayDemo + +# 方式二:Java 命令行 +java -cp org.apache.eventmesh.a2a.demo.gateway.A2AGatewayDemo +``` + +客户端流程: +1. 注册自己的 AgentCard 到 Gateway +2. 列出已注册的 agents +3. 同步提交 task 到 weather-agent +4. 异步提交 task +5. 查询 task 状态 + +## REST API + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/a2a/tasks?mode=sync` | 同步提交 task(等待结果) | +| POST | `/a2a/tasks?mode=async` | 异步提交 task(立即返回 taskId) | +| GET | `/a2a/tasks/{taskId}` | 查询 task 状态 | +| DELETE | `/a2a/tasks/{taskId}` | 取消 task | +| GET | `/a2a/tasks/{taskId}/wait` | 长轮询等待 task 结果 | +| GET | `/a2a/tasks/{taskId}/stream` | SSE 流式推送 task 状态更新 | +| GET | `/a2a/agents` | 列出所有已注册 agents | +| POST | `/a2a/heartbeat` | Agent 心跳 | +| GET | `/a2a/cards/list` | 列出所有 AgentCard | +| POST | `/a2a/cards/card/{org}/{unit}/{agent}` | 注册 AgentCard | + +### 示例:curl 测试 + +```bash +# 同步 task +curl -X POST 'http://localhost:10105/a2a/tasks?mode=sync' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Beijing"}' + +# 异步 task +curl -X POST 'http://localhost:10105/a2a/tasks?mode=async' \ + -H 'Content-Type: application/json' \ + -d '{"targetAgent":"weather-agent","message":"Shanghai"}' + +# 查询状态 +curl http://localhost:10105/a2a/tasks/{taskId} + +# SSE 流 +curl -N http://localhost:10105/a2a/tasks/{taskId}/stream + +# 列出 agents +curl http://localhost:10105/a2a/agents + +# 心跳 +curl -X POST http://localhost:10105/a2a/heartbeat \ + -H 'Content-Type: application/json' \ + -d '{"orgId":"default","unitId":"default","agentId":"weather-agent"}' +``` + +## A2AClient SDK + +```java +A2AClient client = A2AClient.builder() + .gatewayUrl("http://localhost:10105") + .namespace("global") + .agentName("my-agent") + .agentCard(validCard) + .heartbeatInterval(30_000) + .build(); + +client.start(); + +// 同步 task +TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + +// 异步 task +String taskId = client.sendTaskAsync("weather-agent", "Beijing", null); + +// 查询状态 +TaskResult status = client.getTaskStatus(taskId); + +// 取消 +boolean cancelled = client.cancelTask(taskId); + +// 列出 agents +List agents = client.listAgents(); + +client.shutdown(); +``` + +## 测试 + +```bash +# 全部 A2A 测试 +./gradlew :eventmesh-protocol-plugin:eventmesh-protocol-a2a:test \ + :eventmesh-runtime:test --tests "org.apache.eventmesh.runtime.a2a.*" + +# 仅 HTTP 集成测试 +./gradlew :eventmesh-runtime:test --tests "org.apache.eventmesh.runtime.a2a.A2AClientServerIntegrationTest" +``` + +测试覆盖: +- `A2ATopicFactoryTest` — Topic 生成/解析 +- `TaskRegistryTest` — Task 状态机 + TTL 清理 +- `InMemoryA2AMessageTransportTest` — 内存传输投递 +- `A2AGatewayServiceTest` — Gateway 服务层 +- `A2AGatewayEndToEndTest` — 进程内全链路 +- `A2AClientServerIntegrationTest` — 真实 HTTP 客户端-服务端集成测试 diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java new file mode 100644 index 0000000000..e0f6622b8e --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsCaller.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo.ce; + +import org.apache.eventmesh.a2a.demo.A2AAbstractDemo; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; +import org.apache.eventmesh.common.Constants; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventsCaller extends A2AAbstractDemo { + + public static void main(String[] args) throws Exception { + EventMeshHttpClientConfig config = initEventMeshHttpClientConfig("CloudEventsCallerGroup"); + try (EventMeshHttpProducer producer = new EventMeshHttpProducer(config)) { + + // 1. Native CE RPC (Point-to-Point) + sendNativeRpc(producer); + + // 2. Native CE Pub/Sub (Broadcast) + sendNativePubSub(producer); + + // 3. Native CE Streaming + sendNativeStream(producer); + } + } + + /** + * Pattern 1: Native CloudEvent RPC + * Uses 'targetagent' extension for routing. + */ + private static void sendNativeRpc(EventMeshHttpProducer producer) throws Exception { + CloudEvent event = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("ce-client")) + .withType("com.example.rpc.request") + .withSubject("rpc-topic") + .withData("application/text", "RPC Payload".getBytes(StandardCharsets.UTF_8)) + .withExtension("protocol", "A2A") + .withExtension("targetagent", "target-agent-001") // Explicit routing + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)) + .build(); + + log.info("Sending Native CE RPC: {}", event); + producer.publish(event); + } + + /** + * Pattern 2: Native CloudEvent Pub/Sub + * Standard CE behavior using Subject. + */ + private static void sendNativePubSub(EventMeshHttpProducer producer) throws Exception { + CloudEvent event = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("ce-client")) + .withType("com.example.notification") + .withSubject("broadcast.topic") // Broadcast + .withData("application/text", "Broadcast Message".getBytes(StandardCharsets.UTF_8)) + .withExtension("protocol", "A2A") + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)) + .build(); + + log.info("Sending Native CE Pub/Sub: {}", event); + producer.publish(event); + } + + /** + * Pattern 3: Native CloudEvent Streaming + * Uses 'seq' extension. + */ + private static void sendNativeStream(EventMeshHttpProducer producer) throws Exception { + String sessionId = UUID.randomUUID().toString(); + + for (int i = 1; i <= 3; i++) { + CloudEvent event = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("ce-client")) + .withType("com.example.stream") + .withSubject("stream-topic") + .withData("application/text", ("Chunk " + i).getBytes(StandardCharsets.UTF_8)) + .withExtension("protocol", "A2A") + .withExtension("sessionid", sessionId) + .withExtension("seq", String.valueOf(i)) + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)) + .build(); + + log.info("Sending Native CE Stream Chunk {}: {}", i, event); + producer.publish(event); + Thread.sleep(100); + } + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsProvider.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsProvider.java new file mode 100644 index 0000000000..a85ee64df8 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/ce/CloudEventsProvider.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo.ce; + +import org.apache.eventmesh.a2a.demo.A2AAbstractDemo; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.consumer.EventMeshHttpConsumer; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventsProvider extends A2AAbstractDemo { + + public static void main(String[] args) throws Exception { + EventMeshHttpClientConfig config = initEventMeshHttpClientConfig("CloudEventsProviderGroup"); + try (EventMeshHttpConsumer consumer = new EventMeshHttpConsumer(config)) { + + // Subscribe to relevant topics + final List topicList = new ArrayList<>(); + + // 1. Subscribe to RPC Topic + SubscriptionItem rpcItem = new SubscriptionItem(); + rpcItem.setTopic("rpc-topic"); + rpcItem.setMode(SubscriptionMode.CLUSTERING); + rpcItem.setType(SubscriptionType.ASYNC); + topicList.add(rpcItem); + + // 2. Subscribe to Broadcast Topic + SubscriptionItem broadcastItem = new SubscriptionItem(); + broadcastItem.setTopic("broadcast.topic"); + broadcastItem.setMode(SubscriptionMode.BROADCASTING); // Broadcast mode + broadcastItem.setType(SubscriptionType.ASYNC); + topicList.add(broadcastItem); + + // 3. Subscribe to Stream Topic + SubscriptionItem streamItem = new SubscriptionItem(); + streamItem.setTopic("stream-topic"); + streamItem.setMode(SubscriptionMode.CLUSTERING); + streamItem.setType(SubscriptionType.ASYNC); + topicList.add(streamItem); + + consumer.heartBeat(topicList, "http://127.0.0.1:8088/ce/callback"); + + log.info("CloudEvents Provider started. Listening for A2A messages..."); + + while (true) { + Thread.sleep(10000); + } + } + } + + // Simulation of WebController logic + public static void handleCallback(CloudEvent event) { + try { + String protocol = (String) event.getExtension("protocol"); + if (!"A2A".equals(protocol)) { + return; + } + + String subject = event.getSubject(); + String data = new String(event.getData().toBytes(), StandardCharsets.UTF_8); + + log.info("Received Native CloudEvent: Subject={}, Type={}, Data={}", subject, event.getType(), data); + + if ("stream-topic".equals(subject)) { + String seq = (String) event.getExtension("seq"); + String sessionId = (String) event.getExtension("sessionid"); + log.info("Stream processing: Session={}, Seq={}", sessionId, seq); + } + + } catch (Exception e) { + log.error("Error handling callback", e); + } + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/gateway/A2AGatewayDemo.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/gateway/A2AGatewayDemo.java new file mode 100644 index 0000000000..432a255a03 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/gateway/A2AGatewayDemo.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo.gateway; + +import org.apache.eventmesh.protocol.a2a.A2AClient; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; +import org.apache.eventmesh.protocol.a2a.model.AgentSkill; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +/** + * A2A Gateway Client Demo. + * + *

This is a pure HTTP client demo that connects to a running A2A Gateway Server. + * It does NOT depend on any runtime server-side classes. + * + *

Prerequisites: + *

    + *
  1. Start the A2A Gateway Server first: + *
    java org.apache.eventmesh.runtime.a2a.A2AGatewayServer
    + * (server listens on port 10105 by default, with a pre-registered weather-agent)
  2. + *
  3. Then run this client demo.
  4. + *
+ * + *

Flow: + *

+ *   Client -HTTP-> Gateway Server -InMemory-> Weather Agent -> Gateway -> Client
+ * 
+ */ +@Slf4j +public class A2AGatewayDemo { + + private static final String GATEWAY_URL = "http://localhost:10105"; + private static final String NAMESPACE = "global"; + + public static void main(String[] args) throws Exception { + log.info("=== A2A Gateway Client Demo ==="); + log.info("Connecting to Gateway: {}", GATEWAY_URL); + + // 1. Create A2A client (as a caller, not an agent) + A2AClient client = A2AClient.builder() + .gatewayUrl(GATEWAY_URL) + .namespace(NAMESPACE) + .agentName("demo-client") + .agentCard(AgentCard.builder() + .name("demo-client") + .description("A demo client that calls weather-agent") + .version("1.0.0") + .supportedInterfaces(Arrays.asList( + org.apache.eventmesh.protocol.a2a.model.AgentInterface.builder() + .url("http://localhost:0/a2a") + .protocolBinding("JSONRPC") + .protocolVersion("0.3") + .build() + )) + .capabilities(org.apache.eventmesh.protocol.a2a.model.AgentCapabilities.builder() + .streaming(false) + .pushNotifications(false) + .build()) + .skills(Arrays.asList( + AgentSkill.builder() + .id("call-weather") + .name("Call Weather") + .description("Call the weather agent for weather info") + .tags(Arrays.asList("demo", "client")) + .build() + )) + .defaultInputModes(Arrays.asList("text/plain")) + .defaultOutputModes(Arrays.asList("text/plain")) + .build()) + .heartbeatInterval(60_000) + .build(); + + client.start(); + log.info("Client started."); + + // 2. List registered agents + log.info(""); + log.info("--- Listing registered agents ---"); + List agents = client.listAgents(); + log.info("Agents: {}", agents); + + // 3. Submit a task to weather-agent (sync mode) + log.info(""); + log.info("--- Submitting task to weather-agent ---"); + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + log.info("Result: state={}, data={}", result.getState(), result.getData()); + + // 4. Submit another task + log.info(""); + log.info("--- Submitting second task ---"); + A2AClient.TaskResult result2 = client.sendTaskSync("weather-agent", "Shanghai", null); + log.info("Result: state={}, data={}", result2.getState(), result2.getData()); + + // 5. Async task submission + log.info(""); + log.info("--- Async task submission ---"); + java.util.concurrent.CompletableFuture future = + client.sendTask("weather-agent", "Guangzhou"); + A2AClient.TaskResult result3 = future.get(30, TimeUnit.SECONDS); + log.info("Async result: state={}, data={}", result3.getState(), result3.getData()); + + // 6. Query task status + log.info(""); + log.info("--- Querying task status ---"); + A2AClient.TaskResult status = client.getTaskStatus(result.getTaskId()); + log.info("Status: state={}, targetAgent={}", status.getState(), status.getTargetAgent()); + + // 6. Cleanup + log.info(""); + log.info("=== Demo Complete ==="); + client.shutdown(); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpCaller.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpCaller.java new file mode 100644 index 0000000000..8a356e17de --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpCaller.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo.mcp; + +import org.apache.eventmesh.a2a.demo.A2AAbstractDemo; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class McpCaller extends A2AAbstractDemo { + + // MCP JSON-RPC 2.0 Structure + // Request: { "jsonrpc": "2.0", "method": "...", "params": { ... }, "id": "..." } + // Notification: { "jsonrpc": "2.0", "method": "...", "params": { ... } } + + public static void main(String[] args) throws Exception { + EventMeshHttpClientConfig config = initEventMeshHttpClientConfig("McpCallerGroup"); + try (EventMeshHttpProducer producer = new EventMeshHttpProducer(config)) { + + // 1. RPC Pattern (Tools Call) + sendMcpRpc(producer); + + // 2. Pub/Sub Pattern (Notification) + sendMcpPubSub(producer); + + // 3. Streaming Pattern (Sequenced Messages) + sendMcpStream(producer); + } + } + + /** + * Pattern 1: RPC (Request/Response) + * A2A Protocol maps this to P2P routing using '_agentId' or similar. + */ + private static void sendMcpRpc(EventMeshHttpProducer producer) throws Exception { + final String requestId = UUID.randomUUID().toString(); + Map requestParams = new HashMap<>(); + requestParams.put("name", "get_weather"); + requestParams.put("city", "Beijing"); + + String targetAgent = "weather-service-01"; + requestParams.put("_agentId", targetAgent); // Routing hint + + Map requestMap = new HashMap<>(); + requestMap.put("jsonrpc", "2.0"); + requestMap.put("method", "tools/call"); + requestMap.put("params", requestParams); + + requestMap.put("id", requestId); + + CloudEvent event = buildMcpEvent(requestMap, "org.apache.eventmesh.a2a.tools.call.req", "request"); + + log.info("Sending MCP RPC Request: {}", requestMap); + producer.publish(event); + } + + /** + * Pattern 2: Pub/Sub (Broadcast) + * A2A Protocol maps this to PubSub routing using '_topic'. + */ + private static void sendMcpPubSub(EventMeshHttpProducer producer) throws Exception { + Map params = new HashMap<>(); + params.put("message", "System Maintenance in 10 mins"); + params.put("_topic", "system.alerts"); // Broadcast Topic + + Map notification = new HashMap<>(); + notification.put("jsonrpc", "2.0"); + notification.put("method", "notifications/alert"); + notification.put("params", params); + // No ID for notifications + + CloudEvent event = buildMcpEvent(notification, "org.apache.eventmesh.a2a.notifications.alert", "notification"); + + log.info("Sending MCP Pub/Sub Notification: {}", notification); + producer.publish(event); + } + + /** + * Pattern 3: Streaming + * Sends multiple sequenced messages. + */ + private static void sendMcpStream(EventMeshHttpProducer producer) throws Exception { + String streamId = UUID.randomUUID().toString(); + String targetAgent = "log-collector"; + + for (int i = 1; i <= 3; i++) { + Map params = new HashMap<>(); + params.put("logLine", "Log entry " + i); + params.put("_agentId", targetAgent); + params.put("_seq", i); // Sequence number + + Map chunk = new HashMap<>(); + chunk.put("jsonrpc", "2.0"); + chunk.put("method", "message/sendStream"); + chunk.put("params", params); + chunk.put("id", streamId); // Same ID for the session + + CloudEvent event = buildMcpEvent(chunk, "org.apache.eventmesh.a2a.message.sendStream.stream", "request"); + event = CloudEventBuilder.from(event) + .withExtension("seq", String.valueOf(i)) + .build(); + + log.info("Sending MCP Stream Chunk {}: {}", i, chunk); + producer.publish(event); + Thread.sleep(100); + } + } + + private static CloudEvent buildMcpEvent(Map jsonRpcBody, String type, String mcpType) { + String content = JsonUtils.toJSONString(jsonRpcBody); + + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSubject("a2a-mcp-topic") // This might be overridden by the Adaptor based on _topic params + .withSource(URI.create("mcp-client")) + .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) // application/json + .withType(type) + .withData(content.getBytes(StandardCharsets.UTF_8)) + .withExtension("protocol", "A2A") + .withExtension("protocolversion", "2.0") + .withExtension("mcptype", mcpType) + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)) + .build(); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpProvider.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpProvider.java new file mode 100644 index 0000000000..eaad3f403b --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/a2a/demo/mcp/McpProvider.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.eventmesh.a2a.demo.mcp; + +import org.apache.eventmesh.a2a.demo.A2AAbstractDemo; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.consumer.EventMeshHttpConsumer; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import io.cloudevents.CloudEvent; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class McpProvider extends A2AAbstractDemo { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static void main(String[] args) throws Exception { + EventMeshHttpClientConfig config = initEventMeshHttpClientConfig("McpProviderGroup"); + try (EventMeshHttpConsumer consumer = new EventMeshHttpConsumer(config)) { + + // Subscribe to relevant topics + final List topicList = new ArrayList<>(); + + // 1. Subscribe to Broadcast Topic (for Pub/Sub pattern) + SubscriptionItem pubSubItem = new SubscriptionItem(); + pubSubItem.setTopic("system.alerts"); + pubSubItem.setMode(SubscriptionMode.CLUSTERING); + pubSubItem.setType(SubscriptionType.ASYNC); + topicList.add(pubSubItem); + + // 2. Subscribe to P2P Routing (Agent ID as topic or filtered) + // Note: In real A2A, this might be handled by a specific queue or filtered topic + // For demo, we assume the 'a2a-mcp-topic' is used or specific agent topics + SubscriptionItem rpcItem = new SubscriptionItem(); + rpcItem.setTopic("a2a-mcp-topic"); + rpcItem.setMode(SubscriptionMode.CLUSTERING); + rpcItem.setType(SubscriptionType.ASYNC); + topicList.add(rpcItem); + + consumer.heartBeat(topicList, "http://127.0.0.1:8088/mcp/callback"); + + log.info("MCP Provider started. Listening for A2A messages..."); + + // In HTTP Consumer mode for EventMesh, typically a callback URL is registered. + // However, the Java HTTP Consumer also supports pulling or local handling if configured differently. + // Since EventMeshHttpConsumer is designed for Webhooks mostly in "subscribe" mode where it pushes to a URL, + // we simulate the handling logic here as if it received the callback. + + // Simulate processing loop (in a real app, this would be a WebController receiving POSTs from EventMesh) + while (true) { + Thread.sleep(10000); + } + } + } + + // Simulates the logic that would be inside the WebController receiving the callback + public static void handleCallback(CloudEvent event) { + try { + String protocol = (String) event.getExtension("protocol"); + if (!"A2A".equals(protocol)) { + return; + } + + String mcpType = (String) event.getExtension("mcptype"); + byte[] data = event.getData().toBytes(); + String content = new String(data, StandardCharsets.UTF_8); + JsonNode json = objectMapper.readTree(content); + + log.info("Received A2A MCP Message: Type={}, Data={}", mcpType, content); + + if ("request".equals(mcpType)) { + // Handle RPC or Stream + String method = json.get("method").asText(); + String id = json.get("id").asText(); + + if ("tools/call".equals(method)) { + log.info("Executing Tool: {}", json.get("params")); + // Send Response logic here (would require a Producer to send back) + } else if ("message/sendStream".equals(method)) { + String seq = (String) event.getExtension("seq"); + log.info("Received Stream Chunk: Seq={}", seq); + } + } else if ("notification".equals(mcpType)) { + log.info("Received Notification: {}", json.get("params")); + } + + } catch (Exception e) { + log.error("Error handling callback", e); + } + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/common/ExampleConstants.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/common/ExampleConstants.java index 2befeebc5d..9972ca7433 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/common/ExampleConstants.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/common/ExampleConstants.java @@ -27,7 +27,7 @@ public class ExampleConstants { public static final String EVENTMESH_TCP_PORT = "eventmesh.tcp.port"; public static final String EVENTMESH_GRPC_PORT = "eventmesh.grpc.port"; - public static final String DEFAULT_EVENTMESH_IP = "127.0.0.1"; + public static final String DEFAULT_EVENTMESH_IP = "localhost"; public static final String DEFAULT_EVENTMESH_IP_PORT = "127.0.0.1:10105"; public static final String EVENTMESH_GRPC_ASYNC_TEST_TOPIC = "TEST-TOPIC-GRPC-ASYNC"; @@ -42,4 +42,18 @@ public class ExampleConstants { public static final String DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP = "EventMeshTest-producerGroup"; public static final String DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP = "EventMeshTest-consumerGroup"; + public static final String SERVER_NAME = "server.name"; + + public static final String EVENTMESH_CATALOG_NAME = "eventmesh.catalog.name"; + + public static final String EVENTMESH_WORKFLOW_NAME = "eventmesh.workflow.name"; + + public static final String EVENTMESH_SELECTOR_NACOS_ADDRESS = "eventmesh.selector.nacos.address"; + + public static final String EVENTMESH_SELECTOR_TYPE = "eventmesh.selector.type"; + + public static final String ENV = "P"; + public static final String IDC = "FT"; + public static final String SUB_SYS = "1234"; + public static final String SERVER_PORT = "server.port"; } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/GrpcAbstractDemo.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/GrpcAbstractDemo.java new file mode 100644 index 0000000000..dd3fe8cb07 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/GrpcAbstractDemo.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc; + +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.util.Utils; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class GrpcAbstractDemo { + + protected static EventMeshGrpcClientConfig initEventMeshGrpcClientConfig(final String groupName) throws IOException { + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); + final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); + + return EventMeshGrpcClientConfig.builder() + .serverAddr(eventMeshIp) + .serverPort(Integer.parseInt(eventMeshGrpcPort)) + .producerGroup(groupName) + .env("env") + .idc("idc") + .sys("1234") + .build(); + } + + protected static CloudEvent buildCloudEvent(final Map content, String topic) { + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSubject(topic) + .withSource(URI.create("/")) + .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) + .withType(CLOUD_EVENTS_PROTOCOL_NAME) + .withData(JsonUtils.toJSONString(content).getBytes(StandardCharsets.UTF_8)) + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) + .build(); + + } + + protected static EventMeshMessage buildEventMeshMessage(final Map content, String topic) { + return EventMeshMessage.builder() + .content(JsonUtils.toJSONString(content)) + .topic(topic) + .uniqueId(RandomStringUtils.generateNum(30)) + .bizSeqNo(RandomStringUtils.generateNum(30)) + .build() + .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsBatchPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsBatchPublishInstance.java index 54b63f9f8f..264dcc64ab 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsBatchPublishInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsBatchPublishInstance.java @@ -17,70 +17,39 @@ package org.apache.eventmesh.grpc.pub.cloudevents; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; -import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; -import java.util.UUID; +import java.util.concurrent.TimeUnit; import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; import lombok.extern.slf4j.Slf4j; @Slf4j -public class CloudEventsBatchPublishInstance { +public class CloudEventsBatchPublishInstance extends GrpcAbstractDemo { public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); + final Map content = new HashMap<>(); + content.put("content", "testBatchPublishMessage"); - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); - - eventMeshGrpcProducer.init(); - - Map content = new HashMap<>(); - content.put("content", "testRequestReplyMessage"); - - List cloudEventList = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - - cloudEventList.add(event); - } - - eventMeshGrpcProducer.publish(cloudEventList); - Thread.sleep(10000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore + final List cloudEventList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + cloudEventList.add(buildCloudEvent(content, + ExampleConstants.EVENTMESH_GRPC_BROADCAT_TEST_TOPIC)); + } + eventMeshGrpcProducer.publish(cloudEventList); + ThreadUtils.sleep(10, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsPublishInstance.java index b026bea7c9..2885d5a6fd 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsPublishInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsPublishInstance.java @@ -17,68 +17,38 @@ package org.apache.eventmesh.grpc.pub.cloudevents; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; -import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -import java.util.Properties; -import java.util.UUID; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class CloudEventsPublishInstance { +public class CloudEventsPublishInstance extends GrpcAbstractDemo { // This messageSize is also used in SubService.java (Subscriber) - public static final int messageSize = 5; + public static final int MESSAGE_SIZE = 5; public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); + final Map content = new HashMap<>(); + content.put("content", "testAsyncMessage"); - eventMeshGrpcProducer.init(); + for (int i = 0; i < MESSAGE_SIZE; i++) { + eventMeshGrpcProducer.publish(buildCloudEvent(content, + ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC)); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } - Map content = new HashMap<>(); - content.put("content", "testAsyncMessage"); - - for (int i = 0; i < messageSize; i++) { - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - eventMeshGrpcProducer.publish(event); - Thread.sleep(1000); - } - Thread.sleep(30000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore + ThreadUtils.sleep(30, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsRequestInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsRequestInstance.java index 961e0a8b70..8e0be97bb3 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsRequestInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/cloudevents/CloudEventsRequestInstance.java @@ -17,69 +17,37 @@ package org.apache.eventmesh.grpc.pub.cloudevents; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; -import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -import java.util.Properties; -import java.util.UUID; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class CloudEventsRequestInstance { +public class CloudEventsRequestInstance extends GrpcAbstractDemo { - // This messageSize is also used in SubService.java (Subscriber) - public static final int messageSize = 5; + public static final int MESSAGE_SIZE = 5; public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { + final Map content = new HashMap<>(); + content.put("content", "testRequestReplyMessage"); - eventMeshGrpcProducer.init(); + for (int i = 0; i < MESSAGE_SIZE; i++) { + eventMeshGrpcProducer.requestReply(buildCloudEvent(content, + ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC), EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } - Map content = new HashMap<>(); - content.put("content", "testRequestReplyMessage"); - - for (int i = 0; i < messageSize; i++) { - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - - eventMeshGrpcProducer.requestReply(event, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - Thread.sleep(1000); - } - Thread.sleep(30000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore + ThreadUtils.sleep(30, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishBroadcast.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishBroadcast.java index 685600024d..76c59cf276 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishBroadcast.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishBroadcast.java @@ -17,61 +17,36 @@ package org.apache.eventmesh.grpc.pub.eventmeshmessage; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class AsyncPublishBroadcast { +public class AsyncPublishBroadcast extends GrpcAbstractDemo { // This messageSize is also used in SubService.java (Subscriber) - public static final int messageSize = 5; + public static final int MESSAGE_SIZE = 5; public static void main(String[] args) throws Exception { - - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); - - eventMeshGrpcProducer.init(); - - Map content = new HashMap<>(); - content.put("content", "testAsyncMessage"); - - for (int i = 0; i < messageSize; i++) { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .content(JsonUtils.serialize(content)) - .topic(ExampleConstants.EVENTMESH_GRPC_BROADCAT_TEST_TOPIC) - .uniqueId(RandomStringUtils.generateNum(30)) - .bizSeqNo(RandomStringUtils.generateNum(30)) - .build() - .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); - eventMeshGrpcProducer.publish(eventMeshMessage); - Thread.sleep(1000); - } - Thread.sleep(30000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { + + final Map content = new HashMap<>(); + content.put("content", "testAsyncMessage"); + + for (int i = 0; i < MESSAGE_SIZE; i++) { + eventMeshGrpcProducer.publish(buildEventMeshMessage(content, + ExampleConstants.EVENTMESH_GRPC_BROADCAT_TEST_TOPIC)); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + ThreadUtils.sleep(30, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishInstance.java index 924c64eefd..56f4a4561a 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/AsyncPublishInstance.java @@ -17,61 +17,36 @@ package org.apache.eventmesh.grpc.pub.eventmeshmessage; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class AsyncPublishInstance { +public class AsyncPublishInstance extends GrpcAbstractDemo { // This messageSize is also used in SubService.java (Subscriber) - public static final int messageSize = 5; + public static final int MESSAGE_SIZE = 5; public static void main(String[] args) throws Exception { - - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); - - eventMeshGrpcProducer.init(); - - Map content = new HashMap<>(); - content.put("content", "testAsyncMessage"); - - for (int i = 0; i < messageSize; i++) { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .content(JsonUtils.serialize(content)) - .topic(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .uniqueId(RandomStringUtils.generateNum(30)) - .bizSeqNo(RandomStringUtils.generateNum(30)) - .build() - .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); - eventMeshGrpcProducer.publish(eventMeshMessage); - Thread.sleep(1000); - } - Thread.sleep(30000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { + + final Map content = new HashMap<>(); + content.put("content", "testAsyncMessage"); + + for (int i = 0; i < MESSAGE_SIZE; i++) { + eventMeshGrpcProducer.publish(buildEventMeshMessage(content, + ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC)); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + ThreadUtils.sleep(30, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/BatchPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/BatchPublishInstance.java index e7e7a17548..dd56b95b55 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/BatchPublishInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/BatchPublishInstance.java @@ -17,62 +17,39 @@ package org.apache.eventmesh.grpc.pub.eventmeshmessage; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class BatchPublishInstance { +public class BatchPublishInstance extends GrpcAbstractDemo { public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); + Map content = new HashMap<>(); + content.put("content", "testRequestReplyMessage"); - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); + List messageList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + messageList.add(buildEventMeshMessage(content, + ExampleConstants.EVENTMESH_GRPC_BROADCAT_TEST_TOPIC)); + } - eventMeshGrpcProducer.init(); - - Map content = new HashMap<>(); - content.put("content", "testRequestReplyMessage"); - - List messageList = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - EventMeshMessage message = EventMeshMessage.builder() - .topic(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC) - .content((JsonUtils.serialize(content))) - .uniqueId(RandomStringUtils.generateNum(30)) - .bizSeqNo(RandomStringUtils.generateNum(30)) - .build() - .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); - messageList.add(message); - } - - eventMeshGrpcProducer.publish(messageList); - Thread.sleep(10000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore + eventMeshGrpcProducer.publish(messageList); + ThreadUtils.sleep(10, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/RequestReplyInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/RequestReplyInstance.java index 6b56fc7969..b49b584d5a 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/RequestReplyInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/RequestReplyInstance.java @@ -17,63 +17,40 @@ package org.apache.eventmesh.grpc.pub.eventmeshmessage; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class RequestReplyInstance { +public class RequestReplyInstance extends GrpcAbstractDemo { // This messageSize is also used in SubService.java (Subscriber) - public static final int messageSize = 5; + public static final int MESSAGE_SIZE = 5; public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); + final Map content = new HashMap<>(); + content.put("content", "testRequestReplyMessage"); - EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer(eventMeshClientConfig); + for (int i = 0; i < MESSAGE_SIZE; i++) { + eventMeshGrpcProducer.requestReply(buildEventMeshMessage(content, + ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC), + EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + ThreadUtils.sleep(30, TimeUnit.SECONDS); - eventMeshGrpcProducer.init(); - - Map content = new HashMap<>(); - content.put("content", "testRequestReplyMessage"); - - for (int i = 0; i < messageSize; i++) { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .content(JsonUtils.serialize(content)) - .topic(ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC) - .uniqueId(RandomStringUtils.generateNum(30)) - .bizSeqNo(RandomStringUtils.generateNum(30)) - .build() - .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); - - eventMeshGrpcProducer.requestReply(eventMeshMessage, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - Thread.sleep(1000); - } - Thread.sleep(30000); - try (EventMeshGrpcProducer ignore = eventMeshGrpcProducer) { - // ignore } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/WorkflowAsyncPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/WorkflowAsyncPublishInstance.java new file mode 100644 index 0000000000..5c41ef5a2a --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/pub/eventmeshmessage/WorkflowAsyncPublishInstance.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.pub.eventmeshmessage; + +import org.apache.eventmesh.client.grpc.producer.EventMeshGrpcProducer; +import org.apache.eventmesh.client.selector.SelectorFactory; +import org.apache.eventmesh.client.workflow.EventMeshWorkflowClient; +import org.apache.eventmesh.client.workflow.config.EventMeshWorkflowClientConfig; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteRequest; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteResponse; +import org.apache.eventmesh.common.utils.LogUtil; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; +import org.apache.eventmesh.selector.NacosSelector; +import org.apache.eventmesh.util.Utils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import com.alibaba.nacos.shaded.com.google.gson.Gson; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class WorkflowAsyncPublishInstance extends GrpcAbstractDemo { + + public static void main(String[] args) throws Exception { + + Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String workflowServerName = properties.getProperty(ExampleConstants.EVENTMESH_WORKFLOW_NAME); + final String selectorType = properties.getProperty(ExampleConstants.EVENTMESH_SELECTOR_TYPE); + + try (EventMeshGrpcProducer eventMeshGrpcProducer = new EventMeshGrpcProducer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { + + NacosSelector nacosSelector = new NacosSelector(); + nacosSelector.init(); + SelectorFactory.register(selectorType, nacosSelector); + + ExecuteRequest.Builder executeRequest = ExecuteRequest.newBuilder(); + Map content = new HashMap<>(); + content.put("order_no", "workflowmessage"); + executeRequest.setInput(new Gson().toJson(content)); + executeRequest.setId("testcreateworkflow"); + + EventMeshWorkflowClientConfig eventMeshWorkflowClientConfig = EventMeshWorkflowClientConfig.builder() + .serverName(workflowServerName).build(); + EventMeshWorkflowClient eventMeshWorkflowClient = new EventMeshWorkflowClient(eventMeshWorkflowClientConfig); + ExecuteResponse response = eventMeshWorkflowClient.getWorkflowClient().execute(executeRequest.build()); + + LogUtil.info(log, "received response: {}", response::toString); + + ThreadUtils.sleep(1, TimeUnit.MINUTES); + + } + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsAsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsAsyncSubscribe.java index a409389c82..a47da58ea2 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsAsyncSubscribe.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsAsyncSubscribe.java @@ -17,66 +17,56 @@ package org.apache.eventmesh.grpc.sub; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; +import java.io.IOException; import java.util.Collections; import java.util.Optional; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import io.cloudevents.CloudEvent; import lombok.extern.slf4j.Slf4j; @Slf4j -public class CloudEventsAsyncSubscribe implements ReceiveMsgHook { +public class CloudEventsAsyncSubscribe extends GrpcAbstractDemo implements ReceiveMsgHook { - public static CloudEventsAsyncSubscribe handler = new CloudEventsAsyncSubscribe(); - - public static void main(String[] args) throws InterruptedException { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - org.apache.eventmesh.common.protocol.SubscriptionItem subscriptionItem = new SubscriptionItem(); + public static void main(String[] args) throws InterruptedException, IOException { + final SubscriptionItem subscriptionItem = new SubscriptionItem(); subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC); subscriptionItem.setMode(SubscriptionMode.CLUSTERING); subscriptionItem.setType(SubscriptionType.ASYNC); - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { - eventMeshGrpcConsumer.init(); + eventMeshGrpcConsumer.init(); - eventMeshGrpcConsumer.registerListener(handler); + eventMeshGrpcConsumer.registerListener(new CloudEventsAsyncSubscribe()); - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); + eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - Thread.sleep(60000); - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + ThreadUtils.sleep(1, TimeUnit.MINUTES); + eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + } } @Override - public Optional handle(CloudEvent msg) { + public Optional handle(final CloudEvent msg) { log.info("receive async msg: {}", msg); return Optional.empty(); } @Override - public String getProtocolType() { - return EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME; + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.CLOUD_EVENTS; } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsSubscribeReply.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsSubscribeReply.java index 4a9b2aa981..f28f3fbdc5 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsSubscribeReply.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/CloudEventsSubscribeReply.java @@ -17,61 +17,53 @@ package org.apache.eventmesh.grpc.sub; -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; +import java.io.IOException; import java.util.Collections; import java.util.Optional; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import io.cloudevents.CloudEvent; import lombok.extern.slf4j.Slf4j; @Slf4j -public class CloudEventsSubscribeReply implements ReceiveMsgHook { +public class CloudEventsSubscribeReply extends GrpcAbstractDemo implements ReceiveMsgHook { - public static CloudEventsSubscribeReply handler = new CloudEventsSubscribeReply(); - - public static void main(String[] args) throws InterruptedException { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); + public static void main(String[] args) throws InterruptedException, IOException { SubscriptionItem subscriptionItem = new SubscriptionItem(); subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC); subscriptionItem.setMode(SubscriptionMode.CLUSTERING); subscriptionItem.setType(SubscriptionType.SYNC); - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { - eventMeshGrpcConsumer.init(); + eventMeshGrpcConsumer.init(); - eventMeshGrpcConsumer.registerListener(handler); + eventMeshGrpcConsumer.registerListener(new CloudEventsSubscribeReply()); - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); + eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - Thread.sleep(60000); - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + ThreadUtils.sleep(1, TimeUnit.MINUTES); + eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + } } @Override - public Optional handle(CloudEvent msg) { + public Optional handle(final CloudEvent msg) { log.info("receive request-reply msg: {}", msg); + if (msg != null) { return Optional.of(msg); } else { @@ -80,7 +72,7 @@ public Optional handle(CloudEvent msg) { } @Override - public String getProtocolType() { - return EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME; + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.CLOUD_EVENTS; } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshAsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshAsyncSubscribe.java new file mode 100644 index 0000000000..0221c703b0 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshAsyncSubscribe.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.sub; + +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; + +import java.io.IOException; +import java.util.Collections; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshAsyncSubscribe extends GrpcAbstractDemo implements ReceiveMsgHook { + + public static void main(String[] args) throws InterruptedException, IOException { + SubscriptionItem subscriptionItem = new SubscriptionItem(); + subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC); + subscriptionItem.setMode(SubscriptionMode.CLUSTERING); + subscriptionItem.setType(SubscriptionType.ASYNC); + + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { + + eventMeshGrpcConsumer.init(); + + eventMeshGrpcConsumer.registerListener(new EventMeshAsyncSubscribe()); + + eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); + + ThreadUtils.sleep(1, TimeUnit.MINUTES); + eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + } + } + + @Override + public Optional handle(final EventMeshMessage msg) { + log.info("receive async msg: {}", msg); + return Optional.empty(); + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.EVENT_MESH_MESSAGE; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshSubscribeBroadcast.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshSubscribeBroadcast.java new file mode 100644 index 0000000000..ba4038b021 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshSubscribeBroadcast.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.sub; + +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; + +import java.io.IOException; +import java.util.Collections; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshSubscribeBroadcast extends GrpcAbstractDemo implements ReceiveMsgHook { + + public static void main(String[] args) throws InterruptedException, IOException { + + SubscriptionItem subscriptionItem = new SubscriptionItem(); + subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_BROADCAT_TEST_TOPIC); + subscriptionItem.setMode(SubscriptionMode.BROADCASTING); + subscriptionItem.setType(SubscriptionType.ASYNC); + + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { + + eventMeshGrpcConsumer.init(); + + eventMeshGrpcConsumer.registerListener(new EventMeshSubscribeBroadcast()); + + eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); + + ThreadUtils.sleep(1, TimeUnit.MINUTES); + eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + } + } + + @Override + public Optional handle(final EventMeshMessage msg) { + log.info("receive async broadcast msg: {}", msg); + return Optional.empty(); + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.EVENT_MESH_MESSAGE; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshSubscribeReply.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshSubscribeReply.java new file mode 100644 index 0000000000..03722ba2a5 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventMeshSubscribeReply.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.sub; + +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; + +import java.io.IOException; +import java.util.Collections; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshSubscribeReply extends GrpcAbstractDemo implements ReceiveMsgHook { + + public static void main(String[] args) throws InterruptedException, IOException { + SubscriptionItem subscriptionItem = new SubscriptionItem(); + subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC); + subscriptionItem.setMode(SubscriptionMode.CLUSTERING); + subscriptionItem.setType(SubscriptionType.SYNC); + + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { + + eventMeshGrpcConsumer.init(); + + eventMeshGrpcConsumer.registerListener(new EventMeshSubscribeReply()); + + eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); + + ThreadUtils.sleep(1, TimeUnit.MINUTES); + eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); + } + } + + @Override + public Optional handle(final EventMeshMessage msg) { + log.info("receive request-reply msg: {}", msg); + if (msg != null) { + return Optional.of(msg); + } else { + return Optional.empty(); + } + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.EVENT_MESH_MESSAGE; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshAsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshAsyncSubscribe.java deleted file mode 100644 index b372e079a2..0000000000 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshAsyncSubscribe.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.grpc.sub; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.util.Utils; - -import java.util.Collections; -import java.util.Optional; -import java.util.Properties; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class EventmeshAsyncSubscribe implements ReceiveMsgHook { - - public static EventmeshAsyncSubscribe handler = new EventmeshAsyncSubscribe(); - - public static void main(String[] args) throws InterruptedException { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - SubscriptionItem subscriptionItem = new SubscriptionItem(); - subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_ASYNC_TEST_TOPIC); - subscriptionItem.setMode(SubscriptionMode.CLUSTERING); - subscriptionItem.setType(SubscriptionType.ASYNC); - - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - - eventMeshGrpcConsumer.init(); - - eventMeshGrpcConsumer.registerListener(handler); - - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - - Thread.sleep(60000); - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); - } - - @Override - public Optional handle(EventMeshMessage msg) { - log.info("receive async msg: {}", msg); - return Optional.empty(); - } - - @Override - public String getProtocolType() { - return EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME; - } -} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshSubscribeBroadcast.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshSubscribeBroadcast.java deleted file mode 100644 index 28753b4c6c..0000000000 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshSubscribeBroadcast.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.grpc.sub; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.util.Utils; - -import java.util.Collections; -import java.util.Optional; -import java.util.Properties; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class EventmeshSubscribeBroadcast implements ReceiveMsgHook { - - public static EventmeshSubscribeBroadcast handler = new EventmeshSubscribeBroadcast(); - - public static void main(String[] args) throws InterruptedException { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - SubscriptionItem subscriptionItem = new SubscriptionItem(); - subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_BROADCAT_TEST_TOPIC); - subscriptionItem.setMode(SubscriptionMode.BROADCASTING); - subscriptionItem.setType(SubscriptionType.ASYNC); - - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - - eventMeshGrpcConsumer.init(); - - eventMeshGrpcConsumer.registerListener(handler); - - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - - Thread.sleep(60000); - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); - } - - @Override - public Optional handle(EventMeshMessage msg) { - log.info("receive async broadcast msg: {}", msg); - return Optional.empty(); - } - - @Override - public String getProtocolType() { - return EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME; - } -} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshSubscribeReply.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshSubscribeReply.java deleted file mode 100644 index 082dacb9f8..0000000000 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/EventmeshSubscribeReply.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.grpc.sub; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; -import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.util.Utils; - -import java.util.Collections; -import java.util.Optional; -import java.util.Properties; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class EventmeshSubscribeReply implements ReceiveMsgHook { - - public static EventmeshSubscribeReply handler = new EventmeshSubscribeReply(); - - public static void main(String[] args) throws InterruptedException { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() - .serverAddr(eventMeshIp) - .serverPort(Integer.parseInt(eventMeshGrpcPort)) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env("env").idc("idc") - .sys("1234").build(); - - SubscriptionItem subscriptionItem = new SubscriptionItem(); - subscriptionItem.setTopic(ExampleConstants.EVENTMESH_GRPC_RR_TEST_TOPIC); - subscriptionItem.setMode(SubscriptionMode.CLUSTERING); - subscriptionItem.setType(SubscriptionType.SYNC); - - EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); - - eventMeshGrpcConsumer.init(); - - eventMeshGrpcConsumer.registerListener(handler); - - eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem)); - - Thread.sleep(60000); - eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem)); - } - - @Override - public Optional handle(EventMeshMessage msg) { - log.info("receive request-reply msg: {}", msg); - if (msg != null) { - return Optional.of(msg); - } else { - return Optional.empty(); - } - } - - @Override - public String getProtocolType() { - return EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME; - } -} \ No newline at end of file diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowExpressAsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowExpressAsyncSubscribe.java new file mode 100644 index 0000000000..64bf1f445c --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowExpressAsyncSubscribe.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.sub; + +import org.apache.eventmesh.client.catalog.EventMeshCatalogClient; +import org.apache.eventmesh.client.catalog.config.EventMeshCatalogClientConfig; +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; +import org.apache.eventmesh.client.selector.SelectorFactory; +import org.apache.eventmesh.client.workflow.EventMeshWorkflowClient; +import org.apache.eventmesh.client.workflow.config.EventMeshWorkflowClientConfig; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteRequest; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteResponse; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; +import org.apache.eventmesh.selector.NacosSelector; +import org.apache.eventmesh.util.Utils; + +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class WorkflowExpressAsyncSubscribe extends GrpcAbstractDemo implements ReceiveMsgHook { + + private static EventMeshWorkflowClient workflowClient; + + public static void main(String[] args) throws Exception { + Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String serverName = "expressapp"; + final String catalogServerName = properties.getProperty(ExampleConstants.EVENTMESH_CATALOG_NAME); + final String workflowServerName = properties.getProperty(ExampleConstants.EVENTMESH_WORKFLOW_NAME); + final String selectorType = properties.getProperty(ExampleConstants.EVENTMESH_SELECTOR_TYPE); + + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { + eventMeshGrpcConsumer.init(); + eventMeshGrpcConsumer.registerListener(new WorkflowExpressAsyncSubscribe()); + + NacosSelector nacosSelector = new NacosSelector(); + nacosSelector.init(); + SelectorFactory.register(selectorType, nacosSelector); + + EventMeshCatalogClientConfig eventMeshCatalogClientConfig = EventMeshCatalogClientConfig.builder() + .serverName(catalogServerName) + .appServerName(serverName).build(); + EventMeshCatalogClient eventMeshCatalogClient = new EventMeshCatalogClient(eventMeshCatalogClientConfig, + eventMeshGrpcConsumer); + eventMeshCatalogClient.init(); + + EventMeshWorkflowClientConfig eventMeshWorkflowClientConfig = EventMeshWorkflowClientConfig.builder() + .serverName(workflowServerName).build(); + workflowClient = new EventMeshWorkflowClient(eventMeshWorkflowClientConfig); + + ThreadUtils.sleep(60_000, TimeUnit.SECONDS); + eventMeshCatalogClient.destroy(); + } + } + + @Override + public Optional handle(final EventMeshMessage msg) throws Exception { + log.info("receive async msg: {}", msg); + if (msg == null) { + log.info("async msg is null, workflow end."); + return Optional.empty(); + } + + final Map props = msg.getProp(); + final String workflowInstanceId = props.get("workflowinstanceid"); + final String taskInstanceId = props.get("workflowtaskinstanceid"); + + final ExecuteRequest executeRequest = ExecuteRequest.newBuilder().setId("testcreateworkflow") + .setTaskInstanceId(taskInstanceId) + .setInstanceId(workflowInstanceId).build(); + final ExecuteResponse response = workflowClient.getWorkflowClient().execute(executeRequest); + log.info("receive workflow msg: {}", response.getInstanceId()); + return Optional.empty(); + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.EVENT_MESH_MESSAGE; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowOrderAsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowOrderAsyncSubscribe.java new file mode 100644 index 0000000000..c2fb14d993 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowOrderAsyncSubscribe.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.sub; + +import org.apache.eventmesh.client.catalog.EventMeshCatalogClient; +import org.apache.eventmesh.client.catalog.config.EventMeshCatalogClientConfig; +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; +import org.apache.eventmesh.client.selector.SelectorFactory; +import org.apache.eventmesh.client.workflow.EventMeshWorkflowClient; +import org.apache.eventmesh.client.workflow.config.EventMeshWorkflowClientConfig; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteRequest; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteResponse; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; +import org.apache.eventmesh.selector.NacosSelector; +import org.apache.eventmesh.util.Utils; + +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class WorkflowOrderAsyncSubscribe extends GrpcAbstractDemo implements ReceiveMsgHook { + + private static EventMeshWorkflowClient workflowClient; + + public static void main(String[] args) throws Exception { + Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String serverName = "orderapp"; + final String workflowServerName = properties.getProperty(ExampleConstants.EVENTMESH_WORKFLOW_NAME); + final String catalogServerName = properties.getProperty(ExampleConstants.EVENTMESH_CATALOG_NAME); + final String selectorType = properties.getProperty(ExampleConstants.EVENTMESH_SELECTOR_TYPE); + + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { + eventMeshGrpcConsumer.init(); + eventMeshGrpcConsumer.registerListener(new WorkflowOrderAsyncSubscribe()); + + NacosSelector nacosSelector = new NacosSelector(); + nacosSelector.init(); + SelectorFactory.register(selectorType, nacosSelector); + + EventMeshCatalogClientConfig eventMeshCatalogClientConfig = EventMeshCatalogClientConfig.builder() + .serverName(catalogServerName) + .appServerName(serverName).build(); + EventMeshCatalogClient eventMeshCatalogClient = new EventMeshCatalogClient(eventMeshCatalogClientConfig, + eventMeshGrpcConsumer); + eventMeshCatalogClient.init(); + + EventMeshWorkflowClientConfig eventMeshWorkflowClientConfig = EventMeshWorkflowClientConfig.builder() + .serverName(workflowServerName).build(); + workflowClient = new EventMeshWorkflowClient(eventMeshWorkflowClientConfig); + + ThreadUtils.sleep(60_000, TimeUnit.SECONDS); + eventMeshCatalogClient.destroy(); + } + } + + @Override + public Optional handle(final EventMeshMessage msg) throws Exception { + log.info("receive async msg: {}", msg); + + final Map props = msg.getProp(); + final String workflowInstanceId = props.get("workflowinstanceid"); + final String taskInstanceId = props.get("workflowtaskinstanceid"); + + final ExecuteRequest executeRequest = ExecuteRequest.newBuilder().setId("testcreateworkflow") + .setTaskInstanceId(taskInstanceId) + .setInstanceId(workflowInstanceId).build(); + final ExecuteResponse response = workflowClient.getWorkflowClient().execute(executeRequest); + log.info("receive workflow msg: {}", response.getInstanceId()); + return Optional.empty(); + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.EVENT_MESH_MESSAGE; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowPaymentAsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowPaymentAsyncSubscribe.java new file mode 100644 index 0000000000..2bd4381a86 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/WorkflowPaymentAsyncSubscribe.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.grpc.sub; + +import org.apache.eventmesh.client.catalog.EventMeshCatalogClient; +import org.apache.eventmesh.client.catalog.config.EventMeshCatalogClientConfig; +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.grpc.consumer.ReceiveMsgHook; +import org.apache.eventmesh.client.selector.SelectorFactory; +import org.apache.eventmesh.client.workflow.EventMeshWorkflowClient; +import org.apache.eventmesh.client.workflow.config.EventMeshWorkflowClientConfig; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteRequest; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteResponse; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.grpc.GrpcAbstractDemo; +import org.apache.eventmesh.selector.NacosSelector; +import org.apache.eventmesh.util.Utils; + +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class WorkflowPaymentAsyncSubscribe extends GrpcAbstractDemo implements ReceiveMsgHook { + + private static EventMeshWorkflowClient workflowClient; + + public static void main(String[] args) throws Exception { + Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String serverName = "paymentapp"; + final String workflowServerName = properties.getProperty(ExampleConstants.EVENTMESH_WORKFLOW_NAME); + final String catalogServerName = properties.getProperty(ExampleConstants.EVENTMESH_CATALOG_NAME); + final String selectorType = properties.getProperty(ExampleConstants.EVENTMESH_SELECTOR_TYPE); + + try (EventMeshGrpcConsumer eventMeshGrpcConsumer = new EventMeshGrpcConsumer( + initEventMeshGrpcClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP))) { + eventMeshGrpcConsumer.init(); + eventMeshGrpcConsumer.registerListener(new WorkflowPaymentAsyncSubscribe()); + + final NacosSelector nacosSelector = new NacosSelector(); + nacosSelector.init(); + SelectorFactory.register(selectorType, nacosSelector); + + final EventMeshCatalogClientConfig eventMeshCatalogClientConfig = EventMeshCatalogClientConfig.builder() + .serverName(catalogServerName) + .appServerName(serverName).build(); + final EventMeshCatalogClient eventMeshCatalogClient = new EventMeshCatalogClient(eventMeshCatalogClientConfig, + eventMeshGrpcConsumer); + eventMeshCatalogClient.init(); + + final EventMeshWorkflowClientConfig eventMeshWorkflowClientConfig = EventMeshWorkflowClientConfig.builder() + .serverName(workflowServerName).build(); + workflowClient = new EventMeshWorkflowClient(eventMeshWorkflowClientConfig); + + ThreadUtils.sleep(60_000, TimeUnit.SECONDS); + eventMeshCatalogClient.destroy(); + } + } + + @Override + public Optional handle(final EventMeshMessage msg) throws Exception { + log.info("receive async msg: {}", msg); + if (msg == null) { + log.info("async msg is null, workflow end."); + return Optional.empty(); + } + + final Map props = msg.getProp(); + final String workflowInstanceId = props.get("workflowinstanceid"); + final String taskInstanceId = props.get("workflowtaskinstanceid"); + + final ExecuteRequest executeRequest = ExecuteRequest.newBuilder().setId("testcreateworkflow") + .setTaskInstanceId(taskInstanceId) + .setInstanceId(workflowInstanceId).build(); + final ExecuteResponse response = workflowClient.getWorkflowClient().execute(executeRequest); + log.info("receive workflow msg: {}", response.getInstanceId()); + return Optional.empty(); + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.EVENT_MESH_MESSAGE; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/SpringBootDemoApplication.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/SpringBootDemoApplication.java index 0168b4f727..9162adceda 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/SpringBootDemoApplication.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/SpringBootDemoApplication.java @@ -17,11 +17,13 @@ package org.apache.eventmesh.grpc.sub.app; +import org.apache.eventmesh.connector.spring.config.EventMeshAutoConfiguration; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, EventMeshAutoConfiguration.class}) public class SpringBootDemoApplication { public static void main(String[] args) { diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/controller/SubController.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/controller/SubController.java index 57aaa401d7..b3e0ad4b41 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/controller/SubController.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/controller/SubController.java @@ -17,14 +17,9 @@ package org.apache.eventmesh.grpc.sub.app.controller; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.grpc.sub.app.service.SubService; -import org.apache.commons.lang3.StringUtils; - -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -35,40 +30,26 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; -import io.cloudevents.CloudEvent; -import io.cloudevents.core.provider.EventFormatProvider; - import lombok.extern.slf4j.Slf4j; - @Slf4j @RestController @RequestMapping("/sub") public class SubController { @Autowired - private SubService subService; + private transient SubService subService; @RequestMapping(value = "/test", method = RequestMethod.POST) - public String subTest(HttpServletRequest request) { - String protocolType = request.getHeader(ProtocolKey.PROTOCOL_TYPE); - String content = request.getParameter("content"); + public String subTest(final HttpServletRequest request) { + final String content = request.getParameter("content"); log.info("=======receive message======= {}", content); - Map contentMap = JsonUtils.deserialize(content, HashMap.class); - if (StringUtils.equals(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME, protocolType)) { - String contentType = request.getHeader(ProtocolKey.CONTENT_TYPE); - - CloudEvent event = EventFormatProvider.getInstance().resolveFormat(contentType) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); - String data = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - log.info("=======receive data======= {}", data); - } subService.consumeMessage(content); - Map map = new HashMap<>(); + final Map map = new HashMap<>(); map.put("retCode", 1); - return JsonUtils.serialize(map); + return JsonUtils.toJSONString(map); } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/service/SubService.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/service/SubService.java index f48dad1d2d..204f122a49 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/service/SubService.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/grpc/sub/app/service/SubService.java @@ -1,77 +1,85 @@ /* - * 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 + * 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. + * 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. */ package org.apache.eventmesh.grpc.sub.app.service; +import static org.apache.eventmesh.common.ExampleConstants.ENV; +import static org.apache.eventmesh.common.ExampleConstants.IDC; +import static org.apache.eventmesh.common.ExampleConstants.SERVER_PORT; +import static org.apache.eventmesh.common.ExampleConstants.SUB_SYS; +import static org.apache.eventmesh.util.Utils.getURL; + import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; import org.apache.eventmesh.common.ExampleConstants; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.grpc.pub.eventmeshmessage.AsyncPublishInstance; import org.apache.eventmesh.util.Utils; +import java.io.IOException; import java.util.Collections; import java.util.Properties; import java.util.concurrent.CountDownLatch; import javax.annotation.PreDestroy; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; + +@Slf4j @Component public class SubService implements InitializingBean { - public static Logger logger = LoggerFactory.getLogger(SubService.class); - private EventMeshGrpcConsumer eventMeshGrpcConsumer; - final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + private Properties properties; - final SubscriptionItem subscriptionItem = new SubscriptionItem(); + private final SubscriptionItem subscriptionItem = new SubscriptionItem(); + + { + try { + properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + } catch (IOException e) { + log.error("Failed to read the file.", e); + } + } - final String localIp = IPUtils.getLocalAddress(); - final String localPort = properties.getProperty("server.port"); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); - final String url = "http://" + localIp + ":" + localPort + "/sub/test"; - final String env = "P"; - final String idc = "FT"; - final String subsys = "1234"; + private final String localPort = properties.getProperty(SERVER_PORT); + private final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); + private final String eventMeshGrpcPort = properties.getProperty(ExampleConstants.EVENTMESH_GRPC_PORT); + private final String url = getURL(localPort, "/sub/test"); // CountDownLatch size is the same as messageSize in AsyncPublishInstance.java (Publisher) - private CountDownLatch countDownLatch = new CountDownLatch(AsyncPublishInstance.messageSize); + private final CountDownLatch countDownLatch = new CountDownLatch(AsyncPublishInstance.MESSAGE_SIZE); @Override public void afterPropertiesSet() throws Exception { - EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() + final EventMeshGrpcClientConfig eventMeshClientConfig = EventMeshGrpcClientConfig.builder() .serverAddr(eventMeshIp) .serverPort(Integer.parseInt(eventMeshGrpcPort)) .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env(env).idc(idc) - .sys(subsys).build(); + .env(ENV).idc(IDC) + .sys(SUB_SYS) + .build(); eventMeshGrpcConsumer = new EventMeshGrpcConsumer(eventMeshClientConfig); eventMeshGrpcConsumer.init(); @@ -83,40 +91,45 @@ public void afterPropertiesSet() throws Exception { eventMeshGrpcConsumer.subscribe(Collections.singletonList(subscriptionItem), url); // Wait for all messaged to be consumed - Thread stopThread = new Thread(() -> { + final Thread stopThread = new Thread(() -> { try { countDownLatch.await(); } catch (InterruptedException e) { - e.printStackTrace(); + log.warn("exception occurred when countDownLatch.await ", e); + Thread.currentThread().interrupt(); } - logger.info("stopThread start...."); - throw new RuntimeException(); + + log.info("stopThread start...."); + }); + stopThread.start(); } @PreDestroy public void cleanup() { - logger.info("start destory ...."); + log.info("start destroy...."); + try { eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(subscriptionItem), url); } catch (Exception e) { - e.printStackTrace(); + log.error("exception occurred when unsubscribe ", e); } - try (final EventMeshGrpcConsumer ignore = eventMeshGrpcConsumer) { + try (EventMeshGrpcConsumer ignore = eventMeshGrpcConsumer) { // close consumer } catch (Exception e) { - e.printStackTrace(); + log.error("exception occurred when close consumer ", e); } - logger.info("end destory."); + + log.info("end destroy...."); } /** * Count the message already consumed */ - public void consumeMessage(String msg) { - logger.info("consume message: {}", msg); + public void consumeMessage(final String msg) { + log.info("consume message: {}", msg); countDownLatch.countDown(); - logger.info("remaining number of messages to be consumed: {}", countDownLatch.getCount()); + log.info("remaining number of messages to be consumed: {}", countDownLatch.getCount()); } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/HttpAbstractDemo.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/HttpAbstractDemo.java new file mode 100644 index 0000000000..7498afa97a --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/HttpAbstractDemo.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.eventmesh.http.demo; + +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.util.Utils; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class HttpAbstractDemo { + + protected static EventMeshHttpClientConfig initEventMeshHttpClientConfig(final String groupName) + throws IOException { + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); + final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); + + // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 + String eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; + if (StringUtils.isNotBlank(eventMeshIp) || StringUtils.isNotBlank(eventMeshHttpPort)) { + eventMeshIPPort = eventMeshIp + ":" + eventMeshHttpPort; + } + + // Both the producer and consumer require an instance of EventMeshHttpClientConfig class + // that specifies the configuration of EventMesh HTTP client. + return EventMeshHttpClientConfig.builder() + .liteEventMeshAddr(eventMeshIPPort) + .producerGroup(groupName) + .env("env") + .idc("idc") + .ip(IPUtils.getLocalAddress()) + .sys("1234") + .pid(String.valueOf(ThreadUtils.getPID())) + .userName("eventmesh") + .password("pass") + .build(); + } + + protected static CloudEvent buildCloudEvent(final Map content) { + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSubject(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC) + .withSource(URI.create("/")) + .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) + .withType(CLOUD_EVENTS_PROTOCOL_NAME) + .withData(JsonUtils.toJSONString(content).getBytes(StandardCharsets.UTF_8)) + .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)) + .build(); + } + + protected static EventMeshMessage buildMessage(final Map content) { + return EventMeshMessage.builder() + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content(JsonUtils.toJSONString(content)) + .topic(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC) + .uniqueId(RandomStringUtils.generateNum(30)) + .build() + .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4_000)); + + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/cloudevents/AsyncPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/cloudevents/AsyncPublishInstance.java index 73cd4c09fc..e9c3056592 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/cloudevents/AsyncPublishInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/cloudevents/AsyncPublishInstance.java @@ -17,79 +17,34 @@ package org.apache.eventmesh.http.demo.pub.cloudevents; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.common.utils.ThreadUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.http.demo.HttpAbstractDemo; -import org.apache.commons.lang3.StringUtils; - -import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -import java.util.Properties; -import java.util.UUID; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class AsyncPublishInstance { +public class AsyncPublishInstance extends HttpAbstractDemo { public static final int MESSAGE_SIZE = 1; public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); - - // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 - String eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; - if (StringUtils.isNotBlank(eventMeshIp) || StringUtils.isNotBlank(eventMeshHttpPort)) { - eventMeshIPPort = eventMeshIp + ":" + eventMeshHttpPort; - } - - // Both the producer and consumer require an instance of EventMeshHttpClientConfig class - // that specifies the configuration of EventMesh HTTP client. - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())) - .userName("eventmesh") - .password("pass") - .build(); - - try (EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig)) { + try (EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer( + initEventMeshHttpClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { for (int i = 0; i < MESSAGE_SIZE; i++) { Map content = new HashMap<>(); content.put("content", "testAsyncMessage"); - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)) - .build(); - eventMeshHttpProducer.publish(event); + eventMeshHttpProducer.publish(buildCloudEvent(content)); log.info("publish event success content: {}", content); } - Thread.sleep(30000); + ThreadUtils.sleep(30, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncPublishInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncPublishInstance.java index 1d56dd534d..469aa24620 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncPublishInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncPublishInstance.java @@ -17,71 +17,44 @@ package org.apache.eventmesh.http.demo.pub.eventmeshmessage; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.common.utils.RandomStringUtils; import org.apache.eventmesh.common.utils.ThreadUtils; -import org.apache.eventmesh.util.Utils; - -import org.apache.commons.lang3.StringUtils; +import org.apache.eventmesh.http.demo.HttpAbstractDemo; import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class AsyncPublishInstance { +public class AsyncPublishInstance extends HttpAbstractDemo { // This messageSize is also used in SubService.java (Subscriber) - public static final int messageSize = 5; + public static final int MESSAGE_SIZE = 5; public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); - - final String eventMeshIPPort; - if (StringUtils.isBlank(eventMeshIp) || StringUtils.isBlank(eventMeshHttpPort)) { - // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 - eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; - } else { - eventMeshIPPort = eventMeshIp + ":" + eventMeshHttpPort; - } - - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())) - .userName("eventmesh") - .password("pass") - .build(); - - try (EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig)) { - for (int i = 0; i < messageSize; i++) { - Map content = new HashMap<>(); + try (EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer( + initEventMeshHttpClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { + for (int i = 0; i < MESSAGE_SIZE; i++) { + final Map content = new HashMap<>(); content.put("content", "testPublishMessage"); - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .bizSeqNo(RandomStringUtils.generateNum(30)) - .content(JsonUtils.serialize(content)) - .topic(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC) - .uniqueId(RandomStringUtils.generateNum(30)) - .build() - .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); + final EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content(JsonUtils.toJSONString(content)) + .topic(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC) + .uniqueId(RandomStringUtils.generateNum(30)) + .build() + .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); eventMeshHttpProducer.publish(eventMeshMessage); } - Thread.sleep(30000); + ThreadUtils.sleep(30, TimeUnit.SECONDS); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncSyncRequestInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncSyncRequestInstance.java index c3f0ff4f87..9942e807e4 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncSyncRequestInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/AsyncSyncRequestInstance.java @@ -17,83 +17,51 @@ package org.apache.eventmesh.http.demo.pub.eventmeshmessage; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; import org.apache.eventmesh.client.http.producer.RRCallback; import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.RandomStringUtils; import org.apache.eventmesh.common.utils.ThreadUtils; -import org.apache.eventmesh.util.Utils; +import org.apache.eventmesh.http.demo.HttpAbstractDemo; -import org.apache.commons.lang3.StringUtils; - -import java.util.Properties; - -import com.google.common.base.Preconditions; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @Slf4j -public class AsyncSyncRequestInstance { +public class AsyncSyncRequestInstance extends HttpAbstractDemo { public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); - Preconditions.checkNotNull(properties, ExampleConstants.CONFIG_FILE_NAME); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); - - EventMeshHttpProducer eventMeshHttpProducer = null; - try { - String eventMeshIPPort = eventMeshIp + ":" + eventMeshHttpPort; - if (StringUtils.isBlank(eventMeshIPPort)) { - // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 - eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; - } - - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())).build(); - - eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); - + try (EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer( + initEventMeshHttpClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { final long startTime = System.currentTimeMillis(); final EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .bizSeqNo(RandomStringUtils.generateNum(30)) - .content("testAsyncMessage") - .topic(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC) - .uniqueId(RandomStringUtils.generateNum(30)).build(); + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content("testAsyncMessage") + .topic(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC) + .uniqueId(RandomStringUtils.generateNum(30)).build(); eventMeshHttpProducer.request(eventMeshMessage, new RRCallback() { + @Override - public void onSuccess(EventMeshMessage o) { - log.debug("sendmsg: {}, return: {}, cost: {} ms", eventMeshMessage.getContent(), o.getContent(), - System.currentTimeMillis() - startTime); + public void onSuccess(final EventMeshMessage o) { + log.debug("sendmsg: {}, return: {}, cost: {}ms", + eventMeshMessage.getContent(), o.getContent(), System.currentTimeMillis() - startTime); } @Override public void onException(Throwable e) { log.debug("send msg failed", e); } - }, 3000); + }, 3_000); - Thread.sleep(2000); + ThreadUtils.sleep(2, TimeUnit.SECONDS); } catch (Exception e) { - log.warn("async send msg failed", e); + log.error("async send msg failed", e); } + ThreadUtils.sleep(30, TimeUnit.SECONDS); - Thread.sleep(30000); - try (final EventMeshHttpProducer ignore = eventMeshHttpProducer) { - // close producer - } catch (Exception e1) { - log.warn("producer shutdown exception", e1); - } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/SyncRequestInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/SyncRequestInstance.java index a9140cb624..fe600ff868 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/SyncRequestInstance.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/pub/eventmeshmessage/SyncRequestInstance.java @@ -17,74 +17,43 @@ package org.apache.eventmesh.http.demo.pub.eventmeshmessage; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; import org.apache.eventmesh.common.EventMeshMessage; import org.apache.eventmesh.common.ExampleConstants; -import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.RandomStringUtils; import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.http.demo.HttpAbstractDemo; -import org.apache.commons.lang3.StringUtils; +import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; -public class SyncRequestInstance { - - public static Logger logger = LoggerFactory.getLogger(SyncRequestInstance.class); +@Slf4j +public class SyncRequestInstance extends HttpAbstractDemo { public static void main(String[] args) throws Exception { - EventMeshHttpProducer eventMeshHttpProducer = null; - String eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; - String topic = ExampleConstants.EVENTMESH_HTTP_SYNC_TEST_TOPIC; - - try { - if (args.length > 0 && StringUtils.isNotBlank(args[0])) { - eventMeshIPPort = args[0]; - } - if (args.length > 1 && StringUtils.isNotBlank(args[1])) { - topic = args[1]; - } - - if (StringUtils.isBlank(eventMeshIPPort)) { - // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 - eventMeshIPPort = ExampleConstants.DEFAULT_EVENTMESH_IP_PORT; - } + final String topic = ExampleConstants.EVENTMESH_HTTP_SYNC_TEST_TOPIC; - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP) - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())).build(); + try (EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer( + initEventMeshHttpClientConfig(ExampleConstants.DEFAULT_EVENTMESH_TEST_PRODUCER_GROUP))) { - eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); + final long startTime = System.currentTimeMillis(); + final EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content("contentStr with special protocal") + .topic(topic) + .uniqueId(RandomStringUtils.generateNum(30)) + .build(); - long startTime = System.currentTimeMillis(); - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .bizSeqNo(RandomStringUtils.generateNum(30)) - .content("contentStr with special protocal") - .topic(topic) - .uniqueId(RandomStringUtils.generateNum(30)).build(); - - EventMeshMessage rsp = eventMeshHttpProducer.request(eventMeshMessage, 10000); - if (logger.isDebugEnabled()) { - logger.debug("sendmsg: {}, return: {}, cost:{} ms", eventMeshMessage.getContent(), rsp.getContent(), - System.currentTimeMillis() - startTime); - } + final EventMeshMessage rsp = eventMeshHttpProducer.request(eventMeshMessage, 10_000); + log.debug("send msg: {}, return: {}, cost: {}ms", + eventMeshMessage.getContent(), rsp.getContent(), System.currentTimeMillis() - startTime); } catch (Exception e) { - logger.warn("send msg failed", e); + log.error("send msg failed, ", e); } - Thread.sleep(30000); - try (final EventMeshHttpProducer close = eventMeshHttpProducer) { - // close producer - } catch (Exception e1) { - logger.warn("producer shutdown exception", e1); - } + ThreadUtils.sleep(30, TimeUnit.SECONDS); + } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/RemoteSubscribeInstance.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/RemoteSubscribeInstance.java new file mode 100644 index 0000000000..f045bf077b --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/RemoteSubscribeInstance.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.eventmesh.http.demo.sub; + +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.client.http.util.HttpUtils; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.http.body.client.SubscribeRequestBody; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import io.netty.handler.codec.http.HttpMethod; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RemoteSubscribeInstance { + + static final CloseableHttpClient httpClient = HttpClients.createDefault(); + + public static void main(String[] args) throws IOException { + subscribeLocal(); + //subscribeRemote(); + // unsubscribeRemote(); + } + + private static void subscribeLocal() throws IOException { + SubscriptionItem item = new SubscriptionItem(); + item.setTopic(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC); + item.setMode(SubscriptionMode.CLUSTERING); + item.setType(SubscriptionType.ASYNC); + + Map body = new HashMap<>(); + body.put("url", "http://127.0.0.1:8088/sub/test"); + body.put("consumerGroup", "EventMeshTest-consumerGroup"); + body.put("topic", Collections.singletonList(item)); + + String json = JsonUtils.toJSONString(body); + // 2) use HttpPost + HttpPost post = new HttpPost("http://127.0.0.1:10105/eventmesh/subscribe/local"); + post.setHeader("Content-Type", "application/json"); + post.setHeader("env", "prod"); + post.setHeader("idc", "default"); + post.setHeader("sys", "http-client-demo"); + post.setHeader("username", "eventmesh"); + post.setHeader("passwd", "eventmesh"); + post.setHeader("ip", IPUtils.getLocalAddress()); + post.setHeader("language", "JAVA"); + post.setEntity(new StringEntity(json, StandardCharsets.UTF_8)); + + try (CloseableHttpResponse resp = httpClient.execute(post)) { + String respBody = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); + log.info("respStatusLine:{}", resp.getStatusLine()); + log.info("respBody:{}", respBody); + } + } + + private static void subscribeRemote() { + SubscriptionItem subscriptionItem = new SubscriptionItem(); + subscriptionItem.setTopic(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC); + subscriptionItem.setMode(SubscriptionMode.CLUSTERING); + subscriptionItem.setType(SubscriptionType.ASYNC); + + final RequestParam subscribeParam = buildCommonRequestParam() + .addBody(SubscribeRequestBody.TOPIC, JsonUtils.toJSONString(Collections.singletonList(subscriptionItem))) + .addBody(SubscribeRequestBody.CONSUMERGROUP, ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) + .addBody(SubscribeRequestBody.URL, "http://127.0.0.1:8088/sub/test") + .addBody("remoteMesh", "http://127.0.0.1:10105/eventmesh/subscribe/local"); + + postMsg(subscribeParam); + } + + private static void unsubscribeRemote() { + final RequestParam subscribeParam = buildCommonRequestParam() + .addBody(SubscribeRequestBody.TOPIC, JsonUtils.toJSONString(Collections.singletonList(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC))) + .addBody(SubscribeRequestBody.CONSUMERGROUP, ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) + .addBody(SubscribeRequestBody.URL, "http://127.0.0.1:8088/sub/test"); + + postMsg(subscribeParam); + } + + private static void postMsg(RequestParam subscribeParam) { + // cluster2 ip + final String target = "http://127.0.0.1:11105/eventmesh/subscribe/remote"; + try { + final String res = HttpUtils.post(httpClient, target, subscribeParam); + final EventMeshRetObj ret = JsonUtils.parseObject(res, EventMeshRetObj.class); + if (Objects.requireNonNull(ret).getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { + throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); + } + } catch (Exception ex) { + throw new EventMeshException(String.format("Subscribe topic error, target:%s", target), ex); + } + } + + private static RequestParam buildCommonRequestParam() { + return new RequestParam(HttpMethod.POST) + .addHeader(ProtocolKey.ClientInstanceKey.IP.getKey(), IPUtils.getLocalAddress()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .setTimeout(Constants.DEFAULT_HTTP_TIME_OUT); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/SpringBootDemoApplication.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/SpringBootDemoApplication.java index 57a4c5baf4..9b277e48b4 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/SpringBootDemoApplication.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/SpringBootDemoApplication.java @@ -17,11 +17,13 @@ package org.apache.eventmesh.http.demo.sub; +import org.apache.eventmesh.connector.spring.config.EventMeshAutoConfiguration; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, EventMeshAutoConfiguration.class}) public class SpringBootDemoApplication { public static void main(String[] args) { diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/controller/SubController.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/controller/SubController.java index e0708a3419..662a4c45e8 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/controller/SubController.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/controller/SubController.java @@ -17,7 +17,8 @@ package org.apache.eventmesh.http.demo.sub.controller; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; + import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.http.demo.sub.service.SubService; @@ -36,38 +37,44 @@ import org.springframework.web.bind.annotation.RestController; import io.cloudevents.CloudEvent; +import io.cloudevents.CloudEventData; +import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.jackson.JsonFormat; import lombok.extern.slf4j.Slf4j; - @Slf4j @RestController @RequestMapping("/sub") public class SubController { @Autowired - private SubService subService; + private transient SubService subService; @RequestMapping(value = "/test", method = RequestMethod.POST) - public String subTest(HttpServletRequest request) { - String content = request.getParameter("content"); + public String subTest(final HttpServletRequest request) { + final String content = request.getParameter("content"); log.info("receive message: {}", content); - Map contentMap = JsonUtils.deserialize(content, HashMap.class); - if (StringUtils.equals(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME, contentMap.get(ProtocolKey.PROTOCOL_TYPE))) { - CloudEvent event = EventFormatProvider.getInstance() - .resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); - String data = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - log.info("receive data: {}", data); + @SuppressWarnings("unchecked") + final Map contentMap = JsonUtils.parseObject(content, HashMap.class); + if (StringUtils.equals(CLOUD_EVENTS_PROTOCOL_NAME, contentMap.get(ProtocolKey.PROTOCOL_TYPE))) { + final EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); + if (eventFormat != null) { + final CloudEvent event = eventFormat.deserialize(content.getBytes(StandardCharsets.UTF_8)); + final CloudEventData eventData = event.getData(); + if (eventData != null) { + final String data = new String(eventData.toBytes(), StandardCharsets.UTF_8); + log.info("receive data: {}", data); + } + } } subService.consumeMessage(content); - Map map = new HashMap<>(); + final Map map = new HashMap<>(); map.put("retCode", 1); - return JsonUtils.serialize(map); + return JsonUtils.toJSONString(map); } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/service/SubService.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/service/SubService.java index d2aab6f738..25ce5644af 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/service/SubService.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/http/demo/sub/service/SubService.java @@ -1,24 +1,28 @@ /* - * 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 + * 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. + * 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. */ package org.apache.eventmesh.http.demo.sub.service; +import static org.apache.eventmesh.common.ExampleConstants.ENV; +import static org.apache.eventmesh.common.ExampleConstants.IDC; +import static org.apache.eventmesh.common.ExampleConstants.SERVER_PORT; +import static org.apache.eventmesh.common.ExampleConstants.SUB_SYS; +import static org.apache.eventmesh.util.Utils.getURL; + import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; import org.apache.eventmesh.client.http.consumer.EventMeshHttpConsumer; import org.apache.eventmesh.common.ExampleConstants; @@ -30,6 +34,7 @@ import org.apache.eventmesh.http.demo.pub.eventmeshmessage.AsyncPublishInstance; import org.apache.eventmesh.util.Utils; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; @@ -37,93 +42,97 @@ import javax.annotation.PreDestroy; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; + +@Slf4j @Component public class SubService implements InitializingBean { - public static Logger logger = LoggerFactory.getLogger(SubService.class); - private EventMeshHttpConsumer eventMeshHttpConsumer; - final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + private Properties properties; + + { + try { + properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + } catch (IOException e) { + log.error("read properties file failed", e); + } + } + + final String localPort = properties.getProperty(SERVER_PORT); + final String testURL = getURL(localPort, "/sub/test"); - final List topicList = Lists.newArrayList( - new SubscriptionItem(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC) - ); - final String localIp = IPUtils.getLocalAddress(); - final String localPort = properties.getProperty("server.port"); - final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); - final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); - final String url = "http://" + localIp + ":" + localPort + "/sub/test"; - final String env = "P"; - final String idc = "FT"; - final String subsys = "1234"; + private final List topicList = Lists.newArrayList( + new SubscriptionItem(ExampleConstants.EVENTMESH_HTTP_ASYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC)); // CountDownLatch size is the same as messageSize in AsyncPublishInstance.java (Publisher) - private CountDownLatch countDownLatch = new CountDownLatch(AsyncPublishInstance.messageSize); + private final CountDownLatch countDownLatch = new CountDownLatch(AsyncPublishInstance.MESSAGE_SIZE); @Override - public void afterPropertiesSet() throws Exception { - - final String eventMeshIPPort = eventMeshIp + ":" + eventMeshHttpPort; - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) - .env(env) - .idc(idc) - .ip(IPUtils.getLocalAddress()) - .sys(subsys) - .pid(String.valueOf(ThreadUtils.getPID())).build(); + public void afterPropertiesSet() { + final String eventMeshIP = properties.getProperty(ExampleConstants.EVENTMESH_IP); + final String eventMeshHttpPort = properties.getProperty(ExampleConstants.EVENTMESH_HTTP_PORT); + + final String eventMeshIPPort = eventMeshIP + ":" + eventMeshHttpPort; + final EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr(eventMeshIPPort) + .consumerGroup(ExampleConstants.DEFAULT_EVENTMESH_TEST_CONSUMER_GROUP) + .env(ENV) + .idc(IDC) + .ip(IPUtils.getLocalAddress()) + .sys(SUB_SYS) + .pid(String.valueOf(ThreadUtils.getPID())).build(); eventMeshHttpConsumer = new EventMeshHttpConsumer(eventMeshClientConfig); - eventMeshHttpConsumer.heartBeat(topicList, url); - eventMeshHttpConsumer.subscribe(topicList, url); + eventMeshHttpConsumer.heartBeat(topicList, testURL); + eventMeshHttpConsumer.subscribe(topicList, testURL); // Wait for all messaged to be consumed - Thread stopThread = new Thread(() -> { + final Thread stopThread = new Thread(() -> { try { countDownLatch.await(); } catch (InterruptedException e) { - e.printStackTrace(); + log.error("interrupted exception", e); + Thread.currentThread().interrupt(); } - logger.info("stopThread start...."); - throw new RuntimeException(); + log.info("stopThread start...."); }); stopThread.start(); } @PreDestroy public void cleanup() { - logger.info("start destory ...."); + log.info("start destroy...."); + try { - List unSubList = new ArrayList<>(); - for (SubscriptionItem item : topicList) { + final List unSubList = new ArrayList<>(); + for (final SubscriptionItem item : topicList) { unSubList.add(item.getTopic()); } - eventMeshHttpConsumer.unsubscribe(unSubList, url); + eventMeshHttpConsumer.unsubscribe(unSubList, testURL); } catch (Exception e) { - e.printStackTrace(); + log.error("unsubscribe exception", e); } - try (final EventMeshHttpConsumer ignore = eventMeshHttpConsumer) { - // close consumer - } catch (Exception e) { - e.printStackTrace(); + + if (eventMeshHttpConsumer != null) { + eventMeshHttpConsumer.close(); } - logger.info("end destory."); + + log.info("end destroy...."); } /** * Count the message already consumed */ - public void consumeMessage(String msg) { - logger.info("consume message: {}", msg); + public void consumeMessage(final String msg) { + log.info("consume message: {}", msg); countDownLatch.countDown(); - logger.info("remaining number: {} of messages to be consumed", countDownLatch.getCount()); + log.info("remaining number: {} of messages to be consumed", countDownLatch.getCount()); } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/selector/NacosSelector.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/selector/NacosSelector.java new file mode 100644 index 0000000000..23d2a2cbe5 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/selector/NacosSelector.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.selector; + +import org.apache.eventmesh.client.selector.Selector; +import org.apache.eventmesh.client.selector.SelectorException; +import org.apache.eventmesh.client.selector.ServiceInstance; +import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.util.Utils; + +import java.io.IOException; +import java.util.Properties; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingFactory; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; + +public class NacosSelector implements Selector { + + private transient NamingService namingService; + + public void init() throws SelectorException { + try { + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + namingService = NamingFactory.createNamingService( + properties.getProperty(ExampleConstants.EVENTMESH_SELECTOR_NACOS_ADDRESS)); + } catch (NacosException | IOException e) { + throw new SelectorException("NamingService create error", e); + } + } + + @Override + public ServiceInstance selectOne(final String serviceName) throws SelectorException { + try { + final Instance instance = namingService.selectOneHealthyInstance(serviceName); + if (instance == null) { + return null; + } + + final ServiceInstance serviceInstance = new ServiceInstance(); + serviceInstance.setHost(instance.getIp()); + serviceInstance.setPort(instance.getPort()); + serviceInstance.setHealthy(instance.isHealthy()); + serviceInstance.setMetadata(instance.getMetadata()); + return serviceInstance; + } catch (NacosException e) { + throw new SelectorException("NamingService select error", e); + } + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/SpringBootDemoApplication.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/SpringBootDemoApplication.java new file mode 100644 index 0000000000..954deb070e --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/SpringBootDemoApplication.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootDemoApplication.class, args); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/pub/SpringPubController.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/pub/SpringPubController.java new file mode 100644 index 0000000000..a734bb6efa --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/pub/SpringPubController.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.spring.pub; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.connector.spring.source.connector.SpringSourceConnector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendMessageCallback; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +@RequestMapping("/spring") +public class SpringPubController { + + @Autowired + private SpringSourceConnector springSourceConnector; + + @RequestMapping("/pub") + public String publish() { + final Map content = new HashMap<>(); + content.put("content", "testSpringPublishMessage"); + springSourceConnector.send(JsonUtils.toJSONString(content), new SendMessageCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + log.info("Spring source worker send message to EventMesh success! msgId={}, topic={}", + sendResult.getMessageId(), sendResult.getTopic()); + } + + @Override + public void onException(SendExceptionContext sendExceptionContext) { + log.info("Spring source worker send message to EventMesh failed!", sendExceptionContext.getCause()); + } + }); + return "success!"; + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/sub/SpringSubHandler.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/sub/SpringSubHandler.java new file mode 100644 index 0000000000..0dba81acf7 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/spring/sub/SpringSubHandler.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.spring.sub; + +import org.apache.eventmesh.connector.spring.sink.EventMeshListener; + +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class SpringSubHandler { + + @EventMeshListener + public void onMessage(String message) { + log.info("[SPRING--MESSAGE-RECEIVED], data={}", message); + } +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestUtils.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestUtils.java index db3182a446..e66fd6afbf 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestUtils.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/EventMeshTestUtils.java @@ -17,10 +17,11 @@ package org.apache.eventmesh.tcp.common; +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; import static org.apache.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; import org.apache.eventmesh.client.tcp.common.MessageUtils; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.ExampleConstants; import org.apache.eventmesh.common.protocol.tcp.Command; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; @@ -33,6 +34,7 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -41,122 +43,104 @@ public class EventMeshTestUtils { - private static final int seqLength = 10; + private static final int SEQ_LENGTH = 10; + + private static final String ASYNC_MSG_BODY = "testAsyncMessage"; + + private static final String DEFAULT_TTL_MS = "30000"; + + private static UserAgent getUserAgent(Integer port, String subsystem, Integer pid) { + return UserAgent.builder() + .env(UtilsConstants.ENV) + .host(UtilsConstants.HOST) + .password(generateRandomString(UtilsConstants.PASSWORD_LENGTH)) + .username(UtilsConstants.USER_NAME) + .group(UtilsConstants.GROUP) + .path(UtilsConstants.PATH) + .port(port) + .subsystem(subsystem) + .pid(pid) + .version(UtilsConstants.VERSION) + .idc(UtilsConstants.IDC) + .build(); + } // generate pub-client public static UserAgent generateClient1() { - UserAgent agent = UserAgent.builder() - .env("test") - .host("127.0.0.1") - .password(generateRandomString(8)) - .username("PU4283") - .group("EventmeshTestGroup") - .path("/data/app/umg_proxy") - .port(8362) - .subsystem("5023") - .pid(32893) - .version("2.0.11") - .idc("FT") - .build(); + final UserAgent agent = getUserAgent(UtilsConstants.PORT_1, UtilsConstants.SUB_SYSTEM_1, UtilsConstants.PID_1); return MessageUtils.generatePubClient(agent); } // generate sub-client public static UserAgent generateClient2() { - UserAgent agent = UserAgent.builder() - .env("test") - .host("127.0.0.1") - .password(generateRandomString(8)) - .username("PU4283") - .group("EventmeshTestGroup") - .path("/data/app/umg_proxy") - .port(9362) - .subsystem("5017") - .pid(42893) - .version("2.0.11") - .idc("FT") - .build(); + final UserAgent agent = getUserAgent(UtilsConstants.PORT_2, UtilsConstants.SUB_SYSTEM_2, UtilsConstants.PID_2); return MessageUtils.generateSubClient(agent); } - public static Package syncRR() { - Package msg = new Package(); - msg.setHeader(new Header(Command.REQUEST_TO_SERVER, 0, null, generateRandomString(seqLength))); - msg.setBody(generateSyncRRMqMsg()); + private static Package getPackageMsg(Command requestToServer, EventMeshMessage eventMeshMessage) { + final Package msg = new Package(); + msg.setHeader(new Header(requestToServer, 0, null, generateRandomString(SEQ_LENGTH))); + msg.setBody(eventMeshMessage); return msg; } + public static Package syncRR() { + return getPackageMsg(Command.REQUEST_TO_SERVER, generateSyncRRMqMsg()); + } + public static Package asyncRR() { - Package msg = new Package(); - msg.setHeader(new Header(Command.REQUEST_TO_SERVER, 0, null, generateRandomString(seqLength))); - msg.setBody(generateAsyncRRMqMsg()); - return msg; + return getPackageMsg(Command.REQUEST_TO_SERVER, generateAsyncRRMqMsg()); } public static Package asyncMessage() { - Package msg = new Package(); - msg.setHeader(new Header(Command.ASYNC_MESSAGE_TO_SERVER, 0, null, generateRandomString(seqLength))); - msg.setBody(generateAsyncEventMqMsg()); - return msg; + return getPackageMsg(Command.ASYNC_MESSAGE_TO_SERVER, generateAsyncEventMqMsg()); } public static Package broadcastMessage() { - Package msg = new Package(); - msg.setHeader(new Header(Command.BROADCAST_MESSAGE_TO_SERVER, 0, null, generateRandomString(seqLength))); - msg.setBody(generateBroadcastMqMsg()); - return msg; + return getPackageMsg(Command.BROADCAST_MESSAGE_TO_SERVER, generateBroadcastMqMsg()); } - public static Package rrResponse(EventMeshMessage request) { - Package msg = new Package(); - msg.setHeader(new Header(RESPONSE_TO_SERVER, 0, null, generateRandomString(seqLength))); - msg.setBody(request); - return msg; + public static Package rrResponse(final EventMeshMessage request) { + return getPackageMsg(RESPONSE_TO_SERVER, request); } - public static EventMeshMessage generateSyncRRMqMsg() { - EventMeshMessage mqMsg = new EventMeshMessage(); - mqMsg.setTopic(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC); - mqMsg.getProperties().put("msgtype", "persistent"); - mqMsg.getProperties().put("ttl", "300000"); - mqMsg.getProperties().put("keys", generateRandomString(16)); - mqMsg.setBody("testSyncRR"); - return mqMsg; + public static EventMeshMessage getEventMeshMessage(String eventMeshTcpSyncTestTopic, String msgType, String msg, + String keys, String keyMsg, String testMessage) { + final EventMeshMessage mqmsg = new EventMeshMessage(); + mqmsg.setTopic(eventMeshTcpSyncTestTopic); + mqmsg.getProperties().put(msgType, msg); + mqmsg.getProperties().put(UtilsConstants.TTL, DEFAULT_TTL_MS); + mqmsg.getProperties().put(keys, keyMsg); + mqmsg.getHeaders().put(Constants.DATA_CONTENT_TYPE, "text/plain"); + mqmsg.setBody(testMessage); + return mqmsg; } + public static EventMeshMessage generateSyncRRMqMsg() { + return getEventMeshMessage(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC, UtilsConstants.MSG_TYPE, + "persistent", UtilsConstants.KEYS, generateRandomString(16), "testSyncRR"); + } private static EventMeshMessage generateAsyncRRMqMsg() { - EventMeshMessage mqMsg = new EventMeshMessage(); - mqMsg.setTopic(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC); - mqMsg.getProperties().put("replyto", "localhost@ProducerGroup-producerPool-9-access#V1_4_0#CI"); - mqMsg.getProperties().put("ttl", "300000"); - mqMsg.getProperties().put("propertymessagereplyto", "notnull"); - mqMsg.setBody("testAsyncRR"); - return mqMsg; + return getEventMeshMessage(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC, UtilsConstants.REPLY_TO, + "localhost@ProducerGroup-producerPool-9-access#V1_4_0#CI", UtilsConstants.PROPERTY_MESSAGE_REPLY_TO, + "notnull", "testAsyncRR"); } public static EventMeshMessage generateAsyncEventMqMsg() { - EventMeshMessage mqMsg = new EventMeshMessage(); - mqMsg.setTopic(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC); - mqMsg.getProperties().put("replyto", "localhost@ProducerGroup-producerPool-9-access#V1_4_0#CI"); - mqMsg.getProperties().put("ttl", "30000"); - mqMsg.getProperties().put("propertymessagereplyto", "notnull"); - mqMsg.setBody("testAsyncMessage"); - return mqMsg; + return getEventMeshMessage(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC, UtilsConstants.REPLY_TO, + "localhost@ProducerGroup-producerPool-9-access#V1_4_0#CI", UtilsConstants.PROPERTY_MESSAGE_REPLY_TO, + "notnull", ASYNC_MSG_BODY); } public static EventMeshMessage generateBroadcastMqMsg() { - EventMeshMessage mqMsg = new EventMeshMessage(); - mqMsg.setTopic(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC); - mqMsg.getProperties().put("replyto", "localhost@ProducerGroup-producerPool-9-access#V1_4_0#CI"); - mqMsg.getProperties().put("ttl", "30000"); - mqMsg.getProperties().put("propertymessagereplyto", "notnull"); - mqMsg.setBody("testAsyncMessage"); - return mqMsg; + return getEventMeshMessage(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC, UtilsConstants.REPLY_TO, + "localhost@ProducerGroup-producerPool-9-access#V1_4_0#CI", UtilsConstants.PROPERTY_MESSAGE_REPLY_TO, + "notnull", ASYNC_MSG_BODY); } - private static String generateRandomString(int length) { - StringBuilder builder = new StringBuilder(length); + private static String generateRandomString(final int length) { + final StringBuilder builder = new StringBuilder(length); for (int i = 0; i < length; i++) { builder.append((char) ThreadLocalRandom.current().nextInt(48, 57)); } @@ -164,36 +148,34 @@ private static String generateRandomString(int length) { } public static CloudEvent generateCloudEventV1Async() { - Map content = new HashMap<>(); - content.put("content", "testAsyncMessage"); - - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType("application/cloudevents+json") - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension("ttl", "30000") - .build(); - return event; + final Map content = new HashMap<>(); + content.put(UtilsConstants.CONTENT, ASYNC_MSG_BODY); + + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSubject(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC) + .withSource(URI.create("/")) + .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) + .withType(CLOUD_EVENTS_PROTOCOL_NAME) + .withData(Objects.requireNonNull(JsonUtils.toJSONString(content)).getBytes(StandardCharsets.UTF_8)) + .withExtension(UtilsConstants.TTL, DEFAULT_TTL_MS) + .build(); } public static CloudEvent generateCloudEventV1SyncRR() { - Map content = new HashMap<>(); - content.put("content", "testSyncRR"); - - CloudEvent event = CloudEventBuilder.v1() - .withId(UUID.randomUUID().toString()) - .withSubject(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC) - .withSource(URI.create("/")) - .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) - .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) - .withData(JsonUtils.serialize(content).getBytes(StandardCharsets.UTF_8)) - .withExtension("ttl", "30000") - .withExtension("msgtype", "persistent") - .withExtension("keys", generateRandomString(16)) - .build(); - return event; + final Map content = new HashMap<>(); + content.put(UtilsConstants.CONTENT, "testSyncRR"); + + return CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSubject(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC) + .withSource(URI.create("/")) + .withDataContentType(ExampleConstants.CLOUDEVENT_CONTENT_TYPE) + .withType(CLOUD_EVENTS_PROTOCOL_NAME) + .withData(Objects.requireNonNull(JsonUtils.toJSONString(content)).getBytes(StandardCharsets.UTF_8)) + .withExtension(UtilsConstants.TTL, DEFAULT_TTL_MS) + .withExtension(UtilsConstants.MSG_TYPE, "persistent") + .withExtension(UtilsConstants.KEYS, generateRandomString(16)) + .build(); } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/UtilsConstants.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/UtilsConstants.java new file mode 100644 index 0000000000..f3697d2f59 --- /dev/null +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/common/UtilsConstants.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.tcp.common; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class UtilsConstants { + + public static final String ENV = "test"; + public static final String HOST = "localhost"; + public static final Integer PASSWORD_LENGTH = 8; + public static final String USER_NAME = "PU4283"; + public static final String GROUP = "EventmeshTestGroup"; + public static final String PATH = "/data/app/umg_proxy"; + public static final Integer PORT_1 = 8362; + public static final Integer PORT_2 = 9362; + public static final String SUB_SYSTEM_1 = "5023"; + public static final String SUB_SYSTEM_2 = "5017"; + public static final Integer PID_1 = 32_893; + public static final Integer PID_2 = 42_893; + public static final String VERSION = "2.0.11"; + public static final String IDC = "FT"; + /** + * PROPERTY KEY NAME . + */ + public static final String MSG_TYPE = "msgtype"; + public static final String TTL = "ttl"; + public static final String KEYS = "keys"; + public static final String REPLY_TO = "replyto"; + public static final String PROPERTY_MESSAGE_REPLY_TO = "propertymessagereplyto"; + public static final String CONTENT = "content"; + +} diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/AsyncPublish.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/AsyncPublish.java index 3cca2341c0..8160fc8610 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/AsyncPublish.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/AsyncPublish.java @@ -23,47 +23,47 @@ import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; import org.apache.eventmesh.common.ExampleConstants; import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.tcp.common.EventMeshTestUtils; import org.apache.eventmesh.util.Utils; import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.TimeUnit; import io.cloudevents.CloudEvent; -public class AsyncPublish { - - public static Logger logger = LoggerFactory.getLogger(AsyncPublish.class); +import lombok.extern.slf4j.Slf4j; - private static EventMeshTCPClient client; +@Slf4j +public class AsyncPublish { public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); try { - UserAgent userAgent = EventMeshTestUtils.generateClient1(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - client = - EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); - client.init(); + final UserAgent userAgent = EventMeshTestUtils.generateClient1(); + try (final EventMeshTCPClient client = + EventMeshTCPClientFactory.createEventMeshTCPClient( + EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(), + CloudEvent.class)) { + client.init(); - for (int i = 0; i < 2; i++) { - CloudEvent event = EventMeshTestUtils.generateCloudEventV1Async(); - logger.info("begin send async msg[{}]: {}", i, event); - client.publish(event, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + for (int i = 0; i < 2; i++) { + final CloudEvent event = EventMeshTestUtils.generateCloudEventV1Async(); + log.info("begin send async msg[{}]: {}", i, event); + client.publish(event, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - Thread.sleep(1000); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + ThreadUtils.sleep(2, TimeUnit.SECONDS); } - Thread.sleep(2000); } catch (Exception e) { - logger.warn("AsyncPublish failed", e); + log.error("AsyncPublish failed", e); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/SyncRequest.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/SyncRequest.java index 2dceddfcf3..1fe1371b37 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/SyncRequest.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/cloudevents/SyncRequest.java @@ -31,6 +31,8 @@ import java.util.Properties; import io.cloudevents.CloudEvent; +import io.cloudevents.CloudEventData; +import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.jackson.JsonFormat; @@ -39,33 +41,50 @@ @Slf4j public class SyncRequest { - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient1(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); + final UserAgent userAgent = EventMeshTestUtils.generateClient1(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); + try { - client = EventMeshTCPClientFactory.createEventMeshTCPClient( - eventMeshTcpClientConfig, CloudEvent.class); + + final EventMeshTCPClient client = EventMeshTCPClientFactory.createEventMeshTCPClient( + eventMeshTcpClientConfig, CloudEvent.class); client.init(); - CloudEvent event = EventMeshTestUtils.generateCloudEventV1SyncRR(); + final CloudEvent event = EventMeshTestUtils.generateCloudEventV1SyncRR(); + log.info("begin send rr msg: {}", event); - Package response = client.rr(event, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - CloudEvent replyEvent = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(response.getBody().toString().getBytes(StandardCharsets.UTF_8)); - String content = new String(replyEvent.getData().toBytes(), StandardCharsets.UTF_8); + + final Package response = client.rr(event, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + // check-NPE EventFormat + final EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); + if (eventFormat == null) { + log.error("eventFormat is null. end the process"); + return; + } + + final CloudEvent replyEvent = eventFormat + .deserialize(response.getBody().toString().getBytes(StandardCharsets.UTF_8)); + + // check-NPE CloudEventData + final CloudEventData cloudEventData = replyEvent.getData(); + if (cloudEventData == null) { + log.error("replyEvent.data is null. end the process"); + return; + } + + final String content = new String(cloudEventData.toBytes(), StandardCharsets.UTF_8); log.info("receive rr reply: {}|{}", response, content); } catch (Exception e) { - log.warn("SyncRequest failed", e); + log.error("SyncRequest failed", e); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublish.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublish.java index 5a61c2d317..16ebbc458d 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublish.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublish.java @@ -24,46 +24,46 @@ import org.apache.eventmesh.common.ExampleConstants; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.tcp.common.EventMeshTestUtils; import org.apache.eventmesh.util.Utils; import java.util.Properties; +import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class AsyncPublish { - public static Logger logger = LoggerFactory.getLogger(AsyncPublish.class); - - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); try { - UserAgent userAgent = EventMeshTestUtils.generateClient1(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - client = - EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, EventMeshMessage.class); - client.init(); + final UserAgent userAgent = EventMeshTestUtils.generateClient1(); + try (final EventMeshTCPClient client = + EventMeshTCPClientFactory.createEventMeshTCPClient( + EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(), + EventMeshMessage.class)) { + client.init(); - for (int i = 0; i < 5; i++) { - EventMeshMessage eventMeshMessage = EventMeshTestUtils.generateAsyncEventMqMsg(); + for (int i = 0; i < 5; i++) { + final EventMeshMessage eventMeshMessage = EventMeshTestUtils.generateAsyncEventMqMsg(); - logger.info("begin send async msg[{}]: {}", i, eventMeshMessage); - client.publish(eventMeshMessage, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + log.info("begin send async msg[{}]: {}", i, eventMeshMessage); + client.publish(eventMeshMessage, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - Thread.sleep(1000); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + ThreadUtils.sleep(2, TimeUnit.SECONDS); } - Thread.sleep(2000); } catch (Exception e) { - logger.warn("AsyncPublish failed", e); + log.error("AsyncPublish failed", e); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublishBroadcast.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublishBroadcast.java index b84701b3a0..94a5a27b88 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublishBroadcast.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/AsyncPublishBroadcast.java @@ -24,40 +24,42 @@ import org.apache.eventmesh.common.ExampleConstants; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.tcp.common.EventMeshTestUtils; import org.apache.eventmesh.util.Utils; import java.util.Properties; +import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class AsyncPublishBroadcast { - public static Logger logger = LoggerFactory.getLogger(AsyncPublishBroadcast.class); - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient1(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - try (final EventMeshTCPClient client = - EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, EventMeshMessage.class)) { + final UserAgent userAgent = EventMeshTestUtils.generateClient1(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); + final EventMeshTCPClient client = EventMeshTCPClientFactory.createEventMeshTCPClient( + eventMeshTcpClientConfig, EventMeshMessage.class); + try { client.init(); - EventMeshMessage eventMeshMessage = EventMeshTestUtils.generateBroadcastMqMsg(); - logger.info("begin send broadcast msg: {}", eventMeshMessage); + final EventMeshMessage eventMeshMessage = EventMeshTestUtils.generateBroadcastMqMsg(); + + log.info("begin send broadcast msg: {}", eventMeshMessage); client.broadcast(eventMeshMessage, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - Thread.sleep(2000); + ThreadUtils.sleep(2, TimeUnit.SECONDS); } catch (Exception e) { - logger.warn("AsyncPublishBroadcast failed", e); + log.error("AsyncPublishBroadcast failed", e); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/SyncRequest.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/SyncRequest.java index 582c6f7ca9..459fc9678c 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/SyncRequest.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/pub/eventmeshmessage/SyncRequest.java @@ -35,30 +35,30 @@ @Slf4j public class SyncRequest { - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient1(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - try { - client = EventMeshTCPClientFactory.createEventMeshTCPClient( - eventMeshTcpClientConfig, EventMeshMessage.class); + final UserAgent userAgent = EventMeshTestUtils.generateClient1(); + try (final EventMeshTCPClient client = + EventMeshTCPClientFactory.createEventMeshTCPClient( + EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(), + EventMeshMessage.class)) { client.init(); - EventMeshMessage eventMeshMessage = EventMeshTestUtils.generateSyncRRMqMsg(); + final EventMeshMessage eventMeshMessage = EventMeshTestUtils.generateSyncRRMqMsg(); + log.info("begin send rr msg: {}", eventMeshMessage); - Package response = client.rr(eventMeshMessage, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + + final Package response = client.rr(eventMeshMessage, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); log.info("receive rr reply: {}", response); } catch (Exception e) { - log.warn("SyncRequest failed", e); + log.error("SyncRequest failed", e); } } } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/AsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/AsyncSubscribe.java index a4f46a606c..c22fafe3d1 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/AsyncSubscribe.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/AsyncSubscribe.java @@ -39,26 +39,24 @@ @Slf4j public class AsyncSubscribe implements ReceiveMsgHook { - public static AsyncSubscribe handler = new AsyncSubscribe(); - - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient2(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); + final UserAgent userAgent = EventMeshTestUtils.generateClient2(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); try { - client = EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); + final EventMeshTCPClient client = EventMeshTCPClientFactory.createEventMeshTCPClient( + eventMeshTcpClientConfig, CloudEvent.class); client.init(); - client.subscribe(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC); - client.registerSubBusiHandler(handler); + client.subscribe(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, + SubscriptionType.ASYNC); + client.registerSubBusiHandler(new AsyncSubscribe()); client.listen(); } catch (Exception e) { @@ -67,8 +65,13 @@ public static void main(String[] args) throws Exception { } @Override - public Optional handle(CloudEvent msg) { - String content = new String(msg.getData().toBytes(), StandardCharsets.UTF_8); + public Optional handle(final CloudEvent msg) { + if (msg.getData() == null) { + log.warn("receive async msg's data is null."); + return Optional.empty(); + } + + final String content = new String(msg.getData().toBytes(), StandardCharsets.UTF_8); log.info("receive async msg: {}|{}", msg, content); return Optional.empty(); } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/SyncResponse.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/SyncResponse.java index 8314b59926..f6312febc0 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/SyncResponse.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/cloudevents/SyncResponse.java @@ -39,39 +39,40 @@ @Slf4j public class SyncResponse implements ReceiveMsgHook { - public static SyncResponse handler = new SyncResponse(); - - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient2(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); + final UserAgent userAgent = EventMeshTestUtils.generateClient2(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); try { - client = EventMeshTCPClientFactory - .createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); + final EventMeshTCPClient client = EventMeshTCPClientFactory + .createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); client.init(); client.subscribe(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); // Synchronize RR messages - client.registerSubBusiHandler(handler); + client.registerSubBusiHandler(new SyncResponse()); client.listen(); } catch (Exception e) { - log.warn("SyncResponse failed", e); + log.error("SyncResponse failed", e); } } @Override - public Optional handle(CloudEvent event) { - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); + public Optional handle(final CloudEvent event) { + if (event.getData() == null) { + log.warn("receive sync msg's data is null."); + return Optional.empty(); + } + + final String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); log.info("receive sync rr msg: {}|{}", event, content); return Optional.of(event); } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribe.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribe.java index 8a3c325ddb..3c856e9037 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribe.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribe.java @@ -37,38 +37,34 @@ @Slf4j public class AsyncSubscribe implements ReceiveMsgHook { - public static AsyncSubscribe handler = new AsyncSubscribe(); - - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient2(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); + final UserAgent userAgent = EventMeshTestUtils.generateClient2(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); try { - client = - EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, EventMeshMessage.class); + final EventMeshTCPClient client = + EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, EventMeshMessage.class); client.init(); client.subscribe(ExampleConstants.EVENTMESH_TCP_ASYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, - SubscriptionType.ASYNC); - client.registerSubBusiHandler(handler); + SubscriptionType.ASYNC); + client.registerSubBusiHandler(new AsyncSubscribe()); client.listen(); } catch (Exception e) { - log.warn("AsyncSubscribe failed", e); + log.error("AsyncSubscribe failed", e); } } @Override - public Optional handle(EventMeshMessage msg) { + public Optional handle(final EventMeshMessage msg) { log.info("receive async msg: {}", msg); return Optional.empty(); } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribeBroadcast.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribeBroadcast.java index 2a26947e5a..411eafdeda 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribeBroadcast.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/AsyncSubscribeBroadcast.java @@ -37,34 +37,36 @@ @Slf4j public class AsyncSubscribeBroadcast implements ReceiveMsgHook { - public static AsyncSubscribeBroadcast handler = new AsyncSubscribeBroadcast(); - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient2(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); - try (EventMeshTCPClient client = EventMeshTCPClientFactory.createEventMeshTCPClient( - eventMeshTcpClientConfig, EventMeshMessage.class)) { + final UserAgent userAgent = EventMeshTestUtils.generateClient2(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); + + try { + final EventMeshTCPClient client = EventMeshTCPClientFactory.createEventMeshTCPClient( + eventMeshTcpClientConfig, EventMeshMessage.class); + client.init(); - client.subscribe(ExampleConstants.EVENTMESH_TCP_BROADCAST_TEST_TOPIC, SubscriptionMode.BROADCASTING, SubscriptionType.ASYNC); - client.registerSubBusiHandler(handler); + client.subscribe(ExampleConstants.EVENTMESH_TCP_BROADCAST_TEST_TOPIC, SubscriptionMode.BROADCASTING, + SubscriptionType.ASYNC); + client.registerSubBusiHandler(new AsyncSubscribeBroadcast()); client.listen(); } catch (Exception e) { - log.warn("AsyncSubscribeBroadcast failed", e); + log.error("AsyncSubscribeBroadcast failed", e); } } @Override - public Optional handle(EventMeshMessage msg) { + public Optional handle(final EventMeshMessage msg) { log.info("receive broadcast msg: {}", msg); return Optional.empty(); } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/SyncResponse.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/SyncResponse.java index 34517ad270..93495be698 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/SyncResponse.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/tcp/demo/sub/eventmeshmessage/SyncResponse.java @@ -37,38 +37,35 @@ @Slf4j public class SyncResponse implements ReceiveMsgHook { - public static SyncResponse handler = new SyncResponse(); - - private static EventMeshTCPClient client; - public static void main(String[] args) throws Exception { - Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); + final Properties properties = Utils.readPropertiesFile(ExampleConstants.CONFIG_FILE_NAME); final String eventMeshIp = properties.getProperty(ExampleConstants.EVENTMESH_IP); final int eventMeshTcpPort = Integer.parseInt(properties.getProperty(ExampleConstants.EVENTMESH_TCP_PORT)); - UserAgent userAgent = EventMeshTestUtils.generateClient2(); - EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() - .host(eventMeshIp) - .port(eventMeshTcpPort) - .userAgent(userAgent) - .build(); + final UserAgent userAgent = EventMeshTestUtils.generateClient2(); + final EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(eventMeshIp) + .port(eventMeshTcpPort) + .userAgent(userAgent) + .build(); try { - client = EventMeshTCPClientFactory - .createEventMeshTCPClient(eventMeshTcpClientConfig, EventMeshMessage.class); + final EventMeshTCPClient client = EventMeshTCPClientFactory + .createEventMeshTCPClient(eventMeshTcpClientConfig, EventMeshMessage.class); client.init(); - client.subscribe(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); + client.subscribe(ExampleConstants.EVENTMESH_TCP_SYNC_TEST_TOPIC, SubscriptionMode.CLUSTERING, + SubscriptionType.SYNC); // Synchronize RR messages - client.registerSubBusiHandler(handler); + client.registerSubBusiHandler(new SyncResponse()); client.listen(); } catch (Exception e) { - log.warn("SyncResponse failed", e); + log.error("SyncResponse failed", e); } } @Override - public Optional handle(EventMeshMessage msg) { + public Optional handle(final EventMeshMessage msg) { log.info("receive sync rr msg: {}", msg); return Optional.ofNullable(msg); } diff --git a/eventmesh-examples/src/main/java/org/apache/eventmesh/util/Utils.java b/eventmesh-examples/src/main/java/org/apache/eventmesh/util/Utils.java index 003ac5f610..cca5aa23d1 100644 --- a/eventmesh-examples/src/main/java/org/apache/eventmesh/util/Utils.java +++ b/eventmesh-examples/src/main/java/org/apache/eventmesh/util/Utils.java @@ -18,14 +18,15 @@ package org.apache.eventmesh.util; import org.apache.eventmesh.common.ExampleConstants; +import org.apache.eventmesh.common.utils.IPUtils; import org.apache.commons.lang3.SystemUtils; +import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.net.UnknownHostException; import java.util.Enumeration; import java.util.Properties; @@ -33,9 +34,8 @@ public class Utils { /** * Get local IP address - * */ - public static String getLocalIP() throws UnknownHostException { + public static String getLocalIP() throws IOException { if (isWindowsOS()) { return InetAddress.getLocalHost().getHostAddress(); } else { @@ -46,7 +46,7 @@ public static String getLocalIP() throws UnknownHostException { /** * Determine whether the operating system is Windows * - * @return + * @return true - Windows false - other OS */ public static boolean isWindowsOS() { return SystemUtils.IS_OS_WINDOWS; @@ -57,30 +57,26 @@ public static boolean isWindowsOS() { * * @return IP address */ - private static String getLinuxLocalIp() { - String ip = ""; - try { - for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { - NetworkInterface intf = en.nextElement(); - String name = intf.getName(); - if (!name.contains("docker") && !name.contains("lo")) { - for (Enumeration enumIpAddr = intf.getInetAddresses(); - enumIpAddr.hasMoreElements(); ) { - InetAddress inetAddress = enumIpAddr.nextElement(); - if (!inetAddress.isLoopbackAddress()) { - String ipaddress = inetAddress.getHostAddress(); - if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") - && !ipaddress.contains("fe80")) { - ip = ipaddress; - } + private static String getLinuxLocalIp() throws SocketException { + String ip = ExampleConstants.DEFAULT_EVENTMESH_IP; + + for (final Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { + final NetworkInterface intf = en.nextElement(); + final String name = intf.getName(); + if (!name.contains("docker") && !name.contains("lo")) { + for (final Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { + final InetAddress inetAddress = enumIpAddr.nextElement(); + if (!inetAddress.isLoopbackAddress()) { + final String ipaddress = inetAddress.getHostAddress(); + if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") + && !ipaddress.contains("fe80")) { + ip = ipaddress; } } } } - } catch (SocketException ex) { - ip = ExampleConstants.DEFAULT_EVENTMESH_IP; - ex.printStackTrace(); } + return ip; } @@ -88,14 +84,21 @@ private static String getLinuxLocalIp() { * @param fileName * @return Properties */ - public static Properties readPropertiesFile(String fileName) { - try (final InputStream inputStream = Utils.class.getClassLoader().getResourceAsStream(fileName)) { - Properties properties = new Properties(); + public static Properties readPropertiesFile(final String fileName) throws IOException { + try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)) { + final Properties properties = new Properties(); properties.load(inputStream); return properties; - } catch (Exception e) { - throw new IllegalArgumentException(String.format("File: %s is not exist", fileName)); } } + /** + * @param port server port + * @param path path + * @return url + */ + public static String getURL(String port, String path) { + return "http://" + IPUtils.getLocalAddress() + ":" + port + path; + } + } diff --git a/eventmesh-examples/src/main/resources/application.properties b/eventmesh-examples/src/main/resources/application.properties index 51640d82b3..f53b1fb198 100644 --- a/eventmesh-examples/src/main/resources/application.properties +++ b/eventmesh-examples/src/main/resources/application.properties @@ -15,7 +15,17 @@ # limitations under the License. # server.port=8088 +server.name=orderapp eventmesh.ip=127.0.0.1 eventmesh.http.port=10105 eventmesh.tcp.port=10000 -eventmesh.grpc.port=10205 \ No newline at end of file +eventmesh.grpc.port=10205 +eventmesh.selector.type=nacos +eventmesh.selector.nacos.address=127.0.0.1:8848 +eventmesh.catalog.name=EVENTMESH-catalog +eventmesh.workflow.name=EVENTMESH-workflow +eventmesh.connector.dingtalkTemplateType=text +eventmesh.connector.wecomTemplateType=text +eventmesh.connector.templateType4Lark=text +eventmesh.connector.atUsers4lark=id,name;id,name; +eventmesh.connector.atAll4Lark=false diff --git a/eventmesh-examples/src/main/resources/server-config.yml b/eventmesh-examples/src/main/resources/server-config.yml new file mode 100644 index 0000000000..5f66dd0f68 --- /dev/null +++ b/eventmesh-examples/src/main/resources/server-config.yml @@ -0,0 +1,19 @@ +# +# 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. +# + +sourceEnable: true +sinkEnable: true diff --git a/eventmesh-examples/src/main/resources/sink-config.yml b/eventmesh-examples/src/main/resources/sink-config.yml new file mode 100644 index 0000000000..e49b73b984 --- /dev/null +++ b/eventmesh-examples/src/main/resources/sink-config.yml @@ -0,0 +1,28 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-SPRING + idc: FT + env: PRD + group: springSink + appId: 5033 + userName: springSinkUser + passWord: springPassWord +sinkConnectorConfig: + connectorName: springSink diff --git a/eventmesh-examples/src/main/resources/source-config.yml b/eventmesh-examples/src/main/resources/source-config.yml new file mode 100644 index 0000000000..db7dd9f910 --- /dev/null +++ b/eventmesh-examples/src/main/resources/source-config.yml @@ -0,0 +1,28 @@ +# +# 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. +# + +pubSubConfig: + meshAddress: 127.0.0.1:10000 + subject: TEST-TOPIC-SPRING + idc: FT + env: PRD + group: springSource + appId: 5033 + userName: springSourceUser + passWord: springPassWord +sourceConnectorConfig: + connectorName: springSource diff --git a/eventmesh-admin/build.gradle b/eventmesh-function/build.gradle similarity index 100% rename from eventmesh-admin/build.gradle rename to eventmesh-function/build.gradle diff --git a/eventmesh-registry-plugin/build.gradle b/eventmesh-function/eventmesh-function-api/build.gradle similarity index 100% rename from eventmesh-registry-plugin/build.gradle rename to eventmesh-function/eventmesh-function-api/build.gradle diff --git a/eventmesh-function/eventmesh-function-api/src/main/java/org/apache/eventmesh/function/api/AbstractEventMeshFunctionChain.java b/eventmesh-function/eventmesh-function-api/src/main/java/org/apache/eventmesh/function/api/AbstractEventMeshFunctionChain.java new file mode 100644 index 0000000000..8cbb0f9381 --- /dev/null +++ b/eventmesh-function/eventmesh-function-api/src/main/java/org/apache/eventmesh/function/api/AbstractEventMeshFunctionChain.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.api; + +import java.util.ArrayList; +import java.util.List; + +/** + * AbstractEventMeshFunctionChain is an abstract class that implements the {@link EventMeshFunction} interface and provides a framework + * for chaining multiple {@link EventMeshFunction} instances that operate on inputs of type {@code T} and produce outputs of type + * {@code R}. This class can be extended to create specific function chains with customized behavior for different + * data types. + * + *

The primary purpose of this class is to allow the sequential execution of functions, where the output of one + * function is passed as the input to the next function in the chain. The chain can be dynamically modified by adding + * functions either at the beginning or the end of the chain.

+ * + * @param the type of the input to the function + * @param the type of the result of the function + */ +public abstract class AbstractEventMeshFunctionChain implements EventMeshFunction { + + protected final List> functions; + + /** + * Default constructor that initializes an empty function chain. + */ + public AbstractEventMeshFunctionChain() { + this.functions = new ArrayList<>(); + } + + /** + * Constructor that initializes the function chain with a given list of functions. The functions will be executed + * in the order they are provided when the {@link #apply(Object)} method is called. + * + * @param functions the initial list of functions to be added to the chain + */ + public AbstractEventMeshFunctionChain(List> functions) { + this.functions = functions; + } + + /** + * Adds a {@link EventMeshFunction} to the beginning of the chain. The function will be executed first when the + * {@link #apply(Object)} method is called. + * + * @param function the function to be added to the beginning of the chain + */ + public void addFirst(EventMeshFunction function) { + this.functions.add(0, function); + } + + /** + * Adds a {@link EventMeshFunction} to the end of the chain. The function will be executed in sequence after all previously + * added functions when the {@link #apply(Object)} method is called. + * + * @param function the function to be added to the end of the chain + */ + public void addLast(EventMeshFunction function) { + this.functions.add(function); + } +} \ No newline at end of file diff --git a/eventmesh-function/eventmesh-function-api/src/main/java/org/apache/eventmesh/function/api/EventMeshFunction.java b/eventmesh-function/eventmesh-function-api/src/main/java/org/apache/eventmesh/function/api/EventMeshFunction.java new file mode 100644 index 0000000000..973f097ae0 --- /dev/null +++ b/eventmesh-function/eventmesh-function-api/src/main/java/org/apache/eventmesh/function/api/EventMeshFunction.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.api; + +/** + * EventMesh Interface for a function that accepts one argument and produces a result. This is a functional interface whose functional method is + * {@link #apply(Object)}. + * + *

This interface is similar to {@link java.util.function.Function}, + * but it is specifically designed for use within the EventMesh. It allows defining custom functions to process data or events in the EventMesh. The + * main use case is to encapsulate operations that can be passed around and applied to data or event messages in the EventMesh processing + * pipeline.

+ * + * @param the type of the input to the function + * @param the type of the result of the function + */ +public interface EventMeshFunction { + + /** + * Applies this function to the given argument within the context of the EventMesh module. This method encapsulates the logic for processing the + * input data and producing a result, which can be used in the EventMesh event processing pipeline. + * + * @param t the function argument, representing the input data or event to be processed + * @return the function result, representing the processed output + */ + R apply(T t); + +} \ No newline at end of file diff --git a/eventmesh-function/eventmesh-function-filter/build.gradle b/eventmesh-function/eventmesh-function-filter/build.gradle new file mode 100644 index 0000000000..21e28d7baf --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/build.gradle @@ -0,0 +1,21 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-function:eventmesh-function-api") +} \ No newline at end of file diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/PatternEntry.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/PatternEntry.java new file mode 100644 index 0000000000..acc2d5f073 --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/PatternEntry.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter; + +import org.apache.eventmesh.function.filter.condition.Condition; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; + +public class PatternEntry { + + private String patternName; + + private String patternPath; + + private final List conditionList = new ArrayList<>(); + + public PatternEntry(final String patternName, final String patternPath) { + this.patternName = patternName; + this.patternPath = patternPath; + } + + public void addCondition(Condition patternCondition) { + this.conditionList.add(patternCondition); + } + + public String getPatternName() { + return patternName; + } + + public String getPatternPath() { + return patternPath; + } + + // default filter type is OR + // todo: extend the filter type with AND + public boolean match(JsonNode jsonElement) { + for (final Condition patternCondition : conditionList) { + if (patternCondition.match(jsonElement)) { + return true; + } + } + + return false; + + } + + /** + * Returns the condition list for test only + * + * @return the condition list + */ + List getConditionList() { + return conditionList; + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/AnythingButCondition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/AnythingButCondition.java new file mode 100644 index 0000000000..d4f209225e --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/AnythingButCondition.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import com.fasterxml.jackson.databind.JsonNode; + +public class AnythingButCondition implements Condition { + + private List conditionList = new ArrayList<>(); + + public AnythingButCondition(JsonNode condition) { + + if (condition.isValueNode()) { + this.conditionList.add(new SpecifiedCondition(condition)); + } + // [] + if (condition.isArray()) { + for (JsonNode element : condition) { + this.conditionList.add(new SpecifiedCondition(element)); + } + } + + // prefix,suffix + if (condition.isObject()) { + Iterator> iterator = condition.fields(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + String key = entry.getKey(); + JsonNode value = entry.getValue(); + Condition condition1 = new ConditionsBuilder().withKey(key).withParams(value).build(); + this.conditionList.add(condition1); + } + } + + } + + @Override + public boolean match(JsonNode inputEvent) { + if (inputEvent == null) { + return false; + } + + for (Condition condition : conditionList) { + if (condition.match(inputEvent)) { + return false; + } + } + return true; + } + +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/Condition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/Condition.java new file mode 100644 index 0000000000..9890d5e0d3 --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/Condition.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * + */ +public interface Condition { + + boolean match(JsonNode inputEvent); + +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/ConditionsBuilder.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/ConditionsBuilder.java new file mode 100644 index 0000000000..961be85e5b --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/ConditionsBuilder.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import com.fasterxml.jackson.databind.JsonNode; + +public class ConditionsBuilder { + + private String key; + private JsonNode jsonNode; + + public ConditionsBuilder withKey(String key) { + this.key = key; + return this; + } + + public ConditionsBuilder withParams(JsonNode jsonNode) { + this.jsonNode = jsonNode; + return this; + } + + public Condition build() { + Condition condition = null; + switch (this.key) { + case "prefix": + condition = new PrefixCondition(this.jsonNode); + break; + case "suffix": + condition = new SuffixCondition(this.jsonNode); + break; + case "anything-but": + condition = new AnythingButCondition(this.jsonNode); + break; + case "numeric": + condition = new NumericCondition(this.jsonNode); + break; + case "exists": + condition = new ExistsCondition(this.jsonNode); + break; + case "specified": + condition = new SpecifiedCondition(this.jsonNode); + break; + default: + throw new RuntimeException("INVALID CONDITION"); + // Add cases for other keys and conditions + } + + return condition; + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/ExistsCondition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/ExistsCondition.java new file mode 100644 index 0000000000..c085ba6585 --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/ExistsCondition.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import com.fasterxml.jackson.databind.JsonNode; + +public class ExistsCondition implements Condition { + + private JsonNode exists; + + ExistsCondition(JsonNode exists) { + this.exists = exists; + } + + @Override + public boolean match(JsonNode inputEvent) { + + return this.exists.asBoolean() == (inputEvent != null); + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/NumericCondition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/NumericCondition.java new file mode 100644 index 0000000000..40eb16a75e --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/NumericCondition.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; + +public class NumericCondition implements Condition { + + List operators = new ArrayList<>(); + List nums = new ArrayList<>(); + + NumericCondition(JsonNode numeric) { + if (numeric.isArray()) { + if (numeric.size() % 2 != 0) { + throw new RuntimeException("NUMERIC NO RIGHT FORMAT"); + } + for (int i = 0; i < numeric.size(); i += 2) { + JsonNode opt = numeric.get(i); + JsonNode number = numeric.get(i + 1); + operators.add(opt.asText()); + nums.add(number.asDouble()); + } + } else { + throw new RuntimeException("NUMERIC MUST BE ARRAY"); + } + } + + private boolean compareNums(Double rule, Double target, String opt) { + int res = Double.compare(target, rule); + switch (opt) { + case "=": + return res == 0; + case "!=": + return res != 0; + case ">": + return res > 0; + case ">=": + return res >= 0; + case "<": + return res < 0; + case "<=": + return res <= 0; + default: // Never be here + return false; + } + } + + @Override + public boolean match(JsonNode inputEvent) { + if (inputEvent.isNumber()) { + for (int i = 0; i < operators.size(); ++i) { + if (!compareNums(nums.get(i), inputEvent.asDouble(), operators.get(i))) { + return false; + } + + } + + } + + return true; + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/PrefixCondition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/PrefixCondition.java new file mode 100644 index 0000000000..ff5d0313ce --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/PrefixCondition.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import com.fasterxml.jackson.databind.JsonNode; + +public class PrefixCondition implements Condition { + + private final String prefix; + + public PrefixCondition(JsonNode suffix) { + this.prefix = suffix.asText(); + } + + @Override + public boolean match(JsonNode inputEvent) { + return inputEvent.asText().startsWith(prefix); + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/SpecifiedCondition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/SpecifiedCondition.java new file mode 100644 index 0000000000..9eefb6b641 --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/SpecifiedCondition.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import com.fasterxml.jackson.databind.JsonNode; + +public class SpecifiedCondition implements Condition { + + private final JsonNode specified; + + SpecifiedCondition(JsonNode jsonNode) { + specified = jsonNode; + } + + @Override + public boolean match(JsonNode inputEvent) { + return inputEvent.asText().equals(specified.asText()); + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/SuffixCondition.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/SuffixCondition.java new file mode 100644 index 0000000000..090df24834 --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/condition/SuffixCondition.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.condition; + +import com.fasterxml.jackson.databind.JsonNode; + +public class SuffixCondition implements Condition { + + private final String suffix; + + public SuffixCondition(JsonNode suffix) { + this.suffix = suffix.asText(); + } + + @Override + public boolean match(JsonNode inputEvent) { + return inputEvent.asText().endsWith(this.suffix); + } +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/pattern/Pattern.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/pattern/Pattern.java new file mode 100644 index 0000000000..955d9f59ef --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/pattern/Pattern.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.pattern; + +import org.apache.eventmesh.common.utils.JsonPathUtils; +import org.apache.eventmesh.function.api.EventMeshFunction; +import org.apache.eventmesh.function.filter.PatternEntry; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.jayway.jsonpath.PathNotFoundException; + + +public class Pattern implements EventMeshFunction { + + private final List requiredFieldList = new ArrayList<>(); + private final List dataList = new ArrayList<>(); + + public void addRequiredFieldList(PatternEntry patternEntry) { + this.requiredFieldList.add(patternEntry); + } + + public void addDataList(PatternEntry patternEntry) { + this.dataList.add(patternEntry); + } + + public boolean filter(String content) { + return matchRequiredFieldList(content, requiredFieldList) && matchRequiredFieldList(content, dataList); + } + + @Override + public String apply(String content) { + // filter content + return filter(content) ? content : null; + } + + private boolean matchRequiredFieldList(String content, List dataList) { + + for (final PatternEntry patternEntry : dataList) { + JsonNode jsonElement = null; + try { + // content:filter + String matchRes = JsonPathUtils.matchJsonPathValue(content, patternEntry.getPatternPath()); + + if (StringUtils.isNoneBlank(matchRes)) { + jsonElement = JsonPathUtils.parseStrict(matchRes); + } + + if (jsonElement != null && jsonElement.isArray()) { + for (JsonNode element : jsonElement) { + if (patternEntry.match(element)) { + return true; + } + } + } else { + if (!patternEntry.match(jsonElement)) { + return false; + } + } + + } catch (PathNotFoundException | JsonProcessingException e) { + throw new RuntimeException(e); + } + + } + return true; + + } + +} diff --git a/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/patternbuild/PatternBuilder.java b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/patternbuild/PatternBuilder.java new file mode 100644 index 0000000000..60193a4efa --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/main/java/org/apache/eventmesh/function/filter/patternbuild/PatternBuilder.java @@ -0,0 +1,189 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter.patternbuild; + +import org.apache.eventmesh.common.exception.JsonException; +import org.apache.eventmesh.function.filter.PatternEntry; +import org.apache.eventmesh.function.filter.condition.Condition; +import org.apache.eventmesh.function.filter.condition.ConditionsBuilder; +import org.apache.eventmesh.function.filter.pattern.Pattern; + +import java.util.ArrayDeque; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Queue; + +import io.cloudevents.SpecVersion; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class PatternBuilder { + + private static final ObjectMapper mapper = new ObjectMapper(); + + + public static Pattern build(String jsonStr) { + try { + JsonNode jsonNode = mapper.readTree(jsonStr); + if (jsonNode.isEmpty() || !jsonNode.isObject()) { + return null; + } + return build(jsonNode); + } catch (Exception e) { + throw new JsonException("INVALID_JSON_STRING", e); + } + } + + public static Pattern build(Map conditionMap) { + try { + JsonNode jsonNode = mapper.valueToTree(conditionMap); + if (jsonNode.isEmpty() || !jsonNode.isObject()) { + return null; + } + return build(jsonNode); + } catch (Exception e) { + throw new JsonException("INVALID_MAP", e); + } + } + + public static Pattern build(JsonNode jsonNode) { + Pattern pattern = new Pattern(); + + // iter all json data + Iterator> iterator = jsonNode.fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String key = entry.getKey(); + JsonNode value = entry.getValue(); + + if (key.equals("data")) { + + parseDataField(value, pattern); + continue; + } + + if (!value.isArray()) { + throw new JsonException("INVALID_JSON_STRING"); + } + + if (!SpecVersion.V1.getAllAttributes().contains(key)) { + throw new JsonException("INVALID_JSON_KEY"); + } + + // iter all requiredField + parseRequiredField(key, "$." + key, value, pattern); + } + + return pattern; + + } + + private static void parseDataField(JsonNode jsonNode, Pattern pattern) { + if (!jsonNode.isObject()) { + throw new JsonException("INVALID_JSON_KEY"); + } + Queue queueNode = new ArrayDeque<>(); + Node node = new Node("$.data", "data", jsonNode); + queueNode.add(node); + while (!queueNode.isEmpty()) { + Node ele = queueNode.poll(); + String elepath = ele.getPath(); + Iterator> iterator = ele.getValue().fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + // state + String key = entry.getKey(); + // [{"anything-but":"initializing"}] [{"anything-but":123}]} + JsonNode value = entry.getValue(); + PatternEntry patternEntry = new PatternEntry(key, elepath + "." + key); + if (!value.isObject()) { + if (value.isArray()) { + for (JsonNode node11 : value) { + // {"anything-but":"initializing"} + patternEntry.addCondition(parseCondition(node11)); + } + } + pattern.addDataList(patternEntry); + } else { + queueNode.add(new Node(elepath + "." + key, key, value)); + } + } + } + + } + + private static Condition parseCondition(JsonNode jsonNode) { + if (jsonNode.isValueNode()) { + return new ConditionsBuilder().withKey("specified").withParams(jsonNode).build(); + } + + Iterator> iterator = jsonNode.fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + // "anything-but" + String key = entry.getKey(); + // "initializing" + JsonNode value = entry.getValue(); + return new ConditionsBuilder().withKey(key).withParams(value).build(); + } + return null; + } + + private static void parseRequiredField(String patternName, String patternPath, JsonNode jsonNode, Pattern pattern) { + if (jsonNode.isEmpty()) { + // Empty array + throw new JsonException("INVALID_PATTERN_VALUE "); + } + PatternEntry patternEntry = new PatternEntry(patternName, patternPath); + for (final JsonNode objNode : jsonNode) { + Condition condition = parseCondition(objNode); + patternEntry.addCondition(condition); + } + + pattern.addRequiredFieldList(patternEntry); + + } + + static class Node { + + private String path; + private String key; + private JsonNode value; + + Node(String path, String key, JsonNode value) { + this.path = path; + this.key = key; + this.value = value; + } + + String getPath() { + return this.path; + } + + String getKey() { + return this.key; + } + + JsonNode getValue() { + return this.value; + } + } + +} diff --git a/eventmesh-function/eventmesh-function-filter/src/test/java/org/apache/eventmesh/function/filter/PatternTest.java b/eventmesh-function/eventmesh-function-filter/src/test/java/org/apache/eventmesh/function/filter/PatternTest.java new file mode 100644 index 0000000000..bc0aeff4ea --- /dev/null +++ b/eventmesh-function/eventmesh-function-filter/src/test/java/org/apache/eventmesh/function/filter/PatternTest.java @@ -0,0 +1,168 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.filter; + +import org.apache.eventmesh.function.filter.pattern.Pattern; +import org.apache.eventmesh.function.filter.patternbuild.PatternBuilder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PatternTest { + + private final String event = "{\n" + + "\"id\": \"4b26115b-73e-cf74a******\",\n" + + " \"specversion\": \"1.0\",\n" + + "\"source\": \"eventmesh.source\",\n" + + "\"type\": \"object:put\",\n" + + "\"datacontenttype\": \"application/json\",\n" + + "\"subject\": \"xxx.jpg\",\n" + + "\"time\": \"2022-01-17T12:07:48.955Z\",\n" + + "\"data\": {\n" + + "\"name\": \"test01\",\n" + + "\"state\": \"enable\",\n" + + "\"num\": 10 ,\n" + + "\"num1\": 50.7 \n" + + "}\n" + + " }"; + + @Test + public void testSpecifiedFilter() { + String condition = "{\n" + + " \"source\":[\n" + + " {\n" + + " \"prefix\":\"eventmesh.\"\n" + + " }\n" + + " ]\n" + + "}"; + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(true, res); + } + + @Test + public void testPrefixFilter() { + String condition = "{\n" + + " \"source\":[\n" + + " {\n" + + " \"prefix\":\"eventmesh.\"\n" + + " }\n" + + " ]\n" + + "}"; + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(true, res); + } + + @Test + public void testSuffixFilter() { + String condition = "{\n" + + " \"subject\":[\n" + + " {\n" + + " \"suffix\":\".jpg\"\n" + + " }\n" + + " ]\n" + + "}"; + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(true, res); + } + + @Test + public void testNumericFilter() { + String condition = "{\n" + + " \"data\":{\n" + + " \"num\":[\n" + + " {\n" + + " \"numeric\":[\n" + + " \">\",\n" + + " 0,\n" + + " \"<=\",\n" + + " 10\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"num1\":[\n" + + " {\n" + + " \"numeric\":[\n" + + " \"=\",\n" + + " 50.7\n" + + " ]\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(true, res); + } + + @Test + public void testExistsFilter() { + String condition = "{\n" + + " \"data\":{\n" + + " \"state\":[\n" + + " {\n" + + " \"exists\": false\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(false, res); + } + + @Test + public void testAnythingButFilter() { + String condition = "{\n" + + " \"data\":{\n" + + " \"state\":[\n" + + " {\n" + + " \"anything-but\": \"enable\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(false, res); + } + + @Test + public void testPrefixFilterMap() { + // Create the inner Map representing {prefix=eventmesh.} + Map innerMap = new HashMap<>(); + innerMap.put("prefix", "eventmesh."); + // Create a List representing [{prefix=eventmesh.}] + List> sourceList = Collections.singletonList(innerMap); + // Create the condition representing {source=[{prefix=eventmesh.}]} + Map condition = new HashMap<>(); + condition.put("source", sourceList); + + Pattern pattern = PatternBuilder.build(condition); + Boolean res = pattern.filter(event); + Assertions.assertEquals(true, res); + } + +} diff --git a/eventmesh-function/eventmesh-function-router/src/test/java/org/apache/eventmesh/function/router/RouterBuilderTest.java b/eventmesh-function/eventmesh-function-router/src/test/java/org/apache/eventmesh/function/router/RouterBuilderTest.java new file mode 100644 index 0000000000..30af93f185 --- /dev/null +++ b/eventmesh-function/eventmesh-function-router/src/test/java/org/apache/eventmesh/function/router/RouterBuilderTest.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.router; + +import org.apache.eventmesh.function.api.Router; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RouterBuilderTest { + + @Test + public void testBuild() { + String targetTopic = "targetTopic"; + Router router = RouterBuilder.build(targetTopic); + Assertions.assertNotNull(router); + Assertions.assertEquals(targetTopic, router.route("{}")); + } +} diff --git a/eventmesh-function/eventmesh-function-transformer/build.gradle b/eventmesh-function/eventmesh-function-transformer/build.gradle new file mode 100644 index 0000000000..6939bbd483 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/build.gradle @@ -0,0 +1,22 @@ +/* + * 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. + */ + + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-function:eventmesh-function-api") +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/ConstantTransformer.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/ConstantTransformer.java new file mode 100644 index 0000000000..ae77f149f7 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/ConstantTransformer.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +public class ConstantTransformer implements Transformer { + + private final String jsonpath; + + ConstantTransformer(String jsonpath) { + this.jsonpath = jsonpath; + } + + @Override + public String transform(String json) throws TransformException { + return this.jsonpath; + } +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/JsonPathParser.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/JsonPathParser.java new file mode 100644 index 0000000000..c578310dc4 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/JsonPathParser.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import org.apache.eventmesh.common.utils.JsonPathUtils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; + +public class JsonPathParser { + + protected List variablesList = new ArrayList<>(); + + public List getVariablesList() { + return variablesList; + } + + /** + * parser input jsonpath map into variable list + * + * @param jsonPathMap jsonpath map + */ + public JsonPathParser(Map jsonPathMap) { + for (Map.Entry entry : jsonPathMap.entrySet()) { + String name = entry.getKey(); + String value = entry.getValue(); + variablesList.add(new Variable(name, value)); + } + } + + /** + * parser input jsonpath string into variable list + * + * @param jsonPathString + */ + public JsonPathParser(String jsonPathString) { + JsonNode jsonObject = JsonPathUtils.parseStrict(jsonPathString); + Iterator> fields = jsonObject.fields(); + + while (fields.hasNext()) { + Map.Entry entry = fields.next(); + String name = entry.getKey(); + JsonNode valueNode = entry.getValue(); + if (valueNode.isValueNode()) { + variablesList.add(new Variable(name, valueNode.asText())); + } else { + throw new TransformException("invalid config:" + jsonPathString); + } + + } + + } + + /** + * use jsonpath to match json and return result + * + * @param json + * @return + */ + + public List match(String json) throws JsonProcessingException { + if (json == null || json.isEmpty()) { + return new ArrayList<>(); + } + + List variableList = new ArrayList<>(variablesList.size()); + for (Variable element : variablesList) { + if (JsonPathUtils.isValidAndDefinite(element.getValue())) { + String res = JsonPathUtils.matchJsonPathValueWithString(json, element.getValue()); + Variable variable = new Variable(element.getName(), res); + variableList.add(variable); + } else { + variableList.add(element); + } + + } + return variableList; + } +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/OriginalTransformer.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/OriginalTransformer.java new file mode 100644 index 0000000000..59ce0350eb --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/OriginalTransformer.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +class OriginalTransformer implements Transformer { + + @Override + public String transform(String json) { + return json; + } + +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Template.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Template.java new file mode 100644 index 0000000000..29d975c371 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Template.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import org.apache.commons.text.StringSubstitutor; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Template { + + private String template; + + public Template(String template) { + this.template = template; + } + + public String substitute(List variables) throws TransformException { + + Map valuesMap = variables.stream() + .filter(variable -> variable.getValue() != null) + .collect(Collectors.toMap(Variable::getName, Variable::getValue)); + StringSubstitutor sub = new StringSubstitutor(valuesMap); + + return sub.replace(template); + + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } +} \ No newline at end of file diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TemplateTransformer.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TemplateTransformer.java new file mode 100644 index 0000000000..69cee68269 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TemplateTransformer.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; + +class TemplateTransformer implements Transformer { + + private final JsonPathParser jsonPathParser; + + private final Template template; + + TemplateTransformer(JsonPathParser jsonPathParser, Template template) { + this.template = template; + this.jsonPathParser = jsonPathParser; + } + + @Override + public String transform(String json) throws JsonProcessingException { + // 1: get variable match results + List variableList = jsonPathParser.match(json); + // 2: use results replace template + return template.substitute(variableList); + } + +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformException.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformException.java new file mode 100644 index 0000000000..aeb827fc88 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformException.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +/** + * Transform exception + */ +public class TransformException extends RuntimeException { + + private static final long serialVersionUID = -4351489859520642285L; + + public TransformException(String message) { + super(message); + } + + public TransformException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Transformer.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Transformer.java new file mode 100644 index 0000000000..be0e815808 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Transformer.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.function.api.EventMeshFunction; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * EventMesh transformer interface, specified transformer implementation includes: + * 1. Constant + * 2. Original + * 3. Template + */ +public interface Transformer extends EventMeshFunction { + + String transform(String json) throws JsonProcessingException; + + @Override + default String apply(String content) { + try { + return transform(content); + } catch (JsonProcessingException e) { + throw new EventMeshException("Failed to transform content", e); + } + } + +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerBuilder.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerBuilder.java new file mode 100644 index 0000000000..916f1ef7bc --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerBuilder.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import java.util.Map; + +public class TransformerBuilder { + + public static Transformer buildTransformer(TransformerParam transformerParam) { + switch (transformerParam.getTransformerType()) { + case ORIGINAL: + return buildOriginalTransformer(); + case CONSTANT: + return buildConstantTransformer(transformerParam.getValue()); + case TEMPLATE: + return buildTemplateTransFormer(transformerParam.getValue(), transformerParam.getTemplate()); + default: + throw new TransformException("invalid config"); + } + } + + /** + * build template transformer + * @param jsonContent json content, support string and map, other type will throw IllegalArgumentException + * @param template template string + * @return transformer + */ + @SuppressWarnings("unchecked") + public static Transformer buildTemplateTransFormer(Object jsonContent, String template) { + Template templateEntry = new Template(template); + JsonPathParser jsonPathParser; + if (jsonContent instanceof String) { + jsonPathParser = new JsonPathParser((String) jsonContent); + } else if (jsonContent instanceof Map) { + jsonPathParser = new JsonPathParser((Map) jsonContent); + } else { + throw new TransformException("invalid json content"); + } + return new TemplateTransformer(jsonPathParser, templateEntry); + } + + public static Transformer buildConstantTransformer(String constant) { + return new ConstantTransformer(constant); + } + + public static Transformer buildOriginalTransformer() { + return new OriginalTransformer(); + } + +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerParam.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerParam.java new file mode 100644 index 0000000000..915111e01d --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerParam.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +public class TransformerParam { + + private TransformerType transformerType; + private String value; + private String template; + + public TransformerParam() { + } + + public TransformerParam(TransformerType transformerType, String value, String template) { + this.transformerType = transformerType; + this.value = value; + this.template = template; + } + + public TransformerParam(TransformerType transformerType, String value) { + this(transformerType, value, null); + } + + public TransformerType getTransformerType() { + return transformerType; + } + + public void setTransformerType(TransformerType transformerType) { + this.transformerType = transformerType; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerType.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerType.java new file mode 100644 index 0000000000..969c49ce80 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/TransformerType.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum TransformerType { + + ORIGINAL(1, "original"), + CONSTANT(2, "constant"), + TEMPLATE(3, "template"); + + private int code; + + private String type; + + TransformerType(int code, String type) { + this.code = code; + this.type = type; + } + + @JsonCreator + public static TransformerType getItem(String type) { + for (TransformerType transformerType : values()) { + if (Objects.equals(transformerType.getType(), type)) { + return transformerType; + } + } + return null; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + @JsonValue + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Variable.java b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Variable.java new file mode 100644 index 0000000000..aee80e1454 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/main/java/org/apache/eventmesh/function/transformer/Variable.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +public class Variable { + + private String name; + + private String value; + + public Variable(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/eventmesh-function/eventmesh-function-transformer/src/test/java/org/apache/eventmesh/function/transformer/TransformTest.java b/eventmesh-function/eventmesh-function-transformer/src/test/java/org/apache/eventmesh/function/transformer/TransformTest.java new file mode 100644 index 0000000000..f9a444e8f9 --- /dev/null +++ b/eventmesh-function/eventmesh-function-transformer/src/test/java/org/apache/eventmesh/function/transformer/TransformTest.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package org.apache.eventmesh.function.transformer; + +import java.util.Collections; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; + +public class TransformTest { + + public static final String EVENT = "{\n" + + "\"id\": \"5b26115b-73e-cf74a******\",\n" + + " \"specversion\": \"1.0\",\n" + + "\"source\": \"apache.eventmesh\",\n" + + "\"type\": \"object:test\",\n" + + "\"datacontenttype\": \"application/json\",\n" + + "\"subject\": \"xxx.jpg\",\n" + + "\"time\": \"2023-09-17T12:07:48.955Z\",\n" + + "\"data\": {\n" + + "\"name\": \"test-transformer\",\n" + + "\"num\": 100 ,\n" + + "\"boolean\": true,\n" + + "\"nullV\": null\n" + + "}\n" + + " }"; + + @Test + public void testOriginalTransformer() throws JsonProcessingException { + TransformerParam transformerParam = new TransformerParam(); + transformerParam.setTransformerType(TransformerType.ORIGINAL); + + Transformer transformer = TransformerBuilder.buildTransformer(transformerParam); + String output = transformer.transform(EVENT); + Assertions.assertEquals(EVENT, output); + + Transformer transformer1 = TransformerBuilder.buildOriginalTransformer(); + String output1 = transformer1.transform(EVENT); + Assertions.assertEquals(EVENT, output1); + } + + @Test + public void testConstantTransformer() throws JsonProcessingException { + TransformerParam transformerParam = new TransformerParam(TransformerType.CONSTANT, "constant test"); + Transformer transformer = TransformerBuilder.buildTransformer(transformerParam); + String output = transformer.transform(EVENT); + Assertions.assertEquals("constant test", output); + + Transformer transformer1 = TransformerBuilder.buildConstantTransformer("constant test"); + String output1 = transformer1.transform(EVENT); + Assertions.assertEquals("constant test", output1); + + } + + @Test + public void testTemplateTransFormerWithStringValue() throws JsonProcessingException { + String content = "{\"data-name\":\"$.data.name\"}"; + String template = "Transformers test:data name is ${data-name}"; + Transformer transform = TransformerBuilder.buildTemplateTransFormer(content, template); + String output = transform.transform(EVENT); + Assertions.assertEquals("Transformers test:data name is test-transformer", output); + + TransformerParam transformerParam = new TransformerParam(TransformerType.TEMPLATE, content, template); + + Transformer transformer1 = TransformerBuilder.buildTransformer(transformerParam); + String output1 = transformer1.transform(EVENT); + Assertions.assertEquals("Transformers test:data name is test-transformer", output1); + + } + + @Test + public void testTemplateTransFormerWithNullContent() throws JsonProcessingException { + String content = "{}"; + String template = "Transformers test:data num is ${data-num}"; + Transformer transformer = TransformerBuilder.buildTemplateTransFormer(content, template); + String output = transformer.transform(EVENT); + Assertions.assertEquals("Transformers test:data num is ${data-num}", output); + } + + @Test + public void testTemplateTransFormerWithNoMatchContent() throws JsonProcessingException { + String extractJson = "{\"data-num\":\"$.data.no\"}"; + String template = "Transformers test:data num is ${data-num}"; + Transformer transformer = TransformerBuilder.buildTemplateTransFormer(extractJson, template); + String output = transformer.transform(EVENT); + Assertions.assertEquals("Transformers test:data num is null", output); + } + + @Test + public void testTemplateTransFormerWithMatchNumValue() throws JsonProcessingException { + String extractJson = "{\"data-num\":\"$.data.num\"}"; + String template = "Transformers test:data num is ${data-num}"; + Transformer transformer = TransformerBuilder.buildTemplateTransFormer(extractJson, template); + String output = transformer.transform(EVENT); + Assertions.assertEquals("Transformers test:data num is 100", output); + } + + @Test + public void testTemplateTransFormerWithMatchNullValue() throws JsonProcessingException { + String content = "{\"data-null\":\"$.data.nullV\"}"; + String template = "Transformers test:data null is ${data-null}"; + Transformer transformer = TransformerBuilder.buildTemplateTransFormer(content, template); + String output = transformer.transform(EVENT); + Assertions.assertEquals("Transformers test:data null is null", output); + } + + @Test + public void testTemplateTransFormerWithMatchBooleanValue() throws JsonProcessingException { + String extractJson = "{\"boolean\":\"$.data.boolean\"}"; + String template = "Transformers test:data boolean is ${boolean}"; + Transformer transformer = TransformerBuilder.buildTemplateTransFormer(extractJson, template); + String output = transformer.transform(EVENT); + Assertions.assertEquals("Transformers test:data boolean is true", output); + } + + // + @Test + public void testTemplateTransFormerWithConstant() throws JsonProcessingException { + String extractJson = "{\"name\":\"$.data.name\",\"constant\":\"constant\"" + "}"; + String template = "Transformers test:data name is ${name}, constant is ${constant}"; + Transformer transformer = TransformerBuilder.buildTemplateTransFormer(extractJson, template); + String output = transformer.transform(EVENT); + Assertions.assertEquals("Transformers test:data name is test-transformer, constant is constant", + output); + } + + @Test + public void testTemplateTransFormerWithStringValueMap() throws JsonProcessingException { + Map content = Collections.singletonMap("data-name", "$.data.name"); + + String template = "Transformers test:data name is ${data-name}"; + Transformer transform = TransformerBuilder.buildTemplateTransFormer(content, template); + String output = transform.transform(EVENT); + Assertions.assertEquals("Transformers test:data name is test-transformer", output); + + Transformer transformer1 = TransformerBuilder.buildTemplateTransFormer(content, template); + String output1 = transformer1.transform(EVENT); + Assertions.assertEquals("Transformers test:data name is test-transformer", output1); + + } + +} diff --git a/eventmesh-meta/build.gradle b/eventmesh-meta/build.gradle new file mode 100644 index 0000000000..2944f98194 --- /dev/null +++ b/eventmesh-meta/build.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ diff --git a/eventmesh-registry-plugin/eventmesh-registry-api/build.gradle b/eventmesh-meta/eventmesh-meta-api/build.gradle similarity index 100% rename from eventmesh-registry-plugin/eventmesh-registry-api/build.gradle rename to eventmesh-meta/eventmesh-meta-api/build.gradle diff --git a/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/exception/MetaException.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/exception/MetaException.java new file mode 100644 index 0000000000..4f29a04a73 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/exception/MetaException.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.exception; + +/** + * MetaException + */ +public class MetaException extends RuntimeException { + + public MetaException(String message) { + super(message); + } + + public MetaException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/MetaService.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/MetaService.java new file mode 100644 index 0000000000..6dcf4fc132 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/MetaService.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.meta; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * MetaService + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.META) +public interface MetaService { + + void init() throws MetaException; + + void start() throws MetaException; + + void shutdown() throws MetaException; + + List findEventMeshInfoByCluster(String clusterName) throws MetaException; + + List findAllEventMeshInfo() throws MetaException; + + default Map> findEventMeshClientDistributionData( + String clusterName, String group, String purpose) throws MetaException { + // todo find metadata + return Collections.emptyMap(); + } + + void registerMetadata(Map metadataMap); + + Map getMetaData(String key, boolean fuzzyEnabled); + + void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key); + + void updateMetaData(Map metadataMap); + + void removeMetaData(String key); + + boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException; + + boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException; + + default EventMeshAppSubTopicInfo findEventMeshAppSubTopicInfoByGroup(String group) throws MetaException { + return null; + } + + default List findEventMeshServicePubTopicInfos() throws MetaException { + return Collections.emptyList(); + } +} diff --git a/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/MetaServiceListener.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/MetaServiceListener.java new file mode 100644 index 0000000000..b304de7801 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/MetaServiceListener.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.meta; + +/** + * MetaServiceListener + */ +public interface MetaServiceListener { + + void onChange(String key, String value); +} diff --git a/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/bo/EventMeshAppSubTopicInfo.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/bo/EventMeshAppSubTopicInfo.java new file mode 100644 index 0000000000..2698e58955 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/bo/EventMeshAppSubTopicInfo.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.meta.bo; + +import java.util.Set; + +public class EventMeshAppSubTopicInfo { + + String app; + Set topics; + String sub; + String token; + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Set getTopics() { + return topics; + } + + public void setTopics(Set topics) { + this.topics = topics; + } + + public String getSub() { + return sub; + } + + public void setSub(String sub) { + this.sub = sub; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public String toString() { + return "EventMeshAppSubTopicInfo{" + + "app='" + app + '\'' + + ", topics=" + topics + + ", sub='" + sub + '\'' + + '}'; + } +} diff --git a/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/bo/EventMeshServicePubTopicInfo.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/bo/EventMeshServicePubTopicInfo.java new file mode 100644 index 0000000000..0400f66629 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/bo/EventMeshServicePubTopicInfo.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.meta.bo; + +import java.util.Set; + +public class EventMeshServicePubTopicInfo { + + String service; + Set topics; + String token; + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public Set getTopics() { + return topics; + } + + public void setTopics(Set topics) { + this.topics = topics; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + /* + * Service corresponds to an application + */ + @Override + public String toString() { + return "EventMeshServicePubTopicInfo{" + + "service='" + service + '\'' + + ", topics=" + topics + + '}'; + } + +} \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/config/EventMeshMetaConfig.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/config/EventMeshMetaConfig.java new file mode 100644 index 0000000000..d8ea8c8f81 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/config/EventMeshMetaConfig.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.meta.config; + +public class EventMeshMetaConfig { + + public static final String EVENT_MESH_PROTO = "protocol"; + +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshDataInfo.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshDataInfo.java similarity index 95% rename from eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshDataInfo.java rename to eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshDataInfo.java index a478d3deb6..e8dc7debad 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshDataInfo.java +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshDataInfo.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.api.registry.dto; +package org.apache.eventmesh.api.meta.dto; import java.util.Map; @@ -23,6 +23,7 @@ * EventMeshDataInfo */ public class EventMeshDataInfo { + private String eventMeshClusterName; private String eventMeshName; private String endpoint; @@ -31,11 +32,11 @@ public class EventMeshDataInfo { private Map metadata; public EventMeshDataInfo() { - + } public EventMeshDataInfo(String eventMeshClusterName, String eventMeshName, String endpoint, long lastUpdateTimestamp, - Map metadata) { + Map metadata) { this.eventMeshClusterName = eventMeshClusterName; this.eventMeshName = eventMeshName; this.endpoint = endpoint; diff --git a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshRegisterInfo.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshRegisterInfo.java similarity index 98% rename from eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshRegisterInfo.java rename to eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshRegisterInfo.java index 2e5a1d1ff1..898476a3dc 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshRegisterInfo.java +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshRegisterInfo.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.api.registry.dto; +package org.apache.eventmesh.api.meta.dto; import java.util.Map; @@ -23,6 +23,7 @@ * EventMeshRegisterInfo */ public class EventMeshRegisterInfo { + private String eventMeshClusterName; private String eventMeshName; private String endPoint; diff --git a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshUnRegisterInfo.java b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshUnRegisterInfo.java similarity index 97% rename from eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshUnRegisterInfo.java rename to eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshUnRegisterInfo.java index 30cc8995d7..79340f1949 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/dto/EventMeshUnRegisterInfo.java +++ b/eventmesh-meta/eventmesh-meta-api/src/main/java/org/apache/eventmesh/api/meta/dto/EventMeshUnRegisterInfo.java @@ -15,12 +15,13 @@ * limitations under the License. */ -package org.apache.eventmesh.api.registry.dto; +package org.apache.eventmesh.api.meta.dto; /** * EventMeshUnRegisterInfo */ public class EventMeshUnRegisterInfo { + private String eventMeshClusterName; private String eventMeshName; diff --git a/eventmesh-meta/eventmesh-meta-consul/build.gradle b/eventmesh-meta/eventmesh-meta-consul/build.gradle new file mode 100644 index 0000000000..35b4660764 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-consul/build.gradle @@ -0,0 +1,28 @@ +/* + * 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. + */ + +dependencies { + implementation 'com.ecwid.consul:consul-api:1.4.5' + implementation 'org.apache.httpcomponents:httpclient' + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-common") + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-meta/eventmesh-meta-consul/gradle.properties b/eventmesh-meta/eventmesh-meta-consul/gradle.properties new file mode 100644 index 0000000000..a4cd49e2b7 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-consul/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=metaStorage +pluginName=consul \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/config/ConsulTLSConfig.java b/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/config/ConsulTLSConfig.java new file mode 100644 index 0000000000..f63e520861 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/config/ConsulTLSConfig.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.consul.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.common.config.convert.converter.EnumConverter; + +import com.ecwid.consul.transport.TLSConfig.KeyStoreInstanceType; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(prefix = "eventMesh.registry.consul.tls") +public class ConsulTLSConfig { + + @ConfigField(field = "keyStoreInstanceType", converter = EnumConverter.class) + private KeyStoreInstanceType keyStoreInstanceType; + + @ConfigField(field = "certificatePath") + private String certificatePath; + + @ConfigField(field = "certificatePassword") + private String certificatePassword; + + @ConfigField(field = "keyStorePath") + private String keyStorePath; + + @ConfigField(field = "keyStorePassword") + private String keyStorePassword; + +} diff --git a/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/service/ConsulMetaService.java b/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/service/ConsulMetaService.java new file mode 100644 index 0000000000..a3849d2cc8 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/service/ConsulMetaService.java @@ -0,0 +1,215 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.consul.service; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.meta.consul.config.ConsulTLSConfig; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.ecwid.consul.transport.TLSConfig; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.ConsulRawClient.Builder; +import com.ecwid.consul.v1.agent.model.NewService; +import com.ecwid.consul.v1.agent.model.Service; +import com.ecwid.consul.v1.health.HealthServicesRequest; +import com.ecwid.consul.v1.health.model.HealthService; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ConsulMetaService implements MetaService { + + public static final String IP_PORT_SEPARATOR = ":"; + + private final AtomicBoolean initStatus = new AtomicBoolean(false); + + private final AtomicBoolean startStatus = new AtomicBoolean(false); + + private String consulHost; + + private String consulPort; + + @Getter + private ConsulClient consulClient; + + private String token; + + private ConsulTLSConfig tlsConfig; + + @Override + public void init() throws MetaException { + if (initStatus.compareAndSet(false, true)) { + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); + if (commonConfiguration != null) { + String metaStorageAddr = commonConfiguration.getMetaStorageAddr(); + if (StringUtils.isBlank(metaStorageAddr)) { + throw new MetaException("namesrvAddr cannot be null"); + } + String[] addr = metaStorageAddr.split(":"); + if (addr.length != 2) { + throw new MetaException("Illegal namesrvAddr"); + } + this.consulHost = addr[0]; + this.consulPort = addr[1]; + break; + } + } + ConsulTLSConfig tlsConfig = ConfigService.getInstance().buildConfigInstance(ConsulTLSConfig.class); + this.tlsConfig = tlsConfig; + } + } + + @Override + public void start() throws MetaException { + if (!startStatus.compareAndSet(false, true)) { + return; + } + Builder builder = Builder.builder(); + builder.setHost(consulHost); + builder.setPort(Integer.parseInt(consulPort)); + if (tlsConfig != null + && Objects.nonNull(tlsConfig.getKeyStoreInstanceType()) + && !StringUtils.isAnyBlank( + tlsConfig.getCertificatePassword(), + tlsConfig.getCertificatePath(), + tlsConfig.getKeyStorePassword(), + tlsConfig.getKeyStorePath())) { + builder.setTlsConfig(convertToTlsConfig(tlsConfig)); + } + consulClient = new ConsulClient(builder.build()); + } + + private TLSConfig convertToTlsConfig(ConsulTLSConfig tlsConfig) { + return new TLSConfig( + tlsConfig.getKeyStoreInstanceType(), + tlsConfig.getCertificatePath(), + tlsConfig.getCertificatePassword(), + tlsConfig.getKeyStorePath(), + tlsConfig.getKeyStorePassword()); + } + + @Override + public void shutdown() throws MetaException { + if (!initStatus.compareAndSet(true, false)) { + return; + } + if (!startStatus.compareAndSet(true, false)) { + return; + } + consulClient = null; + } + + @Override + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + try { + String[] ipPort = eventMeshRegisterInfo.getEndPoint().split(IP_PORT_SEPARATOR); + if (ipPort == null || ipPort.length < 2) { + return false; + } + NewService service = new NewService(); + service.setPort(Integer.parseInt(ipPort[1])); + service.setAddress(ipPort[0]); + service.setName(eventMeshRegisterInfo.getEventMeshName()); + service.setId(eventMeshRegisterInfo.getEventMeshClusterName() + "-" + eventMeshRegisterInfo.getEventMeshName()); + consulClient.agentServiceRegister(service, token); + } catch (Exception e) { + throw new MetaException(e.getMessage()); + } + log.info("EventMesh successfully registered to consul"); + return true; + } + + @Override + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + try { + consulClient.agentServiceDeregister(eventMeshUnRegisterInfo.getEventMeshClusterName() + "-" + eventMeshUnRegisterInfo.getEventMeshName(), + token); + } catch (Exception e) { + throw new MetaException(e.getMessage()); + } + log.info("EventMesh successfully unregistered to consul"); + return true; + } + + // todo: to be implemented + @Override + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) { + + } + + @Override + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + HealthServicesRequest request = HealthServicesRequest.newBuilder().setPassing(true).setToken(token).build(); + List healthServices = consulClient.getHealthServices(clusterName, request).getValue(); + List eventMeshDataInfos = new ArrayList<>(); + healthServices.forEach(healthService -> { + HealthService.Service service = healthService.getService(); + String[] split = service.getId().split("-"); + eventMeshDataInfos.add(new EventMeshDataInfo(split[0], split[1], service.getAddress() + ":" + service.getPort(), 0, service.getMeta())); + }); + return eventMeshDataInfos; + } + + @Override + public List findAllEventMeshInfo() throws MetaException { + Map agentServices = consulClient.getAgentServices().getValue(); + List eventMeshDataInfos = new ArrayList<>(); + agentServices.forEach((k, v) -> { + String[] split = v.getId().split("-"); + eventMeshDataInfos.add(new EventMeshDataInfo(split[0], split[1], v.getAddress() + ":" + v.getPort(), 0, v.getMeta())); + }); + return eventMeshDataInfos; + } + + @Override + public void registerMetadata(Map metadataMap) { + + } + + @Override + public Map getMetaData(String key, boolean fuzzyEnabled) { + return null; + } + + @Override + public void updateMetaData(Map metadataMap) { + + } + + @Override + public void removeMetaData(String key) { + + } +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/java/org/apache/eventmesh/registry/consul/service/HeatBeatScheduler.java b/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/service/HeatBeatScheduler.java similarity index 96% rename from eventmesh-registry-plugin/eventmesh-registry-consul/src/main/java/org/apache/eventmesh/registry/consul/service/HeatBeatScheduler.java rename to eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/service/HeatBeatScheduler.java index a62db12fd2..fe29a4b3ed 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/java/org/apache/eventmesh/registry/consul/service/HeatBeatScheduler.java +++ b/eventmesh-meta/eventmesh-meta-consul/src/main/java/org/apache/eventmesh/meta/consul/service/HeatBeatScheduler.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.consul.service; +package org.apache.eventmesh.meta.consul.service; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; @@ -38,8 +38,7 @@ public class HeatBeatScheduler { thread.setDaemon(true); thread.setName("ConsulHeartbeatService"); return thread; - } - ); + }); public HeatBeatScheduler(ConsulClient consulClient) { this.consulClient = consulClient; @@ -91,7 +90,7 @@ public void run() { consulClient.agentCheckPass(checkId, aclToken); return; } - if (heartBeatMap.contains(instance)) { + if (heartBeatMap.containsValue(instance)) { consulClient.agentCheckPass(checkId); } } finally { diff --git a/eventmesh-meta/eventmesh-meta-consul/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService b/eventmesh-meta/eventmesh-meta-consul/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService new file mode 100644 index 0000000000..d4718366aa --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-consul/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService @@ -0,0 +1,16 @@ +# 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. + +consul=org.apache.eventmesh.meta.consul.service.ConsulMetaService \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-consul/src/test/java/org/apache/eventmesh/meta/consul/service/ConsulMetaServiceTest.java b/eventmesh-meta/eventmesh-meta-consul/src/test/java/org/apache/eventmesh/meta/consul/service/ConsulMetaServiceTest.java new file mode 100644 index 0000000000..86f7448d00 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-consul/src/test/java/org/apache/eventmesh/meta/consul/service/ConsulMetaServiceTest.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.consul.service; + +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; + +import java.lang.reflect.Field; +import java.util.List; + +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 org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class ConsulMetaServiceTest { + + @Mock + private EventMeshRegisterInfo eventMeshRegisterInfo; + @Mock + private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; + + private ConsulMetaService consulMetaService; + + @BeforeEach + public void registryTest() { + consulMetaService = new ConsulMetaService(); + CommonConfiguration configuration = new CommonConfiguration(); + ConfigurationContextUtil.putIfAbsent(HTTP, configuration); + configuration.setMetaStorageAddr("127.0.0.1:8500"); + Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); + Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); + Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8500"); + + Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); + Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); + } + + @AfterEach + public void after() { + consulMetaService.shutdown(); + } + + @Test + public void testInit() { + consulMetaService.init(); + consulMetaService.start(); + Assertions.assertNotNull(consulMetaService.getConsulClient()); + } + + @Test + public void testStart() { + consulMetaService.init(); + consulMetaService.start(); + Assertions.assertNotNull(consulMetaService.getConsulClient()); + } + + @Test + public void testShutdown() throws NoSuchFieldException, IllegalAccessException { + consulMetaService.init(); + consulMetaService.start(); + consulMetaService.shutdown(); + Assertions.assertNull(consulMetaService.getConsulClient()); + Class consulRegistryServiceClass = ConsulMetaService.class; + Field initStatus = consulRegistryServiceClass.getDeclaredField("initStatus"); + initStatus.setAccessible(true); + Object initStatusField = initStatus.get(consulMetaService); + + Field startStatus = consulRegistryServiceClass.getDeclaredField("startStatus"); + startStatus.setAccessible(true); + Object startStatusField = startStatus.get(consulMetaService); + + Assertions.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); + Assertions.assertFalse((Boolean.parseBoolean(startStatusField.toString()))); + } + + @Test + public void testRegister() { + Assertions.assertThrows(MetaException.class, () -> { + consulMetaService.init(); + consulMetaService.start(); + consulMetaService.register(eventMeshRegisterInfo); + List eventmesh = consulMetaService.findEventMeshInfoByCluster("eventmesh"); + Assertions.assertEquals(1, eventmesh.size()); + }); + } + + @Test + public void testUnRegister() { + Assertions.assertThrows(MetaException.class, () -> { + consulMetaService.init(); + consulMetaService.start(); + consulMetaService.unRegister(eventMeshUnRegisterInfo); + List eventmesh = consulMetaService.findEventMeshInfoByCluster("eventmesh"); + Assertions.assertEquals(0, eventmesh.size()); + }); + } + + @Test + public void findEventMeshInfoByCluster() { + Assertions.assertThrows(MetaException.class, () -> { + consulMetaService.init(); + consulMetaService.start(); + consulMetaService.register(eventMeshRegisterInfo); + List eventmesh = consulMetaService.findEventMeshInfoByCluster("eventmesh"); + Assertions.assertEquals(1, eventmesh.size()); + consulMetaService.unRegister(eventMeshUnRegisterInfo); + }); + } +} diff --git a/eventmesh-meta/eventmesh-meta-etcd/build.gradle b/eventmesh-meta/eventmesh-meta-etcd/build.gradle new file mode 100644 index 0000000000..733776548b --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/build.gradle @@ -0,0 +1,27 @@ +/* + * 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. + */ + +dependencies { + implementation ("io.etcd:jetcd-core:0.3.0") + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-common") + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-meta/eventmesh-meta-etcd/gradle.properties b/eventmesh-meta/eventmesh-meta-etcd/gradle.properties new file mode 100644 index 0000000000..33a92eb97e --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=metaStorage +pluginName=etcd \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/constant/EtcdConstant.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/constant/EtcdConstant.java similarity index 95% rename from eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/constant/EtcdConstant.java rename to eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/constant/EtcdConstant.java index 16c31306d5..5c6e63ebe6 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/constant/EtcdConstant.java +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/constant/EtcdConstant.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.etcd.constant; +package org.apache.eventmesh.meta.etcd.constant; /** * EtcdConstant. @@ -32,5 +32,4 @@ public class EtcdConstant { public static final long TTL = 15L; - } diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdClientFactory.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdClientFactory.java similarity index 85% rename from eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdClientFactory.java rename to eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdClientFactory.java index f69bdb5faa..6eb7608ddc 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdClientFactory.java +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdClientFactory.java @@ -15,11 +15,11 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.etcd.factory; +package org.apache.eventmesh.meta.etcd.factory; -import org.apache.eventmesh.api.exception.RegistryException; +import org.apache.eventmesh.api.exception.MetaException; import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.registry.etcd.constant.EtcdConstant; +import org.apache.eventmesh.meta.etcd.constant.EtcdConstant; import org.apache.commons.lang3.StringUtils; @@ -28,22 +28,18 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.etcd.jetcd.ByteSequence; import io.etcd.jetcd.Client; import io.etcd.jetcd.ClientBuilder; import io.etcd.jetcd.options.LeaseOption; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class EtcdClientFactory { - private static final Logger logger = LoggerFactory.getLogger(EtcdClientFactory.class); - private static final Map etcdLeaseIdMap = new ConcurrentHashMap<>(); - public static Client createClient(Properties properties) { String serverAddr = properties.getProperty(EtcdConstant.SERVER_ADDR); String username = properties.getProperty(EtcdConstant.USERNAME); @@ -66,10 +62,10 @@ public static Client createClient(Properties properties) { etcdLeaseId.setUrl(serverAddr); etcdLeaseId.setClientBuilder(clientBuilder.endpoints(httpAddress)); if (StringUtils.isNoneBlank(username)) { - etcdLeaseId.getClientBuilder().user(ByteSequence.from(username.getBytes())); + etcdLeaseId.getClientBuilder().user(ByteSequence.from(username.getBytes(Constants.DEFAULT_CHARSET))); } if (StringUtils.isNoneBlank(password)) { - etcdLeaseId.getClientBuilder().password(ByteSequence.from(password.getBytes())); + etcdLeaseId.getClientBuilder().password(ByteSequence.from(password.getBytes(Constants.DEFAULT_CHARSET))); } etcdLeaseId.setClientWrapper(new EtcdClientWrapper(etcdLeaseId.getClientBuilder().build())); EtcdClientWrapper client = etcdLeaseId.getClientWrapper(); @@ -82,15 +78,14 @@ public static Client createClient(Properties properties) { etcdLeaseIdMap.put(serverAddr, etcdLeaseId); } catch (Throwable e) { - logger.error("createClient failed, address: {}", serverAddr, e); - throw new RegistryException("createClient failed", e); + log.error("createClient failed, address: {}", serverAddr, e); + throw new MetaException("createClient failed", e); } return etcdLeaseId.getClientWrapper(); } - public static void renewalLeaseId(EtcdLeaseId etcdLeaseId) { - logger.info("renewal of contract. server url: {}", etcdLeaseId.getUrl()); + log.info("renewal of contract. server url: {}", etcdLeaseId.getUrl()); Client client = etcdLeaseId.getClientWrapper(); try { long ttl = client.getLeaseClient().timeToLive(etcdLeaseId.getLeaseId(), LeaseOption.DEFAULT).get().getTTl(); @@ -100,7 +95,7 @@ public static void renewalLeaseId(EtcdLeaseId etcdLeaseId) { etcdLeaseId.setLeaseId(leaseId); } } catch (Throwable e) { - logger.error("renewal error, server url: {}", etcdLeaseId.getUrl(), e); + log.error("renewal error, server url: {}", etcdLeaseId.getUrl(), e); client.getLeaseClient().keepAlive(System.currentTimeMillis(), etcdLeaseId.getEtcdStreamObserver()); } } diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdClientWrapper.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdClientWrapper.java similarity index 97% rename from eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdClientWrapper.java rename to eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdClientWrapper.java index 5e0b8507b0..29019a29b1 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdClientWrapper.java +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdClientWrapper.java @@ -15,8 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.etcd.factory; - +package org.apache.eventmesh.meta.etcd.factory; import io.etcd.jetcd.Auth; import io.etcd.jetcd.Client; @@ -27,7 +26,6 @@ import io.etcd.jetcd.Maintenance; import io.etcd.jetcd.Watch; - class EtcdClientWrapper implements Client { private volatile Client client; diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdLeaseId.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdLeaseId.java similarity index 97% rename from eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdLeaseId.java rename to eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdLeaseId.java index 28ee89f87c..a9d0055b07 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdLeaseId.java +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdLeaseId.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.etcd.factory; +package org.apache.eventmesh.meta.etcd.factory; import java.util.concurrent.atomic.AtomicBoolean; @@ -85,4 +85,3 @@ public void setLeaseId(long leaseId) { this.leaseId = leaseId; } } - diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdStreamObserver.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdStreamObserver.java similarity index 80% rename from eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdStreamObserver.java rename to eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdStreamObserver.java index 6b5efc79ef..fdf5827526 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/factory/EtcdStreamObserver.java +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/factory/EtcdStreamObserver.java @@ -15,19 +15,16 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.etcd.factory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +package org.apache.eventmesh.meta.etcd.factory; import io.etcd.jetcd.lease.LeaseKeepAliveResponse; import io.grpc.stub.StreamObserver; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class EtcdStreamObserver implements StreamObserver { - private static final Logger logger = LoggerFactory.getLogger(EtcdStreamObserver.class); - private EtcdLeaseId etcdLeaseId; @Override @@ -36,12 +33,12 @@ public void onNext(LeaseKeepAliveResponse value) { @Override public void onError(Throwable t) { - logger.debug("EtcdStreamObserver lease renewal Exception", t); + log.debug("EtcdStreamObserver lease renewal Exception", t); } @Override public void onCompleted() { - logger.info("EtcdStreamObserver completed"); + log.info("EtcdStreamObserver completed"); } public void setEtcdLeaseId(EtcdLeaseId etcdLeaseId) { diff --git a/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/service/EtcdCustomService.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/service/EtcdCustomService.java new file mode 100644 index 0000000000..11460cc684 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/service/EtcdCustomService.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.etcd.service; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.meta.etcd.constant.EtcdConstant; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nullable; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.options.GetOption; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EtcdCustomService extends EtcdMetaService { + + private static final String KEY_PREFIX = "eventMesh" + EtcdConstant.KEY_SEPARATOR; + private static final String KEY_APP = "app"; + private static final String KEY_SERVICE = "service"; + + @Nullable + public List findEventMeshServicePubTopicInfos() throws MetaException { + + Client client = getEtcdClient(); + String keyPrefix = KEY_PREFIX + KEY_SERVICE + EtcdConstant.KEY_SEPARATOR; + List keyValues = null; + try { + List eventMeshServicePubTopicInfoList = new ArrayList<>(); + ByteSequence keyByteSequence = ByteSequence.from(keyPrefix.getBytes(Constants.DEFAULT_CHARSET)); + GetOption getOption = GetOption.newBuilder().withPrefix(keyByteSequence).build(); + keyValues = client.getKVClient().get(keyByteSequence, getOption).get().getKvs(); + + if (CollectionUtils.isNotEmpty(keyValues)) { + for (KeyValue kv : keyValues) { + EventMeshServicePubTopicInfo eventMeshServicePubTopicInfo = + JsonUtils.parseObject(new String(kv.getValue().getBytes(), Constants.DEFAULT_CHARSET), EventMeshServicePubTopicInfo.class); + eventMeshServicePubTopicInfoList.add(eventMeshServicePubTopicInfo); + } + return eventMeshServicePubTopicInfoList; + } + } catch (InterruptedException e) { + log.error("[EtcdRegistryService][findEventMeshServicePubTopicInfos] InterruptedException", e); + Thread.currentThread().interrupt(); + } catch (Exception e) { + log.error("[EtcdRegistryService][findEventMeshServicePubTopicInfos] error", e); + throw new MetaException(e.getMessage()); + } + + return Collections.emptyList(); + } + + @Nullable + public EventMeshAppSubTopicInfo findEventMeshAppSubTopicInfoByGroup(String group) throws MetaException { + Client client = getEtcdClient(); + String keyPrefix = KEY_PREFIX + KEY_APP + EtcdConstant.KEY_SEPARATOR + group; + List keyValues = null; + try { + ByteSequence keyByteSequence = ByteSequence.from(keyPrefix.getBytes(Constants.DEFAULT_CHARSET)); + GetOption getOption = GetOption.newBuilder().withPrefix(keyByteSequence).build(); + keyValues = client.getKVClient().get(keyByteSequence, getOption).get().getKvs(); + if (CollectionUtils.isNotEmpty(keyValues)) { + return JsonUtils.parseObject( + new String(keyValues.get(0).getValue().getBytes(), Constants.DEFAULT_CHARSET), + EventMeshAppSubTopicInfo.class); + } + } catch (InterruptedException e) { + log.error("[EtcdRegistryService][findEventMeshAppSubTopicInfoByGroup] InterruptedException", e); + Thread.currentThread().interrupt(); + } catch (Exception e) { + log.error("[EtcdRegistryService][findEventMeshAppSubTopicInfoByGroup] error, group: {}", group, e); + throw new MetaException(e.getMessage()); + } + return null; + } +} diff --git a/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/service/EtcdMetaService.java b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/service/EtcdMetaService.java new file mode 100644 index 0000000000..9d56db249c --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/java/org/apache/eventmesh/meta/etcd/service/EtcdMetaService.java @@ -0,0 +1,316 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.etcd.service; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.meta.etcd.constant.EtcdConstant; +import org.apache.eventmesh.meta.etcd.factory.EtcdClientFactory; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.options.GetOption; +import io.etcd.jetcd.options.PutOption; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EtcdMetaService implements MetaService { + + private final AtomicBoolean initStatus = new AtomicBoolean(false); + + private final AtomicBoolean startStatus = new AtomicBoolean(false); + + private static final String KEY_PREFIX = EtcdConstant.KEY_SEPARATOR + "eventMesh" + EtcdConstant.KEY_SEPARATOR + "registry" + + EtcdConstant.KEY_SEPARATOR; + + private String serverAddr; + + private String username; + + private String password; + + private String instanceIp; + + private String group; + + @Getter + private Client etcdClient; + + private ConcurrentMap eventMeshRegisterInfoMap; + + private ScheduledExecutorService etcdRegistryMonitorExecutorService; + + @Override + public void init() throws MetaException { + + if (!initStatus.compareAndSet(false, true)) { + return; + } + eventMeshRegisterInfoMap = new ConcurrentHashMap<>(ConfigurationContextUtil.KEYS.size()); + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); + if (commonConfiguration == null) { + continue; + } + if (StringUtils.isBlank(commonConfiguration.getMetaStorageAddr())) { + throw new MetaException("namesrvAddr cannot be null"); + } + this.serverAddr = commonConfiguration.getMetaStorageAddr(); + this.username = commonConfiguration.getEventMeshMetaStoragePluginUsername(); + this.password = commonConfiguration.getEventMeshMetaStoragePluginPassword(); + this.instanceIp = IPUtils.getLocalAddress(); + this.group = commonConfiguration.getMeshGroup(); + break; + } + etcdRegistryMonitorExecutorService = ThreadPoolFactory.createSingleScheduledExecutor( + "EtcdRegistryMonitorThread"); + } + + @Override + public void start() throws MetaException { + + if (!startStatus.compareAndSet(false, true)) { + return; + } + try { + Properties properties = new Properties(); + properties.setProperty(EtcdConstant.SERVER_ADDR, serverAddr); + properties.setProperty(EtcdConstant.USERNAME, username); + properties.setProperty(EtcdConstant.PASSWORD, password); + this.etcdClient = EtcdClientFactory.createClient(properties); + + etcdRegistryMonitorExecutorService.scheduleAtFixedRate(new EventMeshEtcdRegisterMonitor(), + 15000L, 15000L, TimeUnit.MILLISECONDS); + } catch (Exception e) { + log.error("[EtcdRegistryService][start] error", e); + throw new MetaException(e.getMessage()); + } + } + + @Override + public void shutdown() throws MetaException { + if (!initStatus.compareAndSet(true, false)) { + return; + } + if (!startStatus.compareAndSet(true, false)) { + return; + } + try { + if (etcdClient != null) { + etcdClient.close(); + } + if (etcdRegistryMonitorExecutorService != null && !etcdRegistryMonitorExecutorService.isShutdown()) { + etcdRegistryMonitorExecutorService.shutdown(); + } + } catch (Exception e) { + log.error("[EtcdRegistryService][shutdown] error", e); + throw new MetaException(e.getMessage()); + } + log.info("EtcdRegistryService closed"); + } + + @Override + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + List eventMeshDataInfoList = new ArrayList<>(); + + try { + String keyPrefix = clusterName == null ? KEY_PREFIX : KEY_PREFIX + EtcdConstant.KEY_SEPARATOR + clusterName; + ByteSequence keyByteSequence = ByteSequence.from(keyPrefix.getBytes(Constants.DEFAULT_CHARSET)); + GetOption getOption = GetOption.newBuilder().withPrefix(keyByteSequence).build(); + List keyValues = etcdClient.getKVClient().get(keyByteSequence, getOption).get().getKvs(); + + if (CollectionUtils.isNotEmpty(keyValues)) { + for (KeyValue kv : keyValues) { + EventMeshDataInfo eventMeshDataInfo = + JsonUtils.parseObject(new String(kv.getValue().getBytes(), Constants.DEFAULT_CHARSET), EventMeshDataInfo.class); + eventMeshDataInfoList.add(eventMeshDataInfo); + } + } + } catch (InterruptedException e) { + log.error("[EtcdRegistryService][findEventMeshInfoByCluster] InterruptedException", e); + Thread.currentThread().interrupt(); + } catch (Exception e) { + log.error("[EtcdRegistryService][findEventMeshInfoByCluster] error, clusterName: {}", clusterName, e); + throw new MetaException(e.getMessage()); + } + return eventMeshDataInfoList; + } + + @Override + public List findAllEventMeshInfo() throws MetaException { + try { + return findEventMeshInfoByCluster(null); + } catch (Exception e) { + log.error("[EtcdRegistryService][findEventMeshInfoByCluster] error", e); + throw new MetaException(e.getMessage()); + } + } + + @Override + public void registerMetadata(Map metadataMap) { + for (Map.Entry eventMeshRegisterInfo : eventMeshRegisterInfoMap.entrySet()) { + EventMeshRegisterInfo registerInfo = eventMeshRegisterInfo.getValue(); + registerInfo.setMetadata(metadataMap); + this.register(registerInfo); + } + } + + @Override + public Map getMetaData(String key, boolean fuzzyEnabled) { + return null; + } + + // todo: to be implemented + @Override + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) { + + } + + @Override + public void updateMetaData(Map metadataMap) { + String etcdMetaKey = instanceIp + "-" + group; + ByteSequence key = ByteSequence.from(etcdMetaKey, StandardCharsets.UTF_8); + ByteSequence value = ByteSequence.from(Objects.requireNonNull(JsonUtils.toJSONString(metadataMap)), StandardCharsets.UTF_8); + etcdClient.getKVClient().put(key, value); + } + + @Override + public void removeMetaData(String key) { + + } + + @Override + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + String eventMeshClusterName = eventMeshRegisterInfo.getEventMeshClusterName(); + String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); + String endPoint = eventMeshRegisterInfo.getEndPoint(); + try { + ByteSequence etcdKey = getEtcdKey(eventMeshClusterName, eventMeshName, endPoint); + EventMeshDataInfo eventMeshDataInfo = + new EventMeshDataInfo(eventMeshClusterName, eventMeshName, + endPoint, System.currentTimeMillis(), eventMeshRegisterInfo.getMetadata()); + ByteSequence etcdValue = ByteSequence.from(Objects.requireNonNull(JsonUtils.toJSONString(eventMeshDataInfo)) + .getBytes(Constants.DEFAULT_CHARSET)); + etcdClient.getKVClient().put(etcdKey, etcdValue, PutOption.newBuilder().withLeaseId(getLeaseId()).build()); + eventMeshRegisterInfoMap.put(eventMeshName, eventMeshRegisterInfo); + + log.info("EventMesh successfully registered to etcd, eventMeshClusterName: {}, eventMeshName: {}", + eventMeshClusterName, eventMeshName); + return true; + } catch (Exception e) { + log.error("[EtcdRegistryService][register] error, eventMeshClusterName: {}, eventMeshName: {}", + eventMeshClusterName, eventMeshName, e); + throw new MetaException(e.getMessage()); + } + } + + @Override + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + String eventMeshClusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); + String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); + try { + ByteSequence etcdKey = getEtcdKey(eventMeshClusterName, eventMeshName, + eventMeshUnRegisterInfo.getEndPoint()); + etcdClient.getKVClient().delete(etcdKey); + eventMeshRegisterInfoMap.remove(eventMeshName); + log.info("EventMesh successfully logout to etcd, eventMeshClusterName: {}, eventMeshName: {}", + eventMeshClusterName, eventMeshName); + return true; + } catch (Exception e) { + log.error("[EtcdRegistryService][unRegister] error, eventMeshClusterName: {}, eventMeshName: {}", + eventMeshClusterName, eventMeshName, e); + throw new MetaException(e.getMessage()); + } + } + + public long getLeaseId() { + return EtcdClientFactory.getLeaseId(serverAddr); + } + + private ByteSequence getEtcdKey(String eventMeshClusterName, String eventMeshName, String endPoint) { + StringBuilder etcdKey = new StringBuilder(KEY_PREFIX).append(eventMeshClusterName); + if (StringUtils.isNoneBlank(eventMeshName)) { + etcdKey.append(EtcdConstant.KEY_SEPARATOR).append(eventMeshName); + } + if (StringUtils.isNoneBlank(endPoint)) { + etcdKey.append(EtcdConstant.KEY_SEPARATOR).append(endPoint); + } + return ByteSequence.from(etcdKey.toString().getBytes(Constants.DEFAULT_CHARSET)); + } + + /** + * check the registered services if alive + */ + private class EventMeshEtcdRegisterMonitor implements Runnable { + + @Override + public void run() { + if (eventMeshRegisterInfoMap.size() > 0) { + for (Map.Entry eventMeshRegisterInfoEntry : eventMeshRegisterInfoMap.entrySet()) { + EventMeshRegisterInfo eventMeshRegisterInfo = eventMeshRegisterInfoEntry.getValue(); + ByteSequence etcdKey = getEtcdKey(eventMeshRegisterInfo.getEventMeshClusterName(), + eventMeshRegisterInfo.getEventMeshName(), eventMeshRegisterInfo.getEndPoint()); + List keyValues = null; + try { + keyValues = etcdClient.getKVClient().get(etcdKey).get().getKvs(); + } catch (InterruptedException e) { + log.error("get etcdKey[{}] failed[InterruptedException]", etcdKey, e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + log.error("get etcdKey[{}] failed", etcdKey, e); + } + if (CollectionUtils.isEmpty(keyValues)) { + log.warn("eventMeshRegisterInfo [{}] is not matched in Etcd , try to register again", + eventMeshRegisterInfo.getEventMeshName()); + EtcdClientFactory.renewalLeaseId(EtcdClientFactory.getEtcdLeaseId(serverAddr)); + register(eventMeshRegisterInfo); + } + } + } + } + } +} diff --git a/eventmesh-meta/eventmesh-meta-etcd/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService b/eventmesh-meta/eventmesh-meta-etcd/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService new file mode 100644 index 0000000000..5f964d6f20 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService @@ -0,0 +1,16 @@ +# 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. + +etcd=org.apache.eventmesh.meta.etcd.service.EtcdMetaService \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdCustomServiceTest.java b/eventmesh-meta/eventmesh-meta-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdCustomServiceTest.java new file mode 100644 index 0000000000..a20564ae01 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdCustomServiceTest.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry.etcd.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.meta.etcd.service.EtcdCustomService; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KV; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.kv.GetResponse; +import io.etcd.jetcd.options.GetOption; + +@ExtendWith(MockitoExtension.class) +public class EtcdCustomServiceTest { + + @Mock + private Client etcdClient; + + @Mock + private KV kvClient; + + @Mock + private KeyValue keyValue; + + @Mock + private GetResponse getResponse; + + @Mock + private CompletableFuture futureResponse; + + @InjectMocks + private EtcdCustomService etcdCustomService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + when(etcdClient.getKVClient()).thenReturn(kvClient); + } + + @Test + public void testFindEventMeshServicePubTopicInfos() throws Exception { + + EventMeshServicePubTopicInfo mockInfo = new EventMeshServicePubTopicInfo(); + mockInfo.setService("testService"); + mockInfo.setTopics(Collections.unmodifiableSet(new HashSet<>(Arrays.asList("topic1", "topic2")))); + + String mockValue = JsonUtils.toJSONString(mockInfo); + ByteSequence mockByteSequence = ByteSequence.from(mockValue, StandardCharsets.UTF_8); + + when(keyValue.getValue()).thenReturn(mockByteSequence); + when(getResponse.getKvs()).thenReturn(Arrays.asList(keyValue)); + when(futureResponse.get()).thenReturn(getResponse); + when(kvClient.get(any(ByteSequence.class), any(GetOption.class))).thenReturn(futureResponse); + + List result = etcdCustomService.findEventMeshServicePubTopicInfos(); + assertNotNull(result); + assertEquals(1, result.size()); + EventMeshServicePubTopicInfo resultInfo = result.get(0); + assertEquals("testService", resultInfo.getService()); + assertEquals(new HashSet<>(Arrays.asList("topic1", "topic2")), resultInfo.getTopics()); + } + + + @Test + public void testFindEventMeshAppSubTopicInfoByGroup() throws Exception { + + String group = "testGroup"; + EventMeshAppSubTopicInfo mockInfo = new EventMeshAppSubTopicInfo(); + + String mockValue = JsonUtils.toJSONString(mockInfo); + ByteSequence mockByteSequence = ByteSequence.from(mockValue, StandardCharsets.UTF_8); + + when(keyValue.getValue()).thenReturn(mockByteSequence); + when(kvClient.get(any(ByteSequence.class), any(GetOption.class))).thenReturn(futureResponse); + when(futureResponse.get()).thenReturn(getResponse); + when(getResponse.getKvs()).thenReturn(Collections.singletonList(keyValue)); + + EventMeshAppSubTopicInfo result = etcdCustomService.findEventMeshAppSubTopicInfoByGroup(group); + + assertNotNull(result); + } + +} diff --git a/eventmesh-meta/eventmesh-meta-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdMetaServiceTest.java b/eventmesh-meta/eventmesh-meta-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdMetaServiceTest.java new file mode 100644 index 0000000000..5efc60d051 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdMetaServiceTest.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry.etcd.service; + +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.meta.etcd.service.EtcdMetaService; + +import java.lang.reflect.Field; +import java.util.List; + +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 org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class EtcdMetaServiceTest { + + @Mock + private EventMeshRegisterInfo eventMeshRegisterInfo; + @Mock + private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; + + private EtcdMetaService etcdMetaService; + + @BeforeEach + public void setUp() { + etcdMetaService = new EtcdMetaService(); + CommonConfiguration configuration = new CommonConfiguration(); + configuration.setMetaStorageAddr("127.0.0.1:2379"); + ConfigurationContextUtil.putIfAbsent(HTTP, configuration); + + // Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); + // Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); + // Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:2379"); + // + // Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); + // Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); + // Mockito.when(eventMeshUnRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:2379"); + } + + @AfterEach + public void after() { + etcdMetaService.shutdown(); + } + + @Test + public void testInit() { + etcdMetaService.init(); + } + + @Test + public void testStart() { + Assertions.assertThrows(MetaException.class, () -> { + etcdMetaService.init(); + etcdMetaService.start(); + Assertions.assertNotNull(etcdMetaService); + }); + + } + + @Test + public void testShutdown() throws NoSuchFieldException, IllegalAccessException { + Assertions.assertThrows(MetaException.class, () -> { + etcdMetaService.init(); + etcdMetaService.start(); + etcdMetaService.shutdown(); + + Class etcdRegistryServiceClass = EtcdMetaService.class; + Field initStatus = etcdRegistryServiceClass.getDeclaredField("initStatus"); + initStatus.setAccessible(true); + Object initStatusField = initStatus.get(etcdMetaService); + + Field startStatus = etcdRegistryServiceClass.getDeclaredField("startStatus"); + startStatus.setAccessible(true); + Object startStatusField = startStatus.get(etcdMetaService); + }); + } + + @Test + public void testRegister() { + Assertions.assertThrows(MetaException.class, () -> { + etcdMetaService.init(); + etcdMetaService.start(); + etcdMetaService.register(eventMeshRegisterInfo); + }); + } + + @Test + public void testFindEventMeshInfo() { + Assertions.assertThrows(MetaException.class, () -> { + etcdMetaService.init(); + etcdMetaService.start(); + etcdMetaService.register(eventMeshRegisterInfo); + List eventMeshDataInfoList = etcdMetaService.findAllEventMeshInfo(); + }); + } + + @Test + public void testUnRegister() { + Assertions.assertThrows(MetaException.class, () -> { + etcdMetaService.init(); + etcdMetaService.start(); + etcdMetaService.unRegister(eventMeshUnRegisterInfo); + }); + } + +} diff --git a/eventmesh-meta/eventmesh-meta-nacos/build.gradle b/eventmesh-meta/eventmesh-meta-nacos/build.gradle new file mode 100644 index 0000000000..fe837b8084 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-nacos/build.gradle @@ -0,0 +1,27 @@ +/* + * 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. + */ + +dependencies { + implementation "com.alibaba.nacos:nacos-client" + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-common") + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-meta/eventmesh-meta-nacos/gradle.properties b/eventmesh-meta/eventmesh-meta-nacos/gradle.properties new file mode 100644 index 0000000000..667be04781 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-nacos/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=metaStorage +pluginName=nacos \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/config/NacosMetaStorageConfiguration.java b/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/config/NacosMetaStorageConfiguration.java new file mode 100644 index 0000000000..d6de51ca8b --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/config/NacosMetaStorageConfiguration.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.nacos.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.client.naming.utils.UtilAndComs; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(prefix = "eventMesh.metaStorage.nacos") +public class NacosMetaStorageConfiguration { + + @ConfigField(field = PropertyKeyConst.ENDPOINT) + private String endpoint; + + @ConfigField(field = PropertyKeyConst.ENDPOINT_PORT) + private String endpointPort; + + @ConfigField(field = PropertyKeyConst.ACCESS_KEY) + private String accessKey; + + @ConfigField(field = PropertyKeyConst.SECRET_KEY) + private String secretKey; + + @ConfigField(field = PropertyKeyConst.CLUSTER_NAME) + private String clusterName; + + @ConfigField(field = PropertyKeyConst.NAMESPACE) + private String namespace; + + @ConfigField(field = PropertyKeyConst.NAMING_POLLING_THREAD_COUNT) + private Integer pollingThreadCount = Runtime.getRuntime().availableProcessors() / 2 + 1; + + @ConfigField(field = UtilAndComs.NACOS_NAMING_LOG_NAME) + private String logFileName; + + @ConfigField(field = UtilAndComs.NACOS_NAMING_LOG_LEVEL) + private String logLevel; + +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/constant/NacosConstant.java b/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/constant/NacosConstant.java similarity index 95% rename from eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/constant/NacosConstant.java rename to eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/constant/NacosConstant.java index 0164dc1336..94281723a7 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/constant/NacosConstant.java +++ b/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/constant/NacosConstant.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.registry.nacos.constant; +package org.apache.eventmesh.meta.nacos.constant; /** * NacosConstant. diff --git a/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/service/NacosMetaService.java b/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/service/NacosMetaService.java new file mode 100644 index 0000000000..92abcf837e --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-nacos/src/main/java/org/apache/eventmesh/meta/nacos/service/NacosMetaService.java @@ -0,0 +1,421 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.nacos.service; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.config.EventMeshMetaConfig; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.meta.nacos.config.NacosMetaStorageConfiguration; +import org.apache.eventmesh.meta.nacos.constant.NacosConstant; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.client.naming.utils.UtilAndComs; +import com.alibaba.nacos.common.utils.CollectionUtils; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.fasterxml.jackson.databind.JsonNode; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class NacosMetaService implements MetaService { + + private final AtomicBoolean initStatus = new AtomicBoolean(false); + + private final AtomicBoolean startStatus = new AtomicBoolean(false); + + @Getter + private String serverAddr; + + @Getter + private String username; + + @Getter + private String password; + + @Getter + private NacosMetaStorageConfiguration nacosConfig; + + private String dataId; + + private String group; + + @Getter + private NamingService nacosNamingService; + + private com.alibaba.nacos.api.config.ConfigService nacosConfigService; + + private ConcurrentMap eventMeshRegisterInfoMap; + + private MetaServiceListener metaServiceListener; + + @Override + public void init() throws MetaException { + + if (!initStatus.compareAndSet(false, true)) { + return; + } + eventMeshRegisterInfoMap = new ConcurrentHashMap<>(ConfigurationContextUtil.KEYS.size()); + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); + if (commonConfiguration == null) { + continue; + } + if (StringUtils.isBlank(commonConfiguration.getMetaStorageAddr())) { + throw new MetaException("namesrvAddr cannot be null"); + } + + this.serverAddr = commonConfiguration.getMetaStorageAddr(); + this.username = commonConfiguration.getEventMeshMetaStoragePluginUsername(); + this.password = commonConfiguration.getEventMeshMetaStoragePluginPassword(); + this.dataId = IPUtils.getLocalAddress(); + this.group = commonConfiguration.getMeshGroup(); + break; + } + ConfigService configService = ConfigService.getInstance(); + NacosMetaStorageConfiguration nacosConfig = configService.buildConfigInstance(NacosMetaStorageConfiguration.class); + if (nacosConfig != null) { + this.nacosConfig = nacosConfig; + } + } + + @Override + public void start() throws MetaException { + + if (!startStatus.compareAndSet(false, true)) { + return; + } + Properties properties = buildProperties(); + // registry + try { + this.nacosNamingService = NacosFactory.createNamingService(properties); + } catch (NacosException e) { + log.error("[NacosRegistryService][start] error", e); + throw new MetaException(e.getMessage()); + } + // config + try { + this.nacosConfigService = NacosFactory.createConfigService(properties); + } catch (NacosException e) { + log.error("[NacosConfigService][start] error", e); + throw new MetaException(e.getMessage()); + } + } + + private Properties buildProperties() { + Properties properties = new Properties(); + properties.setProperty(NacosConstant.SERVER_ADDR, serverAddr); + properties.setProperty(NacosConstant.USERNAME, username); + properties.setProperty(NacosConstant.PASSWORD, password); + if (nacosConfig == null) { + return properties; + } + String endpoint = nacosConfig.getEndpoint(); + if (Objects.nonNull(endpoint) && endpoint.contains(":")) { + int index = endpoint.indexOf(":"); + properties.put(PropertyKeyConst.ENDPOINT, endpoint.substring(0, index)); + properties.put(PropertyKeyConst.ENDPOINT_PORT, endpoint.substring(index + 1)); + } else { + Optional.ofNullable(endpoint).ifPresent(value -> properties.put(PropertyKeyConst.ENDPOINT, endpoint)); + String endpointPort = nacosConfig.getEndpointPort(); + Optional.ofNullable(endpointPort).ifPresent(value -> properties.put(PropertyKeyConst.ENDPOINT_PORT, endpointPort)); + } + String accessKey = nacosConfig.getAccessKey(); + Optional.ofNullable(accessKey).ifPresent(value -> properties.put(PropertyKeyConst.ACCESS_KEY, accessKey)); + String secretKey = nacosConfig.getSecretKey(); + Optional.ofNullable(secretKey).ifPresent(value -> properties.put(PropertyKeyConst.SECRET_KEY, secretKey)); + String clusterName = nacosConfig.getClusterName(); + Optional.ofNullable(clusterName).ifPresent(value -> properties.put(PropertyKeyConst.CLUSTER_NAME, clusterName)); + String logFileName = nacosConfig.getLogFileName(); + Optional.ofNullable(logFileName).ifPresent(value -> properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, logFileName)); + String logLevel = nacosConfig.getLogLevel(); + Optional.ofNullable(logLevel).ifPresent(value -> properties.put(UtilAndComs.NACOS_NAMING_LOG_LEVEL, logLevel)); + Integer pollingThreadCount = nacosConfig.getPollingThreadCount(); + Optional.ofNullable(pollingThreadCount).ifPresent(value -> properties.put(PropertyKeyConst.NAMING_POLLING_THREAD_COUNT, pollingThreadCount)); + String namespace = nacosConfig.getNamespace(); + Optional.ofNullable(namespace).ifPresent(value -> properties.put(PropertyKeyConst.NAMESPACE, namespace)); + return properties; + } + + @Override + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) { + try { + nacosConfigService.addListener(key, group, new Listener() { + + @Override + public Executor getExecutor() { + return null; + } + + @Override + public void receiveConfigInfo(String configInfo) { + metaServiceListener.onChange(key, configInfo); + } + }); + } catch (Exception e) { + throw new RuntimeException("add nacos listener for key " + key + "error", e); + } + } + + @Override + public void shutdown() throws MetaException { + if (!initStatus.compareAndSet(true, false)) { + return; + } + if (!startStatus.compareAndSet(true, false)) { + return; + } + try { + nacosNamingService.shutDown(); + log.info("NacosRegistryService close"); + } catch (NacosException e) { + log.error("[NacosRegistryService][shutdown] error", e); + throw new MetaException(e.getMessage()); + } + try { + nacosConfigService.shutDown(); + log.info("NacosConfigService close"); + } catch (NacosException e) { + log.error("[NacosConfigService][shutdown] error", e); + throw new MetaException(e.getMessage()); + } + } + + @Override + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + return findEventMeshInfos(true, Collections.singletonList(clusterName)); + } + + @Override + public List findAllEventMeshInfo() throws MetaException { + return findEventMeshInfos(false, null); + } + + private List findEventMeshInfos(boolean inCluster, List clusters) { + List eventMeshDataInfoList = new ArrayList<>(); + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration configuration = ConfigurationContextUtil.get(key); + if (Objects.isNull(configuration)) { + continue; + } + String eventMeshName = configuration.getEventMeshName(); + try { + List instances = + nacosNamingService.selectInstances(eventMeshName + "-" + key, + key + "-" + (inCluster ? configuration.getEventMeshCluster() : NacosConstant.GROUP), + clusters, + true); + if (CollectionUtils.isEmpty(instances)) { + continue; + } + for (Instance instance : instances) { + EventMeshDataInfo eventMeshDataInfo = + new EventMeshDataInfo(instance.getClusterName(), instance.getServiceName(), + instance.getIp() + ":" + + instance.getPort(), + 0L, instance.getMetadata()); + eventMeshDataInfoList.add(eventMeshDataInfo); + } + } catch (NacosException e) { + log.error("[NacosRegistryService][findEventMeshInfoByCluster] error", e); + throw new MetaException(e.getMessage()); + } + } + return eventMeshDataInfoList; + } + + @Override + public void registerMetadata(Map metadataMap) { + for (Map.Entry eventMeshRegisterInfo : eventMeshRegisterInfoMap.entrySet()) { + EventMeshRegisterInfo registerInfo = eventMeshRegisterInfo.getValue(); + registerInfo.setMetadata(metadataMap); + this.register(registerInfo); + } + } + + // implement with http + @Override + public Map getMetaData(String key, boolean fuzzyEnabled) { + if (fuzzyEnabled) { + key = key + "*"; + } + int pageNo = 1; + int pageSize = 100; + + Map result = new HashMap<>(); + Map tmpMap; + do { + tmpMap = getResultFromNacos(pageNo, pageSize, key, group, fuzzyEnabled); + result.putAll(tmpMap); + } while (!(tmpMap.size() < pageSize)); + return result; + } + + private Map getResultFromNacos(int pageNo, int pageSize, String key, String group, boolean fuzzyEnabled) { + Map result = new HashMap<>(); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + URIBuilder uriBuilder = new URIBuilder("http://" + serverAddr + "/nacos/v1/cs/configs") + .setParameter("dataId", key) + .setParameter("group", group) + .setParameter("pageNo", String.valueOf(pageNo)) + .setParameter("pageSize", String.valueOf(pageSize)); + if (fuzzyEnabled) { + uriBuilder.setParameter("search", "blur"); + } + URI uri = uriBuilder.build(); + HttpGet httpGet = new HttpGet(uri); + httpGet.setHeader(NacosConstant.USERNAME, username); + httpGet.setHeader(NacosConstant.PASSWORD, password); + try (CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpGet)) { + if (closeableHttpResponse.getStatusLine().getStatusCode() == 200) { + String response = EntityUtils.toString(closeableHttpResponse.getEntity(), StandardCharsets.UTF_8); + result = processResponse(response); + } + } catch (Exception e) { + log.error("get metaData fail", e); + throw new RuntimeException(e); + } + return result; + } catch (Exception e) { + log.error("get metaData fail", e); + throw new RuntimeException(e); + } + } + + private Map processResponse(String response) { + Map result = new HashMap<>(); + JsonNode jsonNode = JacksonUtils.toObj(response); + JsonNode jsonNodeArray = jsonNode.get("pageItems"); + if (jsonNodeArray.isArray()) { + for (JsonNode js : jsonNodeArray) { + String key = js.get("dataId").asText(); + String value = js.get("content").asText(); + result.put(key, value); + } + } + return result; + } + + @Override + public void updateMetaData(Map metadataMap) { + String protocol = metadataMap.get(EventMeshMetaConfig.EVENT_MESH_PROTO); + String nacosDataId = dataId + "-" + protocol; + try { + boolean flag = this.nacosConfigService.publishConfig(nacosDataId, group, JacksonUtils.toJson(metadataMap)); + if (flag) { + log.info("publish metaData {} success", metadataMap); + } else { + log.error("publish metaData {} fail", metadataMap); + } + } catch (NacosException e) { + log.error("failed to publish data to nacos", e); + throw new RuntimeException(e); + } + } + + @Override + public void removeMetaData(String key) { + + } + + @Override + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + try { + String[] ipPort = eventMeshRegisterInfo.getEndPoint().split(NacosConstant.IP_PORT_SEPARATOR); + if (ipPort.length < 2) { + return false; + } + String eventMeshClusterName = eventMeshRegisterInfo.getEventMeshClusterName(); + Map metadata = eventMeshRegisterInfo.getMetadata(); + + Instance instance = new Instance(); + instance.setIp(ipPort[0]); + instance.setPort(Integer.parseInt(ipPort[1])); + instance.setWeight(1.0); + instance.setClusterName(eventMeshClusterName); + instance.setMetadata(metadata); + + String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); + nacosNamingService.registerInstance(eventMeshName, eventMeshRegisterInfo.getProtocolType() + "-" + + NacosConstant.GROUP, instance); + eventMeshRegisterInfoMap.put(eventMeshName, eventMeshRegisterInfo); + } catch (NacosException e) { + log.error("[NacosRegistryService][register] error", e); + throw new MetaException(e.getMessage()); + } + log.info("EventMesh successfully registered to nacos"); + return true; + } + + @Override + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + String[] ipPort = eventMeshUnRegisterInfo.getEndPoint().split(NacosConstant.IP_PORT_SEPARATOR); + try { + Instance instance = new Instance(); + instance.setIp(ipPort[0]); + instance.setPort(Integer.parseInt(ipPort[1])); + String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); + String eventMeshClusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); + instance.setClusterName(eventMeshClusterName); + nacosNamingService.deregisterInstance(eventMeshName, eventMeshUnRegisterInfo.getProtocolType() + + "-" + NacosConstant.GROUP, instance); + eventMeshRegisterInfoMap.remove(eventMeshName); + } catch (NacosException e) { + log.error("[NacosRegistryService][unRegister] error", e); + throw new MetaException(e.getMessage()); + } + log.info("EventMesh successfully logout to nacos"); + return true; + } +} diff --git a/eventmesh-meta/eventmesh-meta-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService b/eventmesh-meta/eventmesh-meta-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService new file mode 100644 index 0000000000..44b15a5198 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService @@ -0,0 +1,16 @@ +# 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. + +nacos=org.apache.eventmesh.meta.nacos.service.NacosMetaService \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-nacos/src/test/java/org/apache/eventmesh/registry/nacos/service/NacosMetaServiceTest.java b/eventmesh-meta/eventmesh-meta-nacos/src/test/java/org/apache/eventmesh/registry/nacos/service/NacosMetaServiceTest.java new file mode 100644 index 0000000000..1065ab4be5 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-nacos/src/test/java/org/apache/eventmesh/registry/nacos/service/NacosMetaServiceTest.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry.nacos.service; + +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.meta.nacos.service.NacosMetaService; + +import java.lang.reflect.Field; + +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 org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class NacosMetaServiceTest { + + @Mock + private EventMeshRegisterInfo eventMeshRegisterInfo; + @Mock + private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; + + private NacosMetaService nacosMetaService; + + @BeforeEach + public void setUp() { + nacosMetaService = new NacosMetaService(); + CommonConfiguration configuration = new CommonConfiguration(); + configuration.setMetaStorageAddr("127.0.0.1"); + configuration.setEventMeshMetaStoragePluginPassword("nacos"); + configuration.setEventMeshMetaStoragePluginUsername("nacos"); + ConfigurationContextUtil.putIfAbsent(HTTP, configuration); + + Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); + Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); + Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); + + Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); + Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); + Mockito.when(eventMeshUnRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); + } + + @AfterEach + public void after() { + nacosMetaService.shutdown(); + } + + @Test + public void testInit() { + nacosMetaService.init(); + nacosMetaService.start(); + Assertions.assertNotNull(nacosMetaService.getServerAddr()); + } + + @Test + public void testStart() { + nacosMetaService.init(); + nacosMetaService.start(); + Assertions.assertNotNull(nacosMetaService.getNacosNamingService()); + + } + + @Test + public void testShutdown() throws NoSuchFieldException, IllegalAccessException { + nacosMetaService.init(); + nacosMetaService.start(); + nacosMetaService.shutdown(); + + Class nacosRegistryServiceClass = NacosMetaService.class; + Field initStatus = nacosRegistryServiceClass.getDeclaredField("initStatus"); + initStatus.setAccessible(true); + Object initStatusField = initStatus.get(nacosMetaService); + + Field startStatus = nacosRegistryServiceClass.getDeclaredField("startStatus"); + startStatus.setAccessible(true); + Object startStatusField = startStatus.get(nacosMetaService); + + Assertions.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); + Assertions.assertFalse((Boolean.parseBoolean(startStatusField.toString()))); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/build.gradle b/eventmesh-meta/eventmesh-meta-raft/build.gradle new file mode 100644 index 0000000000..6abc73dd96 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/build.gradle @@ -0,0 +1,57 @@ +/* + * 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. + */ + +plugins { + id 'com.google.protobuf' version '0.9.4' +} + +def grpcVersion = '1.68.0' +def protobufVersion = '3.25.4' +def protocVersion = protobufVersion + +def jraftVersion = '1.3.14' + +dependencies { + implementation ("io.grpc:grpc-protobuf:${grpcVersion}") { + exclude group: "com.google.protobuf", module: "protobuf-java" + } + implementation("com.google.protobuf:protobuf-java:${protobufVersion}") + implementation "io.grpc:grpc-stub:${grpcVersion}" + implementation "com.google.protobuf:protobuf-java-util:${protobufVersion}" + implementation "javax.annotation:javax.annotation-api:1.3.2" + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-common") + implementation "com.alipay.sofa:jraft-core:${jraftVersion}" + implementation "com.alipay.sofa:rpc-grpc-impl:${jraftVersion}" + implementation group: 'com.caucho', name: 'hessian', version: '4.0.63' + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +protobuf { + protoc { artifact = "com.google.protobuf:protoc:${protocVersion}" } + plugins { + grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" } + } + generateProtoTasks { + all()*.plugins { + grpc {} + } + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/gradle.properties b/eventmesh-meta/eventmesh-meta-raft/gradle.properties new file mode 100644 index 0000000000..0010b2d014 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=metaStorage +pluginName=raft \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/EventClosure.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/EventClosure.java new file mode 100644 index 0000000000..a568a801dc --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/EventClosure.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + +import org.apache.eventmesh.meta.raft.consts.MetaRaftConstants; +import org.apache.eventmesh.meta.raft.rpc.RequestResponse; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import com.alipay.sofa.jraft.Closure; +import com.alipay.sofa.jraft.Status; + + +public abstract class EventClosure implements Closure { + + private CompletableFuture future; + + private RequestResponse requestResponse; + + private EventOperation eventOperation; + + public static EventClosure createDefaultEventClosure() { + return new EventClosure() { + + @Override + public void run(Status status) { + + } + }; + } + + public void setFuture(CompletableFuture future) { + this.future = future; + } + + public void setRequestResponse(RequestResponse requestResponse) { + this.requestResponse = requestResponse; + if (future != null) { + future.complete(getRequestResponse()); + } + } + + public RequestResponse getRequestResponse() { + return requestResponse; + } + + public EventOperation getEventOperation() { + return eventOperation; + } + + protected void failure(final String errorMsg, final String redirect) { + final RequestResponse response = RequestResponse.newBuilder().setSuccess(false).setErrorMsg(errorMsg) + .setRedirect(redirect).build(); + setRequestResponse(response); + } + + public void setEventOperation(EventOperation opreation) { + this.eventOperation = opreation; + } + + protected void success(final Map map) { + + final RequestResponse response = RequestResponse.newBuilder().setValue(MetaRaftConstants.RESPONSE) + .setSuccess(true).putAllInfo(map).build(); + setRequestResponse(response); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/EventOperation.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/EventOperation.java new file mode 100644 index 0000000000..b8c7a6cd55 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/EventOperation.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + +import org.apache.eventmesh.meta.raft.consts.MetaRaftConstants; +import org.apache.eventmesh.meta.raft.rpc.RequestResponse; + +import java.io.Serializable; +import java.util.Map; + + +public class EventOperation implements Serializable { + + private static final long serialVersionUID = -6597003954824547294L; + + public static final byte PUT = 0x01; + + public static final byte GET = 0x02; + + public static final byte DELETE = 0x03; + + private byte op; + private Map data; + + public static EventOperation createOpreation(RequestResponse response) { + if (response.getValue() == MetaRaftConstants.PUT) { + return new EventOperation(PUT, response.getInfoMap()); + } else if (response.getValue() == MetaRaftConstants.GET) { + return new EventOperation(GET, response.getInfoMap()); + } else if (response.getValue() == MetaRaftConstants.DELETE) { + return new EventOperation(DELETE, response.getInfoMap()); + + } + return null; + } + + public EventOperation(byte op, Map data) { + this.op = op; + this.data = data; + } + + public byte getOp() { + return op; + } + + public Map getData() { + return data; + } + + public boolean isReadOp() { + return GET == this.op; + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftMetaService.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftMetaService.java new file mode 100644 index 0000000000..daf636ccd4 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftMetaService.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + + +import org.apache.eventmesh.meta.raft.rpc.RequestResponse; + +/** + * MetaService. + */ +public interface JraftMetaService { + + void handle(RequestResponse request, EventClosure closure); +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftMetaServiceImpl.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftMetaServiceImpl.java new file mode 100644 index 0000000000..1f655eb93e --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftMetaServiceImpl.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + +import org.apache.eventmesh.meta.raft.rpc.RequestResponse; +import org.apache.eventmesh.meta.raft.serialize.EventMeshHessianSerializer; + +import org.apache.commons.lang.StringUtils; + +import java.nio.ByteBuffer; + +import com.alipay.remoting.exception.CodecException; +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.jraft.entity.Task; +import com.alipay.sofa.jraft.error.RaftError; + +public class JraftMetaServiceImpl implements JraftMetaService { + + JraftServer server; + + + public JraftMetaServiceImpl(JraftServer server) { + this.server = server; + } + + @Override + public void handle(RequestResponse request, EventClosure closure) { + applyOperation(EventOperation.createOpreation(request), closure); + } + + public void applyOperation(EventOperation opreation, EventClosure closure) { + if (!isLeader()) { + handlerNotLeaderError(closure); + return; + } + try { + closure.setEventOperation(opreation); + final Task task = new Task(); + task.setData(ByteBuffer.wrap(EventMeshHessianSerializer.getInstance().serialize(opreation))); + task.setDone(closure); + this.server.getNode().apply(task); + } catch (CodecException e) { + String errorMsg = "Fail to encode EventOperation"; + closure.failure(errorMsg, StringUtils.EMPTY); + closure.run(new Status(RaftError.EINTERNAL, errorMsg)); + } + } + + + private String getRedirect() { + return this.server.redirect().getRedirect(); + } + + private boolean isLeader() { + return this.server.getFsm().isLeader(); + } + + + private void handlerNotLeaderError(final EventClosure closure) { + closure.failure("Not leader.", getRedirect()); + closure.run(new Status(RaftError.EPERM, "Not leader")); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftServer.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftServer.java new file mode 100644 index 0000000000..ad8cb14d96 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/JraftServer.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + +import org.apache.eventmesh.meta.raft.rpc.MetaServerHelper; +import org.apache.eventmesh.meta.raft.rpc.RequestProcessor; +import org.apache.eventmesh.meta.raft.rpc.RequestResponse; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; + +import com.alipay.sofa.jraft.Node; +import com.alipay.sofa.jraft.RaftGroupService; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.jraft.option.NodeOptions; +import com.alipay.sofa.jraft.rpc.RaftRpcServerFactory; +import com.alipay.sofa.jraft.rpc.RpcServer; + + +public class JraftServer { + + private RaftGroupService raftGroupService; + + private Node node; + + private MetaStateMachine fsm = new MetaStateMachine(); + + public MetaStateMachine getFsm() { + return fsm; + } + + private JraftMetaServiceImpl metaImpl; + + public JraftServer(final String dataPath, final String groupId, final PeerId serverId, + final NodeOptions nodeOptions) throws IOException { + // init raft data path, it contains log,meta,snapshot + FileUtils.forceMkdir(new File(dataPath)); + // here use same RPC server for raft and business. It also can be seperated generally + final RpcServer rpcServer = RaftRpcServerFactory.createRaftRpcServer(serverId.getEndpoint()); + MetaServerHelper.initGRpc(); + MetaServerHelper.setRpcServer(rpcServer); + // register business processor + metaImpl = new JraftMetaServiceImpl(this); + rpcServer.registerProcessor(new RequestProcessor(metaImpl)); + nodeOptions.setFsm(this.fsm); + // set storage path (log,meta,snapshot) + // log, must + nodeOptions.setLogUri(dataPath + File.separator + "log"); + // meta, must + nodeOptions.setRaftMetaUri(dataPath + File.separator + "raft_meta"); + // snapshot, optional, generally recommended + nodeOptions.setSnapshotUri(dataPath + File.separator + "snapshot"); + // init raft group service framework + this.raftGroupService = new RaftGroupService(groupId, serverId, nodeOptions, rpcServer); + // start raft node + this.node = this.raftGroupService.start(); + + } + + public RequestResponse redirect() { + final RequestResponse.Builder builder = RequestResponse.newBuilder().setSuccess(false); + if (this.node != null) { + final PeerId leader = this.node.getLeaderId(); + if (leader != null) { + builder.setRedirect(leader.toString()); + } + } + return builder.build(); + } + + public JraftMetaServiceImpl getMetaImpl() { + return metaImpl; + } + + public Node getNode() { + return node; + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/MetaStateMachine.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/MetaStateMachine.java new file mode 100644 index 0000000000..0d4690fb1c --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/MetaStateMachine.java @@ -0,0 +1,193 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + +import static org.apache.eventmesh.meta.raft.EventOperation.DELETE; +import static org.apache.eventmesh.meta.raft.EventOperation.GET; +import static org.apache.eventmesh.meta.raft.EventOperation.PUT; + +import org.apache.eventmesh.meta.raft.serialize.EventMeshHessianSerializer; +import org.apache.eventmesh.meta.raft.snapshot.MetaSnapshotFile; + +import org.apache.commons.lang.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicLong; + +import com.alipay.remoting.exception.CodecException; +import com.alipay.sofa.jraft.Closure; +import com.alipay.sofa.jraft.Iterator; +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.jraft.core.StateMachineAdapter; +import com.alipay.sofa.jraft.error.RaftError; +import com.alipay.sofa.jraft.storage.snapshot.SnapshotReader; +import com.alipay.sofa.jraft.storage.snapshot.SnapshotWriter; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MetaStateMachine extends StateMachineAdapter { + + private final AtomicLong leaderTerm = new AtomicLong(-1); + + private static ObjectMapper objectMapper = new ObjectMapper(); + + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + + private Map contentTable = new ConcurrentHashMap<>(); + + public boolean isLeader() { + return this.leaderTerm.get() > 0; + } + + @Override + public boolean onSnapshotLoad(final SnapshotReader reader) { + if (isLeader()) { + log.warn("Leader is not supposed to load snapshot"); + return false; + } + if (reader.getFileMeta("data") == null) { + log.error("Fail to find data file in {}", reader.getPath()); + return false; + } + final MetaSnapshotFile snapshot = new MetaSnapshotFile(reader.getPath() + File.separator + "data"); + try { + Map snapshotLoaded = objectMapper.readValue(snapshot.load(), Map.class); + contentTable.clear(); + contentTable.putAll(snapshotLoaded); + return true; + } catch (final IOException e) { + log.error("Fail to load snapshot from {}", snapshot.getPath()); + return false; + } + + } + + @Override + public void onSnapshotSave(SnapshotWriter writer, Closure done) { + executor.submit(() -> { + final MetaSnapshotFile snapshot = new MetaSnapshotFile(writer.getPath() + File.separator + "data"); + try { + if (snapshot.save(objectMapper.writeValueAsString(contentTable))) { + if (writer.addFile("data")) { + done.run(Status.OK()); + } else { + done.run(new Status(RaftError.EIO, "Fail to add file to writer")); + } + } else { + done.run(new Status(RaftError.EIO, "Fail to save snapshot %s", snapshot.getPath())); + } + } catch (IOException e) { + done.run(new Status(RaftError.EIO, "Fail to deserialize snapshot %s", snapshot.getPath())); + } + }); + } + + @Override + public void onApply(Iterator iter) { + while (iter.hasNext()) { + Exception e1 = null; + EventOperation eventOperation = null; + EventClosure closure = null; + if (iter.done() != null) { + // This task is applied by this node, get value from closure to avoid additional parsing. + closure = (EventClosure) iter.done(); + eventOperation = closure.getEventOperation(); + } else { + // Have to parse FetchAddRequest from this user log. + final ByteBuffer data = iter.getData(); + try { + eventOperation = EventMeshHessianSerializer.getInstance() + .deserialize(data.array(), EventOperation.class.getName()); + } catch (final CodecException e) { + e.printStackTrace(System.err); + e1 = e; + + } + // follower ignore read operation + if (eventOperation != null && eventOperation.isReadOp()) { + iter.next(); + continue; + } + } + if (eventOperation != null) { + switch (eventOperation.getOp()) { + case GET: + break; + case PUT: + Map tempTable = eventOperation.getData(); + contentTable.putAll(tempTable); + log.info("update MetaStateMachine successfully {}", contentTable); + break; + case DELETE: + Map tempTable2 = eventOperation.getData(); + tempTable2.forEach((key, value) -> { + String remove = contentTable.remove(key); + if (Objects.isNull(remove)) { + log.warn("delete MetaStateMachine key: {} fail.", remove); + } else { + log.info("delete MetaStateMachine key: {} successfully.", remove); + } + + }); + + break; + default: + break; + } + + if (closure != null) { + if (e1 != null) { + closure.failure(e1.getMessage(), StringUtils.EMPTY); + } else { + if (eventOperation.getOp() == PUT) { + closure.success(Collections.EMPTY_MAP); + } else { + closure.success(Collections.unmodifiableMap(contentTable)); + } + + } + closure.run(Status.OK()); + } + } + iter.next(); + } + } + + @Override + public void onLeaderStart(final long term) { + this.leaderTerm.set(term); + super.onLeaderStart(term); + + } + + @Override + public void onLeaderStop(final Status status) { + this.leaderTerm.set(-1); + super.onLeaderStop(status); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/RaftMetaService.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/RaftMetaService.java new file mode 100644 index 0000000000..d9cf371630 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/RaftMetaService.java @@ -0,0 +1,398 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.config.EventMeshMetaConfig; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.meta.raft.config.RaftMetaStorageConfiguration; +import org.apache.eventmesh.meta.raft.consts.MetaRaftConstants; +import org.apache.eventmesh.meta.raft.rpc.MetaServerHelper; +import org.apache.eventmesh.meta.raft.rpc.RequestResponse; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.alipay.sofa.jraft.CliService; +import com.alipay.sofa.jraft.RaftServiceFactory; +import com.alipay.sofa.jraft.RouteTable; +import com.alipay.sofa.jraft.conf.Configuration; +import com.alipay.sofa.jraft.core.CliServiceImpl; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.jraft.error.RemotingException; +import com.alipay.sofa.jraft.option.CliOptions; +import com.alipay.sofa.jraft.option.NodeOptions; +import com.alipay.sofa.jraft.rpc.impl.cli.CliClientServiceImpl; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RaftMetaService implements MetaService { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + private ConcurrentMap eventMeshRegisterInfoMap; + + private final AtomicBoolean initStatus = new AtomicBoolean(false); + + private final AtomicBoolean startStatus = new AtomicBoolean(false); + + RaftMetaStorageConfiguration configuration; + + private JraftServer jraftServer; + + private CliService cliService; + + private CliClientServiceImpl cliClientService; + + private PeerId leader; + + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + + + @Override + public void init() throws MetaException { + if (!initStatus.compareAndSet(false, true)) { + return; + } + eventMeshRegisterInfoMap = new ConcurrentHashMap<>(ConfigurationContextUtil.KEYS.size()); + ConfigService configService = ConfigService.getInstance(); + configuration = configService.buildConfigInstance(RaftMetaStorageConfiguration.class); + } + + @Override + public void start() throws MetaException { + final String dataPath = configuration.getDataPath(); + final String groupId = MetaRaftConstants.GROUP; + final String serverIdStr = configuration.getSelfIpAndPort(); + final String initConfStr = configuration.getMembersIpAndPort(); + final NodeOptions nodeOptions = new NodeOptions(); + nodeOptions.setElectionTimeoutMs(configuration.getElectionTimeoutMs() * 1000); + nodeOptions.setDisableCli(false); + nodeOptions.setSnapshotIntervalSecs(configuration.getSnapshotIntervalSecs()); + final PeerId serverId = new PeerId(); + if (!serverId.parse(serverIdStr)) { + throw new MetaException("Fail to parse serverId:" + serverIdStr); + } + final Configuration initConf = new Configuration(); + if (!initConf.parse(initConfStr)) { + throw new MetaException("Fail to parse initConf:" + initConfStr); + } + initConf.addPeer(serverId); + nodeOptions.setInitialConf(initConf); + try { + jraftServer = new JraftServer(dataPath, groupId, serverId, nodeOptions); + } catch (IOException e) { + throw new MetaException("fail to start jraft server", e); + } + log.info("Started jraft server at port: {}", jraftServer.getNode().getNodeId().getPeerId().getPort()); + + final Configuration conf = new Configuration(); + if (!conf.parse(serverIdStr)) { + throw new IllegalArgumentException("Fail to parse conf:" + serverIdStr); + } + RouteTable.getInstance().updateConfiguration(MetaRaftConstants.GROUP, conf); + cliService = RaftServiceFactory.createAndInitCliService(new CliOptions()); + cliClientService = (CliClientServiceImpl) ((CliServiceImpl) this.cliService).getCliClientService(); + while (true) { + try { + refreshleader(); + if (this.leader != null) { + break; + } + } catch (Exception e) { + log.warn("fail to get leader node"); + try { + Thread.sleep(3000L); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + scheduledExecutorService.scheduleAtFixedRate(() -> { + try { + RaftMetaService.this.refreshleader(); + } catch (Exception e) { + log.error("fail to Refresh Leader", e); + } + }, configuration.getRefreshLeaderInterval(), configuration.getRefreshLeaderInterval(), TimeUnit.SECONDS); + + startStatus.compareAndSet(false, true); + } + + private void refreshleader() throws InterruptedException, TimeoutException { + if (!RouteTable.getInstance().refreshLeader(cliClientService, MetaRaftConstants.GROUP, 3000).isOk()) { + throw new IllegalStateException("Refresh leader failed"); + } + this.leader = RouteTable.getInstance().selectLeader(MetaRaftConstants.GROUP); + log.info("raft Leader is {}", leader); + } + + @Override + public void shutdown() throws MetaException { + if (!startStatus.compareAndSet(true, false)) { + return; + } + scheduledExecutorService.shutdown(); + MetaServerHelper.shutDown(); + if (cliService != null) { + cliService.shutdown(); + } + if (cliClientService != null) { + cliClientService.shutdown(); + } + } + + @Override + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + List listEventMeshDataInfo = new ArrayList<>(); + RequestResponse req = RequestResponse.newBuilder().setValue(MetaRaftConstants.GET).build(); + boolean result = false; + try { + CompletableFuture future = commit(req, EventClosure.createDefaultEventClosure()); + RequestResponse requestResponse = future.get(3000, TimeUnit.MILLISECONDS); + if (requestResponse != null) { + result = requestResponse.getSuccess(); + if (result) { + Map infoMap = requestResponse.getInfoMap(); + for (Entry entry : infoMap.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (key.startsWith("eventMeshInfo@@")) { + if (Objects.isNull(clusterName)) { + if (!key.endsWith("@@" + clusterName)) { + continue; + } + } + EventMeshDataInfo eventMeshDataInfo = objectMapper.readValue(value, EventMeshDataInfo.class); + listEventMeshDataInfo.add(eventMeshDataInfo); + } + } + } + } + } catch (Exception e) { + throw new MetaException("fail to get meta data ", e); + } + return listEventMeshDataInfo; + } + + @Override + public List findAllEventMeshInfo() throws MetaException { + return findEventMeshInfoByCluster(null); + } + + @Override + public void registerMetadata(Map metadataMap) { + for (Map.Entry eventMeshRegisterInfo : eventMeshRegisterInfoMap.entrySet()) { + EventMeshRegisterInfo registerInfo = eventMeshRegisterInfo.getValue(); + registerInfo.setMetadata(metadataMap); + this.register(registerInfo); + } + } + + @Override + public Map getMetaData(String key, boolean fuzzyEnabled) { + Map resultMap = new HashMap<>(); + RequestResponse req = RequestResponse.newBuilder().setValue(MetaRaftConstants.GET).build(); + boolean result = false; + try { + CompletableFuture future = commit(req, EventClosure.createDefaultEventClosure()); + RequestResponse requestResponse = future.get(3000, TimeUnit.MILLISECONDS); + if (requestResponse != null) { + result = requestResponse.getSuccess(); + if (result) { + Map infoMap = requestResponse.getInfoMap(); + resultMap.putAll(infoMap); + } + } + } catch (Exception e) { + throw new MetaException("fail to get meta data ", e); + } + if (fuzzyEnabled) { + // todo + } else { + Map finalResult = new HashMap<>(); + finalResult.put(key, resultMap.get(key)); + return finalResult; + } + + return resultMap; + } + + @Override + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) { + //todo + } + + @Override + public void updateMetaData(Map metadataMap) { + String protocol = metadataMap.get(EventMeshMetaConfig.EVENT_MESH_PROTO); + String reftDataId = "Raft" + "@@" + protocol; + boolean result = false; + try { + RequestResponse req = + RequestResponse.newBuilder().setValue(MetaRaftConstants.PUT).putInfo(reftDataId, objectMapper.writeValueAsString(metadataMap)) + .build(); + CompletableFuture future = commit(req, EventClosure.createDefaultEventClosure()); + RequestResponse requestResponse = future.get(3000, TimeUnit.MILLISECONDS); + if (requestResponse != null) { + result = requestResponse.getSuccess(); + } + } catch (Exception e) { + throw new MetaException("fail to serialize ", e); + } + if (!result) { + throw new MetaException("fail to updateMetaData "); + } + + } + + @Override + public void removeMetaData(String key) { + RequestResponse req = RequestResponse.newBuilder().setValue(MetaRaftConstants.DELETE).putInfo(key, StringUtils.EMPTY).build(); + + try { + CompletableFuture future = commit(req, EventClosure.createDefaultEventClosure()); + RequestResponse requestResponse = future.get(3000, TimeUnit.MILLISECONDS); + if (requestResponse != null) { + boolean result = requestResponse.getSuccess(); + if (result) { + throw new MetaException("fail to remove MetaData"); + } + } + } catch (Exception e) { + throw new MetaException("fail to remove MetaData", e); + } + + } + + @Override + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + //key= eventMeshInfo@@eventMeshName@@IP@@PORT@@protocolType@@CLUSTER_NAME + String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); + String protocolType = eventMeshRegisterInfo.getProtocolType(); + String[] ipAndPort = eventMeshRegisterInfo.getEndPoint().split(":"); + String clusterName = eventMeshRegisterInfo.getEventMeshClusterName(); + String key = "eventMeshInfo" + "@@" + eventMeshName + "@@" + ipAndPort[0] + "@@" + ipAndPort[1] + "@@" + protocolType + "@@" + clusterName; + InfoInner infoInner = new InfoInner(eventMeshRegisterInfo); + String registerInfo = null; + boolean result = false; + try { + registerInfo = objectMapper.writeValueAsString(infoInner); + RequestResponse req = RequestResponse.newBuilder().setValue(MetaRaftConstants.PUT).putInfo(key, registerInfo).build(); + CompletableFuture future = commit(req, EventClosure.createDefaultEventClosure()); + RequestResponse requestResponse = future.get(3000, TimeUnit.MILLISECONDS); + if (requestResponse != null) { + result = requestResponse.getSuccess(); + } + } catch (Exception e) { + throw new MetaException("fail to serialize ", e); + } + if (result) { + eventMeshRegisterInfoMap.put(eventMeshName, eventMeshRegisterInfo); + } + return result; + } + + @Override + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + //key= eventMeshInfo@@eventMeshName@@IP@@PORT@@protocolType@@CLUSTER_NAME + String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); + String protocolType = eventMeshUnRegisterInfo.getProtocolType(); + String[] ipAndPort = eventMeshUnRegisterInfo.getEndPoint().split(":"); + String clusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); + String key = "eventMeshInfo" + "@@" + eventMeshName + "@@" + ipAndPort[0] + "@@" + ipAndPort[1] + "@@" + protocolType + "@@" + clusterName; + RequestResponse req = RequestResponse.newBuilder().setValue(MetaRaftConstants.DELETE).putInfo(key, StringUtils.EMPTY).build(); + boolean result = false; + try { + CompletableFuture future = commit(req, EventClosure.createDefaultEventClosure()); + RequestResponse requestResponse = future.get(3000, TimeUnit.MILLISECONDS); + if (requestResponse != null) { + result = requestResponse.getSuccess(); + } + } catch (Exception e) { + throw new MetaException(e.getMessage(), e); + } + if (result) { + eventMeshRegisterInfoMap.remove(eventMeshName); + } + return result; + } + + @Data + class InfoInner implements Serializable { + + EventMeshRegisterInfo eventMeshRegisterInfo; + + public InfoInner(EventMeshRegisterInfo eventMeshRegisterInfo) { + this.eventMeshRegisterInfo = eventMeshRegisterInfo; + } + } + + public CompletableFuture commit(RequestResponse requestResponse, EventClosure eventClosure) + throws RemotingException, InterruptedException { + CompletableFuture future = new CompletableFuture<>(); + eventClosure.setFuture(future); + if (isLeader()) { + this.jraftServer.getMetaImpl().handle(requestResponse, eventClosure); + } else { + invokeToLeader(requestResponse, future); + } + return future; + } + + private void invokeToLeader(RequestResponse requestResponse, CompletableFuture future) + throws RemotingException, InterruptedException { + cliClientService.getRpcClient().invokeAsync(leader.getEndpoint(), requestResponse, (result, err) -> { + if (err != null) { + future.completeExceptionally(err); + return; + } + future.complete((RequestResponse) result); + }, 3000); + } + + + private boolean isLeader() { + return this.jraftServer.getFsm().isLeader(); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/config/RaftMetaStorageConfiguration.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/config/RaftMetaStorageConfiguration.java new file mode 100644 index 0000000000..d5f4a80191 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/config/RaftMetaStorageConfiguration.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.meta.raft.consts.MetaRaftConstants; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(prefix = "eventMesh.metaStorage.raft") +public class RaftMetaStorageConfiguration { + + @ConfigField(field = MetaRaftConstants.DATAPATH) + private String dataPath; + + @ConfigField(field = MetaRaftConstants.SELF) + private String selfIpAndPort; + + @ConfigField(field = MetaRaftConstants.MEMBERS) + private String membersIpAndPort; + + @ConfigField(field = MetaRaftConstants.ELECTIONTIMEOUT) + private Integer electionTimeoutMs; + + @ConfigField(field = MetaRaftConstants.SNAPSHOTINTERVAL) + private Integer snapshotIntervalSecs; + + @ConfigField(field = MetaRaftConstants.REFRESHLEADERINTERVAL) + private Integer refreshLeaderInterval; + +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/consts/MetaRaftConstants.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/consts/MetaRaftConstants.java new file mode 100644 index 0000000000..6be76855e9 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/consts/MetaRaftConstants.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.consts; + +/** + * MetaRaftConstants. + */ + +public interface MetaRaftConstants { + + String GROUP = "EM_META"; + + String SELF = "self"; + + String MEMBERS = "members"; + + String DATAPATH = "dataPath"; + + String ELECTIONTIMEOUT = "electionTimeout"; + + String SNAPSHOTINTERVAL = "snapshotInterval"; + + String REFRESHLEADERINTERVAL = "refreshLeaderInterval"; + + int PUT = 1; + + int GET = 2; + + int DELETE = 3; + + int RESPONSE = 4; +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/rpc/MetaServerHelper.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/rpc/MetaServerHelper.java new file mode 100644 index 0000000000..abaeb58d8d --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/rpc/MetaServerHelper.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.rpc; + +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +import com.alipay.sofa.jraft.rpc.RpcServer; +import com.alipay.sofa.jraft.util.RpcFactoryHelper; +import com.google.protobuf.Message; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MetaServerHelper { + + public static RpcServer rpcServer; + + + public static void setRpcServer(RpcServer rpcServer) { + MetaServerHelper.rpcServer = rpcServer; + } + + + public static void initGRpc() { + if ("com.alipay.sofa.jraft.rpc.impl.GrpcRaftRpcFactory".equals( + RpcFactoryHelper.rpcFactory().getClass().getName())) { + RpcFactoryHelper.rpcFactory() + .registerProtobufSerializer(RequestResponse.class.getName(), + RequestResponse.getDefaultInstance()); + try { + Class clazz = Class.forName("com.alipay.sofa.jraft.rpc.impl.MarshallerHelper"); + Method registerRespInstance = clazz.getMethod("registerRespInstance", String.class, Message.class); + registerRespInstance.invoke(null, RequestResponse.class.getName(), + RequestResponse.getDefaultInstance()); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + } + + public static void shutDown() { + if (rpcServer == null) { + return; + } + rpcServer.shutdown(); + } + + public static void blockUntilShutdown() { + if (rpcServer == null) { + return; + } + if ("com.alipay.sofa.jraft.rpc.impl.GrpcRaftRpcFactory".equals( + RpcFactoryHelper.rpcFactory().getClass().getName())) { + try { + Method getServer = rpcServer.getClass().getMethod("getServer"); + Object grpcServer = getServer.invoke(rpcServer); + + Method shutdown = grpcServer.getClass().getMethod("shutdown"); + Method awaitTerminationLimit = grpcServer.getClass() + .getMethod("awaitTermination", long.class, TimeUnit.class); + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + shutdown.invoke(grpcServer); + awaitTerminationLimit.invoke(grpcServer, 30, TimeUnit.SECONDS); + } catch (Exception e) { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + log.error(e.getMessage(), e); + } + } + }); + Method awaitTermination = grpcServer.getClass().getMethod("awaitTermination"); + awaitTermination.invoke(grpcServer); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/rpc/RequestProcessor.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/rpc/RequestProcessor.java new file mode 100644 index 0000000000..2fd77ec5b2 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/rpc/RequestProcessor.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.rpc; + +import org.apache.eventmesh.meta.raft.EventClosure; +import org.apache.eventmesh.meta.raft.JraftMetaService; + +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.jraft.rpc.RpcContext; +import com.alipay.sofa.jraft.rpc.RpcProcessor; + + +public class RequestProcessor implements RpcProcessor { + + private final JraftMetaService metaService; + + public RequestProcessor(JraftMetaService metaService) { + super(); + this.metaService = metaService; + } + + @Override + public void handleRequest(final RpcContext rpcCtx, final RequestResponse request) { + final EventClosure closure = new EventClosure() { + @Override + public void run(Status status) { + rpcCtx.sendResponse(getRequestResponse()); + } + }; + this.metaService.handle(request, closure); + } + + @Override + public String interest() { + return RequestResponse.class.getName(); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/serialize/EventMeshHessianSerializer.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/serialize/EventMeshHessianSerializer.java new file mode 100644 index 0000000000..646d69c0d3 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/serialize/EventMeshHessianSerializer.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.serialize; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import com.alipay.remoting.exception.CodecException; +import com.alipay.remoting.serialization.HessianSerializer; +import com.caucho.hessian.io.Hessian2Input; +import com.caucho.hessian.io.Hessian2Output; +import com.caucho.hessian.io.SerializerFactory; + +public class EventMeshHessianSerializer extends HessianSerializer { + + private SerializerFactory customizeSerializerFactory = new EventMeshSerializerFactory(); + + private static EventMeshHessianSerializer instance; + + private EventMeshHessianSerializer() { + } + + public static HessianSerializer getInstance() { + if (instance == null) { + synchronized (EventMeshHessianSerializer.class) { + if (instance == null) { + instance = new EventMeshHessianSerializer(); + } + } + } + return instance; + } + + @Override + public byte[] serialize(Object obj) throws CodecException { + ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); + Hessian2Output output = new Hessian2Output(byteArray); + output.setSerializerFactory(customizeSerializerFactory); + try { + output.writeObject(obj); + output.close(); + } catch (IOException e) { + throw new CodecException("IOException occurred when Hessian serializer encode!", e); + } + + return byteArray.toByteArray(); + } + + @Override + public T deserialize(byte[] data, String classOfT) throws CodecException { + Hessian2Input input = new Hessian2Input(new ByteArrayInputStream(data)); + input.setSerializerFactory(customizeSerializerFactory); + Object resultObject; + try { + resultObject = input.readObject(); + input.close(); + } catch (IOException e) { + throw new CodecException("IOException occurred when Hessian serializer decode!", e); + } + return (T) resultObject; + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/serialize/EventMeshSerializerFactory.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/serialize/EventMeshSerializerFactory.java new file mode 100644 index 0000000000..d16796219d --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/serialize/EventMeshSerializerFactory.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.serialize; + +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import com.caucho.hessian.io.SerializerFactory; + +public class EventMeshSerializerFactory extends SerializerFactory { + EventMeshSerializerFactory() { + super(); + super.getClassFactory().setWhitelist(true); + allowBasicType(); + allowCollections(); + allowConcurrent(); + allowTime(); + super.getClassFactory().allow("org.apache.eventmesh.*"); + } + + private void allowBasicType() { + super.getClassFactory().allow(boolean.class.getCanonicalName()); + super.getClassFactory().allow(byte.class.getCanonicalName()); + super.getClassFactory().allow(char.class.getCanonicalName()); + super.getClassFactory().allow(double.class.getCanonicalName()); + super.getClassFactory().allow(float.class.getCanonicalName()); + super.getClassFactory().allow(int.class.getCanonicalName()); + super.getClassFactory().allow(long.class.getCanonicalName()); + super.getClassFactory().allow(short.class.getCanonicalName()); + super.getClassFactory().allow(Boolean.class.getCanonicalName()); + super.getClassFactory().allow(Byte.class.getCanonicalName()); + super.getClassFactory().allow(Character.class.getCanonicalName()); + super.getClassFactory().allow(Double.class.getCanonicalName()); + super.getClassFactory().allow(Float.class.getCanonicalName()); + super.getClassFactory().allow(Integer.class.getCanonicalName()); + super.getClassFactory().allow(Long.class.getCanonicalName()); + super.getClassFactory().allow(Short.class.getCanonicalName()); + + super.getClassFactory().allow(Number.class.getCanonicalName()); + super.getClassFactory().allow(Class.class.getCanonicalName()); + super.getClassFactory().allow(String.class.getCanonicalName()); + } + + private void allowCollections() { + super.getClassFactory().allow(List.class.getCanonicalName()); + super.getClassFactory().allow(ArrayList.class.getCanonicalName()); + super.getClassFactory().allow(LinkedList.class.getCanonicalName()); + + super.getClassFactory().allow(Set.class.getCanonicalName()); + super.getClassFactory().allow(HashSet.class.getCanonicalName()); + super.getClassFactory().allow(LinkedHashSet.class.getCanonicalName()); + super.getClassFactory().allow(TreeSet.class.getCanonicalName()); + + super.getClassFactory().allow(Map.class.getCanonicalName()); + super.getClassFactory().allow(HashMap.class.getCanonicalName()); + super.getClassFactory().allow(LinkedHashMap.class.getCanonicalName()); + super.getClassFactory().allow(TreeMap.class.getCanonicalName()); + super.getClassFactory().allow(WeakHashMap.class.getCanonicalName()); + + super.getClassFactory().allow("java.util.Arrays$ArrayList"); + super.getClassFactory().allow("java.util.Collections$EmptyList"); + super.getClassFactory().allow("java.util.Collections$EmptyMap"); + super.getClassFactory().allow("java.util.Collections$SingletonSet"); + super.getClassFactory().allow("java.util.Collections$SingletonList"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableCollection"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableList"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableMap"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableNavigableMap"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableNavigableSet"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableRandomAccessList"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableSet"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableSortedMap"); + super.getClassFactory().allow("java.util.Collections$UnmodifiableSortedSet"); + } + + private void allowConcurrent() { + super.getClassFactory().allow(AtomicBoolean.class.getCanonicalName()); + super.getClassFactory().allow(AtomicInteger.class.getCanonicalName()); + super.getClassFactory().allow(AtomicLong.class.getCanonicalName()); + super.getClassFactory().allow(AtomicReference.class.getCanonicalName()); + + super.getClassFactory().allow(ConcurrentMap.class.getCanonicalName()); + super.getClassFactory().allow(ConcurrentHashMap.class.getCanonicalName()); + super.getClassFactory().allow(ConcurrentSkipListMap.class.getCanonicalName()); + super.getClassFactory().allow(CopyOnWriteArrayList.class.getCanonicalName()); + } + + private void allowTime() { + super.getClassFactory().allow(SimpleDateFormat.class.getCanonicalName()); + super.getClassFactory().allow(DateTimeFormatter.class.getCanonicalName()); + super.getClassFactory().allow(Instant.class.getCanonicalName()); + super.getClassFactory().allow(LocalDate.class.getCanonicalName()); + super.getClassFactory().allow(LocalDateTime.class.getCanonicalName()); + super.getClassFactory().allow(LocalTime.class.getCanonicalName()); + super.getClassFactory().allow(TimeUnit.class.getCanonicalName()); + super.getClassFactory().allow(Date.class.getCanonicalName()); + super.getClassFactory().allow(Calendar.class.getCanonicalName()); + } + + +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/snapshot/MetaSnapshotFile.java b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/snapshot/MetaSnapshotFile.java new file mode 100644 index 0000000000..b185829a81 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/java/org/apache/eventmesh/meta/raft/snapshot/MetaSnapshotFile.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.raft.snapshot; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MetaSnapshotFile { + + private String path; + + public MetaSnapshotFile(String path) { + super(); + this.path = path; + } + + public String getPath() { + return this.path; + } + + /** + * Save value to snapshot file. + */ + public boolean save(final String str) { + try { + FileUtils.writeStringToFile(new File(path), str, Charset.forName("UTF-8")); + return true; + } catch (IOException e) { + log.error("Fail to save snapshot", e); + return false; + } + } + + public String load() throws IOException { + final String s = FileUtils.readFileToString(new File(path), Charset.forName("UTF-8")); + if (!StringUtils.isBlank(s)) { + return s; + } + throw new IOException("Fail to load snapshot from " + path + ",content: " + s); + } +} diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/proto/request.proto b/eventmesh-meta/eventmesh-meta-raft/src/main/proto/request.proto new file mode 100644 index 0000000000..6865495858 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/proto/request.proto @@ -0,0 +1,32 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_multiple_files = true; + +option java_package = "org.apache.eventmesh.meta.raft.rpc"; + +message RequestResponse { + int64 value = 1; + bool success = 2; + string redirect = 3; + string errorMsg = 4; + map info = 5; +} + + diff --git a/eventmesh-meta/eventmesh-meta-raft/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService b/eventmesh-meta/eventmesh-meta-raft/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService new file mode 100644 index 0000000000..4771d7fc1c --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-raft/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService @@ -0,0 +1,16 @@ +# 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. + +raft=org.apache.eventmesh.meta.raft.RaftMetaService \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/build.gradle b/eventmesh-meta/eventmesh-meta-zookeeper/build.gradle new file mode 100644 index 0000000000..149f78e99d --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/build.gradle @@ -0,0 +1,42 @@ +/* + * 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. + */ + +dependencies { + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + /* + * The exclusion can be removed once ZOOKEEPER-4820 has been fixed. + * + * See https://github.com/apache/zookeeper/pull/2155 + */ + implementation('org.apache.zookeeper:zookeeper') { + exclude group: 'ch.qos.logback', module: 'logback-core' + exclude group: 'ch.qos.logback', module: 'logback-classic' + } + implementation 'org.apache.curator:curator-client' + implementation 'org.apache.curator:curator-framework' + implementation 'org.apache.curator:curator-recipes' + + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-common") + + testImplementation 'org.mockito:mockito-core' + testImplementation 'org.mockito:mockito-junit-jupiter' + testImplementation 'org.apache.curator:curator-test' +} diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/gradle.properties b/eventmesh-meta/eventmesh-meta-zookeeper/gradle.properties new file mode 100644 index 0000000000..d987fd1a0c --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# + +pluginType=metaStorage +pluginName=zookeeper \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/config/ZKRegistryConfiguration.java b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/config/ZKRegistryConfiguration.java new file mode 100644 index 0000000000..7e6f743c89 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/config/ZKRegistryConfiguration.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.zookeeper.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(prefix = "eventMesh.registry.zookeeper") +public class ZKRegistryConfiguration { + + @ConfigField(field = "scheme") + private String scheme; + + @ConfigField(field = "auth") + private String auth; + + @ConfigField(field = "connectionTimeoutMs") + private Integer connectionTimeoutMs = 5000; + + @ConfigField(field = "sessionTimeoutMs") + private Integer sessionTimeoutMs = 40000; + + // Fully qualified name of RetryPolicy implementation + @ConfigField(field = "retryPolicy.class") + private String retryPolicyClass; + + @ConfigField(field = "retryPolicy.baseSleepTimeMs") + private Integer baseSleepTimeMs = 1000; + + @ConfigField(field = "retryPolicy.maxRetries") + private Integer maxRetries = 5; + + @ConfigField(field = "retryPolicy.maxSleepTimeMs") + private Integer maxSleepTimeMs = 5000; + + @ConfigField(field = "retryPolicy.retryIntervalMs") + private Integer retryIntervalTimeMs = 1000; + + @ConfigField(field = "retryPolicy.nTimes") + private Integer retryNTimes = 10; + + @ConfigField(field = "retryPolicy.sleepMsBetweenRetries") + private Integer sleepMsBetweenRetries = 1000; + +} diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/constant/ZookeeperConstant.java b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/constant/ZookeeperConstant.java new file mode 100644 index 0000000000..8ed983befc --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/constant/ZookeeperConstant.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.zookeeper.constant; + +public class ZookeeperConstant { + + public static final String NAMESPACE = "eventmesh"; + + public static final String IP_PORT_SEPARATOR = ":"; + + public static final String PATH_SEPARATOR = "/"; + +} diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/pojo/EventMeshInstance.java b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/pojo/EventMeshInstance.java new file mode 100644 index 0000000000..fbe27ab75a --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/pojo/EventMeshInstance.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.zookeeper.pojo; + +import java.io.Serializable; +import java.util.Map; + +import lombok.Data; + +@Data +public class EventMeshInstance implements Serializable { + + private static final long serialVersionUID = -7953085707514834697L; + + private String ip; + + private int port; + + private Map> instanceNumMap; + + private Map metaData; + +} diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/service/ZookeeperMetaService.java b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/service/ZookeeperMetaService.java new file mode 100644 index 0000000000..18520feb4d --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/java/org/apache/eventmesh/meta/zookeeper/service/ZookeeperMetaService.java @@ -0,0 +1,348 @@ +/* + * 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. + */ + +package org.apache.eventmesh.meta.zookeeper.service; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.meta.zookeeper.config.ZKRegistryConfiguration; +import org.apache.eventmesh.meta.zookeeper.constant.ZookeeperConstant; +import org.apache.eventmesh.meta.zookeeper.pojo.EventMeshInstance; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.curator.RetryPolicy; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.CuratorFrameworkFactory.Builder; +import org.apache.curator.retry.BoundedExponentialBackoffRetry; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.curator.retry.RetryForever; +import org.apache.curator.retry.RetryNTimes; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.data.Stat; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ZookeeperMetaService implements MetaService { + + private final AtomicBoolean initStatus = new AtomicBoolean(false); + + private final AtomicBoolean startStatus = new AtomicBoolean(false); + + @Getter + private String serverAddr; + + @Getter + private CuratorFramework zkClient; + + private ConcurrentMap eventMeshRegisterInfoMap; + + private ZKRegistryConfiguration zkConfig; + + @Override + public void init() throws MetaException { + + if (!initStatus.compareAndSet(false, true)) { + log.warn("[ZookeeperRegistryService] has been init"); + return; + } + eventMeshRegisterInfoMap = new ConcurrentHashMap<>(ConfigurationContextUtil.KEYS.size()); + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); + if (commonConfiguration == null) { + continue; + } + if (StringUtils.isBlank(commonConfiguration.getMetaStorageAddr())) { + throw new MetaException("meta storage address cannot be null"); + } + this.serverAddr = commonConfiguration.getMetaStorageAddr(); + break; + } + ZKRegistryConfiguration zkConfig = ConfigService.getInstance().buildConfigInstance(ZKRegistryConfiguration.class); + this.zkConfig = zkConfig; + } + + @Override + public void start() throws MetaException { + + if (!startStatus.compareAndSet(false, true)) { + log.warn("[ZookeeperRegistryService] has been start"); + return; + } + try { + zkClient = buildZkClient(); + zkClient.start(); + } catch (Exception e) { + throw new MetaException("ZookeeperRegistry starting failed", e); + } + } + + private CuratorFramework buildZkClient() throws ClassNotFoundException { + Builder builder = CuratorFrameworkFactory.builder() + .connectString(serverAddr) + .namespace(ZookeeperConstant.NAMESPACE); + if (zkConfig == null) { + builder.retryPolicy(new ExponentialBackoffRetry(1000, 5)); + return builder.build(); + } + builder.retryPolicy(createRetryPolicy()); + String scheme = zkConfig.getScheme(); + String auth = zkConfig.getAuth(); + if (!StringUtils.isAnyBlank(scheme, auth)) { + builder.authorization(scheme, auth.getBytes(Constants.DEFAULT_CHARSET)); + } + Optional.ofNullable(zkConfig.getConnectionTimeoutMs()).ifPresent((timeout) -> builder.connectionTimeoutMs(timeout)); + Optional.ofNullable(zkConfig.getSessionTimeoutMs()).ifPresent((timeout) -> builder.sessionTimeoutMs(timeout)); + return builder.build(); + } + + private RetryPolicy createRetryPolicy() throws ClassNotFoundException { + String retryPolicyClass = zkConfig.getRetryPolicyClass(); + if (StringUtils.isBlank(retryPolicyClass)) { + return new ExponentialBackoffRetry(1000, 5); + } + Class clazz = Class.forName(retryPolicyClass); + if (clazz == ExponentialBackoffRetry.class) { + return new ExponentialBackoffRetry( + getOrDefault(zkConfig.getBaseSleepTimeMs(), 1000, Integer.class), + getOrDefault(zkConfig.getMaxRetries(), 5, Integer.class)); + } else if (clazz == BoundedExponentialBackoffRetry.class) { + return new BoundedExponentialBackoffRetry( + getOrDefault(zkConfig.getBaseSleepTimeMs(), 1000, Integer.class), + getOrDefault(zkConfig.getMaxSleepTimeMs(), 5000, Integer.class), + getOrDefault(zkConfig.getMaxRetries(), 5, Integer.class)); + } else if (clazz == RetryForever.class) { + return new RetryForever( + getOrDefault(zkConfig.getRetryIntervalTimeMs(), 1000, Integer.class)); + } else if (clazz == RetryNTimes.class) { + return new RetryNTimes( + getOrDefault(zkConfig.getRetryNTimes(), 10, Integer.class), + getOrDefault(zkConfig.getSleepMsBetweenRetries(), 1000, Integer.class)); + } else { + throw new IllegalArgumentException("Unsupported retry policy: " + retryPolicyClass); + } + } + + private T getOrDefault(T value, T defaultValue, Class clazz) { + if (value != null) { + return value; + } + return defaultValue; + } + + @Override + public void shutdown() throws MetaException { + if (!initStatus.compareAndSet(true, false)) { + return; + } + if (!startStatus.compareAndSet(true, false)) { + return; + } + if (zkClient != null) { + zkClient.close(); + } + log.info("ZookeeperRegistryService closed"); + } + + @Override + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + List eventMeshDataInfoList = new ArrayList<>(); + for (String key : ConfigurationContextUtil.KEYS) { + + CommonConfiguration configuration = ConfigurationContextUtil.get(key); + if (Objects.isNull(configuration)) { + continue; + } + String eventMeshName = configuration.getEventMeshName(); + String serviceName = eventMeshName.concat("-").concat(key); + + findEventMeshInfo("findEventMeshInfoByCluster", clusterName, serviceName, eventMeshDataInfoList); + } + return eventMeshDataInfoList; + } + + @Override + public List findAllEventMeshInfo() throws MetaException { + List eventMeshDataInfoList = new ArrayList<>(); + + for (Map.Entry entry : eventMeshRegisterInfoMap.entrySet()) { + + String serviceName = entry.getKey(); + String clusterName = entry.getValue().getEventMeshClusterName(); + + findEventMeshInfo("findAllEventMeshInfo", clusterName, serviceName, eventMeshDataInfoList); + } + return eventMeshDataInfoList; + } + + private void findEventMeshInfo(String tipTitle, String clusterName, + String serviceName, List eventMeshDataInfoList) throws MetaException { + try { + String servicePath = formatServicePath(clusterName, serviceName); + + List instances = zkClient.getChildren().forPath(servicePath); + + if (CollectionUtils.isEmpty(instances)) { + return; + } + + for (String endpoint : instances) { + String instancePath = servicePath.concat(ZookeeperConstant.PATH_SEPARATOR).concat(endpoint); + + Stat stat = new Stat(); + byte[] data; + try { + data = zkClient.getData() + .storingStatIn(stat) + .forPath(instancePath); + } catch (Exception e) { + log.warn("[ZookeeperRegistryService][{}] failed for path: {}", tipTitle, instancePath, e); + continue; + } + + EventMeshInstance eventMeshInstance = JsonUtils.parseObject(new String(data, StandardCharsets.UTF_8), EventMeshInstance.class); + + EventMeshDataInfo eventMeshDataInfo = + new EventMeshDataInfo(clusterName, serviceName, endpoint, stat.getMtime(), + Objects.requireNonNull(eventMeshInstance, "instance must not be Null").getMetaData()); + + eventMeshDataInfoList.add(eventMeshDataInfo); + } + + } catch (Exception e) { + throw new MetaException(String.format("ZookeeperRegistry {0} failed", tipTitle), e); + } + } + + @Override + public void registerMetadata(Map metadataMap) { + for (Map.Entry eventMeshRegisterInfo : eventMeshRegisterInfoMap.entrySet()) { + EventMeshRegisterInfo registerInfo = eventMeshRegisterInfo.getValue(); + registerInfo.setMetadata(metadataMap); + this.register(registerInfo); + } + } + + @Override + public Map getMetaData(String key, boolean fuzzyEnabled) { + return new HashMap<>(); + } + + // todo: to be implemented + @Override + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) { + + } + + @Override + public void updateMetaData(Map metadataMap) { + + } + + @Override + public void removeMetaData(String key) { + + } + + @Override + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + try { + String[] ipPort = eventMeshRegisterInfo.getEndPoint().split(ZookeeperConstant.IP_PORT_SEPARATOR); + if (ipPort == null || ipPort.length < 2) { + return false; + } + String ip = ipPort[0]; + int port = Integer.parseInt(ipPort[1]); + String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); + String eventMeshClusterName = eventMeshRegisterInfo.getEventMeshClusterName(); + Map> instanceNumMap = eventMeshRegisterInfo.getEventMeshInstanceNumMap(); + Map metadata = eventMeshRegisterInfo.getMetadata(); + + EventMeshInstance eventMeshInstance = new EventMeshInstance(); + eventMeshInstance.setIp(ip); + eventMeshInstance.setPort(port); + eventMeshInstance.setInstanceNumMap(instanceNumMap); + eventMeshInstance.setMetaData(metadata); + + // clusterName/eventMeshName/ip:port + final String path = formatInstancePath(eventMeshClusterName, eventMeshName, eventMeshRegisterInfo.getEndPoint()); + + zkClient.create() + .orSetData() + .creatingParentsIfNeeded() + .withMode(CreateMode.EPHEMERAL) + .forPath(path, + Objects.requireNonNull(JsonUtils.toJSONString(eventMeshInstance), "instance must not be Null").getBytes(StandardCharsets.UTF_8)); + + eventMeshRegisterInfoMap.put(eventMeshName, eventMeshRegisterInfo); + } catch (Exception e) { + throw new MetaException("ZookeeperRegistry register failed", e); + } + log.info("EventMesh successfully registered to zookeeper"); + return true; + } + + @Override + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + try { + String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); + String eventMeshClusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); + + String path = formatInstancePath(eventMeshClusterName, eventMeshName, eventMeshUnRegisterInfo.getEndPoint()); + + zkClient.delete().forPath(path); + } catch (Exception e) { + throw new MetaException("ZookeeperRegistry unRegister failed", e); + } + log.info("EventMesh successfully logout to zookeeper"); + return true; + } + + private String formatInstancePath(String clusterName, String serviceName, String endPoint) { + return ZookeeperConstant.PATH_SEPARATOR.concat(clusterName) + .concat(ZookeeperConstant.PATH_SEPARATOR).concat(serviceName) + .concat(ZookeeperConstant.PATH_SEPARATOR).concat(endPoint); + } + + private String formatServicePath(String clusterName, String serviceName) { + return ZookeeperConstant.PATH_SEPARATOR.concat(clusterName) + .concat(ZookeeperConstant.PATH_SEPARATOR).concat(serviceName); + } +} diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService new file mode 100644 index 0000000000..66bf19b4f9 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.meta.MetaService @@ -0,0 +1,16 @@ +# 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. + +zookeeper=org.apache.eventmesh.meta.zookeeper.service.ZookeeperMetaService \ No newline at end of file diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/test/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperMetaServiceTest.java b/eventmesh-meta/eventmesh-meta-zookeeper/src/test/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperMetaServiceTest.java new file mode 100644 index 0000000000..12830ae237 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/test/java/org/apache/eventmesh/registry/zookeeper/service/ZookeeperMetaServiceTest.java @@ -0,0 +1,180 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry.zookeeper.service; + +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.meta.zookeeper.service.ZookeeperMetaService; + +import org.apache.curator.test.TestingServer; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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 org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +import com.google.common.collect.Maps; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class ZookeeperMetaServiceTest { + + @Mock + private EventMeshRegisterInfo eventMeshRegisterInfo; + @Mock + private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; + + private ZookeeperMetaService zkRegistryService; + + private TestingServer testingServer; + + @BeforeEach + public void setUp() throws Exception { + testingServer = new TestingServer(1500, true); + testingServer.start(); + + zkRegistryService = new ZookeeperMetaService(); + CommonConfiguration configuration = new CommonConfiguration(); + configuration.setMetaStorageAddr("127.0.0.1:1500"); + configuration.setEventMeshName("eventmesh"); + ConfigurationContextUtil.putIfAbsent(HTTP, configuration); + + Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmeshCluster"); + Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh-" + HTTP); + Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); + Mockito.when(eventMeshRegisterInfo.getEventMeshInstanceNumMap()).thenReturn(Maps.newHashMap()); + HashMap metaData = Maps.newHashMap(); + metaData.put("test", "a"); + Mockito.when(eventMeshRegisterInfo.getMetadata()).thenReturn(metaData); + + Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmeshCluster"); + Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh-" + HTTP); + Mockito.when(eventMeshUnRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); + } + + @AfterEach + public void after() throws Exception { + zkRegistryService.shutdown(); + testingServer.close(); + } + + @Test + public void testInit() { + zkRegistryService.init(); + zkRegistryService.start(); + Assertions.assertNotNull(zkRegistryService.getServerAddr()); + } + + @Test + public void testStart() { + zkRegistryService.init(); + zkRegistryService.start(); + Assertions.assertNotNull(zkRegistryService.getZkClient()); + } + + @Test + public void testShutdown() throws NoSuchFieldException, IllegalAccessException { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.shutdown(); + + Class zkRegistryServiceClass = ZookeeperMetaService.class; + Field initStatus = zkRegistryServiceClass.getDeclaredField("initStatus"); + initStatus.setAccessible(true); + Object initStatusField = initStatus.get(zkRegistryService); + + Field startStatus = zkRegistryServiceClass.getDeclaredField("startStatus"); + startStatus.setAccessible(true); + Object startStatusField = startStatus.get(zkRegistryService); + + Assertions.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); + Assertions.assertFalse((Boolean.parseBoolean(startStatusField.toString()))); + } + + @Test + public void testFindEventMeshInfoByCluster() { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.register(eventMeshRegisterInfo); + + final List result = zkRegistryService.findEventMeshInfoByCluster(eventMeshRegisterInfo.getEventMeshClusterName()); + + Assertions.assertNotNull(result); + } + + @Test + public void testFindAllEventMeshInfo() { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.register(eventMeshRegisterInfo); + + List result = zkRegistryService.findAllEventMeshInfo(); + + Assertions.assertNotNull(result); + } + + @Test + public void testRegisterMetadata() { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.register(eventMeshRegisterInfo); + Map metaData = Maps.newConcurrentMap(); + metaData.put("test", "a"); + zkRegistryService.registerMetadata(metaData); + List infoList = + zkRegistryService.findEventMeshInfoByCluster(eventMeshRegisterInfo.getEventMeshClusterName()); + + Assertions.assertNotNull(infoList); + } + + @Test + public void testRegister() { + zkRegistryService.init(); + zkRegistryService.start(); + zkRegistryService.register(eventMeshRegisterInfo); + } + + @Test + public void testUnRegister() { + zkRegistryService.init(); + zkRegistryService.start(); + boolean register = zkRegistryService.register(eventMeshRegisterInfo); + + Assertions.assertTrue(register); + + boolean unRegister = zkRegistryService.unRegister(eventMeshUnRegisterInfo); + + Assertions.assertTrue(unRegister); + } +} diff --git a/eventmesh-meta/eventmesh-meta-zookeeper/src/test/resources/log4j.properties b/eventmesh-meta/eventmesh-meta-zookeeper/src/test/resources/log4j.properties new file mode 100644 index 0000000000..6a06772a50 --- /dev/null +++ b/eventmesh-meta/eventmesh-meta-zookeeper/src/test/resources/log4j.properties @@ -0,0 +1,32 @@ +# +# 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. +# + + + +log4j.rootLogger=info, stdout, R +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +# Pattern to output the caller's file name and line number. +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n +log4j.appender.R=org.apache.log4j.RollingFileAppender +log4j.appender.R.File=example.log +log4j.appender.R.MaxFileSize=100KB +# Keep one backup file +log4j.appender.R.MaxBackupIndex=5 +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n + diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle b/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle index c64ce2f79c..ddc5f43270 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/build.gradle @@ -19,10 +19,15 @@ dependencies { api project(":eventmesh-spi") implementation project(":eventmesh-common") + implementation 'io.opentelemetry:opentelemetry-api' - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-inline" +} - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' -} \ No newline at end of file diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/MetricsRegistry.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/MetricsRegistry.java index 6a1bf2ef09..b805ec518e 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/MetricsRegistry.java +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/MetricsRegistry.java @@ -21,13 +21,17 @@ import org.apache.eventmesh.spi.EventMeshExtensionType; import org.apache.eventmesh.spi.EventMeshSPI; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Collection; + /** - * The top-level interface of metrics registry, used to register different metrics. - * It should have multiple sub implementation, e.g. JVM, Prometheus, i.g. + * The top-level interface of metrics registry, used to register different metrics. It should have multiple sub implementation, e.g. JVM, Prometheus, + * i.g. * * @since 1.4.0 */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.METRICS) +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.METRICS) public interface MetricsRegistry { /** @@ -47,6 +51,17 @@ public interface MetricsRegistry { */ void register(Metric metric); + /** + * Register Metrics, if the metric is already exist, it will do nothing. + * + * @param metrics + */ + default void register(Collection metrics) { + if (CollectionUtils.isNotEmpty(metrics)) { + metrics.forEach(metric -> register(metric)); + } + } + /** * Remove a metric, if the metric is not exist, it will do nothing. * diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractMetric.java new file mode 100644 index 0000000000..59f1b09323 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractMetric.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +public abstract class AbstractMetric implements Metric { + + private InstrumentFurther further; + + private String metricName; + + public AbstractMetric(InstrumentFurther further, String metricName) { + this.further = further; + this.metricName = metricName; + } + + public AbstractMetric() { + + } + + @Override + public void setInstrumentFurther(InstrumentFurther further) { + this.further = further; + } + + @Override + public InstrumentFurther getInstrumentFurther() { + return this.further; + } + + @Override + public String getName() { + return metricName; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableDoubleMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableDoubleMetric.java new file mode 100644 index 0000000000..b0165863ca --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableDoubleMetric.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + + +import java.util.function.Supplier; + +public abstract class AbstractObservableDoubleMetric extends AbstractObservableMetric { + + private Supplier supplier; + + public AbstractObservableDoubleMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public AbstractObservableDoubleMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName); + this.supplier = supplier; + } + + public AbstractObservableDoubleMetric() { + + } + + public void supplier(Supplier supplier) { + this.supplier = supplier; + } + + @Override + public Supplier supplier() { + return supplier; + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableLongMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableLongMetric.java new file mode 100644 index 0000000000..bb8189329e --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableLongMetric.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + + +import java.util.function.Supplier; + +public abstract class AbstractObservableLongMetric extends AbstractObservableMetric { + + private Supplier supplier; + + public AbstractObservableLongMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public AbstractObservableLongMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName); + this.supplier = supplier; + } + + public AbstractObservableLongMetric() { + + } + + public void supplier(Supplier supplier) { + this.supplier = supplier; + } + + @Override + public Supplier supplier() { + return supplier; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableMetric.java new file mode 100644 index 0000000000..7c96969fbc --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractObservableMetric.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public abstract class AbstractObservableMetric extends AbstractMetric implements ObservableMetric { + + private Map attributes = new HashMap<>(32); + + public AbstractObservableMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public AbstractObservableMetric() { + + } + + @Override + public void put(String key, String value) { + this.attributes.put(key, value); + } + + @Override + public void putAll(Map attributes) { + if (Objects.isNull(attributes)) { + return; + } + this.attributes.putAll(attributes); + } + + @Override + public Map getAttributes() { + return this.attributes; + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractSyncMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractSyncMetric.java new file mode 100644 index 0000000000..d1ecbee53f --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/AbstractSyncMetric.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +public abstract class AbstractSyncMetric extends AbstractMetric implements SyncMetric { + + public AbstractSyncMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public AbstractSyncMetric() { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleCounterMetric.java new file mode 100644 index 0000000000..b8131184be --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleCounterMetric.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.DoubleCounter; + +public class DoubleCounterMetric extends AbstractSyncMetric { + + private DoubleCounter counter; + + public DoubleCounterMetric(InstrumentFurther further, String metricName, DoubleCounter counter) { + super(further, metricName); + this.counter = counter; + } + + public DoubleCounterMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public DoubleCounterMetric(String metricName) { + super(null, metricName); + } + + public DoubleCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.DOUBLE_COUNTER; + } + + @Override + public DoubleCounter getInstrument() { + return this.counter; + } + + @Override + public void setInstrument(DoubleCounter counter) { + this.counter = counter; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleHistogramMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleHistogramMetric.java new file mode 100644 index 0000000000..0f1c32d569 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleHistogramMetric.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.DoubleHistogram; + +public class DoubleHistogramMetric extends AbstractSyncMetric { + + private DoubleHistogram histogram; + + public DoubleHistogramMetric(InstrumentFurther further, String metricName, DoubleHistogram histogram) { + super(further, metricName); + this.histogram = histogram; + } + + public DoubleHistogramMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public DoubleHistogramMetric(String metricName) { + super(null, metricName); + } + + public DoubleHistogramMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.DOUBLE_HISTOGRAM; + } + + @Override + public DoubleHistogram getInstrument() { + return this.histogram; + } + + @Override + public void setInstrument(DoubleHistogram counter) { + this.histogram = counter; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleUpDownCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleUpDownCounterMetric.java new file mode 100644 index 0000000000..f617615be8 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/DoubleUpDownCounterMetric.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.DoubleUpDownCounter; + +public class DoubleUpDownCounterMetric extends AbstractSyncMetric { + + private DoubleUpDownCounter counter; + + public DoubleUpDownCounterMetric(InstrumentFurther further, String metricName, DoubleUpDownCounter counter) { + super(further, metricName); + this.counter = counter; + } + + public DoubleUpDownCounterMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public DoubleUpDownCounterMetric(String metricName) { + super(null, metricName); + } + + public DoubleUpDownCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.DOUBLE_UP_DOWN_COUNTER; + } + + @Override + public DoubleUpDownCounter getInstrument() { + return this.counter; + } + + @Override + public void setInstrument(DoubleUpDownCounter counter) { + this.counter = counter; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/HttpSummaryMetrics.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/HttpSummaryMetrics.java deleted file mode 100644 index c8c90f6c3c..0000000000 --- a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/HttpSummaryMetrics.java +++ /dev/null @@ -1,457 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.metrics.api.model; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.atomic.AtomicLong; - -import lombok.extern.slf4j.Slf4j; - -// todo: split this class -@Slf4j -public class HttpSummaryMetrics implements Metric { - - private static final int STATIC_PERIOD = 30 * 1000; - - public HttpSummaryMetrics(final ThreadPoolExecutor batchMsgExecutor, - final ThreadPoolExecutor sendMsgExecutor, - final ThreadPoolExecutor pushMsgExecutor, - final DelayQueue httpFailedQueue) { - this.batchMsgExecutor = batchMsgExecutor; - this.sendMsgExecutor = sendMsgExecutor; - this.pushMsgExecutor = pushMsgExecutor; - this.httpFailedQueue = httpFailedQueue; - } - - public static final String EVENTMESH_MONITOR_FORMAT_HTTP = "{\"maxHTTPTPS\":\"%.1f\",\"avgHTTPTPS\":\"%.1f\"," - //EVENTMESH tps related to accepting external http requests - + "\"maxHTTPCOST\":\"%s\",\"avgHTTPCOST\":\"%.1f\",\"avgHTTPBodyDecodeCost\":\"%.1f\", " - + "\"httpDiscard\":\"%s\"}"; - - private float wholeCost = 0f; - - private AtomicLong wholeRequestNum = new AtomicLong(0); - - //cumulative value - private AtomicLong httpDiscard = new AtomicLong(0); - - private AtomicLong maxCost = new AtomicLong(0); - - private AtomicLong httpRequestPerSecond = new AtomicLong(0); - - private LinkedList httpRequestTPSSnapshots = new LinkedList<>(); - - public float avgHTTPCost() { - float cost = (wholeRequestNum.longValue() == 0L) ? 0f : wholeCost / wholeRequestNum.longValue(); - return cost; - } - - public long maxHTTPCost() { - long cost = maxCost.longValue(); - return cost; - } - - public long getHttpDiscard() { - return httpDiscard.longValue(); - } - - public void recordHTTPRequest() { - httpRequestPerSecond.incrementAndGet(); - } - - public void recordHTTPDiscard() { - httpDiscard.incrementAndGet(); - } - - public void snapshotHTTPTPS() { - Integer tps = httpRequestPerSecond.intValue(); - httpRequestTPSSnapshots.add(tps); - httpRequestPerSecond.set(0); - if (httpRequestTPSSnapshots.size() > STATIC_PERIOD / 1000) { - httpRequestTPSSnapshots.removeFirst(); - } - } - - public float maxHTTPTPS() { - float tps = Collections.max(httpRequestTPSSnapshots); - return tps; - } - - public float avgHTTPTPS() { - float tps = avg(httpRequestTPSSnapshots); - return tps; - } - - public void recordHTTPReqResTimeCost(long cost) { - wholeRequestNum.incrementAndGet(); - wholeCost = wholeCost + cost; - if (cost > maxCost.longValue()) { - maxCost.set(cost); - } - } - - public void httpStatInfoClear() { - wholeRequestNum.set(0L); - wholeCost = 0f; - maxCost.set(0L); - httpDecodeNum.set(0L); - httpDecodeTimeCost = 0f; - } - - private float httpDecodeTimeCost = 0f; - - private AtomicLong httpDecodeNum = new AtomicLong(0); - - public void recordDecodeTimeCost(long cost) { - httpDecodeNum.incrementAndGet(); - httpDecodeTimeCost = httpDecodeTimeCost + cost; - } - - public float avgHTTPBodyDecodeCost() { - float cost = (httpDecodeNum.longValue() == 0L) ? 0f : httpDecodeTimeCost / httpDecodeNum.longValue(); - return cost; - } - - - ////////////////////////////////////////////////////////////////////////// - public static final String EVENTMESH_MONITOR_FORMAT_BATCHSENDMSG = "{\"maxBatchSendMsgTPS\":\"%.1f\",\"avgBatchSendMsgTPS\":\"%.1f\"," - + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.2f\", \"discard\":\"%s\"}"; - - private AtomicLong sendBatchMsgNumPerSecond = new AtomicLong(0); - - private AtomicLong sendBatchMsgNumSum = new AtomicLong(0); - - private AtomicLong sendBatchMsgFailNumSum = new AtomicLong(0); - - // This is a cumulative value - private AtomicLong sendBatchMsgDiscardNumSum = new AtomicLong(0); - - public void recordSendBatchMsgDiscard(long delta) { - sendBatchMsgDiscardNumSum.addAndGet(delta); - } - - private LinkedList sendBatchMsgTPSSnapshots = new LinkedList(); - - public void snapshotSendBatchMsgTPS() { - Integer tps = sendBatchMsgNumPerSecond.intValue(); - sendBatchMsgTPSSnapshots.add(tps); - sendBatchMsgNumPerSecond.set(0); - if (sendBatchMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { - sendBatchMsgTPSSnapshots.removeFirst(); - } - } - - public float maxSendBatchMsgTPS() { - float tps = Collections.max(sendBatchMsgTPSSnapshots); - return tps; - } - - public float avgSendBatchMsgTPS() { - float tps = avg(sendBatchMsgTPSSnapshots); - return tps; - } - - public void recordSendBatchMsg(long delta) { - sendBatchMsgNumPerSecond.addAndGet(delta); - sendBatchMsgNumSum.addAndGet(delta); - } - - public void recordSendBatchMsgFailed(long delta) { - sendBatchMsgFailNumSum.getAndAdd(delta); - } - - public long getSendBatchMsgNumSum() { - return sendBatchMsgNumSum.longValue(); - } - - public long getSendBatchMsgFailNumSum() { - return sendBatchMsgFailNumSum.longValue(); - } - - public float getSendBatchMsgFailRate() { - return (sendBatchMsgNumSum.longValue() == 0L) ? 0f : sendBatchMsgFailNumSum.floatValue() / sendBatchMsgNumSum.longValue(); - } - - public void cleanSendBatchStat() { - sendBatchMsgNumSum.set(0L); - sendBatchMsgFailNumSum.set(0L); - } - - public long getSendBatchMsgDiscardNumSum() { - return sendBatchMsgDiscardNumSum.longValue(); - } - - ////////////////////////////////////////////////////////////////////////// - public static final String EVENTMESH_MONITOR_FORMAT_SENDMSG = "{\"maxSendMsgTPS\":\"%.1f\",\"avgSendMsgTPS\":\"%.1f\"," - + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.2f\", \"replyMsg\":\"%s\", \"replyFail\":\"%s\"}"; - - private AtomicLong sendMsgNumSum = new AtomicLong(0); - - private AtomicLong sendMsgFailNumSum = new AtomicLong(0); - - private AtomicLong replyMsgNumSum = new AtomicLong(0); - - private AtomicLong replyMsgFailNumSum = new AtomicLong(0); - - private AtomicLong sendMsgNumPerSecond = new AtomicLong(0); - - private LinkedList sendMsgTPSSnapshots = new LinkedList(); - - public void snapshotSendMsgTPS() { - Integer tps = sendMsgNumPerSecond.intValue(); - sendMsgTPSSnapshots.add(tps); - sendMsgNumPerSecond.set(0); - if (sendMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { - sendMsgTPSSnapshots.removeFirst(); - } - } - - public float maxSendMsgTPS() { - float tps = Collections.max(sendMsgTPSSnapshots); - return tps; - } - - public float avgSendMsgTPS() { - float tps = avg(sendMsgTPSSnapshots); - return tps; - } - - public void recordSendMsg() { - sendMsgNumPerSecond.incrementAndGet(); - sendMsgNumSum.incrementAndGet(); - } - - public void recordReplyMsg() { - replyMsgNumSum.incrementAndGet(); - } - - public void recordReplyMsgFailed() { - replyMsgFailNumSum.incrementAndGet(); - } - - public long getReplyMsgNumSum() { - return replyMsgNumSum.longValue(); - } - - public long getReplyMsgFailNumSum() { - return replyMsgFailNumSum.longValue(); - } - - public long getSendMsgNumSum() { - return sendMsgNumSum.longValue(); - } - - public long getSendMsgFailNumSum() { - return sendMsgFailNumSum.longValue(); - } - - public float getSendMsgFailRate() { - return (sendMsgNumSum.longValue() == 0L) ? 0f : sendMsgFailNumSum.floatValue() / sendMsgNumSum.longValue(); - } - - public void recordSendMsgFailed() { - sendMsgFailNumSum.incrementAndGet(); - } - - public void cleanSendMsgStat() { - sendMsgNumSum.set(0L); - replyMsgNumSum.set(0L); - sendMsgFailNumSum.set(0L); - replyMsgFailNumSum.set(0L); - } - - //////////////////////////////////////////////////////////////////////////// - public static final String EVENTMESH_MONITOR_FORMAT_PUSHMSG = "{\"maxPushMsgTPS\":\"%.1f\",\"avgPushMsgTPS\":\"%.1f\"," - + " \"sum\":\"%s\", \"sumFail\":\"%s\", \"sumFailRate\":\"%.1f\", \"maxClientLatency\":\"%.1f\", \"avgClientLatency\":\"%.1f\"}"; - - private float wholePushCost = 0f; - - private AtomicLong wholePushRequestNum = new AtomicLong(0); - - private AtomicLong maxHttpPushLatency = new AtomicLong(0); - - private AtomicLong pushMsgNumPerSecond = new AtomicLong(0); - - private LinkedList pushMsgTPSSnapshots = new LinkedList(); - - private AtomicLong httpPushMsgNumSum = new AtomicLong(0); - - private AtomicLong httpPushFailNumSum = new AtomicLong(0); - - public void snapshotPushMsgTPS() { - Integer tps = pushMsgNumPerSecond.intValue(); - pushMsgTPSSnapshots.add(tps); - pushMsgNumPerSecond.set(0); - if (pushMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { - pushMsgTPSSnapshots.removeFirst(); - } - } - - public void recordHTTPPushTimeCost(long cost) { - wholePushRequestNum.incrementAndGet(); - wholePushCost = wholePushCost + cost; - if (cost > maxHttpPushLatency.longValue()) { - maxHttpPushLatency.set(cost); - } - } - - public float avgHTTPPushLatency() { - return (wholePushRequestNum.longValue() == 0L) ? 0f : wholePushCost / wholePushRequestNum.longValue(); - } - - public float maxHTTPPushLatency() { - return maxHttpPushLatency.floatValue(); - } - - public float maxPushMsgTPS() { - float tps = Collections.max(pushMsgTPSSnapshots); - return tps; - } - - public float avgPushMsgTPS() { - float tps = avg(pushMsgTPSSnapshots); - return tps; - } - - public void recordPushMsg() { - pushMsgNumPerSecond.incrementAndGet(); - httpPushMsgNumSum.incrementAndGet(); - } - - public long getHttpPushMsgNumSum() { - return httpPushMsgNumSum.longValue(); - } - - public long getHttpPushFailNumSum() { - return httpPushFailNumSum.longValue(); - } - - public float getHttpPushMsgFailRate() { - return (httpPushMsgNumSum.longValue() == 0L) ? 0f : httpPushFailNumSum.floatValue() / httpPushMsgNumSum.longValue(); - } - - public void recordHttpPushMsgFailed() { - sendMsgFailNumSum.incrementAndGet(); - } - - public void cleanHttpPushMsgStat() { - httpPushFailNumSum.set(0L); - httpPushMsgNumSum.set(0L); - wholeRequestNum.set(0L); - wholeCost = 0f; - maxCost.set(0L); - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////// - public static final String EVENTMESH_MONITOR_FORMAT_BLOCKQ = "{\"batchMsgQ\":\"%s\",\"sendMsgQ\":\"%s\"," - + "\"pushMsgQ\":\"%s\",\"httpRetryQ\":\"%s\"}"; - - /////////////////////////////////////////////////////////////////////////// - public static final String EVENTMESH_MONITOR_FORMAT_MQ_CLIENT = "{\"batchAvgSend2MQCost\":\"%.1f\", " - + "\"avgSend2MQCost\":\"%.1f\", \"avgReply2MQCost\":\"%.1f\"}"; - - private float batchSend2MQWholeCost = 0f; - - private AtomicLong batchSend2MQNum = new AtomicLong(0); - - private float send2MQWholeCost = 0f; - - private AtomicLong send2MQNum = new AtomicLong(0); - - private float reply2MQWholeCost = 0f; - - private AtomicLong reply2MQNum = new AtomicLong(0); - - public void recordBatchSendMsgCost(long cost) { - batchSend2MQNum.incrementAndGet(); - batchSend2MQWholeCost = batchSend2MQWholeCost + cost; - } - - public float avgBatchSendMsgCost() { - float cost = (batchSend2MQNum.intValue() == 0) ? 0f : batchSend2MQWholeCost / batchSend2MQNum.intValue(); - return cost; - } - - public void recordSendMsgCost(long cost) { - send2MQNum.incrementAndGet(); - send2MQWholeCost = send2MQWholeCost + cost; - } - - public float avgSendMsgCost() { - float cost = (send2MQNum.intValue() == 0) ? 0f : send2MQWholeCost / send2MQNum.intValue(); - return cost; - } - - public void recordReplyMsgCost(long cost) { - reply2MQNum.incrementAndGet(); - reply2MQWholeCost = reply2MQWholeCost + cost; - } - - public float avgReplyMsgCost() { - float cost = (reply2MQNum.intValue() == 0) ? 0f : reply2MQWholeCost / reply2MQNum.intValue(); - return cost; - } - - public void send2MQStatInfoClear() { - batchSend2MQWholeCost = 0f; - batchSend2MQNum.set(0L); - send2MQWholeCost = 0f; - send2MQNum.set(0L); - reply2MQWholeCost = 0f; - reply2MQNum.set(0L); - } - - // execute metrics - private final ThreadPoolExecutor batchMsgExecutor; - - private final ThreadPoolExecutor sendMsgExecutor; - - private final ThreadPoolExecutor pushMsgExecutor; - - private final DelayQueue httpFailedQueue; - - public int getBatchMsgQueueSize() { - return batchMsgExecutor.getQueue().size(); - } - - public int getSendMsgQueueSize() { - return sendMsgExecutor.getQueue().size(); - } - - public int getPushMsgQueueSize() { - return pushMsgExecutor.getQueue().size(); - } - - public int getHttpRetryQueueSize() { - return httpFailedQueue.size(); - } - - - private float avg(LinkedList linkedList) { - if (linkedList.isEmpty()) { - return 0.0f; - } - - int sum = linkedList.stream().reduce(Integer::sum).get(); - return (float) sum / linkedList.size(); - } - -} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/InstrumentFurther.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/InstrumentFurther.java new file mode 100644 index 0000000000..c309ff6719 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/InstrumentFurther.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Data; + +/** + * Represents an instrument with a name, description, unit, and additional properties. + */ +@Data +public class InstrumentFurther { + + public static final String INSTRUMENT_VIEW = "instrument_view"; + + private String name; + + private String description; + + private String unit; + + private Map ext = new HashMap<>(); + + public void putExt(String key, Object value) { + ext.put(key, value); + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/InstrumentType.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/InstrumentType.java new file mode 100644 index 0000000000..b0511d37de --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/InstrumentType.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.api.metrics.ObservableDoubleCounter; +import io.opentelemetry.api.metrics.ObservableDoubleGauge; +import io.opentelemetry.api.metrics.ObservableDoubleUpDownCounter; +import io.opentelemetry.api.metrics.ObservableLongCounter; +import io.opentelemetry.api.metrics.ObservableLongGauge; +import io.opentelemetry.api.metrics.ObservableLongUpDownCounter; + +public enum InstrumentType { + LONG_COUNTER(LongCounter.class), + DOUBLE_COUNTER(DoubleCounter.class), + LONG_UP_DOWN_COUNTER(LongUpDownCounter.class), + DOUBLE_UP_DOWN_COUNTER(DoubleUpDownCounter.class), + OBSERVABLE_LONG_COUNTER(ObservableLongCounter.class), + OBSERVABLE_LONG_UP_DOWN_COUNTER(ObservableLongUpDownCounter.class), + OBSERVABLE_DOUBLE_COUNTER(ObservableDoubleCounter.class), + OBSERVABLE_DOUBLE_UP_DOWN_COUNTER(ObservableDoubleUpDownCounter.class), + OBSERVABLE_LONG_GAUGE(ObservableLongGauge.class), + OBSERVABLE_DOUBLE_GAUGE(ObservableDoubleGauge.class), + LONG_HISTOGRAM(LongHistogram.class), + DOUBLE_HISTOGRAM(DoubleHistogram.class); + + + private Class type; + + InstrumentType(Class type) { + this.type = type; + } + + public Class getType() { + return this.type; + } +} \ No newline at end of file diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongCounterMetric.java new file mode 100644 index 0000000000..6c8a292c61 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongCounterMetric.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.LongCounter; + +public class LongCounterMetric extends AbstractSyncMetric { + + private LongCounter counter = new NoopLongCounter(); + + public LongCounterMetric(InstrumentFurther further, String metricName, LongCounter counter) { + super(further, metricName); + this.counter = counter; + } + + public LongCounterMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public LongCounterMetric(String metricName) { + super(null, metricName); + } + + public LongCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.LONG_COUNTER; + } + + @Override + public LongCounter getInstrument() { + return this.counter; + } + + @Override + public void setInstrument(LongCounter counter) { + this.counter = counter; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongHistogramMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongHistogramMetric.java new file mode 100644 index 0000000000..af6deb6a31 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongHistogramMetric.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.LongHistogram; + +public class LongHistogramMetric extends AbstractSyncMetric { + + private LongHistogram histogram; + + public LongHistogramMetric(InstrumentFurther further, String metricName, LongHistogram histogram) { + super(further, metricName); + this.histogram = histogram; + } + + public LongHistogramMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public LongHistogramMetric(String metricName) { + super(null, metricName); + } + + public LongHistogramMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.LONG_HISTOGRAM; + } + + @Override + public LongHistogram getInstrument() { + return this.histogram; + } + + @Override + public void setInstrument(LongHistogram counter) { + this.histogram = counter; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongUpDownCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongUpDownCounterMetric.java new file mode 100644 index 0000000000..5cf9b7dd6e --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/LongUpDownCounterMetric.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.metrics.LongUpDownCounter; + +public class LongUpDownCounterMetric extends AbstractSyncMetric { + + private LongUpDownCounter counter; + + public LongUpDownCounterMetric(InstrumentFurther further, String metricName, LongUpDownCounter counter) { + super(further, metricName); + this.counter = counter; + } + + public LongUpDownCounterMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public LongUpDownCounterMetric(String metricName) { + super(null, metricName); + } + + public LongUpDownCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.LONG_UP_DOWN_COUNTER; + } + + @Override + public LongUpDownCounter getInstrument() { + return this.counter; + } + + @Override + public void setInstrument(LongUpDownCounter counter) { + this.counter = counter; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/Metric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/Metric.java index ab8903ba62..0ea918bfbf 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/Metric.java +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/Metric.java @@ -21,4 +21,32 @@ * Top-level metric, all metrics should implement this interface. */ public interface Metric { + + /** + * Sets the instrument further. + * + * @param further the instrument further to be set + */ + void setInstrumentFurther(InstrumentFurther further); + + /** + * Gets the instrument further. + * + * @return the instrument further + */ + InstrumentFurther getInstrumentFurther(); + + /** + * Gets the name of the metric. + * + * @return the name of the metric + */ + String getName(); + + /** + * Gets the type of the instrument. + * + * @return the type of the instrument + */ + InstrumentType getInstrumentType(); } diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleCounter.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleCounter.java new file mode 100644 index 0000000000..69cb054934 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleCounter.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.context.Context; + +public class NoopDoubleCounter implements DoubleCounter { + + /** + * Records a value. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. MUST be non-negative. + */ + @Override + public void add(double value) { + + } + + /** + * Records a value with a set of attributes. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + */ + @Override + public void add(double value, Attributes attributes) { + + } + + /** + * Records a value with a set of attributes. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + @Override + public void add(double value, Attributes attributes, Context context) { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleHistogram.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleHistogram.java new file mode 100644 index 0000000000..1dd2db3624 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleHistogram.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.context.Context; + +public class NoopDoubleHistogram implements DoubleHistogram { + + /** + * Records a value. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The amount of the measurement. MUST be non-negative. + */ + @Override + public void record(double value) { + + } + + /** + * Records a value with a set of attributes. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The amount of the measurement. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + */ + @Override + public void record(double value, Attributes attributes) { + + } + + /** + * Records a value with a set of attributes. + * + * @param value The amount of the measurement. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + @Override + public void record(double value, Attributes attributes, Context context) { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleUpDownCounter.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleUpDownCounter.java new file mode 100644 index 0000000000..ee18d0f21f --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopDoubleUpDownCounter.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.context.Context; + +public class NoopDoubleUpDownCounter implements DoubleUpDownCounter { + + /** + * Records a value. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. May be positive, negative or zero. + */ + @Override + public void add(double value) { + + } + + /** + * Records a value with a set of attributes. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. May be positive, negative or zero. + * @param attributes A set of attributes to associate with the value. + */ + @Override + public void add(double value, Attributes attributes) { + + } + + /** + * Records a value with a set of attributes. + * + * @param value The increment amount. May be positive, negative or zero. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + @Override + public void add(double value, Attributes attributes, Context context) { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongCounter.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongCounter.java new file mode 100644 index 0000000000..d22959a42e --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongCounter.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.context.Context; + +public class NoopLongCounter implements LongCounter { + + /** + * Records a value. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. MUST be non-negative. + */ + @Override + public void add(long value) { + + } + + /** + * Records a value with a set of attributes. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + */ + @Override + public void add(long value, Attributes attributes) { + + } + + /** + * Records a value with a set of attributes. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + @Override + public void add(long value, Attributes attributes, Context context) { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongHistogram.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongHistogram.java new file mode 100644 index 0000000000..605a33b771 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongHistogram.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.context.Context; + +public class NoopLongHistogram implements LongHistogram { + + /** + * Records a value. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The amount of the measurement. MUST be non-negative. + */ + @Override + public void record(long value) { + + } + + /** + * Records a value with a set of attributes. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The amount of the measurement. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + */ + @Override + public void record(long value, Attributes attributes) { + + } + + /** + * Records a value with a set of attributes. + * + * @param value The amount of the measurement. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + @Override + public void record(long value, Attributes attributes, Context context) { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongUpDownCounter.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongUpDownCounter.java new file mode 100644 index 0000000000..b25b1e1fdc --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/NoopLongUpDownCounter.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.context.Context; + +public class NoopLongUpDownCounter implements LongUpDownCounter { + + /** + * Records a value. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. May be positive, negative or zero. + */ + @Override + public void add(long value) { + + } + + /** + * Record a value with a set of attributes. + * + *

Note: This may use {@code Context.current()} to pull the context associated with this + * measurement. + * + * @param value The increment amount. May be positive, negative or zero. + * @param attributes A set of attributes to associate with the value. + */ + @Override + public void add(long value, Attributes attributes) { + + } + + /** + * Records a value with a set of attributes. + * + * @param value The increment amount. May be positive, negative or zero. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + @Override + public void add(long value, Attributes attributes, Context context) { + + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleCounterMetric.java new file mode 100644 index 0000000000..372fb151c1 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleCounterMetric.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.function.Supplier; + +public class ObservableDoubleCounterMetric extends AbstractObservableDoubleMetric { + + public ObservableDoubleCounterMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName, supplier); + } + + public ObservableDoubleCounterMetric(InstrumentFurther further, String metricName) { + super(further, metricName); + } + + public ObservableDoubleCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.OBSERVABLE_DOUBLE_COUNTER; + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleGaugeMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleGaugeMetric.java new file mode 100644 index 0000000000..ff1345ccc8 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleGaugeMetric.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.function.Supplier; + +public class ObservableDoubleGaugeMetric extends AbstractObservableDoubleMetric { + + public ObservableDoubleGaugeMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName, supplier); + } + + public ObservableDoubleGaugeMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.OBSERVABLE_DOUBLE_GAUGE; + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleUpDownCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleUpDownCounterMetric.java new file mode 100644 index 0000000000..95dc8de120 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableDoubleUpDownCounterMetric.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.function.Supplier; + +public class ObservableDoubleUpDownCounterMetric extends AbstractObservableDoubleMetric { + + + public ObservableDoubleUpDownCounterMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName, supplier); + } + + public ObservableDoubleUpDownCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.OBSERVABLE_DOUBLE_UP_DOWN_COUNTER; + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongCounterMetric.java new file mode 100644 index 0000000000..ca8e3227b8 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongCounterMetric.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.function.Supplier; + +public class ObservableLongCounterMetric extends AbstractObservableLongMetric { + + public ObservableLongCounterMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName, supplier); + } + + public ObservableLongCounterMetric(String metricName) { + super(null, metricName); + } + + public ObservableLongCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.OBSERVABLE_LONG_COUNTER; + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongGaugeMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongGaugeMetric.java new file mode 100644 index 0000000000..206398474d --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongGaugeMetric.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.function.Supplier; + +public class ObservableLongGaugeMetric extends AbstractObservableLongMetric { + + public ObservableLongGaugeMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName, supplier); + } + + public ObservableLongGaugeMetric(String metricName) { + super(null, metricName); + } + + public ObservableLongGaugeMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.OBSERVABLE_LONG_GAUGE; + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongUpDownCounterMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongUpDownCounterMetric.java new file mode 100644 index 0000000000..f00075ff27 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableLongUpDownCounterMetric.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + + +import java.util.function.Supplier; + +public class ObservableLongUpDownCounterMetric extends AbstractObservableLongMetric { + + public ObservableLongUpDownCounterMetric(InstrumentFurther further, String metricName, Supplier supplier) { + super(further, metricName, supplier); + } + + public ObservableLongUpDownCounterMetric() { + super(null, null); + } + + @Override + public InstrumentType getInstrumentType() { + return InstrumentType.OBSERVABLE_LONG_UP_DOWN_COUNTER; + } + + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableMetric.java new file mode 100644 index 0000000000..6e53035627 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/ObservableMetric.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +import java.util.Map; +import java.util.function.Supplier; + +/** + * Observable metric interface, all observable(asynchronization) metrics should implement this interface. + */ +public interface ObservableMetric extends Metric { + + /** + * Puts a key-value pair into the metric. + * + * @param key the key to put + * @param value the value to put + */ + void put(Key key, Value value); + + /** + * Puts all key-value pairs from a map into the metric. + * + * @param attributes the map containing key-value pairs + */ + void putAll(Map attributes); + + /** + * Retrieves all attributes of the metric. + * + * @return a map containing all attributes + */ + Map getAttributes(); + + /** + * Retrieves the supplier of the instrument associated with the metric. + * + * @return the supplier of the instrument + */ + Supplier supplier(); +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/SyncMetric.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/SyncMetric.java new file mode 100644 index 0000000000..90948a07cd --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/SyncMetric.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api.model; + +/** + * synchronization metric, all synchronization metrics should implement this interface. + */ +public interface SyncMetric extends Metric { + + Instrument getInstrument(); + + void setInstrument(Instrument instrument); +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/TcpSummaryMetrics.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/TcpSummaryMetrics.java deleted file mode 100644 index 674e5425b0..0000000000 --- a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/main/java/org/apache/eventmesh/metrics/api/model/TcpSummaryMetrics.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.metrics.api.model; - -import java.util.concurrent.atomic.AtomicInteger; - -import lombok.Data; - -@Data -public class TcpSummaryMetrics implements Metric { - private final AtomicInteger client2eventMeshMsgNum; - private final AtomicInteger eventMesh2mqMsgNum; - private final AtomicInteger mq2eventMeshMsgNum; - private final AtomicInteger eventMesh2clientMsgNum; - - private int client2eventMeshTPS; - private int eventMesh2clientTPS; - private int eventMesh2mqTPS; - private int mq2eventMeshTPS; - private int subTopicNum; - - private int allConnections; - - private int retrySize; - - public TcpSummaryMetrics() { - this.client2eventMeshMsgNum = new AtomicInteger(0); - this.eventMesh2mqMsgNum = new AtomicInteger(0); - this.mq2eventMeshMsgNum = new AtomicInteger(0); - this.eventMesh2clientMsgNum = new AtomicInteger(0); - } - - public int client2eventMeshMsgNum() { - return client2eventMeshMsgNum.get(); - } - - public int eventMesh2mqMsgNum() { - return eventMesh2mqMsgNum.get(); - } - - public int mq2eventMeshMsgNum() { - return mq2eventMeshMsgNum.get(); - } - - public int eventMesh2clientMsgNum() { - return eventMesh2clientMsgNum.get(); - } - - public int getClient2eventMeshTPS() { - return client2eventMeshTPS; - } - - public void setClient2eventMeshTPS(int client2eventMeshTPS) { - this.client2eventMeshTPS = client2eventMeshTPS; - } - - public int getEventMesh2clientTPS() { - return eventMesh2clientTPS; - } - - public void setEventMesh2clientTPS(int eventMesh2clientTPS) { - this.eventMesh2clientTPS = eventMesh2clientTPS; - } - - public int getEventMesh2mqTPS() { - return eventMesh2mqTPS; - } - - public void setEventMesh2mqTPS(int eventMesh2mqTPS) { - this.eventMesh2mqTPS = eventMesh2mqTPS; - } - - public int getMq2eventMeshTPS() { - return mq2eventMeshTPS; - } - - public void setMq2eventMeshTPS(int mq2eventMeshTPS) { - this.mq2eventMeshTPS = mq2eventMeshTPS; - } - - public int getAllTPS() { - return client2eventMeshTPS + eventMesh2clientTPS; - } - - public int getSubTopicNum() { - return subTopicNum; - } - - public void setSubTopicNum(int subTopicNum) { - this.subTopicNum = subTopicNum; - } - - public int getAllConnections() { - return allConnections; - } - - public void setAllConnections(int allConnections) { - this.allConnections = allConnections; - } - - public void setRetrySize(int retrySize) { - this.retrySize = retrySize; - } - - public int getRetrySize() { - return retrySize; - } -} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-api/src/test/java/org/apache/eventmesh/metrics/api/MetricsPluginFactoryTest.java b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/test/java/org/apache/eventmesh/metrics/api/MetricsPluginFactoryTest.java new file mode 100644 index 0000000000..16bb8c86d3 --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-api/src/test/java/org/apache/eventmesh/metrics/api/MetricsPluginFactoryTest.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.api; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class MetricsPluginFactoryTest { + + @Test + public void testGetMetricsRegistry_throwException() { + Exception exception = Assertions.assertThrows(NullPointerException.class, () -> MetricsPluginFactory.getMetricsRegistry("security")); + Assertions.assertTrue(exception.getMessage().contains("is not supported")); + } +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/build.gradle b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/build.gradle index 2257341b38..48c3430294 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/build.gradle +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/build.gradle @@ -22,17 +22,20 @@ dependencies { implementation 'org.apache.commons:commons-lang3' implementation 'com.google.guava:guava' - // todo:Can we remove some dependency? - implementation 'io.opentelemetry:opentelemetry-api' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-sdk-metrics' implementation 'io.opentelemetry:opentelemetry-exporter-prometheus' - implementation 'io.prometheus:simpleclient' - implementation 'io.prometheus:simpleclient_httpserver' + implementation 'io.opentelemetry:opentelemetry-semconv' - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' -} \ No newline at end of file + testImplementation "org.mockito:mockito-core" + testImplementation "org.assertj:assertj-core" + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/OpenTelemetryPrometheusManager.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/OpenTelemetryPrometheusManager.java new file mode 100644 index 0000000000..248ce41fde --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/OpenTelemetryPrometheusManager.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.prometheus; + +import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME; + +import org.apache.commons.lang3.StringUtils; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; +import io.opentelemetry.sdk.resources.Resource; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class OpenTelemetryPrometheusManager { + + public static OpenTelemetry initOpenTelemetry(String host, int prometheusExportPort) { + if (StringUtils.isBlank(host)) { + host = "0.0.0.0"; + } + Resource resource = Resource.getDefault().merge(Resource.builder().put(SERVICE_NAME, "EventMeshPrometheusExporter").build()); + SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder(); + //register view for instrument + PrometheusMetricsRegistryManager.getMetricsView().forEach(pair -> meterProviderBuilder.registerView(pair.getLeft(), pair.getRight())); + OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder().setMeterProvider(meterProviderBuilder.setResource(resource) + .registerMetricReader(PrometheusHttpServer.builder().setHost(host).setPort(prometheusExportPort).build()).build()) + .buildAndRegisterGlobal(); + return openTelemetrySdk; + + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistry.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistry.java index d96a07b9ee..8516ffbd42 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistry.java +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistry.java @@ -17,71 +17,73 @@ package org.apache.eventmesh.metrics.prometheus; +import org.apache.eventmesh.common.config.Config; import org.apache.eventmesh.metrics.api.MetricsRegistry; -import org.apache.eventmesh.metrics.api.model.HttpSummaryMetrics; import org.apache.eventmesh.metrics.api.model.Metric; -import org.apache.eventmesh.metrics.api.model.TcpSummaryMetrics; import org.apache.eventmesh.metrics.prometheus.config.PrometheusConfiguration; -import org.apache.eventmesh.metrics.prometheus.metrics.PrometheusHttpExporter; -import org.apache.eventmesh.metrics.prometheus.metrics.PrometheusTcpExporter; -import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; -import io.opentelemetry.exporter.prometheus.PrometheusCollector; -import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.prometheus.client.exporter.HTTPServer; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.sdk.OpenTelemetrySdk; import lombok.extern.slf4j.Slf4j; @Slf4j +@Config(field = "prometheusConfiguration") public class PrometheusMetricsRegistry implements MetricsRegistry { - private volatile HTTPServer prometheusHttpServer; + private final AtomicBoolean started = new AtomicBoolean(false); + + private OpenTelemetry openTelemetry; + + /** + * Unified configuration class corresponding to prometheus.properties + */ + private PrometheusConfiguration prometheusConfiguration; @Override public void start() { - if (prometheusHttpServer == null) { - synchronized (PrometheusMetricsRegistry.class) { - if (prometheusHttpServer == null) { - SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal(); - PrometheusCollector - .builder().setMetricProducer(sdkMeterProvider).buildAndRegister(); - int port = PrometheusConfiguration.getEventMeshPrometheusPort(); - try { - //Use the daemon thread to start an HTTP server to serve the default Prometheus registry. - prometheusHttpServer = new HTTPServer(port, true); - } catch (IOException e) { - log.error("failed to start prometheus server, port: {} due to {}", port, e.getMessage()); - } - } - } + + if (!started.compareAndSet(false, true)) { + return; } + try { + this.prometheusConfiguration = Objects.requireNonNull(this.prometheusConfiguration, "prometheusConfiguration can't be null!"); + String eventMeshPrometheusExportHost = prometheusConfiguration.getEventMeshPrometheusExportHost(); + int eventMeshPrometheusPort = prometheusConfiguration.getEventMeshPrometheusPort(); + this.openTelemetry = OpenTelemetryPrometheusManager.initOpenTelemetry(eventMeshPrometheusExportHost, eventMeshPrometheusPort); + PrometheusMetricsRegistryManager.createMetric(this.openTelemetry); + } catch (Exception e) { + log.error("failed to start prometheus export, Host: {}:{} due to {}", prometheusConfiguration.getEventMeshPrometheusExportHost(), + prometheusConfiguration.getEventMeshPrometheusPort(), e.getMessage()); + } } @Override public void showdown() { - if (prometheusHttpServer != null) { - prometheusHttpServer.stop(); + if (this.openTelemetry instanceof OpenTelemetrySdk) { + + try (OpenTelemetrySdk ignored = (OpenTelemetrySdk) this.openTelemetry) { + //OpenTelemetrySdk will call close auto + } } + } @Override public void register(Metric metric) { - if (metric == null) { - throw new IllegalArgumentException("Metric cannot be null"); - } - if (metric instanceof HttpSummaryMetrics) { - PrometheusHttpExporter.export("apache-eventmesh", (HttpSummaryMetrics) metric); - } - - if (metric instanceof TcpSummaryMetrics) { - PrometheusTcpExporter.export("apache-eventmesh", (TcpSummaryMetrics) metric); - } + PrometheusMetricsRegistryManager.registerMetric(metric); } @Override public void unRegister(Metric metric) { // todo: need to split the current metrics } + + public PrometheusConfiguration getClientConfiguration() { + return this.prometheusConfiguration; + } } diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistryManager.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistryManager.java new file mode 100644 index 0000000000..7d4d13c9ec --- /dev/null +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/PrometheusMetricsRegistryManager.java @@ -0,0 +1,278 @@ +/* + * 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. + */ + +package org.apache.eventmesh.metrics.prometheus; + +import org.apache.eventmesh.common.Pair; +import org.apache.eventmesh.metrics.api.model.InstrumentFurther; +import org.apache.eventmesh.metrics.api.model.InstrumentType; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.metrics.api.model.ObservableMetric; +import org.apache.eventmesh.metrics.api.model.SyncMetric; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.sdk.metrics.InstrumentSelector; +import io.opentelemetry.sdk.metrics.View; + +import lombok.experimental.UtilityClass; + +/** + * Registering and handling Prometheus metrics. + */ +@UtilityClass +public class PrometheusMetricsRegistryManager { + + private static final Map meterCache = new ConcurrentHashMap<>(32); + + private static final Map> metricCache = new ConcurrentHashMap<>(16); + + /** + * Registers a metric in the metric cache. + * + * @param metric The metric to register. + */ + public static void registerMetric(final Metric metric) { + Set metrics = metricCache.computeIfAbsent(metric.getName(), (k) -> new HashSet<>()); + metrics.add(metric); + } + + /** + * Retrieves the metrics associated with a given metric name. + * + * @param metricName The name of the metric. + * @return The set of metrics associated with the metric name. + */ + protected static Set getMetrics(final String metricName) { + return metricCache.get(metricName); + } + + /** + * Creates and associates metrics with a Prometheus meter using the provided OpenTelemetry instance. + * + * @param openTelemetry The OpenTelemetry instance. + */ + public static void createMetric(final OpenTelemetry openTelemetry) { + + metricCache.values().stream().flatMap(metricSet -> metricSet.stream()).forEach(metric -> { + Meter meter = meterCache.computeIfAbsent(metric.getName(), (meterName) -> openTelemetry.getMeter(meterName)); + InstrumentFurther instrumentFurther = metric.getInstrumentFurther(); + if (instrumentFurther == null) { + instrumentFurther = new InstrumentFurther(); + } + + // Handle observable metrics + if (metric instanceof ObservableMetric) { + handleObservableMetric((ObservableMetric) metric, meter, instrumentFurther); + return; + } + + // Handle sync metrics + if (metric instanceof SyncMetric) { + handleMetric((SyncMetric) metric, meter, instrumentFurther); + } + }); + } + + /** + * Retrieves the list of metrics and their corresponding views. + * + * @return The list of metric views. + */ + public static List> getMetricsView() { + Collection> metricSetCollection = metricCache.values(); + return metricSetCollection.stream().map( + metricSet -> metricSet.stream().map(metric -> { + InstrumentFurther instrumentFurther = metric.getInstrumentFurther(); + if (!Objects.nonNull(instrumentFurther)) { + return null; + } + Map ext = instrumentFurther.getExt(); + if (!Objects.nonNull(ext)) { + return null; + } + return (Pair) ext.get(InstrumentFurther.INSTRUMENT_VIEW); + }).filter(pair -> pair != null).collect(Collectors.toList())).flatMap(viewSet -> viewSet.stream()).collect(Collectors.toList()); + } + + /** + * Handles the creation of a sync metric based on its instrument type. + * + * @param metric The sync metric. + * @param meter The Prometheus meter. + * @param instrumentFurther Additional instrument information. + */ + private static void handleMetric(final SyncMetric metric, final Meter meter, final InstrumentFurther instrumentFurther) { + InstrumentType instrumentType = metric.getInstrumentType(); + switch (instrumentType) { + case LONG_COUNTER: { + LongCounter counter = meter.counterBuilder(instrumentFurther.getName()) + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .build(); + metric.setInstrument(counter); + break; + } + case DOUBLE_COUNTER: { + DoubleCounter counter = meter.counterBuilder(instrumentFurther.getName()) + .ofDoubles() + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .build(); + metric.setInstrument(counter); + break; + } + case LONG_HISTOGRAM: { + LongHistogram histogram = meter.histogramBuilder(instrumentFurther.getName()) + .ofLongs() + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .build(); + metric.setInstrument(histogram); + break; + } + case DOUBLE_HISTOGRAM: { + DoubleHistogram histogram = meter.histogramBuilder(instrumentFurther.getName()) + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .build(); + metric.setInstrument(histogram); + break; + } + case LONG_UP_DOWN_COUNTER: { + LongUpDownCounter counter = meter.upDownCounterBuilder(instrumentFurther.getName()) + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .build(); + metric.setInstrument(counter); + break; + } + case DOUBLE_UP_DOWN_COUNTER: { + DoubleUpDownCounter counter = meter.upDownCounterBuilder(instrumentFurther.getName()) + .ofDoubles() + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .build(); + metric.setInstrument(counter); + break; + } + default: + throw new IllegalArgumentException(String.format("%s not Support", instrumentType.getType().getName())); + } + } + + /** + * Handles the observable metric based on the type of the instrument. + * + * @param observableMetric The observable metric that needs to be handled. + * @param meter The meter object used to build the instrument. + * @param instrumentFurther The instrument further which contains the name, description and unit of the instrument. + */ + private static void handleObservableMetric(final ObservableMetric observableMetric, final Meter meter, + final InstrumentFurther instrumentFurther) { + InstrumentType instrumentType = observableMetric.getInstrumentType(); + Attributes attributes = buildAttributes(observableMetric); + switch (instrumentType) { + case OBSERVABLE_LONG_GAUGE: { + meter.gaugeBuilder(instrumentFurther.getName()) + .ofLongs() + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .buildWithCallback( + measurement -> measurement.record((Long) Objects.requireNonNull(observableMetric.supplier()).get(), attributes)); + break; + } + case OBSERVABLE_DOUBLE_GAUGE: { + meter.gaugeBuilder(instrumentFurther.getName()) + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .buildWithCallback( + measurement -> measurement.record((Double) Objects.requireNonNull(observableMetric.supplier()).get(), attributes)); + break; + } + case OBSERVABLE_LONG_COUNTER: { + meter.counterBuilder(instrumentFurther.getName()) + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .buildWithCallback( + measurement -> measurement.record((Long) Objects.requireNonNull(observableMetric.supplier()).get(), attributes)); + + break; + } + case OBSERVABLE_DOUBLE_COUNTER: { + meter.counterBuilder(instrumentFurther.getName()) + .ofDoubles() + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .buildWithCallback( + measurement -> measurement.record((Double) Objects.requireNonNull(observableMetric.supplier()).get(), attributes)); + + break; + } + case OBSERVABLE_LONG_UP_DOWN_COUNTER: { + meter.upDownCounterBuilder(instrumentFurther.getName()) + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .buildWithCallback( + measurement -> measurement.record((Long) Objects.requireNonNull(observableMetric.supplier()).get(), attributes)); + break; + } + case OBSERVABLE_DOUBLE_UP_DOWN_COUNTER: { + meter.upDownCounterBuilder(instrumentFurther.getName()) + .ofDoubles() + .setDescription(instrumentFurther.getDescription()) + .setUnit(instrumentFurther.getUnit()) + .buildWithCallback( + measurement -> measurement.record((Double) Objects.requireNonNull(observableMetric.supplier()).get(), attributes)); + + break; + } + default: + } + } + + /** + * Builds the attributes for an ObservableMetric. + * + * @param observableMetric The ObservableMetric from which to retrieve the attributes. + * @return The built attributes. + */ + private static Attributes buildAttributes(ObservableMetric observableMetric) { + Map attributes = observableMetric.getAttributes(); + AttributesBuilder builder = Attributes.builder(); + attributes.forEach(builder::put); + return builder.build(); + } + +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfiguration.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfiguration.java index 0f9b48e158..0e3adb44ff 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfiguration.java +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfiguration.java @@ -17,65 +17,18 @@ package org.apache.eventmesh.metrics.prometheus.config; -import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; -import org.apache.commons.lang3.StringUtils; +import lombok.Data; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@UtilityClass +@Data +@Config(prefix = "eventMesh.metrics.prometheus", path = "classPath://prometheus.properties") public class PrometheusConfiguration { - private static final String CONFIG_FILE = "prometheus.properties"; - private static final Properties properties = new Properties(); - + @ConfigField(field = "port") private int eventMeshPrometheusPort = 19090; - static { - loadProperties(); - initializeConfig(); - } - - public static int getEventMeshPrometheusPort() { - return eventMeshPrometheusPort; - } - - private void initializeConfig() { - String eventMeshPrometheusPortStr = properties.getProperty("eventMesh.metrics.prometheus.port"); - if (StringUtils.isNotEmpty(eventMeshPrometheusPortStr)) { - eventMeshPrometheusPort = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshPrometheusPortStr)); - } - } - - /** - * Load properties file from classpath and conf home. - * The properties defined in conf home will override classpath. - */ - private void loadProperties() { - try (InputStream resourceAsStream = PrometheusConfiguration.class.getResourceAsStream(File.separator + CONFIG_FILE)) { - if (resourceAsStream != null) { - properties.load(resourceAsStream); - } - } catch (IOException e) { - throw new RuntimeException(String.format("Load %s file from classpath error", CONFIG_FILE)); - } - try { - String configPath = Constants.EVENTMESH_CONF_HOME + File.separator + CONFIG_FILE; - if (new File(configPath).exists()) { - properties.load(new BufferedReader(new FileReader(configPath))); - } - } catch (IOException e) { - throw new IllegalArgumentException(String.format("Cannot load %s file from conf", CONFIG_FILE)); - } - } - + @ConfigField(field = "export.host") + private String eventMeshPrometheusExportHost = "0.0.0.0"; } diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/metrics/PrometheusHttpExporter.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/metrics/PrometheusHttpExporter.java deleted file mode 100644 index 0f87aa8eaf..0000000000 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/metrics/PrometheusHttpExporter.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.metrics.prometheus.metrics; - -import org.apache.eventmesh.metrics.api.model.HttpSummaryMetrics; - -import io.opentelemetry.api.metrics.GlobalMeterProvider; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.api.metrics.common.Labels; - -import lombok.experimental.UtilityClass; - -@UtilityClass -public class PrometheusHttpExporter { - - public static void export(String name, HttpSummaryMetrics summaryMetrics) { - Meter meter = GlobalMeterProvider.getMeter(name); - //maxHTTPTPS - meter - .doubleValueObserverBuilder("eventmesh.http.request.tps.max") - .setDescription("max TPS of HTTP.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.maxHTTPTPS(), Labels.empty())) - .build(); - - //avgHTTPTPS - meter - .doubleValueObserverBuilder("eventmesh.http.request.tps.avg") - .setDescription("avg TPS of HTTP.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgHTTPTPS(), Labels.empty())) - .build(); - - //maxHTTPCost - meter - .longValueObserverBuilder("eventmesh.http.request.cost.max") - .setDescription("max cost of HTTP.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.maxHTTPCost(), Labels.empty())) - .build(); - - //avgHTTPCost - meter - .doubleValueObserverBuilder("eventmesh.http.request.cost.avg") - .setDescription("avg cost of HTTP.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgHTTPCost(), Labels.empty())) - .build(); - - //avgHTTPBodyDecodeCost - meter - .doubleValueObserverBuilder("eventmesh.http.body.decode.cost.avg") - .setDescription("avg body decode cost of HTTP.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgHTTPBodyDecodeCost(), Labels.empty())) - .build(); - - //httpDiscard - meter - .longValueObserverBuilder("eventmesh.http.request.discard.num") - .setDescription("http request discard num.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getHttpDiscard(), Labels.empty())) - .build(); - - //maxBatchSendMsgTPS - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.tps.max") - .setDescription("max of batch send message tps.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.maxSendBatchMsgTPS(), Labels.empty())) - .build(); - - //avgBatchSendMsgTPS - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.tps.avg") - .setDescription("avg of batch send message tps.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgSendBatchMsgTPS(), Labels.empty())) - .build(); - - //sum - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.num") - .setDescription("sum of batch send message number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendBatchMsgNumSum(), Labels.empty())) - .build(); - - //sumFail - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.fail.num") - .setDescription("sum of batch send message fail message number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendBatchMsgFailNumSum(), Labels.empty())) - .build(); - - //sumFailRate - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.fail.rate") - .setDescription("send batch message fail rate.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendBatchMsgFailRate(), Labels.empty())) - .build(); - - //discard - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.discard.num") - .setDescription("sum of send batch message discard number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendBatchMsgDiscardNumSum(), Labels.empty())) - .build(); - - //maxSendMsgTPS - meter - .doubleValueObserverBuilder("eventmesh.send.message.tps.max") - .setDescription("max of send message tps.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.maxSendMsgTPS(), Labels.empty())) - .build(); - - //avgSendMsgTPS - meter - .doubleValueObserverBuilder("eventmesh.send.message.tps.avg") - .setDescription("avg of send message tps.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgSendMsgTPS(), Labels.empty())) - .build(); - - //sum - meter - .doubleValueObserverBuilder("eventmesh.send.message.num") - .setDescription("sum of send message number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendMsgNumSum(), Labels.empty())) - .build(); - - //sumFail - meter - .doubleValueObserverBuilder("eventmesh.send.message.fail.num") - .setDescription("sum of send message fail number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendMsgFailNumSum(), Labels.empty())) - .build(); - - //sumFailRate - meter - .doubleValueObserverBuilder("eventmesh.send.message.fail.rate") - .setDescription("send message fail rate.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendMsgFailRate(), Labels.empty())) - .build(); - - //replyMsg - meter - .doubleValueObserverBuilder("eventmesh.reply.message.num") - .setDescription("sum of reply message number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getReplyMsgNumSum(), Labels.empty())) - .build(); - - //replyFail - meter - .doubleValueObserverBuilder("eventmesh.reply.message.fail.num") - .setDescription("sum of reply message fail number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getReplyMsgFailNumSum(), Labels.empty())) - .build(); - - //maxPushMsgTPS - meter - .doubleValueObserverBuilder("eventmesh.push.message.tps.max") - .setDescription("max of push message tps.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.maxPushMsgTPS(), Labels.empty())) - .build(); - - //avgPushMsgTPS - meter - .doubleValueObserverBuilder("eventmesh.push.message.tps.avg") - .setDescription("avg of push message tps.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgPushMsgTPS(), Labels.empty())) - .build(); - - //sum - meter - .doubleValueObserverBuilder("eventmesh.http.push.message.num") - .setDescription("sum of http push message number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getHttpPushMsgNumSum(), Labels.empty())) - .build(); - - //sumFail - meter - .doubleValueObserverBuilder("eventmesh.http.push.message.fail.num") - .setDescription("sum of http push message fail number.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getHttpPushFailNumSum(), Labels.empty())) - .build(); - - //sumFailRate - meter - .doubleValueObserverBuilder("eventmesh.http.push.message.fail.rate") - .setDescription("http push message fail rate.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getHttpPushMsgFailRate(), Labels.empty())) - .build(); - - //maxClientLatency - meter - .doubleValueObserverBuilder("eventmesh.http.push.latency.max") - .setDescription("max of http push latency.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.maxHTTPPushLatency(), Labels.empty())) - .build(); - - //avgClientLatency - meter - .doubleValueObserverBuilder("eventmesh.http.push.latency.avg") - .setDescription("avg of http push latency.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgHTTPPushLatency(), Labels.empty())) - .build(); - - //batchMsgQ - meter - .longValueObserverBuilder("eventmesh.batch.message.queue.size") - .setDescription("size of batch message queue.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getBatchMsgQueueSize(), Labels.empty())) - .build(); - - //sendMsgQ - meter - .longValueObserverBuilder("eventmesh.send.message.queue.size") - .setDescription("size of send message queue.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getSendMsgQueueSize(), Labels.empty())) - .build(); - - //pushMsgQ - meter - .longValueObserverBuilder("eventmesh.push.message.queue.size") - .setDescription("size of push message queue.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getPushMsgQueueSize(), Labels.empty())) - .build(); - - //httpRetryQ - meter - .longValueObserverBuilder("eventmesh.http.retry.queue.size") - .setDescription("size of http retry queue.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.getHttpRetryQueueSize(), Labels.empty())) - .build(); - - //batchAvgSend2MQCost - meter - .doubleValueObserverBuilder("eventmesh.batch.send.message.cost.avg") - .setDescription("avg of batch send message cost.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgBatchSendMsgCost(), Labels.empty())) - .build(); - - //avgSend2MQCost - meter - .doubleValueObserverBuilder("eventmesh.send.message.cost.avg") - .setDescription("avg of send message cost.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgSendMsgCost(), Labels.empty())) - .build(); - - //avgReply2MQCost - meter - .doubleValueObserverBuilder("eventmesh.reply.message.cost.avg") - .setDescription("avg of reply message cost.") - .setUnit("HTTP") - .setUpdater(result -> result.observe(summaryMetrics.avgReplyMsgCost(), Labels.empty())) - .build(); - } - -} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/metrics/PrometheusTcpExporter.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/metrics/PrometheusTcpExporter.java deleted file mode 100644 index 01edb55496..0000000000 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/main/java/org/apache/eventmesh/metrics/prometheus/metrics/PrometheusTcpExporter.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.metrics.prometheus.metrics; - -import org.apache.eventmesh.metrics.api.model.TcpSummaryMetrics; - -import io.opentelemetry.api.metrics.GlobalMeterProvider; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.api.metrics.common.Labels; - -import lombok.experimental.UtilityClass; - -@UtilityClass -public class PrometheusTcpExporter { - - public static void export(final String meterName, final TcpSummaryMetrics summaryMetrics) { - final Meter meter = GlobalMeterProvider.getMeter(meterName); - //retryQueueSize - meter.doubleValueObserverBuilder("eventmesh.tcp.retry.queue.size") - .setDescription("get size of retry queue.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getRetrySize(), Labels.empty())) - .build(); - - //client2eventMeshTPS - meter.doubleValueObserverBuilder("eventmesh.tcp.server.tps") - .setDescription("get tps of client to eventMesh.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getClient2eventMeshTPS(), Labels.empty())) - .build(); - - //eventMesh2mqTPS - meter.doubleValueObserverBuilder("eventmesh.tcp.mq.provider.tps") - .setDescription("get tps of eventMesh to mq.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getEventMesh2mqTPS(), Labels.empty())) - .build(); - - //mq2eventMeshTPS - meter.doubleValueObserverBuilder("eventmesh.tcp.mq.consumer.tps") - .setDescription("get tps of mq to eventMesh.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getMq2eventMeshTPS(), Labels.empty())) - .build(); - - //eventMesh2clientTPS - meter.doubleValueObserverBuilder("eventmesh.tcp.client.tps") - .setDescription("get tps of eventMesh to client.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getEventMesh2clientTPS(), Labels.empty())) - .build(); - - //allTPS - meter.doubleValueObserverBuilder("eventmesh.tcp.all.tps") - .setDescription("get all TPS.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getAllTPS(), Labels.empty())) - .build(); - - //EventMeshTcpConnectionHandler.connections - meter.doubleValueObserverBuilder("eventmesh.tcp.connection.num") - .setDescription("EventMeshTcpConnectionHandler.connections.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getAllConnections(), Labels.empty())) - .build(); - - //subTopicNum - meter.doubleValueObserverBuilder("eventmesh.tcp.sub.topic.num") - .setDescription("get sub topic num.") - .setUnit("TCP") - .setUpdater(result -> result.observe(summaryMetrics.getSubTopicNum(), Labels.empty())) - .build(); - } -} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfigurationTest.java b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfigurationTest.java index 12a3f8a0ef..3a4227e3ae 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfigurationTest.java +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/java/org/apache/eventmesh/metrics/prometheus/config/PrometheusConfigurationTest.java @@ -17,14 +17,24 @@ package org.apache.eventmesh.metrics.prometheus.config; -import org.junit.Assert; -import org.junit.Test; +import org.apache.eventmesh.metrics.api.MetricsPluginFactory; +import org.apache.eventmesh.metrics.prometheus.PrometheusMetricsRegistry; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class PrometheusConfigurationTest { @Test - public void getEventMeshPrometheusPort() { - int eventMeshPrometheusPort = PrometheusConfiguration.getEventMeshPrometheusPort(); - Assert.assertEquals(19090, eventMeshPrometheusPort); + public void getConfigWhenPrometheusMetricsRegistryInit() { + PrometheusMetricsRegistry registry = + (PrometheusMetricsRegistry) MetricsPluginFactory.getMetricsRegistry("prometheus"); + + PrometheusConfiguration config = registry.getClientConfiguration(); + assertConfig(config); + } + + private void assertConfig(PrometheusConfiguration config) { + Assertions.assertEquals(config.getEventMeshPrometheusPort(), 19091); } -} \ No newline at end of file +} diff --git a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/resources/prometheus.properties b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/resources/prometheus.properties index d4fb5a13c3..dd5ec0b83a 100644 --- a/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/resources/prometheus.properties +++ b/eventmesh-metrics-plugin/eventmesh-metrics-prometheus/src/test/resources/prometheus.properties @@ -15,4 +15,4 @@ # limitations under the License. # -eventMesh.metrics.prometheus.port=19090 \ No newline at end of file +eventMesh.metrics.prometheus.port=19091 \ No newline at end of file diff --git a/eventmesh-openconnect/README.md b/eventmesh-openconnect/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/eventmesh-openconnect/build.gradle b/eventmesh-openconnect/build.gradle new file mode 100644 index 0000000000..d973dcedae --- /dev/null +++ b/eventmesh-openconnect/build.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/build.gradle b/eventmesh-openconnect/eventmesh-openconnect-java/build.gradle new file mode 100644 index 0000000000..b41f7fbfae --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + +dependencies { + api "org.slf4j:slf4j-api" + + implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.fasterxml.jackson.core:jackson-core" + implementation "com.fasterxml.jackson.core:jackson-annotations" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" + + api project (":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api") + implementation project (":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-nacos") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + implementation project(":eventmesh-common") + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-connector-plugin/gradle.properties b/eventmesh-openconnect/eventmesh-openconnect-java/gradle.properties similarity index 100% rename from eventmesh-connector-plugin/gradle.properties rename to eventmesh-openconnect/eventmesh-openconnect-java/gradle.properties diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/Application.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/Application.java new file mode 100644 index 0000000000..b28f6387a9 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/Application.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.Connector; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.util.ConfigUtil; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Application { + + public static final Map CONNECTOR_MAP = new HashMap<>(); + + public static final String CREATE_EXTENSION_KEY = "createExtension"; + + private Map extensions; + + public Application() { + + } + + public Application(Map extensions) { + this.extensions = extensions; + } + + public void run(Class clazz) throws Exception { + + Connector connector = null; + try { + if (MapUtils.isNotEmpty(extensions) && extensions.containsKey(CREATE_EXTENSION_KEY)) { + String spiKey = extensions.get(CREATE_EXTENSION_KEY); + ConnectorCreateService createService = + EventMeshExtensionFactory.getExtension(ConnectorCreateService.class, spiKey); + if (createService != null) { + connector = createService.create(); + } + } + if (connector == null) { + connector = clazz.getDeclaredConstructor().newInstance(); + } + } catch (Exception e) { + log.error("new connector error", e); + return; + } + Config config; + try { + config = ConfigUtil.parse(connector.configClass()); + } catch (Exception e) { + log.error("parse config error", e); + return; + } + + ConnectorWorker worker; + if (isSink(clazz)) { + worker = new SinkWorker((Sink) connector, (SinkConfig) config); + } else if (isSource(clazz)) { + worker = new SourceWorker((Source) connector, (SourceConfig) config); + } else { + log.error("class {} is not sink and source", clazz); + return; + } + worker.init(); + + CONNECTOR_MAP.putIfAbsent(connector.name(), connector); + Connector finalConnector = connector; + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + worker.stop(); + log.info("connector {} stopped", finalConnector.name()); + })); + worker.start(); + log.info("connector {} started", connector.name()); + } + + public static boolean isAssignableFrom(Class c, Class cls) { + Class[] clazzArr = c.getInterfaces(); + for (Class clazz : clazzArr) { + if (clazz.isAssignableFrom(cls)) { + return true; + } + } + return false; + } + + public static boolean isSink(Class c) { + while (c != null && c != Object.class) { + if (isAssignableFrom(c, Sink.class)) { + return true; + } + c = c.getSuperclass(); + } + return false; + } + + public static boolean isSource(Class c) { + while (c != null && c != Object.class) { + if (isAssignableFrom(c, Source.class)) { + return true; + } + c = c.getSuperclass(); + } + return false; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/ConnectorWorker.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/ConnectorWorker.java new file mode 100644 index 0000000000..908464711f --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/ConnectorWorker.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect; + +/** + * Connector worker interface + */ +public interface ConnectorWorker { + + void init(); + + /** + * Starts the worker + */ + void start(); + + /** + * Stops the worker + */ + void stop(); +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/SinkWorker.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/SinkWorker.java new file mode 100644 index 0000000000..57ad4b8ec3 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/SinkWorker.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect; + +import org.apache.eventmesh.client.tcp.EventMeshTCPClient; +import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory; +import org.apache.eventmesh.client.tcp.common.MessageUtils; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.SystemUtils; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SinkWorker implements ConnectorWorker { + + private final Sink sink; + private final SinkConfig config; + + private final EventMeshTCPClient eventMeshTCPClient; + + public SinkWorker(Sink sink, SinkConfig config) { + this.sink = sink; + this.config = config; + eventMeshTCPClient = buildEventMeshSubClient(config); + } + + private EventMeshTCPClient buildEventMeshSubClient(SinkConfig config) { + String meshAddress = config.getPubSubConfig().getMeshAddress(); + String meshIp = meshAddress.split(":")[0]; + int meshPort = Integer.parseInt(meshAddress.split(":")[1]); + UserAgent agent = UserAgent.builder() + .env(config.getPubSubConfig().getEnv()) + .host("localhost") + .password(config.getPubSubConfig().getPassWord()) + .username(config.getPubSubConfig().getUserName()) + .group(config.getPubSubConfig().getGroup()) + .path("/") + .port(8362) + .subsystem(config.getPubSubConfig().getAppId()) + .pid(Integer.parseInt(SystemUtils.getProcessId())) + .version("2.0") + .idc(config.getPubSubConfig().getIdc()) + .build(); + UserAgent userAgent = MessageUtils.generateSubClient(agent); + + EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(meshIp) + .port(meshPort) + .userAgent(userAgent) + .build(); + return EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); + } + + @Override + public void init() { + SinkConnectorContext sinkConnectorContext = new SinkConnectorContext(); + sinkConnectorContext.setSinkConfig(config); + try { + sink.init(sinkConnectorContext); + } catch (Exception e) { + throw new RuntimeException(e); + } + eventMeshTCPClient.init(); + } + + @Override + public void start() { + log.info("sink worker starting {}", sink.name()); + log.info("event mesh address is {}", config.getPubSubConfig().getMeshAddress()); + try { + sink.start(); + } catch (Exception e) { + log.error("sink worker[{}] start fail", sink.name(), e); + return; + } + eventMeshTCPClient.subscribe(config.getPubSubConfig().getSubject(), SubscriptionMode.CLUSTERING, + SubscriptionType.ASYNC); + eventMeshTCPClient.registerSubBusiHandler(new EventHandler(sink)); + eventMeshTCPClient.listen(); + } + + @Override + public void stop() { + log.info("sink worker stopping"); + try { + eventMeshTCPClient.unsubscribe(); + eventMeshTCPClient.close(); + } catch (Exception e) { + log.error("event mesh client close", e); + } + try { + sink.stop(); + } catch (Exception e) { + log.error("sink destroy error", e); + } + log.info("source worker stopped"); + } + + static class EventHandler implements ReceiveMsgHook { + + private final Sink sink; + + public EventHandler(Sink sink) { + this.sink = sink; + } + + @Override + public Optional handle(CloudEvent event) { + ConnectRecord connectRecord = CloudEventUtil.convertEventToRecord(event); + List connectRecords = new ArrayList<>(); + connectRecords.add(connectRecord); + sink.put(connectRecords); + return Optional.empty(); + } + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/SourceWorker.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/SourceWorker.java new file mode 100644 index 0000000000..2a2162a7af --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/SourceWorker.java @@ -0,0 +1,375 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect; + +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; + +import org.apache.eventmesh.client.tcp.EventMeshTCPClient; +import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory; +import org.apache.eventmesh.client.tcp.common.MessageUtils; +import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.SystemUtils; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendMessageCallback; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.RecordOffsetManagement; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.DefaultOffsetManagementServiceImpl; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetStorageReaderImpl; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetStorageWriterImpl; +import org.apache.eventmesh.openconnect.util.CloudEventUtil; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import org.apache.commons.collections4.CollectionUtils; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SourceWorker implements ConnectorWorker { + + private final Source source; + private final SourceConfig config; + + private static final int MAX_RETRY_TIMES = 3; + + public static final String CALLBACK_EXTENSION = "callBackExtension"; + + private OffsetStorageWriterImpl offsetStorageWriter; + + private OffsetStorageReaderImpl offsetStorageReader; + + private OffsetManagementService offsetManagementService; + + private RecordOffsetManagement offsetManagement; + + private volatile RecordOffsetManagement.CommittableOffsets committableOffsets; + + private final ExecutorService pollService = + ThreadPoolFactory.createSingleExecutor("eventMesh-sourceWorker-pollService"); + + private final ExecutorService startService = + ThreadPoolFactory.createSingleExecutor("eventMesh-sourceWorker-startService"); + + private final BlockingQueue queue; + private final EventMeshTCPClient eventMeshTCPClient; + + private volatile boolean isRunning = false; + + public SourceWorker(Source source, SourceConfig config) { + this.source = source; + this.config = config; + queue = new LinkedBlockingQueue<>(1000); + eventMeshTCPClient = buildEventMeshPubClient(config); + } + + private EventMeshTCPClient buildEventMeshPubClient(SourceConfig config) { + String meshAddress = config.getPubSubConfig().getMeshAddress(); + String meshIp = meshAddress.split(":")[0]; + int meshPort = Integer.parseInt(meshAddress.split(":")[1]); + UserAgent agent = UserAgent.builder() + .env(config.getPubSubConfig().getEnv()) + .host("localhost") + .password(config.getPubSubConfig().getPassWord()) + .username(config.getPubSubConfig().getUserName()) + .group(config.getPubSubConfig().getGroup()) + .path("/") + .port(8362) + .subsystem(config.getPubSubConfig().getAppId()) + .pid(Integer.parseInt(SystemUtils.getProcessId())) + .version("2.0") + .idc(config.getPubSubConfig().getIdc()) + .build(); + UserAgent userAgent = MessageUtils.generatePubClient(agent); + + EventMeshTCPClientConfig eventMeshTcpClientConfig = EventMeshTCPClientConfig.builder() + .host(meshIp) + .port(meshPort) + .userAgent(userAgent) + .build(); + return EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, CloudEvent.class); + } + + @Override + public void init() { + SourceConnectorContext sourceConnectorContext = new SourceConnectorContext(); + sourceConnectorContext.setSourceConfig(config); + sourceConnectorContext.setOffsetStorageReader(offsetStorageReader); + try { + source.init(sourceConnectorContext); + } catch (Exception e) { + throw new RuntimeException(e); + } + eventMeshTCPClient.init(); + // spi load offsetMgmtService + this.offsetManagement = new RecordOffsetManagement(); + this.committableOffsets = RecordOffsetManagement.CommittableOffsets.EMPTY; + OffsetStorageConfig offsetStorageConfig = config.getOffsetStorageConfig(); + this.offsetManagementService = Optional.ofNullable(offsetStorageConfig) + .map(OffsetStorageConfig::getOffsetStorageType) + .map(storageType -> EventMeshExtensionFactory.getExtension(OffsetManagementService.class, storageType)) + .orElse(new DefaultOffsetManagementServiceImpl()); + this.offsetManagementService.initialize(offsetStorageConfig); + this.offsetStorageWriter = new OffsetStorageWriterImpl(offsetManagementService); + this.offsetStorageReader = new OffsetStorageReaderImpl(offsetManagementService); + } + + @Override + public void start() { + log.info("source worker starting {}", source.name()); + log.info("event mesh address is {}", config.getPubSubConfig().getMeshAddress()); + // start offsetMgmtService + offsetManagementService.start(); + isRunning = true; + pollService.execute(this::startPollAndSend); + + startService.execute( + () -> { + try { + startConnector(); + } catch (Exception e) { + log.error("source worker[{}] start fail", source.name(), e); + this.stop(); + } + }); + } + + public void startPollAndSend() { + while (isRunning) { + ConnectRecord connectRecord = null; + try { + connectRecord = queue.poll(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("poll connect record error", e); + } + if (connectRecord == null) { + continue; + } + // todo: convert connectRecord to cloudevent + CloudEvent event = convertRecordToEvent(connectRecord); + Optional submittedRecordPosition = prepareToUpdateRecordOffset(connectRecord); + Optional callback = Optional.ofNullable(connectRecord.getExtensionObj(CALLBACK_EXTENSION)) + .map(v -> (SendMessageCallback) v); + + int retryTimes = 0; + // retry until MAX_RETRY_TIMES is reached + while (retryTimes < MAX_RETRY_TIMES) { + try { + Package sendResult = eventMeshTCPClient.publish(event, 3000); + if (sendResult.getHeader().getCode() == OPStatus.SUCCESS.getCode()) { + // publish success + // commit record + this.source.commit(connectRecord); + submittedRecordPosition.ifPresent(RecordOffsetManagement.SubmittedPosition::ack); + callback.ifPresent(cb -> cb.onSuccess(convertToSendResult(event))); + break; + } + throw new EventMeshException("failed to send record."); + } catch (Throwable t) { + retryTimes++; + log.error("{} failed to send record to {}, retry times = {}, failed record {}, throw {}", + this, event.getSubject(), retryTimes, connectRecord, t.getMessage()); + callback.ifPresent(cb -> cb.onException(convertToExceptionContext(event, t))); + } + } + + offsetManagement.awaitAllMessages(5000, TimeUnit.MILLISECONDS); + // update & commit offset + updateCommittableOffsets(); + commitOffsets(); + } + } + + private void startConnector() throws Exception { + source.start(); + while (isRunning) { + List connectorRecordList = source.poll(); + if (CollectionUtils.isEmpty(connectorRecordList)) { + continue; + } + for (ConnectRecord record : connectorRecordList) { + queue.put(record); + } + } + } + + private CloudEvent convertRecordToEvent(ConnectRecord connectRecord) { + CloudEventBuilder cloudEventBuilder = CloudEventBuilder.v1(); + + cloudEventBuilder.withId(UUID.randomUUID().toString()) + .withSubject(config.getPubSubConfig().getSubject()) + .withSource(URI.create("/")) + .withDataContentType("application/cloudevents+json") + .withType(CLOUD_EVENTS_PROTOCOL_NAME) + .withData(Objects.requireNonNull(JsonUtils.toJSONString(connectRecord.getData())).getBytes(StandardCharsets.UTF_8)) + .withExtension("ttl", 10000); + + if (connectRecord.getExtensions() != null) { + for (String key : connectRecord.getExtensions().keySet()) { + if (CloudEventUtil.validateExtensionType(connectRecord.getExtensionObj(key))) { + cloudEventBuilder.withExtension(key, connectRecord.getExtension(key)); + } + } + } + return cloudEventBuilder.build(); + } + + private SendResult convertToSendResult(CloudEvent event) { + SendResult result = new SendResult(); + result.setMessageId(event.getId()); + result.setTopic(event.getSubject()); + return result; + } + + private SendExceptionContext convertToExceptionContext(CloudEvent event, Throwable cause) { + SendExceptionContext exceptionContext = new SendExceptionContext(); + exceptionContext.setTopic(event.getId()); + exceptionContext.setMessageId(event.getId()); + exceptionContext.setCause(cause); + return exceptionContext; + } + + @Override + public void stop() { + log.info("source worker stopping"); + isRunning = false; + try { + source.stop(); + } catch (Exception e) { + log.error("source destroy error", e); + } + log.info("pollService stopping"); + pollService.shutdown(); + try { + pollService.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + log.error("awaitTermination error", e); + } + log.info("offsetMgmtService stopping"); + offsetManagementService.stop(); + + try { + log.info("eventmesh client closing"); + eventMeshTCPClient.close(); + } catch (Exception e) { + log.error("event mesh client close error", e); + } + log.info("source worker stopped"); + } + + public Optional prepareToUpdateRecordOffset(ConnectRecord record) { + return Optional.of(this.offsetManagement.submitRecord(record.getPosition())); + } + + public void updateCommittableOffsets() { + RecordOffsetManagement.CommittableOffsets newOffsets = offsetManagement.committableOffsets(); + synchronized (this) { + this.committableOffsets = this.committableOffsets.updatedWith(newOffsets); + } + } + + public boolean commitOffsets() { + log.info("Start Committing offsets"); + + long timeout = System.currentTimeMillis() + 5000L; + + RecordOffsetManagement.CommittableOffsets offsetsToCommit; + synchronized (this) { + offsetsToCommit = this.committableOffsets; + this.committableOffsets = RecordOffsetManagement.CommittableOffsets.EMPTY; + } + + if (committableOffsets.isEmpty()) { + log.debug("Either no records were produced since the last offset commit, " + + "or every record has been filtered out by a transformation " + + "or dropped due to transformation or conversion errors."); + // We continue with the offset commit process here instead of simply returning immediately + // in order to invoke SourceTask::commit and record metrics for a successful offset commit + } else { + log.info("{} Committing offsets for {} acknowledged messages", this, committableOffsets.numCommittableMessages()); + if (committableOffsets.hasPending()) { + log.debug("{} There are currently {} pending messages spread across {} source partitions whose offsets will not be committed. " + + "The source partition with the most pending messages is {}, with {} pending messages", + this, + committableOffsets.numUncommittableMessages(), + committableOffsets.numDeques(), + committableOffsets.largestDequePartition(), + committableOffsets.largestDequeSize()); + } else { + log.debug("{} There are currently no pending messages for this offset commit; " + + "all messages dispatched to the task's producer since the last commit have been acknowledged", + this); + } + } + + // write offset to memory + offsetsToCommit.offsets().forEach(offsetStorageWriter::writeOffset); + + // begin flush + if (!offsetStorageWriter.beginFlush()) { + return true; + } + + // using offsetManagementService to persist offset + Future flushFuture = offsetStorageWriter.doFlush(); + try { + flushFuture.get(Math.max(timeout - System.currentTimeMillis(), 0), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.warn("{} Flush of offsets interrupted, cancelling", this); + offsetStorageWriter.cancelFlush(); + return false; + } catch (ExecutionException e) { + log.error("{} Flush of offsets threw an unexpected exception: ", this, e); + offsetStorageWriter.cancelFlush(); + return false; + } catch (TimeoutException e) { + log.error("{} Timed out waiting to flush offsets to storage; will try again on next flush interval with latest offsets", this); + offsetStorageWriter.cancelFlush(); + return false; + } + return true; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/ConnectorCreateService.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/ConnectorCreateService.java new file mode 100644 index 0000000000..15e645474c --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/ConnectorCreateService.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api; + +import org.apache.eventmesh.openconnect.api.connector.Connector; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * SPI interface for connector creation. + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.CONNECTOR) +public interface ConnectorCreateService { + + T create(); +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/Connector.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/Connector.java new file mode 100644 index 0000000000..07e44aea94 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/Connector.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.connector; + +import org.apache.eventmesh.common.ComponentLifeCycle; +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +/** + * Connector + */ +public interface Connector extends ComponentLifeCycle { + + /** + * Returns the class type of the configuration for this Connector. + * + * @return Class type of the configuration + */ + Class configClass(); + + /** + * This init method is obsolete. For detailed discussion, please see here + *

+ * Initializes the Connector with the provided configuration. + * + * @param config Configuration object + * @throws Exception if initialization fails + */ + @Deprecated + void init(Config config) throws Exception; + + /** + * Initializes the Connector with the provided context. + * + * @param connectorContext connectorContext + * @throws Exception if initialization fails + */ + void init(ConnectorContext connectorContext) throws Exception; + + /** + * Commits the specified ConnectRecord object. + * + * @param record ConnectRecord object to commit + */ + void commit(ConnectRecord record); + + /** + * Returns the name of the Connector. + * + * @return String name of the Connector + */ + String name(); + + /** + * This method will be called when an exception occurs while processing a ConnectRecord object. This method can be used to handle the exception, + * such as logging error information, or stopping the connector's operation when an exception occurs. + * + * @param record The ConnectRecord object that was being processed when the exception occurred + */ + void onException(ConnectRecord record); + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/ConnectorContext.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/ConnectorContext.java new file mode 100644 index 0000000000..bc4298fde5 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/ConnectorContext.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.connector; + +/** + * Connector Context + */ +public interface ConnectorContext { + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SinkConnector.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SinkConnector.java new file mode 100644 index 0000000000..9b271746f3 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SinkConnector.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.connector; + +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.openconnect.api.sink.Sink; + +public abstract class SinkConnector implements Sink { + + private final SinkConfig sinkConfig; + + protected SinkConnector(SinkConfig sinkConfig) { + this.sinkConfig = sinkConfig; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SinkConnectorContext.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SinkConnectorContext.java new file mode 100644 index 0000000000..1ef048b06c --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SinkConnectorContext.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.connector; + +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.common.remote.job.JobType; + +import java.util.Map; + +import lombok.Data; + +/** + * Sink Connector Context + */ +@Data +public class SinkConnectorContext implements ConnectorContext { + + public SinkConfig sinkConfig; + + public Map runtimeConfig; + + public JobType jobType; + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SourceConnector.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SourceConnector.java new file mode 100644 index 0000000000..95279c2d41 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SourceConnector.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.connector; + +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.openconnect.api.source.Source; + +public abstract class SourceConnector implements Source { + + private final SourceConfig sourceConfig; + + protected SourceConnector(SourceConfig sourceConfig) { + this.sourceConfig = sourceConfig; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SourceConnectorContext.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SourceConnectorContext.java new file mode 100644 index 0000000000..957452bb10 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/connector/SourceConnectorContext.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.connector; + +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetStorageReader; + +import java.util.List; +import java.util.Map; + +import lombok.Data; + +/** + * Source Connector Context + */ +@Data +public class SourceConnectorContext implements ConnectorContext { + + public OffsetStorageReader offsetStorageReader; + + public SourceConfig sourceConfig; + + public Map runtimeConfig; + + public JobType jobType; + + // initial record position + public List recordPositionList; + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/factory/ConnectorPluginFactory.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/factory/ConnectorPluginFactory.java new file mode 100644 index 0000000000..7a6f2e0a9c --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/factory/ConnectorPluginFactory.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.factory; + +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.SinkConnector; +import org.apache.eventmesh.openconnect.api.connector.SourceConnector; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + + +/** + * The factory to get connector {@link SourceConnector} and {@link SinkConnector} + */ +public class ConnectorPluginFactory { + + /** + * Get ConnectorCreateService instance by plugin name + * + * @param connectorPluginName plugin name + * @return ConnectorCreateService instance + */ + public static ConnectorCreateService createConnector(String connectorPluginName) { + return EventMeshExtensionFactory.getExtension(ConnectorCreateService.class, connectorPluginName); + } + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/AbstractConnectorMonitor.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/AbstractConnectorMonitor.java new file mode 100644 index 0000000000..b9205804a4 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/AbstractConnectorMonitor.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.monitor; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAdder; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +public abstract class AbstractConnectorMonitor implements Monitor { + + private final String taskId; + private final String jobId; + private final String ip; + private final LongAdder totalRecordNum; + private final LongAdder totalTimeCost; + protected final AtomicLong startTime; + private final AtomicLong maxTimeCost; + private long averageTime = 0; + private double tps = 0; + + public AbstractConnectorMonitor(String taskId, String jobId, String ip) { + this.taskId = taskId; + this.jobId = jobId; + this.ip = ip; + this.totalRecordNum = new LongAdder(); + this.totalTimeCost = new LongAdder(); + this.startTime = new AtomicLong(System.currentTimeMillis()); + this.maxTimeCost = new AtomicLong(); + } + + @Override + public synchronized void recordProcess(long timeCost) { + totalRecordNum.increment(); + totalTimeCost.add(timeCost); + maxTimeCost.updateAndGet(max -> Math.max(max, timeCost)); + } + + @Override + public synchronized void recordProcess(int recordCount, long timeCost) { + totalRecordNum.add(recordCount); + totalTimeCost.add(timeCost); + maxTimeCost.updateAndGet(max -> Math.max(max, timeCost)); + } + + @Override + public synchronized void printMetrics() { + long totalRecords = totalRecordNum.sum(); + long totalCost = totalTimeCost.sum(); + averageTime = totalRecords > 0 ? totalCost / totalRecords : 0; + long elapsedTime = (System.currentTimeMillis() - startTime.get()) / 1000; // in seconds + tps = elapsedTime > 0 ? (double) totalRecords / elapsedTime : 0; + + log.info("========== Metrics =========="); + log.info("TaskId: {}|JobId: {}|ip: {}", taskId, jobId, ip); + log.info("Total records: {}", totalRecordNum); + log.info("Total time (ms): {}", totalTimeCost); + log.info("Max time per record (ms): {}", maxTimeCost); + log.info("Average time per record (ms): {}", averageTime); + log.info("TPS: {}", tps); + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/Monitor.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/Monitor.java new file mode 100644 index 0000000000..4d4d9efb0c --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/Monitor.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.monitor; + +/** + * Monitor Interface. + * All monitors should implement this interface. + */ +public interface Monitor { + void recordProcess(long timeCost); + + void recordProcess(int recordCount, long timeCost); + + void printMetrics(); +} \ No newline at end of file diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/MonitorRegistry.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/MonitorRegistry.java new file mode 100644 index 0000000000..904efc5d3f --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/monitor/MonitorRegistry.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.monitor; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Getter; + +public class MonitorRegistry { + + @Getter + private static final List monitors = new ArrayList<>(); + + public static void registerMonitor(Monitor monitor) { + monitors.add(monitor); + } + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/sink/Sink.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/sink/Sink.java new file mode 100644 index 0000000000..bcacd1ebae --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/sink/Sink.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.sink; + +import org.apache.eventmesh.openconnect.api.connector.Connector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +/** + * Sink + */ +public interface Sink extends Connector { + + void put(List sinkRecords); + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/source/Source.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/source/Source.java new file mode 100644 index 0000000000..d2b35a931d --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/api/source/Source.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.api.source; + +import org.apache.eventmesh.openconnect.api.connector.Connector; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.util.List; + +/** + * Source + */ +public interface Source extends Connector { + + List poll(); + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/util/CloudEventUtil.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/util/CloudEventUtil.java new file mode 100644 index 0000000000..3fb5ea2b74 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/util/CloudEventUtil.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.util; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.LogUtil; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.OffsetDateTime; +import java.util.Objects; +import java.util.Optional; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventUtil { + + public static CloudEvent convertRecordToEvent(ConnectRecord connectRecord) { + final CloudEventBuilder cloudEventBuilder = CloudEventBuilder.v1().withData((byte[]) connectRecord.getData()); + Optional.ofNullable(connectRecord.getExtensions()).ifPresent((extensions) -> extensions.keySet().forEach(key -> { + switch (key) { + case "id": + cloudEventBuilder.withId(connectRecord.getExtension(key)); + break; + case "topic": + cloudEventBuilder.withSubject(connectRecord.getExtension(key)); + break; + case "source": + try { + cloudEventBuilder.withSource(new URI(connectRecord.getExtension(key))); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + break; + case "type": + cloudEventBuilder.withType(connectRecord.getExtension(key)); + break; + default: + if (validateExtensionType(connectRecord.getExtensionObj(key))) { + cloudEventBuilder.withExtension(key, connectRecord.getExtension(key)); + } + } + })); + return cloudEventBuilder.build(); + } + + public static ConnectRecord convertEventToRecord(CloudEvent event) { + byte[] body = Objects.requireNonNull(event.getData()).toBytes(); + LogUtil.info(log, "handle receive events {}", () -> new String(event.getData().toBytes(), Constants.DEFAULT_CHARSET)); + + ConnectRecord connectRecord = new ConnectRecord(null, null, System.currentTimeMillis(), body); + for (String extensionName : event.getExtensionNames()) { + connectRecord.addExtension(extensionName, Objects.requireNonNull(event.getExtension(extensionName)).toString()); + } + connectRecord.addExtension("id", event.getId()); + connectRecord.addExtension("topic", event.getSubject()); + connectRecord.addExtension("source", event.getSource().toString()); + connectRecord.addExtension("type", event.getType()); + connectRecord.addExtension("datacontenttype", event.getDataContentType()); + return connectRecord; + } + + public static boolean validateExtensionType(Object obj) { + return obj instanceof String || obj instanceof Number || obj instanceof Boolean + || obj instanceof URI || obj instanceof OffsetDateTime || obj instanceof byte[]; + } + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/util/ConfigUtil.java b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/util/ConfigUtil.java new file mode 100644 index 0000000000..066dae3385 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-java/src/main/java/org/apache/eventmesh/openconnect/util/ConfigUtil.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.util; + +import org.apache.eventmesh.common.config.connector.Config; +import org.apache.eventmesh.common.config.connector.Constants; +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.common.config.connector.SourceConfig; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URL; +import java.util.Map; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ConfigUtil { + + public static Config parse(Class c) throws Exception { + if (c == null) { + return null; + } + if (isSourceConfig(c)) { + return parseSourceConfig(c); + } else if (isSinkConfig(c)) { + return parseSinkConfig(c); + } else { + throw new RuntimeException("illegal config, parse config error"); + } + } + + public static T parse(Class c, String filePathName) throws Exception { + ObjectMapper objectMapper; + if (filePathName.endsWith("json")) { + objectMapper = new ObjectMapper(); + } else { + objectMapper = new ObjectMapper(new YAMLFactory()); + } + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + File file = new File(filePathName); + if (file.exists()) { + return objectMapper.readValue(file, c); + } + URL url = ConfigUtil.class.getClassLoader().getResource(filePathName); + if (url == null) { + throw new FileNotFoundException(filePathName); + } + return objectMapper.readValue(url, c); + } + + public static T parse(Map map, Class c) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.convertValue(map, c); + } + + private static Config parseSourceConfig(Class c) throws Exception { + String configFile = System.getProperty(Constants.ENV_SOURCE_CONFIG_FILE, System.getenv(Constants.ENV_SOURCE_CONFIG_FILE)); + if (configFile == null || configFile.isEmpty()) { + configFile = "source-config.yml"; + } + return parse(c, configFile); + } + + private static Config parseSinkConfig(Class c) throws Exception { + String configFile = System.getProperty(Constants.ENV_SINK_CONFIG_FILE, System.getenv(Constants.ENV_SINK_CONFIG_FILE)); + if (configFile == null || configFile.isEmpty()) { + configFile = "sink-config.yml"; + } + return parse(c, configFile); + } + + public static boolean isSinkConfig(Class c) { + if (c != null && c != Object.class) { + return SinkConfig.class.isAssignableFrom(c); + } + return false; + } + + public static boolean isSourceConfig(Class c) { + if (c != null && c != Object.class) { + return SourceConfig.class.isAssignableFrom(c); + } + return false; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/build.gradle b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/build.gradle new file mode 100644 index 0000000000..537c74fafc --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/build.gradle @@ -0,0 +1,31 @@ +/* + * 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. + */ + +dependencies { + api "org.slf4j:slf4j-api" + + implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.fasterxml.jackson.core:jackson-core" + implementation "com.fasterxml.jackson.core:jackson-annotations" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" + + implementation project(":eventmesh-common") + implementation project(":eventmesh-sdks:eventmesh-sdk-java") + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/build.gradle b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/build.gradle new file mode 100644 index 0000000000..70defef627 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/build.gradle @@ -0,0 +1,31 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api") + implementation project(":eventmesh-common") + testImplementation "org.mockito:mockito-core" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + implementation "io.grpc:grpc-core" + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty" + implementation "io.grpc:grpc-netty-shaded" +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/gradle.properties b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/gradle.properties new file mode 100644 index 0000000000..09957a9d24 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/gradle.properties @@ -0,0 +1,18 @@ +# +# 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. +# +pluginType=offsetMgmt +pluginName=admin \ No newline at end of file diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/admin/AdminOffsetService.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/admin/AdminOffsetService.java new file mode 100644 index 0000000000..993352a979 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/admin/AdminOffsetService.java @@ -0,0 +1,291 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.admin; + +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc.AdminServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc.AdminServiceStub; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.TaskState; +import org.apache.eventmesh.common.remote.datasource.DataSourceType; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.common.remote.request.FetchPositionRequest; +import org.apache.eventmesh.common.remote.request.ReportPositionRequest; +import org.apache.eventmesh.common.remote.response.FetchPositionResponse; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.KeyValueStore; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.MemoryBasedKeyValueStore; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.stub.StreamObserver; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AdminOffsetService implements OffsetManagementService { + + private String adminServerAddr; + + private ManagedChannel channel; + + private AdminServiceStub adminServiceStub; + + private AdminServiceBlockingStub adminServiceBlockingStub; + + StreamObserver responseObserver; + + StreamObserver requestObserver; + + public KeyValueStore positionStore; + + private String jobId; + + private TaskState jobState; + + private DataSourceType dataSourceType; + + private DataSourceType dataSinkType; + + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + @Override + public void configure(OffsetStorageConfig config) { + OffsetManagementService.super.configure(config); + } + + @Override + public void persist() { + Map recordMap = positionStore.getKVMap(); + + List recordToSyncList = new ArrayList<>(); + for (Map.Entry entry : recordMap.entrySet()) { + RecordPosition recordPosition = new RecordPosition(entry.getKey(), entry.getValue()); + recordToSyncList.add(recordPosition); + } + + ReportPositionRequest reportPositionRequest = new ReportPositionRequest(); + reportPositionRequest.setJobID(jobId); + reportPositionRequest.setState(jobState); + reportPositionRequest.setDataSourceType(dataSourceType); + reportPositionRequest.setAddress(IPUtils.getLocalAddress()); + + reportPositionRequest.setRecordPositionList(recordToSyncList); + + log.debug("start report position request: {}", JsonUtils.toJSONString(reportPositionRequest)); + + Metadata metadata = Metadata.newBuilder() + .setType(ReportPositionRequest.class.getSimpleName()) + .build(); + Payload payload = Payload.newBuilder() + .setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(reportPositionRequest)))) + .build()) + .build(); + requestObserver.onNext(payload); + log.debug("end report position request: {}", JsonUtils.toJSONString(reportPositionRequest)); + + for (Map.Entry entry : recordMap.entrySet()) { + positionStore.remove(entry.getKey()); + } + } + + @Override + public void load() { + + } + + @Override + public void synchronize() { + + } + + @Override + public Map getPositionMap() { + // get from memory storage first + if (positionStore.getKVMap() == null || positionStore.getKVMap().isEmpty()) { + log.info("fetch position from admin server"); + FetchPositionRequest fetchPositionRequest = new FetchPositionRequest(); + fetchPositionRequest.setJobID(jobId); + fetchPositionRequest.setAddress(IPUtils.getLocalAddress()); + fetchPositionRequest.setDataSourceType(dataSourceType); + + Metadata metadata = Metadata.newBuilder() + .setType(FetchPositionRequest.class.getSimpleName()) + .build(); + + Payload request = Payload.newBuilder() + .setMetadata(metadata) + .setBody( + Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(fetchPositionRequest)))) + .build()) + .build(); + Payload response = adminServiceBlockingStub.invoke(request); + if (response.getMetadata().getType().equals(FetchPositionResponse.class.getSimpleName())) { + FetchPositionResponse fetchPositionResponse = + JsonUtils.parseObject(response.getBody().getValue().toStringUtf8(), FetchPositionResponse.class); + assert fetchPositionResponse != null; + if (fetchPositionResponse.isSuccess()) { + for (RecordPosition recordPosition : fetchPositionResponse.getRecordPosition()) { + positionStore.put(recordPosition.getRecordPartition(), recordPosition.getRecordOffset()); + } + } + } + } + log.info("memory position map {}", positionStore.getKVMap()); + return positionStore.getKVMap(); + } + + @Override + public RecordOffset getPosition(RecordPartition partition) { + // get from memory storage first + if (positionStore.get(partition) == null) { + log.info("fetch position from admin server"); + FetchPositionRequest fetchPositionRequest = new FetchPositionRequest(); + fetchPositionRequest.setJobID(jobId); + fetchPositionRequest.setAddress(IPUtils.getLocalAddress()); + fetchPositionRequest.setDataSourceType(dataSourceType); + RecordPosition fetchRecordPosition = new RecordPosition(); + fetchRecordPosition.setRecordPartition(partition); + fetchPositionRequest.setRecordPosition(fetchRecordPosition); + + Metadata metadata = Metadata.newBuilder() + .setType(FetchPositionRequest.class.getSimpleName()) + .build(); + + Payload request = Payload.newBuilder() + .setMetadata(metadata) + .setBody( + Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(fetchPositionRequest)))) + .build()) + .build(); + Payload response = adminServiceBlockingStub.invoke(request); + if (response.getMetadata().getType().equals(FetchPositionResponse.class.getSimpleName())) { + FetchPositionResponse fetchPositionResponse = + JsonUtils.parseObject(response.getBody().getValue().toStringUtf8(), FetchPositionResponse.class); + assert fetchPositionResponse != null; + if (fetchPositionResponse.isSuccess()) { + for (RecordPosition recordPosition : fetchPositionResponse.getRecordPosition()) { + positionStore.put(recordPosition.getRecordPartition(), recordPosition.getRecordOffset()); + } + } + } + } + log.info("memory record position {}", positionStore.get(partition)); + return positionStore.get(partition); + } + + @Override + public void putPosition(Map positions) { + positionStore.putAll(positions); + } + + @Override + public void putPosition(RecordPartition partition, RecordOffset position) { + positionStore.put(partition, position); + } + + @Override + public void removePosition(List partitions) { + if (partitions == null) { + return; + } + for (RecordPartition partition : partitions) { + positionStore.remove(partition); + } + } + + @Override + public void initialize(OffsetStorageConfig offsetStorageConfig) { + this.dataSourceType = offsetStorageConfig.getDataSourceType(); + this.dataSinkType = offsetStorageConfig.getDataSinkType(); + + this.adminServerAddr = getRandomAdminServerAddr(offsetStorageConfig.getOffsetStorageAddr()); + this.channel = ManagedChannelBuilder.forTarget(adminServerAddr) + .usePlaintext() + .build(); + this.adminServiceStub = AdminServiceGrpc.newStub(channel).withWaitForReady(); + this.adminServiceBlockingStub = AdminServiceGrpc.newBlockingStub(channel).withWaitForReady(); + + responseObserver = new StreamObserver() { + @Override + public void onNext(Payload response) { + log.info("receive message: {} ", response); + } + + @Override + public void onError(Throwable t) { + log.error("receive error message: {}", t.getMessage()); + } + + @Override + public void onCompleted() { + log.info("finished receive message and completed"); + } + }; + + requestObserver = adminServiceStub.invokeBiStream(responseObserver); + + this.positionStore = new MemoryBasedKeyValueStore<>(); + String offset = offsetStorageConfig.getExtensions().get("offset"); + if (offset != null) { + Map initialRecordOffsetMap = JsonUtils.parseTypeReferenceObject(offset, + new TypeReference>() { + }); + log.info("init record offset {}", initialRecordOffsetMap); + positionStore.putAll(initialRecordOffsetMap); + } + this.jobState = TaskState.RUNNING; + this.jobId = offsetStorageConfig.getExtensions().get("jobId"); + } + + private String getRandomAdminServerAddr(String adminServerAddrList) { + String[] addresses = adminServerAddrList.split(";"); + if (addresses.length == 0) { + throw new IllegalArgumentException("Admin server address list is empty"); + } + Random random = new Random(); + int randomIndex = random.nextInt(addresses.length); + return addresses[randomIndex]; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService new file mode 100644 index 0000000000..11b4466d79 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-admin/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService @@ -0,0 +1,16 @@ +# 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. + +admin=org.apache.eventmesh.openconnect.offsetmgmt.admin.AdminOffsetService \ No newline at end of file diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/build.gradle b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/build.gradle new file mode 100644 index 0000000000..1338b0b7d8 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/build.gradle @@ -0,0 +1,31 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + api project(":eventmesh-spi") + api "org.slf4j:slf4j-api" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + implementation project(":eventmesh-common") + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-core" +} diff --git a/eventmesh-webhook/eventmesh-webhook-admin/gradle.properties b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/gradle.properties similarity index 100% rename from eventmesh-webhook/eventmesh-webhook-admin/gradle.properties rename to eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/gradle.properties diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendExceptionContext.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendExceptionContext.java new file mode 100644 index 0000000000..974b19a547 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendExceptionContext.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.callback; + +public class SendExceptionContext { + + private String messageId; + private String topic; + private Throwable cause; + + public SendExceptionContext() { + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getTopic() { + return this.topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public Throwable getCause() { + return this.cause; + } + + public void setCause(Throwable cause) { + this.cause = cause; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendMessageCallback.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendMessageCallback.java new file mode 100644 index 0000000000..8346cf36b4 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendMessageCallback.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.callback; + +/** + * Message sending callback interface. + */ +public interface SendMessageCallback { + + void onSuccess(SendResult sendResult); + + void onException(SendExceptionContext sendExceptionContext); +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendResult.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendResult.java new file mode 100644 index 0000000000..9afc745f3d --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/callback/SendResult.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.callback; + +public class SendResult { + + private String messageId; + private String topic; + + public SendResult() { + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getTopic() { + return this.topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String toString() { + return "SendResult[topic=" + this.topic + ", messageId=" + this.messageId + ']'; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/ConnectRecord.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/ConnectRecord.java new file mode 100644 index 0000000000..0a41e18f7c --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/ConnectRecord.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.data; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.RecordPosition; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendMessageCallback; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import lombok.Getter; +import lombok.Setter; + +/** + * SourceDataEntries are generated by SourceTasks and passed to specific message queue to store. + */ +@Getter +public class ConnectRecord { + + private final String recordId = UUID.randomUUID().toString(); + + @Setter + private Long timestamp; + + @Setter + private Object data; + + @Setter + private RecordPosition position; + + @Setter + private KeyValue extensions; + + @Setter + private SendMessageCallback callback; + + public ConnectRecord() { + + } + + public ConnectRecord(RecordPartition recordPartition, RecordOffset recordOffset, + Long timestamp) { + this(recordPartition, recordOffset, timestamp, null); + } + + public ConnectRecord(RecordPartition recordPartition, RecordOffset recordOffset, + Long timestamp, Object data) { + if (recordPartition == null || recordOffset == null) { + this.position = null; + } else { + this.position = new RecordPosition(recordPartition, recordOffset); + } + this.timestamp = timestamp; + this.data = data; + } + + public void addExtension(KeyValue extensions) { + if (this.extensions == null) { + this.extensions = new DefaultKeyValue(); + } + Set keySet = extensions.keySet(); + for (String key : keySet) { + this.extensions.put(key, extensions.getObject(key)); + } + } + + public void addExtension(String key, Object value) { + if (this.extensions == null) { + this.extensions = new DefaultKeyValue(); + } + this.extensions.put(key, value); + } + + public String getExtension(String key) { + if (this.extensions == null || !extensions.containsKey(key)) { + return null; + } + return this.extensions.getString(key); + } + + public T getExtension(String key, Class c) { + if (this.extensions == null) { + return null; + } + return this.extensions.getObject(key, c); + } + + public Object getExtensionObj(String key) { + if (this.extensions == null) { + return null; + } + return this.extensions.getObject(key); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ConnectRecord)) { + return false; + } + ConnectRecord that = (ConnectRecord) o; + return Objects.equals(recordId, that.recordId) && Objects.equals(timestamp, that.timestamp) && Objects.equals(data, that.data) + && Objects.equals(position, that.position) && Objects.equals(extensions, that.extensions); + } + + @Override + public int hashCode() { + return Objects.hash(recordId, timestamp, data, position, extensions); + } + + @Override + public String toString() { + return "ConnectRecord{" + + "recordId=" + recordId + + ", timestamp=" + timestamp + + ", data=" + data + + ", position=" + position + + ", extensions=" + extensions + + "}"; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/DefaultKeyValue.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/DefaultKeyValue.java new file mode 100644 index 0000000000..891df482be --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/DefaultKeyValue.java @@ -0,0 +1,307 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.data; + +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class DefaultKeyValue implements KeyValue { + + private final Map properties; + + public DefaultKeyValue() { + properties = new ConcurrentHashMap<>(); + } + + @Override + public KeyValue put(String key, Boolean value) { + properties.put(key, value); + return this; + } + + @Override + public KeyValue put(String key, Number value) { + properties.put(key, value); + return this; + + } + + @Override + public KeyValue put(String key, byte[] value) { + properties.put(key, value); + return this; + } + + @Override + public KeyValue put(String key, String value) { + properties.put(key, value); + return this; + } + + @Override + public KeyValue put(String key, URI value) { + properties.put(key, value); + return this; + } + + @Override + public KeyValue put(String key, OffsetDateTime value) { + properties.put(key, value); + return this; + } + + @Override + public KeyValue put(String key, Object value) { + properties.put(key, value); + return this; + } + + @Override + public boolean getBoolean(String key) { + if (!properties.containsKey(key)) { + return false; + } + Object val = properties.get(key); + if (val instanceof Boolean) { + return (Boolean) val; + } + return false; + } + + @Override + public boolean getBoolean(String key, boolean defaultValue) { + return properties.containsKey(key) ? getBoolean(key) : defaultValue; + } + + @Override + public byte getByte(String key) { + if (!properties.containsKey(key)) { + return 0; + } + Object val = properties.get(key); + if (val instanceof Byte) { + return (Byte) val; + } + return 0; + } + + @Override + public byte getByte(String key, byte defaultValue) { + return properties.containsKey(key) ? getByte(key) : defaultValue; + + } + + @Override + public short getShort(String key) { + if (!properties.containsKey(key)) { + return 0; + } + Object val = properties.get(key); + if (val instanceof Short) { + return (Short) val; + } + return 0; + } + + @Override + public short getShort(String key, short defaultValue) { + return properties.containsKey(key) ? getShort(key) : defaultValue; + } + + @Override + public int getInt(String key) { + if (!properties.containsKey(key)) { + return 0; + } + Object val = properties.get(key); + if (val instanceof Integer) { + return (Integer) val; + } + return 0; + } + + @Override + public int getInt(final String key, final int defaultValue) { + return properties.containsKey(key) ? getInt(key) : defaultValue; + } + + @Override + public long getLong(String key) { + if (!properties.containsKey(key)) { + return 0; + } + Object val = properties.get(key); + if (val instanceof Long) { + return (Long) val; + } + return 0; + } + + @Override + public long getLong(final String key, final long defaultValue) { + return properties.containsKey(key) ? getLong(key) : defaultValue; + } + + @Override + public float getFloat(String key) { + if (!properties.containsKey(key)) { + return 0; + } + Object val = properties.get(key); + if (val instanceof Float) { + return (Float) val; + } + return 0; + } + + @Override + public float getFloat(String key, float defaultValue) { + return properties.containsKey(key) ? getFloat(key) : defaultValue; + } + + @Override + public double getDouble(String key) { + if (!properties.containsKey(key)) { + return 0; + } + Object val = properties.get(key); + if (val instanceof Double) { + return (Double) val; + } + return 0; + } + + @Override + public double getDouble(final String key, final double defaultValue) { + return properties.containsKey(key) ? getDouble(key) : defaultValue; + } + + @Override + public byte[] getBytes(String key) { + if (!properties.containsKey(key)) { + return new byte[]{}; + } + Object val = properties.get(key); + if (val instanceof byte[]) { + return (byte[]) val; + } + return new byte[]{}; + } + + @Override + public byte[] getBytes(String key, byte[] defaultValue) { + return properties.containsKey(key) ? getBytes(key) : defaultValue; + } + + @Override + public String getString(String key) { + if (!properties.containsKey(key)) { + return ""; + } + Object val = properties.get(key); + if (val instanceof String) { + return (String) val; + } + return ""; + } + + @Override + public String getString(final String key, final String defaultValue) { + return properties.containsKey(key) ? getString(key) : defaultValue; + } + + @Override + public URI getURI(String key) { + if (!properties.containsKey(key)) { + return null; + } + Object val = properties.get(key); + if (val instanceof URI) { + return (URI) val; + } + return null; + } + + @Override + public URI getURI(String key, URI defaultValue) { + return properties.containsKey(key) ? getURI(key) : defaultValue; + } + + @Override + public OffsetDateTime getOffsetDateTime(String key) { + if (!properties.containsKey(key)) { + return null; + } + Object val = properties.get(key); + if (val instanceof OffsetDateTime) { + return (OffsetDateTime) val; + } + return null; + } + + @Override + public OffsetDateTime getOffsetDateTime(String key, OffsetDateTime defaultValue) { + return properties.containsKey(key) ? getOffsetDateTime(key) : defaultValue; + } + + @Override + public Object getObject(String key) { + return properties.getOrDefault(key, null); + } + + @Override + public Object getObject(String key, Object defaultValue) { + return properties.getOrDefault(key, defaultValue); + } + + @SuppressWarnings("unchecked") + @Override + public T getObject(String key, Class c) { + if (!properties.containsKey(key)) { + return null; + } + Object val = properties.get(key); + if (val.getClass() == c) { + return (T) val; + } + return null; + } + + @Override + public T getObject(String key, T defaultValue, Class c) { + return properties.containsKey(key) ? getObject(key, c) : defaultValue; + } + + @Override + public Set keySet() { + return properties.keySet(); + } + + @Override + public boolean containsKey(String key) { + return properties.containsKey(key); + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/KeyValue.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/KeyValue.java new file mode 100644 index 0000000000..1cff3ddfc7 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/KeyValue.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.data; + +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.Set; + +/** + * used for connector-record extension + */ +public interface KeyValue { + + KeyValue put(String key, Boolean value); + + KeyValue put(String key, Number value); + + KeyValue put(String key, byte[] value); + + KeyValue put(String key, String value); + + KeyValue put(String key, URI value); + + KeyValue put(String key, OffsetDateTime value); + + KeyValue put(String key, Object value); + + boolean getBoolean(String key); + + boolean getBoolean(String key, boolean defaultValue); + + byte getByte(String key); + + byte getByte(String key, byte defaultValue); + + short getShort(String key); + + short getShort(String key, short defaultValue); + + int getInt(String key); + + int getInt(String key, int defaultValue); + + long getLong(String key); + + long getLong(String key, long defaultValue); + + float getFloat(String key); + + float getFloat(String key, float defaultValue); + + double getDouble(String key); + + double getDouble(String key, double defaultValue); + + byte[] getBytes(String key); + + byte[] getBytes(String key, byte[] defaultValue); + + String getString(String key); + + String getString(String key, String defaultValue); + + URI getURI(String key); + + URI getURI(String key, URI defaultValue); + + OffsetDateTime getOffsetDateTime(String key); + + OffsetDateTime getOffsetDateTime(String key, OffsetDateTime defaultValue); + + Object getObject(String key); + + Object getObject(String key, Object defaultValue); + + T getObject(String key, Class c); + + T getObject(String key, T defaultValue, Class c); + + Set keySet(); + + boolean containsKey(String key); +} \ No newline at end of file diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/RecordOffsetManagement.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/RecordOffsetManagement.java new file mode 100644 index 0000000000..7e6b5042f8 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/data/RecordOffsetManagement.java @@ -0,0 +1,269 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.data; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.common.remote.offset.RecordPosition; + +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RecordOffsetManagement { + + final Map> records = new HashMap<>(); + private final AtomicInteger numUnacked = new AtomicInteger(0); + + private CountDownLatch messageDrainLatch; + + public RecordOffsetManagement() { + } + + /** + * submit record + * + * @param position + * @return + */ + public SubmittedPosition submitRecord(RecordPosition position) { + SubmittedPosition submittedPosition = new SubmittedPosition(position); + records.computeIfAbsent(position.getRecordPartition(), e -> new LinkedList<>()).add(submittedPosition); + // ensure thread safety in operation + synchronized (this) { + numUnacked.incrementAndGet(); + } + return submittedPosition; + } + + /** + * @param submittedPositions + * @return + */ + private RecordOffset pollOffsetWhile(Deque submittedPositions) { + RecordOffset offset = null; + // Stop pulling if there is an uncommitted breakpoint + while (canCommitHead(submittedPositions)) { + offset = submittedPositions.poll().getPosition().getRecordOffset(); + } + return offset; + } + + private boolean canCommitHead(Deque submittedPositions) { + return submittedPositions.peek() != null && submittedPositions.peek().getAcked(); + } + + public boolean awaitAllMessages(long timeout, TimeUnit timeUnit) { + // Create a new message drain latch as a local variable to avoid SpotBugs warnings about inconsistent synchronization + // on an instance variable when invoking CountDownLatch::await outside a synchronized block + CountDownLatch messageDrainLatch; + synchronized (this) { + messageDrainLatch = new CountDownLatch(numUnacked.get()); + this.messageDrainLatch = messageDrainLatch; + } + try { + return messageDrainLatch.await(timeout, timeUnit); + } catch (InterruptedException e) { + return false; + } + } + + public CommittableOffsets committableOffsets() { + Map offsets = new HashMap<>(); + int totalCommittableMessages = 0; + int totalUncommittableMessages = 0; + int largestDequeSize = 0; + RecordPartition largestDequePartition = null; + for (Map.Entry> entry : records.entrySet()) { + RecordPartition partition = entry.getKey(); + Deque queuedRecords = entry.getValue(); + int initialDequeSize = queuedRecords.size(); + if (canCommitHead(queuedRecords)) { + RecordOffset offset = pollOffsetWhile(queuedRecords); + offsets.put(partition, offset); + } + // uncommited messages + int uncommittableMessages = queuedRecords.size(); + // committed messages + int committableMessages = initialDequeSize - uncommittableMessages; + + // calc total + totalCommittableMessages += committableMessages; + totalUncommittableMessages += uncommittableMessages; + + if (uncommittableMessages > largestDequeSize) { + largestDequeSize = uncommittableMessages; + largestDequePartition = partition; + } + } + // Clear out all empty deques from the map to keep it from growing indefinitely + records.values().removeIf(Deque::isEmpty); + return new CommittableOffsets(offsets, totalCommittableMessages, totalUncommittableMessages, + records.size(), largestDequeSize, largestDequePartition); + } + + // Synchronize in order to ensure that the number of unacknowledged messages isn't modified in the middle of a call + // to awaitAllMessages (which might cause us to decrement first, then create a new message drain latch, then count down + // that latch here, effectively double-acking the message) + private synchronized void messageAcked() { + numUnacked.decrementAndGet(); + if (messageDrainLatch != null) { + messageDrainLatch.countDown(); + } + } + + /** + * Contains a snapshot of offsets that can be committed for a source task and metadata for that offset commit (such as the number of messages for + * which offsets can and cannot be committed). + */ + public static class CommittableOffsets { + + /** + * An "empty" snapshot that contains no offsets to commit and whose metadata contains no committable or uncommitable messages. + */ + public static final CommittableOffsets EMPTY = new CommittableOffsets(Collections.emptyMap(), 0, 0, 0, 0, null); + + private final Map offsets; + private final RecordPartition largestDequePartition; + private final int numCommittableMessages; + private final int numUncommittableMessages; + private final int numDeques; + private final int largestDequeSize; + + CommittableOffsets( + Map offsets, + int numCommittableMessages, + int numUncommittableMessages, + int numDeques, + int largestDequeSize, + RecordPartition largestDequePartition) { + this.offsets = offsets != null ? new HashMap<>(offsets) : Collections.emptyMap(); + this.numCommittableMessages = numCommittableMessages; + this.numUncommittableMessages = numUncommittableMessages; + this.numDeques = numDeques; + this.largestDequeSize = largestDequeSize; + this.largestDequePartition = largestDequePartition; + } + + public Map offsets() { + return Collections.unmodifiableMap(offsets); + } + + public int numCommittableMessages() { + return numCommittableMessages; + } + + public int numUncommittableMessages() { + return numUncommittableMessages; + } + + public int numDeques() { + return numDeques; + } + + public int largestDequeSize() { + return largestDequeSize; + } + + public RecordPartition largestDequePartition() { + return largestDequePartition; + } + + public boolean hasPending() { + return numUncommittableMessages > 0; + } + + public boolean isEmpty() { + return numCommittableMessages == 0 && numUncommittableMessages == 0 && offsets.isEmpty(); + } + + public CommittableOffsets updatedWith(CommittableOffsets newerOffsets) { + Map offsets = new HashMap<>(this.offsets); + offsets.putAll(newerOffsets.offsets); + + return new CommittableOffsets( + offsets, + this.numCommittableMessages + newerOffsets.numCommittableMessages, + newerOffsets.numUncommittableMessages, + newerOffsets.numDeques, + newerOffsets.largestDequeSize, + newerOffsets.largestDequePartition); + } + } + + public class SubmittedPosition { + + private final RecordPosition position; + private final AtomicBoolean acked; + + public SubmittedPosition(RecordPosition position) { + this.position = position; + acked = new AtomicBoolean(false); + } + + /** + * Acknowledge this record; signals that its offset may be safely committed. + */ + public void ack() { + if (this.acked.compareAndSet(false, true)) { + messageAcked(); + } + } + + /** + * remove record + * + * @return + */ + public boolean remove() { + Deque deque = records.get(position.getRecordPartition()); + if (deque == null) { + return false; + } + boolean result = deque.removeLastOccurrence(this); + if (deque.isEmpty()) { + records.remove(position.getRecordPartition()); + } + if (result) { + messageAcked(); + } else { + log.warn("Attempted to remove record from submitted queue for partition {}, " + + "but the record has not been submitted or has already been removed", position.getRecordPartition()); + } + return result; + } + + public RecordPosition getPosition() { + return position; + } + + public Boolean getAcked() { + return acked.get(); + } + } + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/DefaultOffsetManagementServiceImpl.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/DefaultOffsetManagementServiceImpl.java new file mode 100644 index 0000000000..be72097911 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/DefaultOffsetManagementServiceImpl.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.List; +import java.util.Map; + +public class DefaultOffsetManagementServiceImpl implements OffsetManagementService { + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + @Override + public void persist() { + + } + + @Override + public void load() { + + } + + @Override + public void synchronize() { + + } + + @Override + public Map getPositionMap() { + return null; + } + + @Override + public RecordOffset getPosition(RecordPartition partition) { + return null; + } + + @Override + public void putPosition(Map positions) { + + } + + @Override + public void putPosition(RecordPartition partition, RecordOffset position) { + + } + + @Override + public void removePosition(List partitions) { + + } + + @Override + public void initialize(OffsetStorageConfig connectorConfig) { + + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/KeyValueStore.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/KeyValueStore.java new file mode 100644 index 0000000000..2d9a41290d --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/KeyValueStore.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import java.util.Map; + +/** + * Key value based store interface. + * + * @param + * @param + */ +public interface KeyValueStore { + + /** + * Put a key/value into the store. + * + * @param key + * @param value + * @return + */ + V put(K key, V value); + + /** + * Put a set of key/value into the store. + * + * @param map + */ + void putAll(Map map); + + /** + * Remove a specified key. + * + * @param key + * @return + */ + V remove(K key); + + /** + * Get the size of current key/value store. + * + * @return + */ + int size(); + + /** + * Whether a key is contained in current store. + * + * @param key + * @return + */ + boolean containsKey(K key); + + /** + * Get the value of a key. + * + * @param key + * @return + */ + V get(K key); + + /** + * Get all data from the current store. Not recommend to use this method when the data set is large. + * + * @return + */ + Map getKVMap(); + + /** + * Load the data from back store. + * + * @return + */ + boolean load(); + + /** + * Persist all data into the store. + */ + void persist(); + + Stage getStage(); + + enum Stage { + CONNECTOR, + TASK, + POSITION, + UNIVERSAL + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/MemoryBasedKeyValueStore.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/MemoryBasedKeyValueStore.java new file mode 100644 index 0000000000..e13e1fe231 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/MemoryBasedKeyValueStore.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MemoryBasedKeyValueStore implements KeyValueStore { + + protected Map data; + + public MemoryBasedKeyValueStore() { + this.data = new ConcurrentHashMap<>(); + } + + @Override + public V put(K key, V value) { + return this.data.put(key, value); + } + + @Override + public void putAll(Map map) { + data.putAll(map); + } + + @Override + public V remove(K key) { + return this.data.remove(key); + } + + @Override + public int size() { + return this.data.size(); + } + + @Override + public boolean containsKey(K key) { + return this.data.containsKey(key); + } + + @Override + public V get(K key) { + return this.data.get(key); + } + + @Override + public Map getKVMap() { + return this.data; + } + + @Override + public boolean load() { + return true; + } + + @Override + public void persist() { + + } + + @Override + public Stage getStage() { + return Stage.UNIVERSAL; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetManagementService.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetManagementService.java new file mode 100644 index 0000000000..62327a1ae9 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetManagementService.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +import java.util.List; +import java.util.Map; + +/** + * Interface for offset manager. + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.OFFSETMGMT) +public interface OffsetManagementService { + + /** + * Start the manager. + */ + void start(); + + /** + * Stop the manager. + */ + void stop(); + + /** + * Configure class with the given key-value pairs + */ + default void configure(OffsetStorageConfig config) { + + } + + /** + * Persist position info in a persisted store. + */ + void persist(); + + /** + * load position info in a persisted store. + */ + void load(); + + /** + * Synchronize to other nodes. + */ + void synchronize(); + + /** + * Get the current position table. + * + * @return + */ + Map getPositionMap(); + + RecordOffset getPosition(RecordPartition partition); + + /** + * Put a position info. + */ + void putPosition(Map positions); + + void putPosition(RecordPartition partition, RecordOffset position); + + /** + * Remove a position info. + * + * @param partitions + */ + void removePosition(List partitions); + + void initialize(OffsetStorageConfig offsetStorageConfig); + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageReader.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageReader.java new file mode 100644 index 0000000000..30546b96cb --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageReader.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Collection; +import java.util.Map; + +/** + * OffsetStorageReader + */ +public interface OffsetStorageReader { + + RecordOffset readOffset(RecordPartition recordPartition); + + Map readOffsets(Collection collection); + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageReaderImpl.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageReaderImpl.java new file mode 100644 index 0000000000..ca4ad2c751 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageReaderImpl.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class OffsetStorageReaderImpl implements OffsetStorageReader { + + private OffsetManagementService offsetManagementService; + + public OffsetStorageReaderImpl(OffsetManagementService offsetManagementService) { + this.offsetManagementService = offsetManagementService; + } + + @Override + public RecordOffset readOffset(RecordPartition partition) { + return offsetManagementService.getPositionMap().get(partition); + } + + @Override + public Map readOffsets(Collection partitions) { + Map result = new HashMap<>(); + Map allData = offsetManagementService.getPositionMap(); + for (RecordPartition key : partitions) { + if (allData.containsKey(key)) { + result.put(key, allData.get(key)); + } + } + return result; + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageWriter.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageWriter.java new file mode 100644 index 0000000000..fb30acc918 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageWriter.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.util.Map; + +/** + * OffsetStorageWriter + */ +public interface OffsetStorageWriter { + + void writeOffset(RecordPartition recordPartition, RecordOffset recordOffset); + + void writeOffset(Map map); + +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageWriterImpl.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageWriterImpl.java new file mode 100644 index 0000000000..ef52602d60 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-api/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/api/storage/OffsetStorageWriterImpl.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.api.storage; + +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; + +import java.io.Closeable; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OffsetStorageWriterImpl implements OffsetStorageWriter, Closeable { + + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final OffsetManagementService offsetManagementService; + /** + * Offset data in Connect format + */ + private Map data = new HashMap<>(); + private Map toFlush = null; + + // Unique ID for each flush request to handle callbacks after timeouts + private long currentFlushId = 0; + + public OffsetStorageWriterImpl(OffsetManagementService offsetManagementService) { + this.offsetManagementService = offsetManagementService; + } + + @Override + public void writeOffset(RecordPartition partition, RecordOffset offset) { + if (partition != null) { + data.put(partition, offset); + } + } + + /** + * write offsets + * + * @param positions positions + */ + @Override + public void writeOffset(Map positions) { + for (Map.Entry offset : positions.entrySet()) { + writeOffset(offset.getKey(), offset.getValue()); + } + } + + private boolean isFlushing() { + return toFlush != null; + } + + /** + * begin flush offset + * + * @return + */ + public synchronized boolean beginFlush() { + if (isFlushing()) { + log.warn("OffsetStorageWriter is already flushing"); + return false; + } + if (data.isEmpty()) { + return false; + } + this.toFlush = this.data; + this.data = new HashMap<>(); + return true; + } + + /** + * do flush offset + */ + public Future doFlush() { + final long flushId = currentFlushId; + return sendOffsetFuture(flushId); + } + + /** + * Cancel a flush that has been initiated by {@link #beginFlush}. + */ + public synchronized void cancelFlush() { + if (isFlushing()) { + // rollback to inited + toFlush.putAll(data); + data = toFlush; + currentFlushId++; + toFlush = null; + } + } + + private Future sendOffsetFuture(long flushId) { + FutureTask futureTask = new FutureTask<>(new SendOffsetCallback(flushId)); + executorService.submit(futureTask); + return futureTask; + } + + /** + * Closes this stream and releases any system resources associated + * with it. If the stream is already closed then invoking this + * method has no effect. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + executorService.shutdown(); + } + + /** + * send offset callback + */ + private class SendOffsetCallback implements Callable { + + long flushId; + + public SendOffsetCallback(long flushId) { + this.flushId = flushId; + } + + /** + * Computes a result, or throws an exception if unable to do so. + * + * @return computed result + * @throws Exception if unable to compute a result + */ + @Override + public Void call() { + try { + // has been canceled + if (flushId != currentFlushId) { + return null; + } + offsetManagementService.putPosition(toFlush); + log.debug("Submitting {} entries to backing store. The offsets are: {}", toFlush.size(), toFlush); + offsetManagementService.persist(); + offsetManagementService.synchronize(); + // persist finished + toFlush = null; + currentFlushId++; + } catch (Throwable throwable) { + // rollback + cancelFlush(); + } + return null; + } + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/build.gradle b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/build.gradle new file mode 100644 index 0000000000..8637d73371 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/build.gradle @@ -0,0 +1,26 @@ +/* + * 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. + */ + +dependencies { + implementation "com.alibaba.nacos:nacos-client" + implementation project(":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api") + implementation project(":eventmesh-common") + testImplementation "org.mockito:mockito-core" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-webhook/eventmesh-webhook-api/gradle.properties b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/gradle.properties similarity index 100% rename from eventmesh-webhook/eventmesh-webhook-api/gradle.properties rename to eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/gradle.properties diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/nacos/NacosConfigService.java b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/nacos/NacosConfigService.java new file mode 100644 index 0000000000..67c53d4d6d --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/src/main/java/org/apache/eventmesh/openconnect/offsetmgmt/nacos/NacosConfigService.java @@ -0,0 +1,222 @@ +/* + * 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. + */ + +package org.apache.eventmesh.openconnect.offsetmgmt.nacos; + +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; +import org.apache.eventmesh.common.remote.offset.RecordOffset; +import org.apache.eventmesh.common.remote.offset.RecordPartition; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.KeyValueStore; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.MemoryBasedKeyValueStore; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class NacosConfigService implements OffsetManagementService { + + @Getter + private String serverAddr; + + @Getter + private String dataId; + + @Getter + private String group; + + private ConfigService configService; + + private Listener listener; + + public KeyValueStore positionStore; + + @Override + public void start() { + try { + configService.addListener(dataId, group, listener); + } catch (NacosException e) { + log.error("nacos start error", e); + } + } + + // merge the updated connectorRecord & recordOffset to memory store + public void mergeOffset(RecordPartition recordPartition, RecordOffset recordOffset) { + if (recordPartition == null) { + return; + } + if (positionStore.getKVMap().containsKey(recordPartition)) { + RecordOffset existedOffset = positionStore.getKVMap().get(recordPartition); + // update + if (!recordOffset.equals(existedOffset)) { + positionStore.put(recordPartition, recordOffset); + } + } else { + // add new position + positionStore.put(recordPartition, recordOffset); + } + } + + @Override + public void stop() { + configService.removeListener(dataId, group, listener); + } + + @Override + public void configure(OffsetStorageConfig config) { + + } + + // only file based storage need to imply + @Override + public void persist() { + + } + + @Override + public void load() { + + } + + @Override + public void synchronize() { + try { + Map recordMap = positionStore.getKVMap(); + + List> recordToSyncList = new ArrayList<>(); + for (Map.Entry entry : recordMap.entrySet()) { + Map synchronizeMap = new HashMap<>(); + synchronizeMap.put("recordPartition", entry.getKey()); + synchronizeMap.put("recordOffset", entry.getValue()); + recordToSyncList.add(synchronizeMap); + } + log.info("start publish config: dataId={}|group={}|value={}", dataId, group, recordToSyncList); + configService.publishConfig(dataId, group, JacksonUtils.toJson(recordToSyncList)); + } catch (NacosException e) { + throw new RuntimeException("Nacos Service publish config error", e); + } + } + + @Override + public Map getPositionMap() { + // get from memory storage first + if (positionStore.getKVMap() == null || positionStore.getKVMap().isEmpty()) { + try { + Map configMap = JacksonUtils.toObj(configService.getConfig(dataId, group, 5000L), + new TypeReference>() { + }); + positionStore.putAll(configMap); + log.info("nacos position map {}", configMap); + return configMap; + } catch (NacosException e) { + throw new RuntimeException(e); + } + } + log.info("memory position map {}", positionStore.getKVMap()); + return positionStore.getKVMap(); + } + + @Override + public RecordOffset getPosition(RecordPartition partition) { + // get from memory storage first + if (positionStore.get(partition) == null) { + try { + Map recordMap = JacksonUtils.toObj(configService.getConfig(dataId, group, 5000L), + new TypeReference>() { + }); + log.info("nacos record position {}", recordMap.get(partition)); + return recordMap.get(partition); + } catch (NacosException e) { + throw new RuntimeException(e); + } + } + log.info("memory record position {}", positionStore.get(partition)); + return positionStore.get(partition); + } + + @Override + public void putPosition(Map positions) { + positionStore.putAll(positions); + } + + @Override + public void putPosition(RecordPartition partition, RecordOffset position) { + positionStore.put(partition, position); + } + + @Override + public void removePosition(List partitions) { + if (partitions == null) { + return; + } + for (RecordPartition partition : partitions) { + positionStore.remove(partition); + } + } + + @Override + public void initialize(OffsetStorageConfig config) { + this.serverAddr = config.getOffsetStorageAddr(); + this.dataId = config.getExtensions().get("dataId"); + this.group = config.getExtensions().get("group"); + this.positionStore = new MemoryBasedKeyValueStore<>(); + try { + configService = NacosFactory.createConfigService(serverAddr); + } catch (NacosException e) { + log.error("nacos init error", e); + } + this.listener = new Listener() { + + @Override + public Executor getExecutor() { + return null; + } + + @Override + public void receiveConfigInfo(String configInfo) { + log.info("nacos config service receive configInfo: {}", configInfo); + List> recordOffsetList = JacksonUtils.toObj(configInfo, + new TypeReference>>() { + }); + + for (Map recordPartitionOffsetMap : recordOffsetList) { + RecordPartition recordPartition = JacksonUtils.toObj( + JacksonUtils.toJson(recordPartitionOffsetMap.get("recordPartition")), + RecordPartition.class); + RecordOffset recordOffset = JacksonUtils.toObj(JacksonUtils.toJson(recordPartitionOffsetMap.get("recordOffset")), + RecordOffset.class); + // update the offset in memory store + mergeOffset(recordPartition, recordOffset); + } + } + }; + + } +} diff --git a/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService new file mode 100644 index 0000000000..a7e24c70a2 --- /dev/null +++ b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/eventmesh-openconnect-offsetmgmt-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService @@ -0,0 +1,16 @@ +# 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. + +nacos=org.apache.eventmesh.openconnect.offsetmgmt.nacos.NacosConfigService \ No newline at end of file diff --git a/eventmesh-webhook/eventmesh-webhook-receive/gradle.properties b/eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/gradle.properties similarity index 100% rename from eventmesh-webhook/eventmesh-webhook-receive/gradle.properties rename to eventmesh-openconnect/eventmesh-openconnect-offsetmgmt-plugin/gradle.properties diff --git a/eventmesh-webhook/gradle.properties b/eventmesh-openconnect/gradle.properties similarity index 100% rename from eventmesh-webhook/gradle.properties rename to eventmesh-openconnect/gradle.properties diff --git a/eventmesh-operator/.dockerignore b/eventmesh-operator/.dockerignore new file mode 100644 index 0000000000..0f046820f1 --- /dev/null +++ b/eventmesh-operator/.dockerignore @@ -0,0 +1,4 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore build and test binaries. +bin/ +testbin/ diff --git a/eventmesh-operator/.gitignore b/eventmesh-operator/.gitignore new file mode 100644 index 0000000000..e917e5cefe --- /dev/null +++ b/eventmesh-operator/.gitignore @@ -0,0 +1,26 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin +testbin/* +Dockerfile.cross + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ diff --git a/eventmesh-operator/Dockerfile b/eventmesh-operator/Dockerfile new file mode 100644 index 0000000000..14a2e63f0d --- /dev/null +++ b/eventmesh-operator/Dockerfile @@ -0,0 +1,51 @@ +# +# 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. +# + +# Build the manager binary +FROM golang:1.19 as builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY main.go main.go +COPY api/ api/ +COPY controllers/ controllers/ +COPY share/ share/ + +# Build +# the GOARCH has not a default value to allow the binary be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /workspace/manager . +USER 65532:65532 + +ENTRYPOINT ["/manager"] diff --git a/eventmesh-operator/Makefile b/eventmesh-operator/Makefile new file mode 100644 index 0000000000..285b47a8c7 --- /dev/null +++ b/eventmesh-operator/Makefile @@ -0,0 +1,317 @@ +# +# 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. +# + +# VERSION defines the project version for the bundle. +# Update this value when you upgrade the version of your project. +# To re-generate a bundle for another specific version without changing the standard setup, you can: +# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) +# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) +VERSION ?= 0.0.1 + +# CHANNELS define the bundle channels used in the bundle. +# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") +# To re-generate a bundle for other specific channels without changing the standard setup, you can: +# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) +# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif + +# DEFAULT_CHANNEL defines the default channel used in the bundle. +# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") +# To re-generate a bundle for any other default channel without changing the default setup, you can: +# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) +# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) + +# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. +# This variable is used to construct full image tags for bundle and catalog images. +# +# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both +# eventmesh/eventmesh-operator-bundle:$VERSION and eventmesh/eventmesh-operator-catalog:$VERSION. +IMAGE_TAG_BASE ?= eventmesh/eventmesh-operator + +# BUNDLE_IMG defines the image:tag used for the bundle. +# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) +BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) + +# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command +BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + +# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests +# You can enable this value if you would like to use SHA Based Digests +# To enable set flag to true +USE_IMAGE_DIGESTS ?= false +ifeq ($(USE_IMAGE_DIGESTS), true) + BUNDLE_GEN_FLAGS += --use-image-digests +endif + +# Set the Operator SDK version to use. By default, what is installed on the system is used. +# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. +OPERATOR_SDK_VERSION ?= v1.31.0 + +# Image URL to use all building/pushing image targets +IMG ?= controller:latest +# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. +ENVTEST_K8S_VERSION = 1.26.0 + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +.PHONY: all +all: build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Development + +.PHONY: manifests +manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. + $(CONTROLLER_GEN) rbac:roleName=eventmesh-operator crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + +.PHONY: generate +generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: manifests generate fmt vet envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out + +##@ Build + +.PHONY: build +build: manifests generate fmt vet ## Build manager binary. + go build -o bin/manager main.go + +.PHONY: run +run: manifests generate fmt vet ## Run a controller from your host. + go run ./main.go + +# If you wish built the manager image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: test ## Build docker image with the manager. + docker build -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the manager. + docker push ${IMG} + +# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ +# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> then the export will fail) +# To properly provided solutions that supports more than one platform you should use this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: test ## Build and push docker image for the manager for cross-platform support + # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile + sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross + - docker buildx create --name project-v3-builder + docker buildx use project-v3-builder + - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - docker buildx rm project-v3-builder + rm Dockerfile.cross + +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +.PHONY: install +install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + kubectl create -f config/crd/bases/eventmesh-operator.eventmesh_runtimes.yaml + kubectl create -f config/crd/bases/eventmesh-operator.eventmesh_connectors.yaml + +.PHONY: uninstall +uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/crd/bases/eventmesh-operator.eventmesh_runtimes.yaml + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/crd/bases/eventmesh-operator.eventmesh_connectors.yaml + +.PHONY: create +create: + kubectl create -f config/samples/eventmesh_v1_runtime.yaml + kubectl create -f config/samples/eventmesh_v1_runtime_cluster.yaml + kubectl create -f config/samples/eventmesh_v1_connectors_rocketmq.yaml + +.PHONY: delete +delete: + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/samples/eventmesh_v1_runtime.yaml + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/samples/eventmesh_v1_runtime_cluster.yaml + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/samples/eventmesh_v1_connectors_rocketmq.yaml + +.PHONY: deploy +deploy: manifests install ## Deploy controller to the K8s cluster specified in ~/.kube/config. + kubectl create -f config/rbac/service_account.yaml + kubectl create -f config/rbac/role.yaml + kubectl create -f config/rbac/role_binding.yaml + kubectl create -f config/samples/eventmesh_operator.yaml + +.PHONY: undeploy +undeploy: uninstall ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/rbac/service_account.yaml + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/rbac/role.yaml + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/rbac/role_binding.yaml + kubectl delete --ignore-not-found=$(ignore-not-found) -f config/samples/eventmesh_operator.yaml + +##@ Build Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +## Tool Binaries +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest + +## Tool Versions +KUSTOMIZE_VERSION ?= v3.8.7 +CONTROLLER_TOOLS_VERSION ?= v0.11.1 + +KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading. +$(KUSTOMIZE): $(LOCALBIN) + @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \ + echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ + rm -rf $(LOCALBIN)/kustomize; \ + fi + test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten. +$(CONTROLLER_GEN): $(LOCALBIN) + test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \ + GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + +.PHONY: envtest +envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +$(ENVTEST): $(LOCALBIN) + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + +.PHONY: operator-sdk +OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk +operator-sdk: ## Download operator-sdk locally if necessary. +ifeq (,$(wildcard $(OPERATOR_SDK))) +ifeq (, $(shell which operator-sdk 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPERATOR_SDK)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\ + chmod +x $(OPERATOR_SDK) ;\ + } +else +OPERATOR_SDK = $(shell which operator-sdk) +endif +endif + +.PHONY: bundle +bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. + $(OPERATOR_SDK) generate kustomize manifests -q + cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) + $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) + $(OPERATOR_SDK) bundle validate ./bundle + +.PHONY: bundle-build +bundle-build: ## Build the bundle image. + docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + +.PHONY: bundle-push +bundle-push: ## Push the bundle image. + $(MAKE) docker-push IMG=$(BUNDLE_IMG) + +.PHONY: opm +OPM = ./bin/opm +opm: ## Download opm locally if necessary. +ifeq (,$(wildcard $(OPM))) +ifeq (,$(shell which opm 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPM)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\ + chmod +x $(OPM) ;\ + } +else +OPM = $(shell which opm) +endif +endif + +# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). +# These images MUST exist in a registry and be pull-able. +BUNDLE_IMGS ?= $(BUNDLE_IMG) + +# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). +CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) + +# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. +ifneq ($(origin CATALOG_BASE_IMG), undefined) +FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) +endif + +# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. +# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: +# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator +.PHONY: catalog-build +catalog-build: opm ## Build a catalog image. + $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + +# Push the catalog image. +.PHONY: catalog-push +catalog-push: ## Push a catalog image. + $(MAKE) docker-push IMG=$(CATALOG_IMG) diff --git a/eventmesh-operator/PROJECT b/eventmesh-operator/PROJECT new file mode 100644 index 0000000000..9b15faf803 --- /dev/null +++ b/eventmesh-operator/PROJECT @@ -0,0 +1,40 @@ +# +# 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. +# + +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html +domain: eventmesh +layout: +- go.kubebuilder.io/v3 +plugins: + manifests.sdk.operatorframework.io/v2: {} + scorecard.sdk.operatorframework.io/v2: {} +projectName: eventmesh-operator +repo: github.com/apache/eventmesh/eventmesh-operator +resources: +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: eventmesh + group: eventmesh-operator + kind: EventMeshOperator + path: github.com/apache/eventmesh/eventmesh-operator/api/v1 + version: v1 +version: "3" diff --git a/eventmesh-operator/README.md b/eventmesh-operator/README.md new file mode 100644 index 0000000000..d67dbefaf8 --- /dev/null +++ b/eventmesh-operator/README.md @@ -0,0 +1,96 @@ +## **EventMesh Operator Quick Start** + +### Preparing: +- docker +- golang (version 1.19) +- kubernetes(kubectl) + **Note:** There is some compatibility between kubernetes an docker, please check the version compatibility between them and download the corresponding version to ensure that they work properly together. + +### Quick Start + +#### Deployment + +1. Go to the eventmesh-operator directory. +```shell +cd eventmesh-operator +``` + +2. Install CRD into the specified k8s cluster. +```shell +make install + +# Uninstall CRDs from the K8s cluster +make uninstall +``` + +If you get error eventmesh-operator/bin/controller-gen: No such file or directory +Run the following command: +```shell +# download controller-gen locally if necessary. +make controller-gen +# download kustomize locally if necessary. +make kustomize +``` + +Success +```shell +# run the following command to view crds information: +kubectl get crds + +NAME CREATED AT +connectors.eventmesh-operator.eventmesh 2023-11-28T01:35:21Z +runtimes.eventmesh-operator.eventmesh 2023-11-28T01:35:21Z +``` + +3. Create and delete CRs: + Custom resource objects are located at: /config/samples + When deleting CR, simply replace create with delete. +```shell +# Create CR for eventmesh-runtime、eventmesh-connector-rocketmq,Creating a clusterIP lets eventmesh-runtime communicate with other components. +make create + +#success: +configmap/runtime-config created +runtime.eventmesh-operator.eventmesh/eventmesh-runtime created +service/runtime-cluster-service created +configmap/connector-rocketmq-config created +connectors.eventmesh-operator.eventmesh/connector-rocketmq created + +# View the created Service. +kubectl get service +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +runtime-cluster-service ClusterIP 127.0.0.1 10000/TCP 17s + +# Delete CR +make delete +``` + +4. Run eventmesh-operator create pods +```shell +make run +# success run log +go fmt ./... +go vet ./... +go run ./main.go +INFO controller-runtime.metrics Metrics server is starting to listen {"addr": ":9020"} +INFO setup starting manager +INFO Starting server {"kind": "health probe", "addr": "[::]:8081"} +INFO Starting server {"path": "/metrics", "kind": "metrics", "addr": "[::]:9020"} +INFO runtime Creating a new eventMeshRuntime StatefulSet. {"StatefulSet.Namespace": "default", "StatefulSet.Name": "eventmesh-runtime-0-a"} +INFO connector Creating a new Connector StatefulSet. {"StatefulSet.Namespace": "default", "StatefulSet.Name": "connector-rocketmq"} +INFO runtime Successful reconciliation! +INFO connector Successful reconciliation! + + + +# After the pods are successfully started, run the following command to view pods. +kubectl get pods +NAME READY STATUS RESTARTS AGE +connector-rocketmq-0 1/1 Running 0 12m +eventmesh-runtime-0-a-0 1/1 Running 0 12m + +kubectl get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +connector-rocketmq-0 1/1 Running 0 13m 10.244.0.21 minikube +eventmesh-runtime-0-a-0 1/1 Running 0 13m 10.244.0.20 minikube +``` diff --git a/eventmesh-operator/api/v1/connectors_types.go b/eventmesh-operator/api/v1/connectors_types.go new file mode 100644 index 0000000000..0e6f9026fa --- /dev/null +++ b/eventmesh-operator/api/v1/connectors_types.go @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ConnectorsSpec defines the desired state of ConnectorsSpec +type ConnectorsSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + // Foo is an example field of Connectors. Edit connectors_types.go to remove/update + + // Size of connector + Size int `json:"size"` + // ConnectorContainers define some configuration + ConnectorContainers []corev1.Container `json:"connectorContainers"` + // HostNetwork can be true or false + HostNetwork bool `json:"hostNetwork,omitempty"` + // DNSPolicy Set DNS policy for the pod. + DNSPolicy corev1.DNSPolicy `json:"dnsPolicy,omitempty"` + // Volumes define the connector config + Volumes []corev1.Volume `json:"volumes"` + // ImagePullPolicy defines how the image is pulled + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` + // PodSecurityContext Pod Security Context + PodSecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"` + // ContainerSecurityContext Container Security Context + ContainerSecurityContext *corev1.SecurityContext `json:"containerSecurityContext,omitempty"` + // ImagePullSecrets The secrets used to pull image from private registry + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` + // Affinity the pod's scheduling constraints + Affinity *corev1.Affinity `json:"affinity,omitempty"` + // Tolerations the pod's tolerations. + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + // NodeSelector is a selector which must be true for the pod to fit on a node + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // PriorityClassName indicates the pod's priority + PriorityClassName string `json:"priorityClassName,omitempty"` + // ServiceAccountName + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +// ConnectorsStatus defines the observed state of ConnectorsStatus +type ConnectorsStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + Size int `json:"size"` + + Nodes []string `json:"nodes"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Connectors is the Schema for the Connectors API +type Connectors struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ConnectorsSpec `json:"spec,omitempty"` + Status ConnectorsStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ConnectorsList contains a list of Connectors +type ConnectorsList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Connectors `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Connectors{}, &ConnectorsList{}) +} diff --git a/eventmesh-operator/api/v1/groupversion_info.go b/eventmesh-operator/api/v1/groupversion_info.go new file mode 100644 index 0000000000..6e5593efcc --- /dev/null +++ b/eventmesh-operator/api/v1/groupversion_info.go @@ -0,0 +1,37 @@ +/* + * 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. + */ + +// Package v1 contains API Schema definitions for the eventmesh-operator v1 API group +// +kubebuilder:object:generate=true +// +groupName=eventmesh-operator.eventmesh +package v1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "eventmesh-operator.eventmesh", Version: "v1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/eventmesh-operator/api/v1/runtime_types.go b/eventmesh-operator/api/v1/runtime_types.go new file mode 100644 index 0000000000..46e7a2f80a --- /dev/null +++ b/eventmesh-operator/api/v1/runtime_types.go @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// RuntimeSpec defines the desired state of Runtime +type RuntimeSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + // Foo is an example field of Runtime. Edit runtime_types.go to remove/update + + // Size of runtime + Size int `json:"size"` + // AllowRestart defines whether allow pod restart + AllowRestart bool `json:"allowRestart"` + // ReplicaPerGroup each runtime's replica number + ReplicaPerGroup int `json:"replicaPerGroup"` + // RuntimePodTemplate define some configuration + RuntimePodTemplate corev1.PodTemplate `json:"runtimePodTemplate"` + // PodSecurityContext Pod Security Context + PodSecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"` + // ContainerSecurityContext Container Security Context + ContainerSecurityContext *corev1.SecurityContext `json:"containerSecurityContext,omitempty"` +} + +// RuntimeStatus defines the observed state of Runtime +type RuntimeStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + Size int `json:"size"` + + Nodes []string `json:"nodes"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Runtime is the Schema for the Runtime API +type Runtime struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RuntimeSpec `json:"spec,omitempty"` + Status RuntimeStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// RuntimeList contains a list of Runtime +type RuntimeList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Runtime `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Runtime{}, &RuntimeList{}) +} diff --git a/eventmesh-operator/api/v1/zz_generated.deepcopy.go b/eventmesh-operator/api/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..765f5d68db --- /dev/null +++ b/eventmesh-operator/api/v1/zz_generated.deepcopy.go @@ -0,0 +1,275 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + * 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. + */ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Connectors) DeepCopyInto(out *Connectors) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connectors. +func (in *Connectors) DeepCopy() *Connectors { + if in == nil { + return nil + } + out := new(Connectors) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Connectors) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectorsList) DeepCopyInto(out *ConnectorsList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Connectors, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectorsList. +func (in *ConnectorsList) DeepCopy() *ConnectorsList { + if in == nil { + return nil + } + out := new(ConnectorsList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ConnectorsList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectorsSpec) DeepCopyInto(out *ConnectorsSpec) { + *out = *in + if in.ConnectorContainers != nil { + in, out := &in.ConnectorContainers, &out.ConnectorContainers + *out = make([]corev1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]corev1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PodSecurityContext != nil { + in, out := &in.PodSecurityContext, &out.PodSecurityContext + *out = new(corev1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.ContainerSecurityContext != nil { + in, out := &in.ContainerSecurityContext, &out.ContainerSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(corev1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]corev1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectorsSpec. +func (in *ConnectorsSpec) DeepCopy() *ConnectorsSpec { + if in == nil { + return nil + } + out := new(ConnectorsSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectorsStatus) DeepCopyInto(out *ConnectorsStatus) { + *out = *in + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectorsStatus. +func (in *ConnectorsStatus) DeepCopy() *ConnectorsStatus { + if in == nil { + return nil + } + out := new(ConnectorsStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Runtime) DeepCopyInto(out *Runtime) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Runtime. +func (in *Runtime) DeepCopy() *Runtime { + if in == nil { + return nil + } + out := new(Runtime) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Runtime) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuntimeList) DeepCopyInto(out *RuntimeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Runtime, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuntimeList. +func (in *RuntimeList) DeepCopy() *RuntimeList { + if in == nil { + return nil + } + out := new(RuntimeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RuntimeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuntimeSpec) DeepCopyInto(out *RuntimeSpec) { + *out = *in + in.RuntimePodTemplate.DeepCopyInto(&out.RuntimePodTemplate) + if in.PodSecurityContext != nil { + in, out := &in.PodSecurityContext, &out.PodSecurityContext + *out = new(corev1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.ContainerSecurityContext != nil { + in, out := &in.ContainerSecurityContext, &out.ContainerSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuntimeSpec. +func (in *RuntimeSpec) DeepCopy() *RuntimeSpec { + if in == nil { + return nil + } + out := new(RuntimeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuntimeStatus) DeepCopyInto(out *RuntimeStatus) { + *out = *in + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuntimeStatus. +func (in *RuntimeStatus) DeepCopy() *RuntimeStatus { + if in == nil { + return nil + } + out := new(RuntimeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/eventmesh-operator/config/crd/bases/eventmesh-operator.eventmesh_connectors.yaml b/eventmesh-operator/config/crd/bases/eventmesh-operator.eventmesh_connectors.yaml new file mode 100644 index 0000000000..c62dbd8c56 --- /dev/null +++ b/eventmesh-operator/config/crd/bases/eventmesh-operator.eventmesh_connectors.yaml @@ -0,0 +1,4095 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: connectors.eventmesh-operator.eventmesh +spec: + group: eventmesh-operator.eventmesh + names: + kind: Connectors + listKind: ConnectorsList + plural: connectors + singular: connectors + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Connectors is the Schema for the Connectors API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ConnectorsSpec defines the desired state of ConnectorsSpec + properties: + affinity: + description: Affinity the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the + pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to + nodes that satisfy the affinity expressions specified by + this field, but it may choose a node that violates one or + more of the expressions. The node that is most preferred + is the one with the greatest sum of weights, i.e. for each + node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, + etc.), compute a sum by iterating through the elements of + this field and adding "weight" to the sum if the node matches + the corresponding matchExpressions; the node(s) with the + highest sum are the most preferred. + items: + description: An empty preferred scheduling term matches + all objects with implicit weight 0 (i.e. it's a no-op). + A null preferred scheduling term matches no objects (i.e. + is also a no-op). + properties: + preference: + description: A node selector term, associated with the + corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string values. If + the operator is In or NotIn, the values + array must be non-empty. If the operator + is Exists or DoesNotExist, the values array + must be empty. If the operator is Gt or + Lt, the values array must have a single + element, which will be interpreted as an + integer. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string values. If + the operator is In or NotIn, the values + array must be non-empty. If the operator + is Exists or DoesNotExist, the values array + must be empty. If the operator is Gt or + Lt, the values array must have a single + element, which will be interpreted as an + integer. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding + nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this + field are not met at scheduling time, the pod will not be + scheduled onto the node. If the affinity requirements specified + by this field cease to be met at some point during pod execution + (e.g. due to an update), the system may or may not try to + eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: A null or empty node selector term matches + no objects. The requirements of them are ANDed. The + TopologySelectorTerm type implements a subset of the + NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string values. If + the operator is In or NotIn, the values + array must be non-empty. If the operator + is Exists or DoesNotExist, the values array + must be empty. If the operator is Gt or + Lt, the values array must have a single + element, which will be interpreted as an + integer. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string values. If + the operator is In or NotIn, the values + array must be non-empty. If the operator + is Exists or DoesNotExist, the values array + must be empty. If the operator is Gt or + Lt, the values array must have a single + element, which will be interpreted as an + integer. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate + this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to + nodes that satisfy the affinity expressions specified by + this field, but it may choose a node that violates one or + more of the expressions. The node that is most preferred + is the one with the greatest sum of weights, i.e. for each + node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, + etc.), compute a sum by iterating through the elements of + this field and adding "weight" to the sum if the node has + pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces field. + null selector and null or empty namespaces list + means "this pod's namespace". An empty selector + ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. The + term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces list + and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified namespaces, + where co-located is defined as running on a node + whose value of the label with key topologyKey + matches that of any node on which any of the selected + pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the corresponding + podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this + field are not met at scheduling time, the pod will not be + scheduled onto the node. If the affinity requirements specified + by this field cease to be met at some point during pod execution + (e.g. due to a pod label update), the system may or may + not try to eventually evict the pod from its node. When + there are multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. all terms + must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or not co-located + (anti-affinity) with, where co-located is defined as running + on a node whose value of the label with key + matches that of any node on which a pod of the set of + pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied to the + union of the namespaces selected by this field and + the ones listed in the namespaces field. null selector + and null or empty namespaces list means "this pod's + namespace". An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list of namespace + names that the term applies to. The term is applied + to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. null or + empty namespaces list and null namespaceSelector means + "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where + co-located is defined as running on a node whose value + of the label with key topologyKey matches that of + any node on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. + avoid putting this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to + nodes that satisfy the anti-affinity expressions specified + by this field, but it may choose a node that violates one + or more of the expressions. The node that is most preferred + is the one with the greatest sum of weights, i.e. for each + node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, + etc.), compute a sum by iterating through the elements of + this field and adding "weight" to the sum if the node has + pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces field. + null selector and null or empty namespaces list + means "this pod's namespace". An empty selector + ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. The + term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces list + and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified namespaces, + where co-located is defined as running on a node + whose value of the label with key topologyKey + matches that of any node on which any of the selected + pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the corresponding + podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by + this field are not met at scheduling time, the pod will + not be scheduled onto the node. If the anti-affinity requirements + specified by this field cease to be met at some point during + pod execution (e.g. due to a pod label update), the system + may or may not try to eventually evict the pod from its + node. When there are multiple elements, the lists of nodes + corresponding to each podAffinityTerm are intersected, i.e. + all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or not co-located + (anti-affinity) with, where co-located is defined as running + on a node whose value of the label with key + matches that of any node on which a pod of the set of + pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied to the + union of the namespaces selected by this field and + the ones listed in the namespaces field. null selector + and null or empty namespaces list means "this pod's + namespace". An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static list of namespace + names that the term applies to. The term is applied + to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. null or + empty namespaces list and null namespaceSelector means + "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where + co-located is defined as running on a node whose value + of the label with key topologyKey matches that of + any node on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + connectorContainers: + description: ConnectorContainers define some configuration + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container image''s + CMD is used if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If a variable + cannot be resolved, the reference in the input string will + be unchanged. Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within a shell. + The container image''s ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the reference + in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: + i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether + the variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. + If a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment variables + in the container. The keys defined within a source must be + a C_IDENTIFIER. All invalid keys will be reported as an event + when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take + precedence. Values defined by an Env with a duplicate key + will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management + to default or override container images in workload controllers + like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take + in response to container lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately after a container + is created. If the handler fails, the container is terminated + and restarted according to its restart policy. Other management + of the container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's + filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, you need + to explicitly call out to that shell. Exit status + of 0 is treated as live/healthy and non-zero is + unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward compatibility. + There are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before a container + is terminated due to an API request or management event + such as liveness/startup probe failure, preemption, resource + contention, etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the container + will eventually terminate within the Pod''s termination + grace period (unless delayed by finalizers). Other management + of the container blocks until the hook completes or until + the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's + filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, you need + to explicitly call out to that shell. Exit status + of 0 is treated as live/healthy and non-zero is + unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward compatibility. + There are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. Container + will be restarted if the probe fails. Cannot be updated. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + This is a beta field and requires enabling GRPCContainerProbe + feature gate. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not + specifying a port here DOES NOT prevent that port from being + exposed. Any port which is listening on the default "0.0.0.0" + address inside a container will be accessible from the network. + Modifying this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: Number of port to expose on the pod's IP + address. This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: Number of port to expose on the host. If + specified, this must be a valid port number, 0 < x < + 65536. If HostNetwork is specified, this must match + ContainerPort. Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in a pod + must have a unique name. Name for the port that can + be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe + fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + This is a beta field and requires enabling GRPCContainerProbe + feature gate. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security options the + container should be run with. If set, the fields of SecurityContext + override the equivalent fields of PodSecurityContext. More + info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN Note that this field cannot be set + when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by + the container runtime. Note that this field cannot be + set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent to + root on the host. Defaults to false. Note that this field + cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to + use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. Note that this field cannot + be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when + spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a + non-root user. If true, the Kubelet will validate the + image at runtime to ensure that it does not run as UID + 0 (root) and fail to start the container if it does. If + unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the value specified + in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a + random SELinux context for each container. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when + spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + Note that this field cannot be set when spec.os.name is + windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile + must be preconfigured on the node to work. Must be + a descending path, relative to the kubelet's configured + seccomp profile location. Must only be set if type + is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - + a profile defined in a file on the node should be + used. RuntimeDefault - the container runtime default + profile should be used. Unconfined - no profile should + be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options from the PodSecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is + linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named + by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should + be run as a 'Host Process' container. This field is + alpha-level and will only be honored by components + that enable the WindowsHostProcessContainers feature + flag. Setting this field without the feature flag + will result in errors when validating the Pod. All + of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). In + addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully + initialized. If specified, no other probes are executed until + this completes successfully. If this probe fails, the Pod + will be restarted, just as if the livenessProbe failed. This + can be used to provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time to load + data or warm a cache, than during steady-state operation. + This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + This is a beta field and requires enabling GRPCContainerProbe + feature gate. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate a buffer + for stdin in the container runtime. If this is not set, reads + from stdin in the container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the + stdin channel after it has been opened by a single attach. + When stdin is true the stdin stream will remain open across + multiple attach sessions. If stdinOnce is set to true, stdin + is opened on container start, is empty until the first client + attaches to stdin, and then remains open and accepts data + until the client disconnects, at which time stdin is closed + and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the + container''s termination message will be written is mounted + into the container''s filesystem. Message written is intended + to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. + The total message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be + populated. File will use the contents of terminationMessagePath + to populate the container status message on both success and + failure. FallbackToLogsOnError will use the last chunk of + container log output if the termination message file is empty + and the container exited with an error. The log output is + limited to 2048 bytes or 80 lines, whichever is smaller. Defaults + to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY for + itself, also requires 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the volume + should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are + propagated from the host to container and the other + way around. When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves similarly + to SubPath but environment variable references $(VAR_NAME) + are expanded using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath are mutually + exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which might + be configured in the container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + containerSecurityContext: + description: ContainerSecurityContext Container Security Context + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a process + can gain more privileges than its parent process. This bool + directly controls if the no_new_privs flag will be set on the + container process. AllowPrivilegeEscalation is true always when + the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container + runtime. Note that this field cannot be set when spec.os.name + is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes in privileged + containers are essentially equivalent to root on the host. Defaults + to false. Note that this field cannot be set when spec.os.name + is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use for + the containers. The default is DefaultProcMount which uses the + container runtime defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. + Default is false. Note that this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container process. + Uses runtime default if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no such validation + will be performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. If + seccomp options are provided at both the pod & container level, + the container options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must be + preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a profile + defined in a file on the node should be used. RuntimeDefault + - the container runtime default profile should be used. + Unconfined - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will + be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named by + the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA + credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should + be run as a 'Host Process' container. This field is alpha-level + and will only be honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature flag + will result in errors when validating the Pod. All of a + Pod's containers must have the same effective HostProcess + value (it is not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: string + type: object + type: object + dnsPolicy: + description: DNSPolicy Set DNS policy for the pod. + type: string + hostNetwork: + description: HostNetwork can be true or false + type: boolean + imagePullPolicy: + description: ImagePullPolicy defines how the image is pulled + type: string + imagePullSecrets: + description: ImagePullSecrets The secrets used to pull image from + private registry + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + nodeSelector: + additionalProperties: + type: string + description: NodeSelector is a selector which must be true for the + pod to fit on a node + type: object + priorityClassName: + description: PriorityClassName indicates the pod's priority + type: string + securityContext: + description: PodSecurityContext Pod Security Context + properties: + fsGroup: + description: "A special supplemental group that applies to all + containers in a pod. Some volume types allow the Kubelet to + change the ownership of that volume to be owned by the pod: + \n 1. The owning GID will be the FSGroup 2. The setgid bit is + set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- \n If unset, + the Kubelet will not modify the ownership and permissions of + any volume. Note that this field cannot be set when spec.os.name + is windows." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of changing + ownership and permission of the volume before being exposed + inside Pod. This field will only apply to volume types which + support fsGroup based ownership(and permissions). It will have + no effect on ephemeral volume types such as: secret, configmaps + and emptydir. Valid values are "OnRootMismatch" and "Always". + If not specified, "Always" is used. Note that this field cannot + be set when spec.os.name is windows.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container process. + Uses runtime default if unset. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no such validation + will be performed. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the value specified + in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers in this + pod. Note that this field cannot be set when spec.os.name is + windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must be + preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a profile + defined in a file on the node should be used. RuntimeDefault + - the container runtime default profile should be used. + Unconfined - no profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process run + in each container, in addition to the container's primary GID, + the fsGroup (if specified), and group memberships defined in + the container image for the uid of the container process. If + unspecified, no additional groups are added to any container. + Note that group memberships defined in the container image for + the uid of the container process are still effective, even if + they are not included in this list. Note that this field cannot + be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls used for + the pod. Pods with unsupported sysctls (by the container runtime) + might fail to launch. Note that this field cannot be set when + spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named by + the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA + credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should + be run as a 'Host Process' container. This field is alpha-level + and will only be honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature flag + will result in errors when validating the Pod. All of a + Pod's containers must have the same effective HostProcess + value (it is not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: string + type: object + type: object + serviceAccountName: + description: ServiceAccountName + type: string + size: + description: Size of connector + type: integer + tolerations: + description: Tolerations the pod's tolerations. + items: + description: The pod this Toleration is attached to tolerates any + taint that matches the triple using the matching + operator . + properties: + effect: + description: Effect indicates the taint effect to match. Empty + means match all taint effects. When specified, allowed values + are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies + to. Empty means match all taint keys. If the key is empty, + operator must be Exists; this combination means to match all + values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the + value. Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod + can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time + the toleration (which must be of effect NoExecute, otherwise + this field is ignored) tolerates the taint. By default, it + is not set, which means tolerate the taint forever (do not + evict). Zero and negative values will be treated as 0 (evict + immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + volumes: + description: Volumes define the connector config + items: + description: Volume represents a named volume in a pod that may + be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk resource + that is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume that + you want to mount. If omitted, the default is to mount + by volume name. Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the readOnly + setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent disk + resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount on + the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: None, + Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in the + blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the blob + storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must be + a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single blob + disk per storage account Managed: azure managed data + disk (only in managed availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service mount + on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that contains + Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host that + shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is a collection + of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted root, + rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is the + path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference + to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados user name, + default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached and + mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. Must + be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to + be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret + object containing parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should populate + this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used to + set permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. Defaults to + 0644. Directories within the path are not affected by + this setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value pair in + the Data field of the referenced ConfigMap will be projected + into the volume as a file whose name is the key and content + is the value. If specified, the listed keys will be projected + into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in + the ConfigMap, the volume setup will error unless it is + marked optional. Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to + set permissions on this file. Must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. If not + specified, the volume defaultMode will be used. + This might be in conflict with other options that + affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the file + to map the key to. May not be an absolute path. + May not contain the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap or its + keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents ephemeral + storage that is handled by certain external CSI drivers (Beta + feature). + properties: + driver: + description: driver is the name of the CSI driver that handles + this volume. Consult with your admin for the correct name + as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated + CSI driver which will determine the default filesystem + to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to the + secret object containing sensitive information to pass + to the CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This field is optional, + and may be empty if no secret is required. If the secret + object contains more than one secret, all secret references + are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific properties + that are passed to the CSI driver. Consult your driver's + documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about the pod + that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created files + by default. Must be a Optional: mode bits used to set + permissions on created files by default. Must be an octal + value between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. Defaults to + 0644. Directories within the path are not affected by + this setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the pod: + only annotations, labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to set permissions + on this file, must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. YAML + accepts both octal and decimal values, JSON requires + decimal values for mode bits. If not specified, + the volume defaultMode will be used. This might + be in conflict with other options that affect the + file mode, like fsGroup, and the result can be other + mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative path + name of the file to be created. Must not be absolute + or contain the ''..'' path. Must be utf-8 encoded. + The first item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory that + shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage medium + should back this directory. The default is "" which means + to use the node''s default medium. Must be an empty string + (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local storage + required for this EmptyDir volume. The size limit is also + applicable for memory medium. The maximum usage on memory + medium EmptyDir would be the minimum value between the + SizeLimit specified here and the sum of memory limits + of all containers in a pod. The default is nil which means + that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that is handled + by a cluster storage driver. The volume's lifecycle is tied + to the pod that defines it - it will be created before the + pod starts, and deleted when the pod is removed. \n Use this + if: a) the volume is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot or capacity + tracking are needed, c) the storage driver is specified through + a storage class, and d) the storage driver supports dynamic + volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between this volume + type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that persist + for longer than the lifecycle of an individual pod. \n Use + CSI for light-weight local ephemeral volumes if the CSI driver + is meant to be used that way - see the documentation of the + driver for more information. \n A pod can use both types of + ephemeral volumes and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC to + provision the volume. The pod in which this EphemeralVolumeSource + is embedded will be the owner of the PVC, i.e. the PVC + will be deleted together with the pod. The name of the + PVC will be `-` where `` is the name from the `PodSpec.Volumes` array entry. + Pod validation will reject the pod if the concatenated + name is not valid for a PVC (for example, too long). \n + An existing PVC with that name that is not owned by the + pod will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC + is meant to be used by the pod, the PVC has to updated + with an owner reference to the pod once the pod exists. + Normally this should not be necessary, but it may be useful + when manually reconstructing a broken cluster. \n This + field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. \n Required, must + not be nil." + properties: + metadata: + description: May contain labels and annotations that + will be copied into the PVC when creating it. No other + fields are allowed and will be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into the PVC + that gets created from this template. The same fields + as in a PersistentVolumeClaim are also valid here. + properties: + accessModes: + description: 'accessModes contains the desired access + modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used to specify + either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) If the + provisioner or an external controller can support + the specified data source, it will create a new + volume based on the contents of the specified + data source. When the AnyVolumeDataSource feature + gate is enabled, dataSource contents will be copied + to dataSourceRef, and dataSourceRef contents will + be copied to dataSource when dataSourceRef.namespace + is not specified. If the namespace is specified, + then dataSourceRef will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group for the resource + being referenced. If APIGroup is not specified, + the specified Kind must be in the core API + group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the object + from which to populate the volume with data, if + a non-empty volume is desired. This may be any + object from a non-empty API group (non core object) + or a PersistentVolumeClaim object. When this field + is specified, volume binding will only succeed + if the type of the specified object matches some + installed volume populator or dynamic provisioner. + This field will replace the functionality of the + dataSource field and as such if both fields are + non-empty, they must have the same value. For + backwards compatibility, when namespace isn''t + specified in dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to the same value + automatically if one of them is empty and the + other is non-empty. When namespace is specified + in dataSourceRef, dataSource isn''t set to the + same value and must be empty. There are three + important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types + of objects, dataSourceRef allows any non-core + object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping + them), dataSourceRef preserves all values, and + generates an error if a disallowed value is specified. + * While dataSource only allows local objects, + dataSourceRef allows objects in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource + feature gate to be enabled. (Alpha) Using the + namespace field of dataSourceRef requires the + CrossNamespaceVolumeDataSource feature gate to + be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the resource + being referenced. If APIGroup is not specified, + the specified Kind must be in the core API + group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + namespace: + description: Namespace is the namespace of resource + being referenced Note that when a namespace + is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferenceGrant documentation + for details. (Alpha) This field requires the + CrossNamespaceVolumeDataSource feature gate + to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the minimum resources + the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to specify + resource requirements that are lower than previous + value but must still be higher than capacity recorded + in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over volumes + to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the name of the + StorageClass required by the claim. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of volume + is required by the claim. Value of Filesystem + is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that is + attached to a kubelet's host machine and then exposed to the + pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. Must + be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. TODO: how do we prevent errors in the + filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world wide identifiers + (wwids) Either wwids or combination of targetWWNs and + lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume resource + that is provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use for + this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. Must + be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends + on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds extra + command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference + to the secret object containing sensitive information + to pass to the plugin scripts. This may be empty if no + secret object is specified. If the secret object contains + more than one secret, all secrets are passed to the plugin + scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached to + a kubelet's host machine. This depends on the Flocker control + service being running + properties: + datasetName: + description: datasetName is Name of the dataset stored as + metadata -> name on the dataset for Flocker should be + considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. This + is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume that + you want to mount. Tip: Ensure that the filesystem type + is supported by the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume that + you want to mount. If omitted, the default is to mount + by volume name. Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume partition + for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource in + GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision + a container with a git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the EmptyDir into + the Pod''s container.' + properties: + directory: + description: directory is the target directory name. Must + not contain or start with '..'. If '.' is supplied, the + volume directory will be the git repository. Otherwise, + if specified, the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount on the + host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs volume + to be mounted with read-only permissions. Defaults to + false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file or directory + on the host machine that is directly exposed to the container. + This is generally used for system agents or other privileged + things that are allowed to see the host machine. Most containers + will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host directory + mounts and who can/can not mount host directories as read/write.' + properties: + path: + description: 'path of the directory on the host. If the + path is a symlink, it will follow the link to the real + path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource that is + attached to a kubelet''s host machine and then exposed to + the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support iSCSI + Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support iSCSI + Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that uses + an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal List. The + portal is either an IP or ip_addr:port if the port is + other than default (typically TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI target + and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. The Portal + is either an IP or ip_addr:port if the port is other than + default (typically TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL and unique + within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that shares + a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. More + info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export to + be mounted with read-only permissions. Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of the + NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents a + reference to a PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting in + VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem type to mount. Must + be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used to set permissions + on created files by default. Must be an octal value between + 0000 and 0777 or a decimal value between 0 and 511. YAML + accepts both octal and decimal values, JSON requires decimal + values for mode bits. Directories within the path are + not affected by this setting. This might be in conflict + with other options that affect the file mode, like fsGroup, + and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along with + other supported volume types + properties: + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the ConfigMap, the volume + setup will error unless it is marked optional. + Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the downwardAPI + data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to + set permissions on this file, must be + an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu + and requests.memory) are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret data + to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the Secret, the volume setup + will error unless it is marked optional. Paths + must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional field specify whether the + Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information about + the serviceAccountToken data to project + properties: + audience: + description: audience is the intended audience + of the token. A recipient of a token must identify + itself with an identifier specified in the audience + of the token, and otherwise should reject the + token. The audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested + duration of validity of the service account + token. As the token approaches expiration, the + kubelet volume plugin will proactively rotate + the service account token. The kubelet will + start trying to rotate the token if the token + is older than 80 percent of its time to live + or if the token is older than 24 hours.Defaults + to 1 hour and must be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative to the + mount point of the file to project the token + into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default is no + group + type: string + readOnly: + description: readOnly here will force the Quobyte volume + to be mounted with read-only permissions. Defaults to + false. + type: boolean + registry: + description: registry represents a single or multiple Quobyte + Registry services specified as a string as host:port pair + (multiple entries are separated with commas) which acts + as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume in the + Backend Used with dynamically provisioned Quobyte volumes, + value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to serivceaccount + user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount on the + host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication secret + for RBDUser. If provided overrides keyring. Default is + nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. Must + be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for ScaleIO + user and other sensitive information. If this is not provided, + Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage for + a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool associated + with the protection domain. + type: string + system: + description: system is the name of the storage system as + configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already + created in the ScaleIO system that is associated with + this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used to + set permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. Defaults to + 0644. Directories within the path are not affected by + this setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value pair in + the Data field of the referenced Secret will be projected + into the volume as a file whose name is the key and content + is the value. If specified, the listed keys will be projected + into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in + the Secret, the volume setup will error unless it is marked + optional. Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to + set permissions on this file. Must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. If not + specified, the volume defaultMode will be used. + This might be in conflict with other options that + affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the file + to map the key to. May not be an absolute path. + May not contain the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret or + its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in the + pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. Must + be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for obtaining + the StorageOS API credentials. If not specified, default + values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name of the + StorageOS volume. Volume names are only unique within + a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of the + volume within StorageOS. If no namespace is specified + then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS + for tighter integration. Set VolumeName to any name to + override the default behaviour. Set to "default" if you + are not using namespaces within StorageOS. Namespaces + that do not pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. Must be + a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy Based + Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies vSphere + volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + required: + - connectorContainers + - size + - volumes + type: object + status: + description: ConnectorsStatus defines the observed state of ConnectorsStatus + properties: + nodes: + items: + type: string + type: array + size: + type: integer + required: + - nodes + - size + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/eventmesh-operator/config/crd/bases/eventmesh-operator.eventmesh_runtimes.yaml b/eventmesh-operator/config/crd/bases/eventmesh-operator.eventmesh_runtimes.yaml new file mode 100644 index 0000000000..b56d1a55f4 --- /dev/null +++ b/eventmesh-operator/config/crd/bases/eventmesh-operator.eventmesh_runtimes.yaml @@ -0,0 +1,8158 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: runtimes.eventmesh-operator.eventmesh +spec: + group: eventmesh-operator.eventmesh + names: + kind: Runtime + listKind: RuntimeList + plural: runtimes + singular: runtime + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Runtime is the Schema for the Runtime API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RuntimeSpec defines the desired state of Runtime + properties: + allowRestart: + description: AllowRestart defines whether allow pod restart + type: boolean + containerSecurityContext: + description: ContainerSecurityContext Container Security Context + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a process + can gain more privileges than its parent process. This bool + directly controls if the no_new_privs flag will be set on the + container process. AllowPrivilegeEscalation is true always when + the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container + runtime. Note that this field cannot be set when spec.os.name + is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes in privileged + containers are essentially equivalent to root on the host. Defaults + to false. Note that this field cannot be set when spec.os.name + is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use for + the containers. The default is DefaultProcMount which uses the + container runtime defaults for readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. + Default is false. Note that this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container process. + Uses runtime default if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no such validation + will be performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. Note that this + field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. If + seccomp options are provided at both the pod & container level, + the container options override the pod options. Note that this + field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must be + preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a profile + defined in a file on the node should be used. RuntimeDefault + - the container runtime default profile should be used. + Unconfined - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will + be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named by + the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA + credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should + be run as a 'Host Process' container. This field is alpha-level + and will only be honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature flag + will result in errors when validating the Pod. All of a + Pod's containers must have the same effective HostProcess + value (it is not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: string + type: object + type: object + replicaPerGroup: + description: ReplicaPerGroup each runtime's replica number + type: integer + runtimePodTemplate: + description: RuntimePodTemplate define some configuration + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this + representation of an object. Servers should convert recognized + schemas to the latest internal value, and may reject unrecognized + values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource + this object represents. Servers may infer this from the endpoint + the client submits requests to. Cannot be updated. In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + type: object + template: + description: Template defines the pods that will be created from + this pod template. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + metadata: + description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + type: object + spec: + description: 'Specification of the desired behavior of the + pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' + properties: + activeDeadlineSeconds: + description: Optional duration in seconds the pod may + be active on the node relative to StartTime before the + system will actively try to mark it failed and kill + associated containers. Value must be a positive integer. + format: int64 + type: integer + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose a + node that violates one or more of the expressions. + The node that is most preferred is the one with + the greatest sum of weights, i.e. for each node + that meets all of the scheduling requirements + (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by + iterating through the elements of this field + and adding "weight" to the sum if the node matches + the corresponding matchExpressions; the node(s) + with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term + matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling + term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string + values. If the operator is In + or NotIn, the values array must + be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + If the operator is Gt or Lt, + the values array must have a + single element, which will be + interpreted as an integer. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string + values. If the operator is In + or NotIn, the values array must + be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + If the operator is Gt or Lt, + the values array must have a + single element, which will be + interpreted as an integer. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in + the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, + the pod will not be scheduled onto the node. + If the affinity requirements specified by this + field cease to be met at some point during pod + execution (e.g. due to an update), the system + may or may not try to eventually evict the pod + from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: A null or empty node selector + term matches no objects. The requirements + of them are ANDed. The TopologySelectorTerm + type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string + values. If the operator is In + or NotIn, the values array must + be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + If the operator is Gt or Lt, + the values array must have a + single element, which will be + interpreted as an integer. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, and + Lt. + type: string + values: + description: An array of string + values. If the operator is In + or NotIn, the values array must + be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + If the operator is Gt or Lt, + the values array must have a + single element, which will be + interpreted as an integer. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules + (e.g. co-locate this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose a + node that violates one or more of the expressions. + The node that is most preferred is the one with + the greatest sum of weights, i.e. for each node + that meets all of the scheduling requirements + (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by + iterating through the elements of this field + and adding "weight" to the sum if the node has + pods which matches the corresponding podAffinityTerm; + the node(s) with the highest sum are the most + preferred. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added per-node + to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's + namespace". An empty selector ({}) + matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a + static list of namespace names that + the term applies to. The term is applied + to the union of the namespaces listed + in this field and the ones selected + by namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running on + a node whose value of the label with + key topologyKey matches that of any + node on which any of the selected + pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in + the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, + the pod will not be scheduled onto the node. + If the affinity requirements specified by this + field cease to be met at some point during pod + execution (e.g. due to a pod label update), + the system may or may not try to eventually + evict the pod from its node. When there are + multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. + all terms must be satisfied. + items: + description: Defines a set of pods (namely those + matching the labelSelector relative to the + given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) + with, where co-located is defined as running + on a node whose value of the label with key + matches that of any node on + which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of + resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + The term is applied to the union of the + namespaces selected by this field and + the ones listed in the namespaces field. + null selector and null or empty namespaces + list means "this pod's namespace". An + empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. The term is applied to the + union of the namespaces listed in this + field and the ones selected by namespaceSelector. + null or empty namespaces list and null + namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling + rules (e.g. avoid putting this pod in the same node, + zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the anti-affinity + expressions specified by this field, but it + may choose a node that violates one or more + of the expressions. The node that is most preferred + is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + anti-affinity expressions, etc.), compute a + sum by iterating through the elements of this + field and adding "weight" to the sum if the + node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest + sum are the most preferred. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added per-node + to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's + namespace". An empty selector ({}) + matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a + static list of namespace names that + the term applies to. The term is applied + to the union of the namespaces listed + in this field and the ones selected + by namespaceSelector. null or empty + namespaces list and null namespaceSelector + means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running on + a node whose value of the label with + key topologyKey matches that of any + node on which any of the selected + pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in + the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto the + node. If the anti-affinity requirements specified + by this field cease to be met at some point + during pod execution (e.g. due to a pod label + update), the system may or may not try to eventually + evict the pod from its node. When there are + multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. + all terms must be satisfied. + items: + description: Defines a set of pods (namely those + matching the labelSelector relative to the + given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) + with, where co-located is defined as running + on a node whose value of the label with key + matches that of any node on + which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of + resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies to. + The term is applied to the union of the + namespaces selected by this field and + the ones listed in the namespaces field. + null selector and null or empty namespaces + list means "this pod's namespace". An + empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. The term is applied to the + union of the namespaces listed in this + field and the ones selected by namespaceSelector. + null or empty namespaces list and null + namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + automountServiceAccountToken: + description: AutomountServiceAccountToken indicates whether + a service account token should be automatically mounted. + type: boolean + containers: + description: List of containers belonging to the pod. + Containers cannot currently be added or removed. There + must be at least one container in a Pod. Cannot be updated. + items: + description: A single application container that you + want to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot + be resolved, the reference in the input string + will be unchanged. Double $$ are reduced to a + single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot + be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set + in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container and + any service environment variables. If a + variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container + is starting. When a key exists in multiple sources, + the value associated with the last source will + take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be + updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a + C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to an + API request or management event such as liveness/startup + probe failure, preemption, resource contention, + etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination grace + period (unless delayed by finalizers). Other + management of the container blocks until the + hook completes or until the termination grace + period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that + port from being exposed. Any port which is listening + on the default "0.0.0.0" address inside a container + will be accessible from the network. Modifying + this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on the + pod's IP address. This must be a valid port + number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the + host. If specified, this must be a valid + port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an + IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique + name. Name for the port that can be referred + to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, + TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If set, + the fields of SecurityContext override the equivalent + fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run + as Privileged 2) has CAP_SYS_ADMIN Note that + this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when + running containers. Defaults to the default + set of capabilities granted by the container + runtime. Note that this field cannot be set + when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults to + false. Note that this field cannot be set + when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default + is DefaultProcMount which uses the container + runtime defaults for readonly paths and masked + paths. This requires the ProcMountType feature + flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of + the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must + run as a non-root user. If true, the Kubelet + will validate the image at runtime to ensure + that it does not run as UID 0 (root) and fail + to start the container if it does. If unset + or false, no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of + the container process. Defaults to user specified + in image metadata if unspecified. May also + be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be preconfigured + on the node to work. Must be a descending + path, relative to the kubelet's configured + seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. Valid + options are: \n Localhost - a profile + defined in a file on the node should be + used. RuntimeDefault - the container runtime + default profile should be used. Unconfined + - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the + name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a + container should be run as a 'Host Process' + container. This field is alpha-level and + will only be honored by components that + enable the WindowsHostProcessContainers + feature flag. Setting this field without + the feature flag will result in errors + when validating the Pod. All of a Pod's + containers must have the same effective + HostProcess value (it is not allowed to + have a mix of HostProcess containers and + non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container process. + Defaults to the user specified in image + metadata if unspecified. May also be set + in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod + has successfully initialized. If specified, no + other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it + might take a long time to load data or warm a + cache, than during steady-state operation. This + cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If + this is not set, reads from stdin in the container + will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is + opened on container start, is empty until the + first client attaches to stdin, and then remains + open and accepts data until the client disconnects, + at which time stdin is closed and remains closed + until the container is restarted. If this flag + is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to + which the container''s termination message will + be written is mounted into the container''s filesystem. + Message written is intended to be brief final + status, such as an assertion failure message. + Will be truncated by the node if greater than + 4096 bytes. The total message length across all + containers will be limited to 12kb. Defaults to + /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. FallbackToLogsOnError + will use the last chunk of container log output + if the termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will be + mapped to. + type: string + name: + description: name must match the name of a + persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how + mounts are propagated from the host to container + and the other way around. When not set, + MountPropagationNone is used. This field + is beta in 1.10. + type: string + name: + description: This must match the Name of a + Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults + to false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not + specified, the container runtime's default will + be used, which might be configured in the container + image. Cannot be updated. + type: string + required: + - name + type: object + type: array + dnsConfig: + description: Specifies the DNS parameters of a pod. Parameters + specified here will be merged to the generated DNS configuration + based on DNSPolicy. + properties: + nameservers: + description: A list of DNS name server IP addresses. + This will be appended to the base nameservers generated + from DNSPolicy. Duplicated nameservers will be removed. + items: + type: string + type: array + options: + description: A list of DNS resolver options. This + will be merged with the base options generated from + DNSPolicy. Duplicated entries will be removed. Resolution + options given in Options will override those that + appear in the base DNSPolicy. + items: + description: PodDNSConfigOption defines DNS resolver + options of a pod. + properties: + name: + description: Required. + type: string + value: + type: string + type: object + type: array + searches: + description: A list of DNS search domains for host-name + lookup. This will be appended to the base search + paths generated from DNSPolicy. Duplicated search + paths will be removed. + items: + type: string + type: array + type: object + dnsPolicy: + description: Set DNS policy for the pod. Defaults to "ClusterFirst". + Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', + 'Default' or 'None'. DNS parameters given in DNSConfig + will be merged with the policy selected with DNSPolicy. + To have DNS options set along with hostNetwork, you + have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. + type: string + enableServiceLinks: + description: 'EnableServiceLinks indicates whether information + about services should be injected into pod''s environment + variables, matching the syntax of Docker links. Optional: + Defaults to true.' + type: boolean + ephemeralContainers: + description: List of ephemeral containers run in this + pod. Ephemeral containers may be run in an existing + pod to perform user-initiated actions such as debugging. + This list cannot be specified when creating a pod, and + it cannot be modified by updating the pod spec. In order + to add an ephemeral container to an existing pod, use + the pod's ephemeralcontainers subresource. + items: + description: "An EphemeralContainer is a temporary container + that you may add to an existing Pod for user-initiated + activities such as debugging. Ephemeral containers + have no resource or scheduling guarantees, and they + will not be restarted when they exit or when a Pod + is removed or restarted. The kubelet may evict a Pod + if an ephemeral container causes the Pod to exceed + its resource allocation. \n To add an ephemeral container, + use the ephemeralcontainers subresource of an existing + Pod. Ephemeral containers may not be removed or restarted." + properties: + args: + description: 'Arguments to the entrypoint. The image''s + CMD is used if this is not provided. Variable + references $(VAR_NAME) are expanded using the + container''s environment. If a variable cannot + be resolved, the reference in the input string + will be unchanged. Double $$ are reduced to a + single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The image''s ENTRYPOINT is used if this + is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for + escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot + be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set + in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container and + any service environment variables. If a + variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container + is starting. When a key exists in multiple sources, + the value associated with the last source will + take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be + updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a + C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Lifecycle is not allowed for ephemeral + containers. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to an + API request or management event such as liveness/startup + probe failure, preemption, resource contention, + etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination grace + period (unless delayed by finalizers). Other + management of the container blocks until the + hook completes or until the termination grace + period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: Probes are not allowed for ephemeral + containers. + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the ephemeral container specified + as a DNS_LABEL. This name must be unique among + all containers, init containers and ephemeral + containers. + type: string + ports: + description: Ports are not allowed for ephemeral + containers. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on the + pod's IP address. This must be a valid port + number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the + host. If specified, this must be a valid + port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an + IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique + name. Name for the port that can be referred + to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, + TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: Probes are not allowed for ephemeral + containers. + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: Resources are not allowed for ephemeral + containers. Ephemeral containers use spare resources + already allocated to the pod. + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'Optional: SecurityContext defines + the security options the ephemeral container should + be run with. If set, the fields of SecurityContext + override the equivalent fields of PodSecurityContext.' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run + as Privileged 2) has CAP_SYS_ADMIN Note that + this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when + running containers. Defaults to the default + set of capabilities granted by the container + runtime. Note that this field cannot be set + when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults to + false. Note that this field cannot be set + when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default + is DefaultProcMount which uses the container + runtime defaults for readonly paths and masked + paths. This requires the ProcMountType feature + flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of + the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must + run as a non-root user. If true, the Kubelet + will validate the image at runtime to ensure + that it does not run as UID 0 (root) and fail + to start the container if it does. If unset + or false, no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of + the container process. Defaults to user specified + in image metadata if unspecified. May also + be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be preconfigured + on the node to work. Must be a descending + path, relative to the kubelet's configured + seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. Valid + options are: \n Localhost - a profile + defined in a file on the node should be + used. RuntimeDefault - the container runtime + default profile should be used. Unconfined + - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the + name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a + container should be run as a 'Host Process' + container. This field is alpha-level and + will only be honored by components that + enable the WindowsHostProcessContainers + feature flag. Setting this field without + the feature flag will result in errors + when validating the Pod. All of a Pod's + containers must have the same effective + HostProcess value (it is not allowed to + have a mix of HostProcess containers and + non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container process. + Defaults to the user specified in image + metadata if unspecified. May also be set + in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: Probes are not allowed for ephemeral + containers. + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If + this is not set, reads from stdin in the container + will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is + opened on container start, is empty until the + first client attaches to stdin, and then remains + open and accepts data until the client disconnects, + at which time stdin is closed and remains closed + until the container is restarted. If this flag + is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + targetContainerName: + description: "If set, the name of the container + from PodSpec that this ephemeral container targets. + The ephemeral container will be run in the namespaces + (IPC, PID, etc) of this container. If not set + then the ephemeral container uses the namespaces + configured in the Pod spec. \n The container runtime + must implement support for this feature. If the + runtime does not support namespace targeting then + the result of setting this field is undefined." + type: string + terminationMessagePath: + description: 'Optional: Path at which the file to + which the container''s termination message will + be written is mounted into the container''s filesystem. + Message written is intended to be brief final + status, such as an assertion failure message. + Will be truncated by the node if greater than + 4096 bytes. The total message length across all + containers will be limited to 12kb. Defaults to + /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. FallbackToLogsOnError + will use the last chunk of container log output + if the termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will be + mapped to. + type: string + name: + description: name must match the name of a + persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Subpath mounts are not allowed for + ephemeral containers. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how + mounts are propagated from the host to container + and the other way around. When not set, + MountPropagationNone is used. This field + is beta in 1.10. + type: string + name: + description: This must match the Name of a + Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults + to false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not + specified, the container runtime's default will + be used, which might be configured in the container + image. Cannot be updated. + type: string + required: + - name + type: object + type: array + hostAliases: + description: HostAliases is an optional list of hosts + and IPs that will be injected into the pod's hosts file + if specified. This is only valid for non-hostNetwork + pods. + items: + description: HostAlias holds the mapping between IP + and hostnames that will be injected as an entry in + the pod's hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + ip: + description: IP address of the host file entry. + type: string + type: object + type: array + hostIPC: + description: 'Use the host''s ipc namespace. Optional: + Default to false.' + type: boolean + hostNetwork: + description: Host networking requested for this pod. Use + the host's network namespace. If this option is set, + the ports that will be used must be specified. Default + to false. + type: boolean + hostPID: + description: 'Use the host''s pid namespace. Optional: + Default to false.' + type: boolean + hostUsers: + description: 'Use the host''s user namespace. Optional: + Default to true. If set to true or not present, the + pod will be run in the host user namespace, useful for + when the pod needs a feature only available to the host + user namespace, such as loading a kernel module with + CAP_SYS_MODULE. When set to false, a new userns is created + for the pod. Setting false is useful for mitigating + container breakout vulnerabilities even allowing users + to run their containers as root without actually having + root privileges on the host. This field is alpha-level + and is only honored by servers that enable the UserNamespacesSupport + feature.' + type: boolean + hostname: + description: Specifies the hostname of the Pod If not + specified, the pod's hostname will be set to a system-defined + value. + type: string + imagePullSecrets: + description: 'ImagePullSecrets is an optional list of + references to secrets in the same namespace to use for + pulling any of the images used by this PodSpec. If specified, + these secrets will be passed to individual puller implementations + for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod' + items: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the + same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + description: 'List of initialization containers belonging + to the pod. Init containers are executed in order prior + to containers being started. If any init container fails, + the pod is considered to have failed and is handled + according to its restartPolicy. The name for an init + container or normal container must be unique among all + containers. Init containers may not have Lifecycle actions, + Readiness probes, Liveness probes, or Startup probes. + The resourceRequirements of an init container are taken + into account during scheduling by finding the highest + request/limit for each resource type, and then using + the max of of that value or the sum of the normal containers. + Limits are applied to init containers in a similar fashion. + Init containers cannot currently be added or removed. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/' + items: + description: A single application container that you + want to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container + image''s CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using + the container''s environment. If a variable cannot + be resolved, the reference in the input string + will be unchanged. Double $$ are reduced to a + single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will + never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot + be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set + in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container and + any service environment variables. If a + variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal + "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable + exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: + supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined within + a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container + is starting. When a key exists in multiple sources, + the value associated with the last source will + take precedence. Values defined by an Env with + a duplicate key will take precedence. Cannot be + updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be a + C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config + management to default or override container images + in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. Cannot + be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due to an + API request or management event such as liveness/startup + probe failure, preemption, resource contention, + etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace + period countdown begins before the PreStop + hook is executed. Regardless of the outcome + of the handler, the container will eventually + terminate within the Pod''s termination grace + period (unless delayed by finalizers). Other + management of the container blocks until the + hook completes or until the termination grace + period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in HTTP + probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT + supported as a LifecycleHandler and kept + for the backward compatibility. There + are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler + is specified. + properties: + host: + description: 'Optional: Host name to + connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number + must be in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. + Not specifying a port here DOES NOT prevent that + port from being exposed. Any port which is listening + on the default "0.0.0.0" address inside a container + will be accessible from the network. Modifying + this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on the + pod's IP address. This must be a valid port + number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on the + host. If specified, this must be a valid + port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an + IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique + name. Name for the port that can be referred + to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, + TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are used + by this container. \n This is an alpha field + and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If Requests + is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If set, + the fields of SecurityContext override the equivalent + fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run + as Privileged 2) has CAP_SYS_ADMIN Note that + this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when + running containers. Defaults to the default + set of capabilities granted by the container + runtime. Note that this field cannot be set + when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults to + false. Note that this field cannot be set + when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc + mount to use for the containers. The default + is DefaultProcMount which uses the container + runtime defaults for readonly paths and masked + paths. This requires the ProcMountType feature + flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only + root filesystem. Default is false. Note that + this field cannot be set when spec.os.name + is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of + the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must + run as a non-root user. If true, the Kubelet + will validate the image at runtime to ensure + that it does not run as UID 0 (root) and fail + to start the container if it does. If unset + or false, no such validation will be performed. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of + the container process. Defaults to user specified + in image metadata if unspecified. May also + be set in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this + container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be preconfigured + on the node to work. Must be a descending + path, relative to the kubelet's configured + seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. Valid + options are: \n Localhost - a profile + defined in a file on the node should be + used. RuntimeDefault - the container runtime + default profile should be used. Unconfined + - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot be + set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the + name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a + container should be run as a 'Host Process' + container. This field is alpha-level and + will only be honored by components that + enable the WindowsHostProcessContainers + feature flag. Setting this field without + the feature flag will result in errors + when validating the Pod. All of a Pod's + containers must have the same effective + HostProcess value (it is not allowed to + have a mix of HostProcess containers and + non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container process. + Defaults to the user specified in image + metadata if unspecified. May also be set + in PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that the Pod + has successfully initialized. If specified, no + other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters + at the beginning of a Pod''s lifecycle, when it + might take a long time to load data or warm a + cache, than during steady-state operation. This + cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line + to execute inside the container, the working + directory for the command is root ('/') + in the container's filesystem. The command + is simply exec'd, it is not run inside + a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, + you need to explicitly call out to that + shell. Exit status of 0 is treated as + live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for + the probe to be considered failed after having + succeeded. Defaults to 3. Minimum value is + 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. This is a beta field and requires + enabling GRPCContainerProbe feature gate. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, defaults + to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: The header field name + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container + has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for + the probe to be considered successful after + having failed. Defaults to 1. Must be 1 for + liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the + pod needs to terminate gracefully upon probe + failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly halted + with a kill signal. Set this value longer + than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds + will be used. Otherwise, this value overrides + the value provided by the pod spec. Value + must be non-negative integer. The value zero + indicates stop immediately via the kill signal + (no opportunity to shut down). This is a beta + field and requires enabling ProbeTerminationGracePeriod + feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds + is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. If + this is not set, reads from stdin in the container + will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is + opened on container start, is empty until the + first client attaches to stdin, and then remains + open and accepts data until the client disconnects, + at which time stdin is closed and remains closed + until the container is restarted. If this flag + is false, a container processes that reads from + stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to + which the container''s termination message will + be written is mounted into the container''s filesystem. + Message written is intended to be brief final + status, such as an assertion failure message. + Will be truncated by the node if greater than + 4096 bytes. The total message length across all + containers will be limited to 12kb. Defaults to + /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. FallbackToLogsOnError + will use the last chunk of container log output + if the termination message file is empty and the + container exited with an error. The log output + is limited to 2048 bytes or 80 lines, whichever + is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will be + mapped to. + type: string + name: + description: name must match the name of a + persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how + mounts are propagated from the host to container + and the other way around. When not set, + MountPropagationNone is used. This field + is beta in 1.10. + type: string + name: + description: This must match the Name of a + Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write + otherwise (false or unspecified). Defaults + to false. + type: boolean + subPath: + description: Path within the volume from which + the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not + specified, the container runtime's default will + be used, which might be configured in the container + image. Cannot be updated. + type: string + required: + - name + type: object + type: array + nodeName: + description: NodeName is a request to schedule this pod + onto a specific node. If it is non-empty, the scheduler + simply schedules this pod onto that node, assuming that + it fits resource requirements. + type: string + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must be + true for the pod to fit on a node. Selector which must + match a node''s labels for the pod to be scheduled on + that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + x-kubernetes-map-type: atomic + os: + description: "Specifies the OS of the containers in the + pod. Some pod and container fields are restricted if + this is set. \n If the OS field is set to linux, the + following fields must be unset: -securityContext.windowsOptions + \n If the OS field is set to windows, following fields + must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers + - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile + - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy + - spec.securityContext.sysctls - spec.shareProcessNamespace + - spec.securityContext.runAsUser - spec.securityContext.runAsGroup + - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions + - spec.containers[*].securityContext.seccompProfile + - spec.containers[*].securityContext.capabilities - + spec.containers[*].securityContext.readOnlyRootFilesystem + - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation + - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser + - spec.containers[*].securityContext.runAsGroup" + properties: + name: + description: 'Name is the name of the operating system. + The currently supported values are linux and windows. + Additional value may be defined in future and can + be one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration + Clients should expect to handle additional values + and treat unrecognized values in this field as os: + null' + type: string + required: + - name + type: object + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Overhead represents the resource overhead + associated with running a pod for a given RuntimeClass. + This field will be autopopulated at admission time by + the RuntimeClass admission controller. If the RuntimeClass + admission controller is enabled, overhead must not be + set in Pod create requests. The RuntimeClass admission + controller will reject Pod create requests which have + the overhead already set. If RuntimeClass is configured + and selected in the PodSpec, Overhead will be set to + the value defined in the corresponding RuntimeClass, + otherwise it will remain unset and treated as zero. + More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md' + type: object + preemptionPolicy: + description: PreemptionPolicy is the Policy for preempting + pods with lower priority. One of Never, PreemptLowerPriority. + Defaults to PreemptLowerPriority if unset. + type: string + priority: + description: The priority value. Various system components + use this field to find the priority of the pod. When + Priority Admission Controller is enabled, it prevents + users from setting this field. The admission controller + populates this field from PriorityClassName. The higher + the value, the higher the priority. + format: int32 + type: integer + priorityClassName: + description: If specified, indicates the pod's priority. + "system-node-critical" and "system-cluster-critical" + are two special keywords which indicate the highest + priorities with the former being the highest priority. + Any other name must be defined by creating a PriorityClass + object with that name. If not specified, the pod priority + will be default or zero if there is no default. + type: string + readinessGates: + description: 'If specified, all readiness gates will be + evaluated for pod readiness. A pod is ready when all + its containers are ready AND all conditions specified + in the readiness gates have status equal to "True" More + info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates' + items: + description: PodReadinessGate contains the reference + to a pod condition + properties: + conditionType: + description: ConditionType refers to a condition + in the pod's condition list with matching type. + type: string + required: + - conditionType + type: object + type: array + resourceClaims: + description: "ResourceClaims defines which ResourceClaims + must be allocated and reserved before the Pod is allowed + to start. The resources will be made available to those + containers which consume them by name. \n This is an + alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: PodResourceClaim references exactly one + ResourceClaim through a ClaimSource. It adds a name + to it that uniquely identifies the ResourceClaim inside + the Pod. Containers that need access to the ResourceClaim + reference it with this name. + properties: + name: + description: Name uniquely identifies this resource + claim inside the pod. This must be a DNS_LABEL. + type: string + source: + description: Source describes where to find the + ResourceClaim. + properties: + resourceClaimName: + description: ResourceClaimName is the name of + a ResourceClaim object in the same namespace + as this pod. + type: string + resourceClaimTemplateName: + description: "ResourceClaimTemplateName is the + name of a ResourceClaimTemplate object in + the same namespace as this pod. \n The template + will be used to create a new ResourceClaim, + which will be bound to this pod. When this + pod is deleted, the ResourceClaim will also + be deleted. The name of the ResourceClaim + will be -, where + is the PodResourceClaim.Name. + Pod validation will reject the pod if the + concatenated name is not valid for a ResourceClaim + (e.g. too long). \n An existing ResourceClaim + with that name that is not owned by the pod + will not be used for the pod to avoid using + an unrelated resource by mistake. Scheduling + and pod startup are then blocked until the + unrelated ResourceClaim is removed. \n This + field is immutable and no changes will be + made to the corresponding ResourceClaim by + the control plane after creating the ResourceClaim." + type: string + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + restartPolicy: + description: 'Restart policy for all containers within + the pod. One of Always, OnFailure, Never. Default to + Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy' + type: string + runtimeClassName: + description: 'RuntimeClassName refers to a RuntimeClass + object in the node.k8s.io group, which should be used + to run this pod. If no RuntimeClass resource matches + the named class, the pod will not be run. If unset or + empty, the "legacy" RuntimeClass will be used, which + is an implicit class with an empty definition that uses + the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class' + type: string + schedulerName: + description: If specified, the pod will be dispatched + by specified scheduler. If not specified, the pod will + be dispatched by default scheduler. + type: string + schedulingGates: + description: "SchedulingGates is an opaque list of values + that if specified will block scheduling the pod. More + info: https://git.k8s.io/enhancements/keps/sig-scheduling/3521-pod-scheduling-readiness. + \n This is an alpha-level feature enabled by PodSchedulingReadiness + feature gate." + items: + description: PodSchedulingGate is associated to a Pod + to guard its scheduling. + properties: + name: + description: Name of the scheduling gate. Each scheduling + gate must have a unique name field. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + securityContext: + description: 'SecurityContext holds pod-level security + attributes and common container settings. Optional: + Defaults to empty. See type description for default + values of each field.' + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume + to be owned by the pod: \n 1. The owning GID will + be the FSGroup 2. The setgid bit is set (new files + created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- \n + If unset, the Kubelet will not modify the ownership + and permissions of any volume. Note that this field + cannot be set when spec.os.name is windows." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior + of changing ownership and permission of the volume + before being exposed inside Pod. This field will + only apply to volume types which support fsGroup + based ownership(and permissions). It will have no + effect on ephemeral volume types such as: secret, + configmaps and emptydir. Valid values are "OnRootMismatch" + and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name + is windows.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in SecurityContext. If set in both + SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for + that container. Note that this field cannot be set + when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not + run as UID 0 (root) and fail to start the container + if it does. If unset or false, no such validation + will be performed. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified in + image metadata if unspecified. May also be set in + SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. Note that this + field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + all containers. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. Note that this field cannot + be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. Note that this field cannot be set + when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file on + the node should be used. RuntimeDefault - the + container runtime default profile should be + used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first + process run in each container, in addition to the + container's primary GID, the fsGroup (if specified), + and group memberships defined in the container image + for the uid of the container process. If unspecified, + no additional groups are added to any container. + Note that group memberships defined in the container + image for the uid of the container process are still + effective, even if they are not included in this + list. Note that this field cannot be set when spec.os.name + is windows. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls + (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name + is windows. + items: + description: Sysctl defines a kernel parameter to + be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options within + a container's SecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be honored + by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. All of a Pod's containers must have + the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the + entrypoint of the container process. Defaults + to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + serviceAccount: + description: 'DeprecatedServiceAccount is a depreciated + alias for ServiceAccountName. Deprecated: Use serviceAccountName + instead.' + type: string + serviceAccountName: + description: 'ServiceAccountName is the name of the ServiceAccount + to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/' + type: string + setHostnameAsFQDN: + description: If true the pod's hostname will be configured + as the pod's FQDN, rather than the leaf name (the default). + In Linux containers, this means setting the FQDN in + the hostname field of the kernel (the nodename field + of struct utsname). In Windows containers, this means + setting the registry value of hostname for the registry + key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters + to FQDN. If a pod does not have FQDN, this has no effect. + Default to false. + type: boolean + shareProcessNamespace: + description: 'Share a single process namespace between + all of the containers in a pod. When this is set containers + will be able to view and signal processes from other + containers in the same pod, and the first process in + each container will not be assigned PID 1. HostPID and + ShareProcessNamespace cannot both be set. Optional: + Default to false.' + type: boolean + subdomain: + description: If specified, the fully qualified Pod hostname + will be "...svc.". If not specified, the pod will not have a + domainname at all. + type: string + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully. May be decreased in delete + request. Value must be non-negative integer. The value + zero indicates stop immediately via the kill signal + (no opportunity to shut down). If this value is nil, + the default grace period will be used instead. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and + the time when the processes are forcibly halted with + a kill signal. Set this value longer than the expected + cleanup time for your process. Defaults to 30 seconds. + format: int64 + type: integer + tolerations: + description: If specified, the pod's tolerations. + items: + description: The pod this Toleration is attached to + tolerates any taint that matches the triple + using the matching operator . + properties: + effect: + description: Effect indicates the taint effect to + match. Empty means match all taint effects. When + specified, allowed values are NoSchedule, PreferNoSchedule + and NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; + this combination means to match all values and + all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints + of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period + of time the toleration (which must be of effect + NoExecute, otherwise this field is ignored) tolerates + the taint. By default, it is not set, which means + tolerate the taint forever (do not evict). Zero + and negative values will be treated as 0 (evict + immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration + matches to. If the operator is Exists, the value + should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints describes how a + group of pods ought to spread across topology domains. + Scheduler will schedule pods in a way which abides by + the constraints. All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how + to spread matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. Pods that match this label selector are + counted to determine the number of pods in their + corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: MatchLabelKeys is a set of pod label + keys to select the pods over which spreading will + be calculated. The keys are used to lookup values + from the incoming pod labels, those key-value + labels are ANDed with labelSelector to select + the group of existing pods over which spreading + will be calculated for the incoming pod. Keys + that don't exist in the incoming pod labels will + be ignored. A null or empty list means only match + against labelSelector. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: 'MaxSkew describes the degree to which + pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, + it is the maximum permitted difference between + the number of matching pods in the target topology + and the global minimum. The global minimum is + the minimum number of matching pods in an eligible + domain or zero if the number of eligible domains + is less than MinDomains. For example, in a 3-zone + cluster, MaxSkew is set to 1, and pods with the + same labelSelector spread as 2/2/1: In this case, + the global minimum is 1. | zone1 | zone2 | zone3 + | | P P | P P | P | - if MaxSkew is 1, + incoming pod can only be scheduled to zone3 to + become 2/2/2; scheduling it onto zone1(zone2) + would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). - if MaxSkew is 2, incoming + pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, + it is used to give higher precedence to topologies + that satisfy it. It''s a required field. Default + value is 1 and 0 is not allowed.' + format: int32 + type: integer + minDomains: + description: "MinDomains indicates a minimum number + of eligible domains. When the number of eligible + domains with matching topology keys is less than + minDomains, Pod Topology Spread treats \"global + minimum\" as 0, and then the calculation of Skew + is performed. And when the number of eligible + domains with matching topology keys equals or + greater than minDomains, this value has no effect + on scheduling. As a result, when the number of + eligible domains is less than minDomains, scheduler + won't schedule more than maxSkew Pods to those + domains. If value is nil, the constraint behaves + as if MinDomains is equal to 1. Valid values are + integers greater than 0. When value is not nil, + WhenUnsatisfiable must be DoNotSchedule. \n For + example, in a 3-zone cluster, MaxSkew is set to + 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: | zone1 | zone2 + | zone3 | | P P | P P | P P | The number + of domains is less than 5(MinDomains), so \"global + minimum\" is treated as 0. In this situation, + new pod with the same labelSelector cannot be + scheduled, because computed skew will be 3(3 - + 0) if new Pod is scheduled to any of the three + zones, it will violate MaxSkew. \n This is a beta + field and requires the MinDomainsInPodTopologySpread + feature gate to be enabled (enabled by default)." + format: int32 + type: integer + nodeAffinityPolicy: + description: "NodeAffinityPolicy indicates how we + will treat Pod's nodeAffinity/nodeSelector when + calculating pod topology spread skew. Options + are: - Honor: only nodes matching nodeAffinity/nodeSelector + are included in the calculations. - Ignore: nodeAffinity/nodeSelector + are ignored. All nodes are included in the calculations. + \n If this value is nil, the behavior is equivalent + to the Honor policy. This is a beta-level feature + default enabled by the NodeInclusionPolicyInPodTopologySpread + feature flag." + type: string + nodeTaintsPolicy: + description: "NodeTaintsPolicy indicates how we + will treat node taints when calculating pod topology + spread skew. Options are: - Honor: nodes without + taints, along with tainted nodes for which the + incoming pod has a toleration, are included. - + Ignore: node taints are ignored. All nodes are + included. \n If this value is nil, the behavior + is equivalent to the Ignore policy. This is a + beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread + feature flag." + type: string + topologyKey: + description: TopologyKey is the key of node labels. + Nodes that have a label with this key and identical + values are considered to be in the same topology. + We consider each as a "bucket", and + try to put balanced number of pods into each bucket. + We define a domain as a particular instance of + a topology. Also, we define an eligible domain + as a domain whose nodes meet the requirements + of nodeAffinityPolicy and nodeTaintsPolicy. e.g. + If TopologyKey is "kubernetes.io/hostname", each + Node is a domain of that topology. And, if TopologyKey + is "topology.kubernetes.io/zone", each zone is + a domain of that topology. It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how to + deal with a pod if it doesn''t satisfy the spread + constraint. - DoNotSchedule (default) tells the + scheduler not to schedule it. - ScheduleAnyway + tells the scheduler to schedule the pod in any + location, but giving higher precedence to topologies + that would help reduce the skew. A constraint + is considered "Unsatisfiable" for an incoming + pod if and only if every possible node assignment + for that pod would violate "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set + to 1, and pods with the same labelSelector spread + as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, + incoming pod can only be scheduled to zone2(zone3) + to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) + satisfies MaxSkew(1). In other words, the cluster + can still be imbalanced, but scheduler won''t + make it *more* imbalanced. It''s a required field.' + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + description: 'List of volumes that can be mounted by containers + belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes' + items: + description: Volume represents a named volume in a pod + that may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an + AWS Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force + the readOnly setting in VolumeMounts. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data + Disk mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk + in the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the + host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File + Service mount on the host and bind mount to the + pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on + the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the + mounted root, rather than the full Ceph tree, + default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default + is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the + rados user name, default is admin More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters used + to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the + volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that + should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode + bits used to set permissions on created files + by default. Must be an octal value between + 0000 and 0777 or a decimal value between 0 + and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within + the path are not affected by this setting. + This might be in conflict with other options + that affect the file mode, like fsGroup, and + the result can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified + which is not present in the ConfigMap, the + volume setup will error unless it is marked + optional. Paths must be relative and may not + contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 + and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, like + fsGroup, and the result can be other + mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May not + be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver + that handles this volume. Consult with your + admin for the correct name as registered in + the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which + will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive + information to pass to the CSI driver to complete + the CSI NodePublishVolume and NodeUnpublishVolume + calls. This field is optional, and may be + empty if no secret is required. If the secret + object contains more than one secret, all + secret references are passed. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults to + false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for supported + values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API + about the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on + created files by default. Must be a Optional: + mode bits used to set permissions on created + files by default. Must be an octal value between + 0000 and 0777 or a decimal value between 0 + and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within + the path are not affected by this setting. + This might be in conflict with other options + that affect the file mode, like fsGroup, and + the result can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API + volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. + YAML accepts both octal and decimal + values, JSON requires decimal values + for mode bits. If not specified, the + volume defaultMode will be used. This + might be in conflict with other options + that affect the file mode, like fsGroup, + and the result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. + Must not be absolute or contain the + ''..'' path. Must be utf-8 encoded. + The first item of the relative path + must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and + requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) are + currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of + storage medium should back this directory. + The default is "" which means to use the node''s + default medium. Must be an empty string (default) + or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage on memory + medium EmptyDir would be the minimum value + between the SizeLimit specified here and the + sum of memory limits of all containers in + a pod. The default is nil which means that + the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: "ephemeral represents a volume that + is handled by a cluster storage driver. The volume's + lifecycle is tied to the pod that defines it - + it will be created before the pod starts, and + deleted when the pod is removed. \n Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from + snapshot or capacity tracking are needed, c) the + storage driver is specified through a storage + class, and d) the storage driver supports dynamic + volume provisioning through a PersistentVolumeClaim + (see EphemeralVolumeSource for more information + on the connection between this volume type and + PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes + that persist for longer than the lifecycle of + an individual pod. \n Use CSI for light-weight + local ephemeral volumes if the CSI driver is meant + to be used that way - see the documentation of + the driver for more information. \n A pod can + use both types of ephemeral volumes and persistent + volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in which + this EphemeralVolumeSource is embedded will + be the owner of the PVC, i.e. the PVC will + be deleted together with the pod. The name + of the PVC will be `-` + where `` is the name from the + `PodSpec.Volumes` array entry. Pod validation + will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + \n An existing PVC with that name that is + not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume + by mistake. Starting the pod is then blocked + until the unrelated PVC is removed. If such + a pre-created PVC is meant to be used by the + pod, the PVC has to updated with an owner + reference to the pod once the pod exists. + Normally this should not be necessary, but + it may be useful when manually reconstructing + a broken cluster. \n This field is read-only + and no changes will be made by Kubernetes + to the PVC after it has been created. \n Required, + must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when + creating it. No other fields are allowed + and will be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged + into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains the + desired access modes the volume should + have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create a new + volume based on the contents of the + specified data source. When the AnyVolumeDataSource + feature gate is enabled, dataSource + contents will be copied to dataSourceRef, + and dataSourceRef contents will be + copied to dataSource when dataSourceRef.namespace + is not specified. If the namespace + is specified, then dataSourceRef will + not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any other + third-party types, APIGroup is + required. + type: string + kind: + description: Kind is the type of + resource being referenced + type: string + name: + description: Name is the name of + resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may be any + object from a non-empty API group + (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed if + the type of the specified object matches + some installed volume populator or + dynamic provisioner. This field will + replace the functionality of the dataSource + field and as such if both fields are + non-empty, they must have the same + value. For backwards compatibility, + when namespace isn''t specified in + dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to + the same value automatically if one + of them is empty and the other is + non-empty. When namespace is specified + in dataSourceRef, dataSource isn''t + set to the same value and must be + empty. There are three important differences + between dataSource and dataSourceRef: + * While dataSource only allows two + specific types of objects, dataSourceRef + allows any non-core object, as well + as PersistentVolumeClaim objects. + * While dataSource ignores disallowed + values (dropping them), dataSourceRef + preserves all values, and generates + an error if a disallowed value is + specified. * While dataSource only + allows local objects, dataSourceRef + allows objects in any namespaces. + (Beta) Using this field requires the + AnyVolumeDataSource feature gate to + be enabled. (Alpha) Using the namespace + field of dataSourceRef requires the + CrossNamespaceVolumeDataSource feature + gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any other + third-party types, APIGroup is + required. + type: string + kind: + description: Kind is the type of + resource being referenced + type: string + name: + description: Name is the name of + resource being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note + that when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. + See the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the + minimum resources the volume should + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but + must still be higher than capacity + recorded in the status field of the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names + of resources, defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field is + immutable." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry in + pod.spec.resourceClaims + of the Pod where this field + is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the + maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, it + defaults to Limits if that is + explicitly specified, otherwise + to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is + a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector + requirement is a selector that + contains values, a key, and + an operator that relates the + key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In or + NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be + empty. This array is replaced + during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single + {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator is + "In", and the values array contains + only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is the + name of the StorageClass required + by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what + type of volume is required by the + claim. Value of Filesystem is implied + when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and + then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun + number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not + both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using an + exec based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". The default filesystem depends + on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume + attached to a kubelet's host machine. This depends + on the Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset + for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the + dataset. This is unique identifier of a Flocker + dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE + Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk + in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container with a + git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the + EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will + be the git repository. Otherwise, if specified, + the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for + the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount + on the host that shares a pod''s lifetime. More + info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name + that details Glusterfs topology. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. + Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that is + directly exposed to the container. This is generally + used for system agents or other privileged things + that are allowed to see the host machine. Most + containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can + use host directory mounts and who can/can not + mount host directories as read/write.' + properties: + path: + description: 'path of the directory on the host. + If the path is a symlink, it will follow the + link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun + number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the + host that shares a pod''s lifetime More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS + server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS + export to be mounted with read-only permissions. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address + of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a + Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML + accepts both octal and decimal values, JSON + requires decimal values for mode bits. Directories + within the path are not affected by this setting. + This might be in conflict with other options + that affect the file mode, like fsGroup, and + the result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced ConfigMap + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and unlisted + keys will not be present. If a key + is specified which is not present + in the ConfigMap, the volume setup + will error unless it is marked optional. + Paths must be relative and may not + contain the '..' path or start with + '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between + 0 and 511. YAML accepts both + octal and decimal values, + JSON requires decimal values + for mode bits. If not specified, + the volume defaultMode will + be used. This might be in + conflict with other options + that affect the file mode, + like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the + path element '..'. May not + start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version of + the schema the FieldPath + is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the + field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode + bits used to set permissions + on this file, must be an octal + value between 0000 and 0777 + or a decimal value between + 0 and 511. YAML accepts both + octal and decimal values, + JSON requires decimal values + for mode bits. If not specified, + the volume defaultMode will + be used. This might be in + conflict with other options + that affect the file mode, + like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path + is the relative path name + of the file to be created. + Must not be absolute or contain + the ''..'' path. Must be utf-8 + encoded. The first item of + the relative path must not + start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container + name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about + the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced Secret will + be projected into the volume as + a file whose name is the key and + content is the value. If specified, + the listed keys will be projected + into the specified paths, and unlisted + keys will not be present. If a key + is specified which is not present + in the Secret, the volume setup + will error unless it is marked optional. + Paths must be relative and may not + contain the '..' path or start with + '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between + 0 and 511. YAML accepts both + octal and decimal values, + JSON requires decimal values + for mode bits. If not specified, + the volume defaultMode will + be used. This might be in + conflict with other options + that affect the file mode, + like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the + path element '..'. May not + start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to + project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself + with an identifier specified in + the audience of the token, and otherwise + should reject the token. The audience + defaults to the identifier of the + apiserver. + type: string + expirationSeconds: + description: expirationSeconds is + the requested duration of validity + of the service account token. As + the token approaches expiration, + the kubelet volume plugin will proactively + rotate the service account token. + The kubelet will start trying to + rotate the token if the token is + older than 80 percent of its time + to live or if the token is older + than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file to + project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount + on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default + is no group + type: string + readOnly: + description: readOnly here will force the Quobyte + volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: registry represents a single or + multiple Quobyte Registry services specified + as a string as host:port pair (multiple entries + are separated with commas) which acts as the + central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is set + by the plugin + type: string + user: + description: user to map volume access to Defaults + to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides + keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of + the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of + the ScaleIO Protection Domain for the configured + storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation will + fail. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that + is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should + populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode + bits used to set permissions on created files + by default. Must be an octal value between + 0000 and 0777 or a decimal value between 0 + and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within + the path are not affected by this setting. + This might be in conflict with other options + that affect the file mode, like fsGroup, and + the result can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified + which is not present in the Secret, the volume + setup will error unless it is marked optional. + Paths must be relative and may not contain + the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 + and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, like + fsGroup, and the result can be other + mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May not + be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the + secret in the pod''s namespace to use. More + info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope + of the volume within StorageOS. If no namespace + is specified then the Pod's namespace will + be used. This allows the Kubernetes name + scoping to be mirrored within StorageOS for + tighter integration. Set VolumeName to any + name to override the default behaviour. Set + to "default" if you are not using namespaces + within StorageOS. Namespaces that do not pre-exist + within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the + host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile ID + associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + required: + - containers + type: object + type: object + type: object + securityContext: + description: PodSecurityContext Pod Security Context + properties: + fsGroup: + description: "A special supplemental group that applies to all + containers in a pod. Some volume types allow the Kubelet to + change the ownership of that volume to be owned by the pod: + \n 1. The owning GID will be the FSGroup 2. The setgid bit is + set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- \n If unset, + the Kubelet will not modify the ownership and permissions of + any volume. Note that this field cannot be set when spec.os.name + is windows." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of changing + ownership and permission of the volume before being exposed + inside Pod. This field will only apply to volume types which + support fsGroup based ownership(and permissions). It will have + no effect on ephemeral volume types such as: secret, configmaps + and emptydir. Valid values are "OnRootMismatch" and "Always". + If not specified, "Always" is used. Note that this field cannot + be set when spec.os.name is windows.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container process. + Uses runtime default if unset. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no such validation + will be performed. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the value specified + in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers in this + pod. Note that this field cannot be set when spec.os.name is + windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must be + preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a profile + defined in a file on the node should be used. RuntimeDefault + - the container runtime default profile should be used. + Unconfined - no profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process run + in each container, in addition to the container's primary GID, + the fsGroup (if specified), and group memberships defined in + the container image for the uid of the container process. If + unspecified, no additional groups are added to any container. + Note that group memberships defined in the container image for + the uid of the container process are still effective, even if + they are not included in this list. Note that this field cannot + be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls used for + the pod. Pods with unsupported sysctls (by the container runtime) + might fail to launch. Note that this field cannot be set when + spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named by + the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA + credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should + be run as a 'Host Process' container. This field is alpha-level + and will only be honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature flag + will result in errors when validating the Pod. All of a + Pod's containers must have the same effective HostProcess + value (it is not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: string + type: object + type: object + size: + description: Size of runtime + type: integer + required: + - allowRestart + - replicaPerGroup + - runtimePodTemplate + - size + type: object + status: + description: RuntimeStatus defines the observed state of Runtime + properties: + nodes: + items: + type: string + type: array + size: + type: integer + required: + - nodes + - size + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/eventmesh-operator/config/crd/kustomization.yaml b/eventmesh-operator/config/crd/kustomization.yaml new file mode 100644 index 0000000000..727b138bb5 --- /dev/null +++ b/eventmesh-operator/config/crd/kustomization.yaml @@ -0,0 +1,39 @@ +# +# 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. +# + +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/eventmesh-operator.eventmesh_runtimes.yaml +- bases/eventmesh-operator.eventmesh_connectors.yaml +#+kubebuilder:scaffold:crdkustomizeresource + +patchesStrategicMerge: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +#- patches/webhook_in_eventmeshoperators.yaml +#+kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +#- patches/cainjection_in_eventmeshoperators.yaml +#+kubebuilder:scaffold:crdkustomizecainjectionpatch + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/eventmesh-operator/config/crd/kustomizeconfig.yaml b/eventmesh-operator/config/crd/kustomizeconfig.yaml new file mode 100644 index 0000000000..85c3fa88a0 --- /dev/null +++ b/eventmesh-operator/config/crd/kustomizeconfig.yaml @@ -0,0 +1,36 @@ +# +# 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. +# + +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/eventmesh-operator/config/crd/patches/cainjection_in_eventmeshoperators.yaml b/eventmesh-operator/config/crd/patches/cainjection_in_eventmeshoperators.yaml new file mode 100644 index 0000000000..4e262406a0 --- /dev/null +++ b/eventmesh-operator/config/crd/patches/cainjection_in_eventmeshoperators.yaml @@ -0,0 +1,24 @@ +# +# 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. +# + +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: eventmeshoperators.eventmesh-operator.eventmesh diff --git a/eventmesh-operator/config/crd/patches/webhook_in_eventmeshoperators.yaml b/eventmesh-operator/config/crd/patches/webhook_in_eventmeshoperators.yaml new file mode 100644 index 0000000000..ced7cacb2d --- /dev/null +++ b/eventmesh-operator/config/crd/patches/webhook_in_eventmeshoperators.yaml @@ -0,0 +1,33 @@ +# +# 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. +# + +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: eventmeshoperators.eventmesh-operator.eventmesh +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/eventmesh-operator/config/default/kustomization.yaml b/eventmesh-operator/config/default/kustomization.yaml new file mode 100644 index 0000000000..d4c395e546 --- /dev/null +++ b/eventmesh-operator/config/default/kustomization.yaml @@ -0,0 +1,89 @@ +# +# 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. +# + +# Adds namespace to all resources. +namespace: eventmesh-operator-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: eventmesh-operator- + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +bases: +- ../crd +- ../rbac +- ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus + +patchesStrategicMerge: +# Protect the /metrics endpoint by putting it behind auth. +# If you want your controller-manager to expose the /metrics +# endpoint w/o any authn/z, please comment the following line. +- manager_auth_proxy_patch.yaml + + + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- manager_webhook_patch.yaml + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. +# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. +# 'CERTMANAGER' needs to be enabled to use ca injection +#- webhookcainjection_patch.yaml + +# the following config is for teaching kustomize how to do var substitution +vars: +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR +# objref: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # this name should match the one in certificate.yaml +# fieldref: +# fieldpath: metadata.namespace +#- name: CERTIFICATE_NAME +# objref: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # this name should match the one in certificate.yaml +#- name: SERVICE_NAMESPACE # namespace of the service +# objref: +# kind: Service +# version: v1 +# name: webhook-service +# fieldref: +# fieldpath: metadata.namespace +#- name: SERVICE_NAME +# objref: +# kind: Service +# version: v1 +# name: webhook-service diff --git a/eventmesh-operator/config/default/manager_auth_proxy_patch.yaml b/eventmesh-operator/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 0000000000..e74132a855 --- /dev/null +++ b/eventmesh-operator/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,72 @@ +# +# 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. +# + +# This patch inject a sidecar container which is a HTTP proxy for the +# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - arm64 + - ppc64le + - s390x + - key: kubernetes.io/os + operator: In + values: + - linux + containers: + - name: kube-rbac-proxy + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=0" + ports: + - containerPort: 8443 + protocol: TCP + name: https + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - name: manager + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" diff --git a/eventmesh-operator/config/default/manager_config_patch.yaml b/eventmesh-operator/config/default/manager_config_patch.yaml new file mode 100644 index 0000000000..483d5c6a2e --- /dev/null +++ b/eventmesh-operator/config/default/manager_config_patch.yaml @@ -0,0 +1,27 @@ +# +# 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. +# + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager diff --git a/eventmesh-operator/config/manager/kustomization.yaml b/eventmesh-operator/config/manager/kustomization.yaml new file mode 100644 index 0000000000..8cc58d49df --- /dev/null +++ b/eventmesh-operator/config/manager/kustomization.yaml @@ -0,0 +1,25 @@ +# +# 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. +# + +resources: +- manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: controller + newTag: latest diff --git a/eventmesh-operator/config/manager/manager.yaml b/eventmesh-operator/config/manager/manager.yaml new file mode 100644 index 0000000000..a5e1a12233 --- /dev/null +++ b/eventmesh-operator/config/manager/manager.yaml @@ -0,0 +1,119 @@ +# +# 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. +# + +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: namespace + app.kubernetes.io/instance: system + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager + app.kubernetes.io/name: deployment + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: controller-manager + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + # TODO(user): Uncomment the following code to configure the nodeAffinity expression + # according to the platforms which are supported by your solution. + # It is considered best practice to support multiple architectures. You can + # build your manager image using the makefile target docker-buildx. + # affinity: + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/arch + # operator: In + # values: + # - amd64 + # - arm64 + # - ppc64le + # - s390x + # - key: kubernetes.io/os + # operator: In + # values: + # - linux + securityContext: + runAsNonRoot: true + # TODO(user): For common cases that do not require escalating privileges + # it is recommended to ensure that all your Pods/Containers are restrictive. + # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted + # Please uncomment the following code if your project does NOT have to work on old Kubernetes + # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). + # seccompProfile: + # type: RuntimeDefault + containers: + - command: + - /manager + args: + - --leader-elect + image: controller:latest + name: manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + # TODO(user): Configure the resources accordingly based on the project requirements. + # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 diff --git a/eventmesh-operator/config/manifests/kustomization.yaml b/eventmesh-operator/config/manifests/kustomization.yaml new file mode 100644 index 0000000000..ffcc68cbc6 --- /dev/null +++ b/eventmesh-operator/config/manifests/kustomization.yaml @@ -0,0 +1,44 @@ +# +# 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. +# + +# These resources constitute the fully configured set of manifests +# used to generate the 'manifests/' directory in a bundle. +resources: +- bases/eventmesh-operator.clusterserviceversion.yaml +- ../default +- ../samples +- ../scorecard + +# [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. +# Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. +# These patches remove the unnecessary "cert" volume and its manager container volumeMount. +#patchesJson6902: +#- target: +# group: apps +# version: v1 +# kind: Deployment +# name: controller-manager +# namespace: system +# patch: |- +# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. +# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. +# - op: remove +# path: /spec/template/spec/containers/1/volumeMounts/0 +# # Remove the "cert" volume, since OLM will create and mount a set of certs. +# # Update the indices in this path if adding or removing volumes in the manager's Deployment. +# - op: remove +# path: /spec/template/spec/volumes/0 diff --git a/eventmesh-operator/config/prometheus/kustomization.yaml b/eventmesh-operator/config/prometheus/kustomization.yaml new file mode 100644 index 0000000000..8995548d73 --- /dev/null +++ b/eventmesh-operator/config/prometheus/kustomization.yaml @@ -0,0 +1,19 @@ +# +# 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. +# + +resources: +- monitor.yaml diff --git a/eventmesh-operator/config/prometheus/monitor.yaml b/eventmesh-operator/config/prometheus/monitor.yaml new file mode 100644 index 0000000000..72ecd1f6a6 --- /dev/null +++ b/eventmesh-operator/config/prometheus/monitor.yaml @@ -0,0 +1,42 @@ +# +# 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. +# + +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: servicemonitor + app.kubernetes.io/instance: controller-manager-metrics-monitor + app.kubernetes.io/component: metrics + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager diff --git a/eventmesh-operator/config/rbac/auth_proxy_client_clusterrole.yaml b/eventmesh-operator/config/rbac/auth_proxy_client_clusterrole.yaml new file mode 100644 index 0000000000..7b9528c3c1 --- /dev/null +++ b/eventmesh-operator/config/rbac/auth_proxy_client_clusterrole.yaml @@ -0,0 +1,33 @@ +# +# 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. +# + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/eventmesh-operator/config/rbac/auth_proxy_role.yaml b/eventmesh-operator/config/rbac/auth_proxy_role.yaml new file mode 100644 index 0000000000..60fcc84420 --- /dev/null +++ b/eventmesh-operator/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,41 @@ +# +# 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. +# + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: proxy-role + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/eventmesh-operator/config/rbac/auth_proxy_role_binding.yaml b/eventmesh-operator/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 0000000000..fb8506e637 --- /dev/null +++ b/eventmesh-operator/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,36 @@ +# +# 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. +# + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/instance: proxy-rolebinding + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/eventmesh-operator/config/rbac/auth_proxy_service.yaml b/eventmesh-operator/config/rbac/auth_proxy_service.yaml new file mode 100644 index 0000000000..20dd3d9efb --- /dev/null +++ b/eventmesh-operator/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,38 @@ +# +# 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. +# + +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: service + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager diff --git a/eventmesh-operator/config/rbac/eventmeshoperator_editor_role.yaml b/eventmesh-operator/config/rbac/eventmeshoperator_editor_role.yaml new file mode 100644 index 0000000000..eeeee009c4 --- /dev/null +++ b/eventmesh-operator/config/rbac/eventmeshoperator_editor_role.yaml @@ -0,0 +1,48 @@ +# +# 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. +# + +# permissions for end users to edit eventmeshoperators. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: eventmeshoperator-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: eventmeshoperator-editor-role +rules: +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - eventmeshoperators + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - eventmeshoperators/status + verbs: + - get diff --git a/eventmesh-operator/config/rbac/eventmeshoperator_viewer_role.yaml b/eventmesh-operator/config/rbac/eventmeshoperator_viewer_role.yaml new file mode 100644 index 0000000000..dce25a53e0 --- /dev/null +++ b/eventmesh-operator/config/rbac/eventmeshoperator_viewer_role.yaml @@ -0,0 +1,44 @@ +# +# 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. +# + +# permissions for end users to view eventmeshoperators. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: eventmeshoperator-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: eventmeshoperator-viewer-role +rules: +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - eventmeshoperators + verbs: + - get + - list + - watch +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - eventmeshoperators/status + verbs: + - get diff --git a/eventmesh-operator/config/rbac/kustomization.yaml b/eventmesh-operator/config/rbac/kustomization.yaml new file mode 100644 index 0000000000..b6005d5f2b --- /dev/null +++ b/eventmesh-operator/config/rbac/kustomization.yaml @@ -0,0 +1,35 @@ +# +# 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. +# + +resources: +# All RBAC will be applied under this service account in +# the deployment namespace. You may comment out this resource +# if your manager will use a service account that exists at +# runtime. Be sure to update RoleBinding and ClusterRoleBinding +# subjects if changing service account names. +- service_account.yaml +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +# Comment the following 4 lines if you want to disable +# the auth proxy (https://github.com/brancz/kube-rbac-proxy) +# which protects your /metrics endpoint. +- auth_proxy_service.yaml +- auth_proxy_role.yaml +- auth_proxy_role_binding.yaml +- auth_proxy_client_clusterrole.yaml diff --git a/eventmesh-operator/config/rbac/leader_election_role.yaml b/eventmesh-operator/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000000..3ebce84cb1 --- /dev/null +++ b/eventmesh-operator/config/rbac/leader_election_role.yaml @@ -0,0 +1,61 @@ +# +# 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. +# + +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/name: role + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/eventmesh-operator/config/rbac/leader_election_role_binding.yaml b/eventmesh-operator/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000000..5ae79ac276 --- /dev/null +++ b/eventmesh-operator/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,36 @@ +# +# 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. +# + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: rolebinding + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: eventmesh-operator + app.kubernetes.io/part-of: eventmesh-operator + app.kubernetes.io/managed-by: kustomize + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/eventmesh-operator/config/rbac/role.yaml b/eventmesh-operator/config/rbac/role.yaml new file mode 100644 index 0000000000..2391c5a67f --- /dev/null +++ b/eventmesh-operator/config/rbac/role.yaml @@ -0,0 +1,150 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: eventmesh-operator +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - pods + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - pods/exec + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - connectors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - connectors/finalizers + verbs: + - update +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - connectors/status + verbs: + - get + - patch + - update +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - runtimes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - runtimes/finalizers + verbs: + - update +- apiGroups: + - eventmesh-operator.eventmesh + resources: + - runtimes/status + verbs: + - get + - patch + - update diff --git a/eventmesh-operator/config/rbac/role_binding.yaml b/eventmesh-operator/config/rbac/role_binding.yaml new file mode 100644 index 0000000000..7c1c095234 --- /dev/null +++ b/eventmesh-operator/config/rbac/role_binding.yaml @@ -0,0 +1,29 @@ +# +# 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. +# + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: eventmesh-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: eventmesh-operator +subjects: +- kind: ServiceAccount + name: eventmesh-operator + namespace: default diff --git a/eventmesh-operator/config/rbac/service_account.yaml b/eventmesh-operator/config/rbac/service_account.yaml new file mode 100644 index 0000000000..7279388adc --- /dev/null +++ b/eventmesh-operator/config/rbac/service_account.yaml @@ -0,0 +1,22 @@ +# +# 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. +# + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: eventmesh-operator + namespace: default diff --git a/eventmesh-operator/config/samples/eventmesh_operator.yaml b/eventmesh-operator/config/samples/eventmesh_operator.yaml new file mode 100644 index 0000000000..29164e9049 --- /dev/null +++ b/eventmesh-operator/config/samples/eventmesh_operator.yaml @@ -0,0 +1,74 @@ +# +# 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. +# + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: eventmesh-operator +spec: + replicas: 1 + selector: + matchLabels: + name: eventmesh-operator + template: + metadata: + labels: + name: eventmesh-operator + spec: + serviceAccountName: eventmesh-operator + terminationGracePeriodSeconds: 10 + containers: + - name: eventmesh-operator + # image + image: alonexc/eventmesh-operator:latest + command: + - /manager + args: + - --leader-elect + imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 200m + memory: 2048Mi + requests: + cpu: 100m + memory: 1024Mi + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: "eventmesh-operator" diff --git a/eventmesh-operator/config/samples/eventmesh_v1_connectors_rocketmq.yaml b/eventmesh-operator/config/samples/eventmesh_v1_connectors_rocketmq.yaml new file mode 100644 index 0000000000..96cff08456 --- /dev/null +++ b/eventmesh-operator/config/samples/eventmesh_v1_connectors_rocketmq.yaml @@ -0,0 +1,105 @@ +# +# 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. +# + +apiVersion: v1 +kind: ConfigMap +metadata: + name: connector-rocketmq-config +data: + server-config.yml: | + sourceEnable: true + sinkEnable: true + sink-config.yml: | + pubSubConfig: + meshAddress: runtime-cluster-service:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSink + appId: 5031 + userName: rocketmqSinkUser + passWord: rocketmqPassWord + connectorConfig: + connectorName: rocketmqSink + nameServer: 127.0.0.1:9876 + topic: TopicTest + source-config.yml: | + pubSubConfig: + meshAddress: runtime-cluster-service:10000 + subject: TopicTest + idc: FT + env: PRD + group: rocketmqSource + appId: 5032 + userName: rocketmqSourceUser + passWord: rocketmqPassWord + connectorConfig: + connectorName: rocketmqSource + nameserver: 127.0.0.1:9876 + topic: TopicTest + commitOffsetIntervalMs: 5000 + offsetStorageConfig: + offsetStorageType: nacos + offsetStorageAddr: 127.0.0.1:8848 + extensions: { + #same with topic + dataId: TopicTest, + #same with group + group: rocketmqSource + } +--- + +apiVersion: eventmesh-operator.eventmesh/v1 +kind: Connectors +metadata: + name: connector-rocketmq +spec: + # size of connector-rocketmq + size: 1 + # imagePullPolicy is the image pull policy + imagePullPolicy: Always + # set DNS policy for the pod + # dnsPolicy: ClusterFirstWithHostNet + # define the connector-rocketmq container. + connectorContainers: + - name: connector-rocketmq + # connectorImage is the customized docker image repo of the EventMesh Connectors + image: alonexc/eventmesh-connectors:connector-rocketmq-1.9.0 + # mount the configuration file to the container. + volumeMounts: + - mountPath: "/data/app/eventmesh-connector-rocketmq/conf" + name: connector-rocketmq-config + # resources describes the compute resource requirements and limits + resources: + requests: + memory: 512Mi + cpu: 250m + limits: + memory: 1024Mi + cpu: 1000m + # configuration file settings to be mounted. + volumes: + - name: connector-rocketmq-config + configMap: + name: connector-rocketmq-config + items: + - key: server-config.yml + path: server-config.yml + - key: sink-config.yml + path: sink-config.yml + - key: source-config.yml + path: source-config.yml \ No newline at end of file diff --git a/eventmesh-operator/config/samples/eventmesh_v1_runtime.yaml b/eventmesh-operator/config/samples/eventmesh_v1_runtime.yaml new file mode 100644 index 0000000000..590928ca97 --- /dev/null +++ b/eventmesh-operator/config/samples/eventmesh_v1_runtime.yaml @@ -0,0 +1,299 @@ +# +# 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. +# + +apiVersion: v1 +kind: ConfigMap +metadata: + name: runtime-config +data: + rocketmq.properties: | + #######################rocketmq-client################## + eventMesh.server.rocketmq.namesrvAddr=127.0.0.1:9876;127.0.0.1:9876 + eventMesh.server.rocketmq.cluster=DefaultCluster + eventMesh.server.rocketmq.accessKey=******** + eventMesh.server.rocketmq.secretKey=******** + + eventmesh.properties: | + ###############################EVNETMESH-runtime ENV################################# + eventMesh.server.idc=DEFAULT + eventMesh.server.env=PRD + eventMesh.server.provide.protocols=HTTP,TCP,GRPC + eventMesh.server.cluster=COMMON + eventMesh.server.name=EVENTMESH-runtime + eventMesh.sysid=0000 + eventMesh.server.tcp.port=10000 + eventMesh.server.http.port=10105 + eventMesh.server.grpc.port=10205 + # HTTP Admin Server + eventMesh.server.admin.http.port=10106 + ########################## eventMesh tcp configuration ############################ + eventMesh.server.tcp.readerIdleSeconds=120 + eventMesh.server.tcp.writerIdleSeconds=120 + eventMesh.server.tcp.allIdleSeconds=120 + eventMesh.server.tcp.clientMaxNum=10000 + # client isolation time if the message send failure + eventMesh.server.tcp.pushFailIsolateTimeInMills=30000 + # rebalance internal + eventMesh.server.tcp.RebalanceIntervalInMills=30000 + # session expire time about client + eventMesh.server.session.expiredInMills=60000 + # flow control, include the global level and session level + eventMesh.server.tcp.msgReqnumPerSecond=15000 + eventMesh.server.http.msgReqnumPerSecond=15000 + eventMesh.server.session.upstreamBufferSize=20 + + # for single event publish, maximum size allowed per event + eventMesh.server.maxEventSize=1000 + # for batch event publish, maximum number of events allowed in one batch + eventMesh.server.maxEventBatchSize=10 + + # thread number about global scheduler + eventMesh.server.global.scheduler=5 + eventMesh.server.tcp.taskHandleExecutorPoolSize=8 + #retry + eventMesh.server.retry.async.pushRetryTimes=3 + eventMesh.server.retry.sync.pushRetryTimes=3 + eventMesh.server.retry.async.pushRetryDelayInMills=500 + eventMesh.server.retry.sync.pushRetryDelayInMills=500 + eventMesh.server.retry.pushRetryQueueSize=10000 + + #sleep interval between closing client of different group in server graceful shutdown + eventMesh.server.gracefulShutdown.sleepIntervalInMills=1000 + eventMesh.server.rebalanceRedirect.sleepIntervalInMills=200 + + #ip address blacklist + eventMesh.server.blacklist.ipv4=0.0.0.0/8,127.0.0.0/8,169.254.0.0/16,255.255.255.255/32 + eventMesh.server.blacklist.ipv6=::/128,::1/128,ff00::/8 + + #storage plugin + eventMesh.storage.plugin.type=standalone + + #security plugin + eventMesh.server.security.enabled=false + eventMesh.security.plugin.type=security + eventMesh.security.validation.type.token=false + eventMesh.security.publickey= + + #metaStorage plugin + eventMesh.metaStorage.plugin.enabled=false + eventMesh.metaStorage.plugin.type=nacos + eventMesh.metaStorage.plugin.server-addr=127.0.0.1:8848 + eventMesh.metaStorage.plugin.username=nacos + eventMesh.metaStorage.plugin.password=nacos + # metaStorage plugin: nacos + #eventMesh.metaStorage.nacos.endpoint= + #eventMesh.metaStorage.nacos.accessKey= + #eventMesh.metaStorage.nacos.secretKey= + #eventMesh.metaStorage.nacos.clusterName= + #eventMesh.metaStorage.nacos.namespace= + # The default value is half of CPU's num + #eventMesh.metaStorage.nacos.namingPollingThreadCount=5 + + # metaStorage plugin: zookeeper + #eventMesh.metaStorage.zookeeper.scheme= + #eventMesh.metaStorage.zookeeper.auth= + #eventMesh.metaStorage.zookeeper.connectionTimeoutMs= + #eventMesh.metaStorage.zookeeper.sessionTimeoutMs= + + # Fully qualified name of org.apache.curator.RetryPolicy implementation + #eventMesh.metaStorage.zookeeper.retryPolicy.class= + + # Constructor arguments for different org.apache.curator.RetryPolicy implementations + #eventMesh.metaStorage.zookeeper.retryPolicy.baseSleepTimeMs= + #eventMesh.metaStorage.zookeeper.retryPolicy.maxRetries= + #eventMesh.metaStorage.zookeeper.retryPolicy.maxSleepTimeMs= + #eventMesh.metaStorage.zookeeper.retryPolicy.retryIntervalMs= + #eventMesh.metaStorage.zookeeper.retryPolicy.nTimes= + #eventMesh.metaStorage.zookeeper.retryPolicy.sleepMsBetweenRetries= + + # The TLS configuration of metaStorage plugin: consul + # keyStoreInstanceType's value can refer to com.ecwid.consul.transport.TLSConfig.KeyStoreInstanceType + #eventMesh.metaStorage.consul.tls.keyStoreInstanceType= + #eventMesh.metaStorage.consul.tls.certificatePath= + #eventMesh.metaStorage.consul.tls.certificatePassword= + #eventMesh.metaStorage.consul.tls.keyStorePath= + #eventMesh.metaStorage.consul.tls.keyStorePassword= + + # metrics plugin, if you have multiple plugin, you can use ',' to split + eventMesh.metrics.plugin=prometheus + + # trace plugin + eventMesh.server.trace.enabled=false + eventMesh.trace.plugin=zipkin + + # webhook + # Start webhook admin service + eventMesh.webHook.admin.start=true + # Webhook event configuration storage mode. Currently, only file and Nacos are supported + eventMesh.webHook.operationMode=file + # The file storage path of the file storage mode. If #{eventmeshhome} is written, it is in the eventmesh root directory + eventMesh.webHook.fileMode.filePath= #{eventMeshHome}/webhook + # Nacos storage mode, and the configuration naming rule is eventmesh webHook. nacosMode. {nacos native configuration key} please see the specific configuration [nacos github api](https://github.com/alibaba/nacos/blob/develop/api/src/main/java/com/alibaba/nacos/api/SystemPropertyKeyConst.java) + ## Address of Nacos + eventMesh.webHook.nacosMode.serverAddr=127.0.0.1:8848 + # Webhook CloudEvent sending mode. This property is the same as the eventMesh.storage.plugin.type configuration. + eventMesh.webHook.producer.storage=standalone + server.env: | + APP_START_JVM_OPTION:::-server -Xms128M -Xmx256M -Xmn128m -XX:SurvivorRatio=4 -Duser.language=zh + log4j2.xml: | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +--- + +apiVersion: eventmesh-operator.eventmesh/v1 +kind: Runtime +metadata: + name: eventmesh-runtime +spec: + # size is the number of the runtime cluster + size: 1 + # replicaPerGroup is the number of each runtime cluster + replicaPerGroup: 1 + # allowRestart defines whether allow pod restart + allowRestart: true + # define runtime pod template + runtimePodTemplate: + template: + spec: + # Host networking requested for this pod. Use the host's network namespace. + # If this option is set, the ports that will be used must be specified. + # Default to false. + hostNetwork: false + # Defaults to "ClusterFirst" + # Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. + # DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. + # To have DNS options set along with hostNetwork, you have to specify DNS policy + # explicitly to 'ClusterFirstWithHostNet'. + dnsPolicy: ClusterFirstWithHostNet + # define the runtime container. + containers: + - name: eventmesh-runtime + image: alonexc/eventmesh-runtime:runtime-1.9.0 + ports: + - name: tcp + containerPort: 10000 + - name: http + containerPort: 10105 + - name: grpc + containerPort: 10205 + volumeMounts: + - mountPath: "/data/app/eventmesh/conf" + name: runtime-config + # imagePullPolicy is the image pull policy + imagePullPolicy: Always + # resources describes the compute resource requirements and limits + resources: + requests: + memory: 2048Mi + cpu: 2000m + limits: + memory: 8192Mi + cpu: 8000m + # configuration file settings to be mounted. + volumes: + - name: runtime-config + configMap: + name: runtime-config + items: + - key: rocketmq.properties + path: rocketmq.properties + - key: eventmesh.properties + path: eventmesh.properties + - key: server.env + path: server.env + - key: log4j2.xml + path: log4j2.xml \ No newline at end of file diff --git a/eventmesh-operator/config/samples/eventmesh_v1_runtime_cluster.yaml b/eventmesh-operator/config/samples/eventmesh_v1_runtime_cluster.yaml new file mode 100644 index 0000000000..ec9d0f7274 --- /dev/null +++ b/eventmesh-operator/config/samples/eventmesh_v1_runtime_cluster.yaml @@ -0,0 +1,31 @@ +# +# 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. +# + +apiVersion: v1 +kind: Service +metadata: + name: runtime-cluster-service +spec: + type: ClusterIP + selector: + app: eventmesh-runtime + ports: + - name: tcp + port: 10000 + targetPort: 10000 + protocol: TCP +--- \ No newline at end of file diff --git a/eventmesh-operator/config/samples/kustomization.yaml b/eventmesh-operator/config/samples/kustomization.yaml new file mode 100644 index 0000000000..ab43080bab --- /dev/null +++ b/eventmesh-operator/config/samples/kustomization.yaml @@ -0,0 +1,22 @@ +# +# 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. +# + +## Append samples you want in your CSV to this file as resources ## +resources: +- eventmesh_v1_runtime.yaml +- eventmesh_v1_connectors_rocketmq.yaml +#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/eventmesh-operator/config/scorecard/bases/config.yaml b/eventmesh-operator/config/scorecard/bases/config.yaml new file mode 100644 index 0000000000..6d618c1474 --- /dev/null +++ b/eventmesh-operator/config/scorecard/bases/config.yaml @@ -0,0 +1,24 @@ +# +# 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. +# + +apiVersion: scorecard.operatorframework.io/v1alpha3 +kind: Configuration +metadata: + name: config +stages: +- parallel: true + tests: [] diff --git a/eventmesh-operator/config/scorecard/kustomization.yaml b/eventmesh-operator/config/scorecard/kustomization.yaml new file mode 100644 index 0000000000..606f84d0ed --- /dev/null +++ b/eventmesh-operator/config/scorecard/kustomization.yaml @@ -0,0 +1,33 @@ +# +# 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. +# + +resources: +- bases/config.yaml +patchesJson6902: +- path: patches/basic.config.yaml + target: + group: scorecard.operatorframework.io + version: v1alpha3 + kind: Configuration + name: config +- path: patches/olm.config.yaml + target: + group: scorecard.operatorframework.io + version: v1alpha3 + kind: Configuration + name: config +#+kubebuilder:scaffold:patchesJson6902 diff --git a/eventmesh-operator/config/scorecard/patches/basic.config.yaml b/eventmesh-operator/config/scorecard/patches/basic.config.yaml new file mode 100644 index 0000000000..e1e6431a98 --- /dev/null +++ b/eventmesh-operator/config/scorecard/patches/basic.config.yaml @@ -0,0 +1,27 @@ +# +# 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. +# + +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - basic-check-spec + image: quay.io/operator-framework/scorecard-test:v1.31.0 + labels: + suite: basic + test: basic-check-spec-test diff --git a/eventmesh-operator/config/scorecard/patches/olm.config.yaml b/eventmesh-operator/config/scorecard/patches/olm.config.yaml new file mode 100644 index 0000000000..a91313d862 --- /dev/null +++ b/eventmesh-operator/config/scorecard/patches/olm.config.yaml @@ -0,0 +1,67 @@ +# +# 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. +# + +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-bundle-validation + image: quay.io/operator-framework/scorecard-test:v1.31.0 + labels: + suite: olm + test: olm-bundle-validation-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-crds-have-validation + image: quay.io/operator-framework/scorecard-test:v1.31.0 + labels: + suite: olm + test: olm-crds-have-validation-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-crds-have-resources + image: quay.io/operator-framework/scorecard-test:v1.31.0 + labels: + suite: olm + test: olm-crds-have-resources-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-spec-descriptors + image: quay.io/operator-framework/scorecard-test:v1.31.0 + labels: + suite: olm + test: olm-spec-descriptors-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-status-descriptors + image: quay.io/operator-framework/scorecard-test:v1.31.0 + labels: + suite: olm + test: olm-status-descriptors-test diff --git a/eventmesh-operator/controllers/eventmesh_connectors/connectors_controller.go b/eventmesh-operator/controllers/eventmesh_connectors/connectors_controller.go new file mode 100644 index 0000000000..e9a9896a93 --- /dev/null +++ b/eventmesh-operator/controllers/eventmesh_connectors/connectors_controller.go @@ -0,0 +1,342 @@ +/* + * 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. + */ + +package eventmesh_connectors + +import ( + "context" + "fmt" + eventmeshoperatorv1 "github.com/apache/eventmesh/eventmesh-operator/api/v1" + "github.com/apache/eventmesh/eventmesh-operator/share" + "github.com/go-logr/logr" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "reflect" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + _ "strings" + "time" +) + +// ConnectorsReconciler reconciles a Connectors object +type ConnectorsReconciler struct { + Client client.Client + Scheme *runtime.Scheme + Logger logr.Logger +} + +// SetupWithManager creates a new Connectors Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func SetupWithManager(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ConnectorsReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: mgr.GetLogger().WithName("connector"), + } +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("connectors-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource connector + err = c.Watch(&source.Kind{Type: &eventmeshoperatorv1.Connectors{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create that are owned by the primary resource + // Watch for changes to secondary resource Pods and requeue the owner runtime + err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &eventmeshoperatorv1.Connectors{}, + }) + if err != nil { + return err + } + + return nil +} + +//+kubebuilder:rbac:groups=eventmesh-operator.eventmesh,resources=connectors,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=eventmesh-operator.eventmesh,resources=connectors/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=eventmesh-operator.eventmesh,resources=connectors/finalizers,verbs=update +//+kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",resources=pods/exec,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="apps",resources=statefulsets,verbs=get;list;watch;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +func (r ConnectorsReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { + r.Logger.Info("connectors start reconciling", + "Namespace", req.Namespace, "Name", req.Name) + + connector := &eventmeshoperatorv1.Connectors{} + err := r.Client.Get(context.TODO(), req.NamespacedName, connector) + if err != nil { + if errors.IsNotFound(err) { + r.Logger.Info("connector resource not found. Ignoring since object must be deleted.") + return reconcile.Result{}, nil + } + r.Logger.Error(err, "Failed to get connector") + return reconcile.Result{}, err + } + + // Dependency Check: Check if Runtime is ready + runtimeList := &eventmeshoperatorv1.RuntimeList{} + listOps := &client.ListOptions{Namespace: connector.Namespace} + err = r.Client.List(context.TODO(), runtimeList, listOps) + if err != nil { + r.Logger.Error(err, "Failed to list Runtimes for dependency check") + return reconcile.Result{}, err + } + + runtimeReady := false + for _, runtime := range runtimeList.Items { + // Simple check: if at least one runtime has size > 0 + if runtime.Status.Size > 0 { + runtimeReady = true + break + } + } + + if !runtimeReady { + r.Logger.Info("Connector waiting for EventMesh Runtime to be ready...") + return reconcile.Result{Requeue: true, RequeueAfter: time.Duration(share.RequeueAfterSecond) * time.Second}, nil + } + + // 1. Reconcile Service + connectorService := r.getConnectorService(connector) + foundService := &corev1.Service{} + err = r.Client.Get(context.TODO(), types.NamespacedName{ + Name: connectorService.Name, + Namespace: connectorService.Namespace, + }, foundService) + if err != nil && errors.IsNotFound(err) { + r.Logger.Info("Creating a new Connector Service.", "Namespace", connectorService.Namespace, "Name", connectorService.Name) + err = r.Client.Create(context.TODO(), connectorService) + if err != nil { + r.Logger.Error(err, "Failed to create new Connector Service") + return reconcile.Result{}, err + } + } else if err != nil { + r.Logger.Error(err, "Failed to get Connector Service") + return reconcile.Result{}, err + } + + // 2. Reconcile StatefulSet + connectorStatefulSet := r.getConnectorStatefulSet(connector) + found := &appsv1.StatefulSet{} + err = r.Client.Get(context.TODO(), types.NamespacedName{ + Name: connectorStatefulSet.Name, + Namespace: connectorStatefulSet.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + r.Logger.Info("Creating a new Connector StatefulSet.", + "StatefulSet.Namespace", connectorStatefulSet.Namespace, + "StatefulSet.Name", connectorStatefulSet.Name) + err = r.Client.Create(context.TODO(), connectorStatefulSet) + if err != nil { + r.Logger.Error(err, "Failed to create new Connector StatefulSet", + "StatefulSet.Namespace", connectorStatefulSet.Namespace, + "StatefulSet.Name", connectorStatefulSet.Name) + return reconcile.Result{}, err + } + } else if err != nil { + r.Logger.Error(err, "Failed to list Connector StatefulSet.") + return reconcile.Result{}, err + } + + podList := &corev1.PodList{} + labelSelector := labels.SelectorFromSet(getLabels(connector.Name)) + podListOps := &client.ListOptions{ + Namespace: connector.Namespace, + LabelSelector: labelSelector, + } + err = r.Client.List(context.TODO(), podList, podListOps) + if err != nil { + r.Logger.Error(err, "Failed to list pods.", "Connector.Namespace", connector.Namespace, + "Connector.Name", connector.Name) + return reconcile.Result{}, err + } + podNames := getConnectorPodNames(podList.Items) + + // Update Status + var needsUpdate bool + if connector.Spec.Size != connector.Status.Size { + connector.Status.Size = connector.Spec.Size + needsUpdate = true + } + if !reflect.DeepEqual(podNames, connector.Status.Nodes) { + connector.Status.Nodes = podNames + needsUpdate = true + } + + if needsUpdate { + r.Logger.Info("Updating connector status") + err = r.Client.Status().Update(context.TODO(), connector) + if err != nil { + r.Logger.Error(err, "Failed to update Connector status.") + return reconcile.Result{}, err + } + } + + r.Logger.Info("Successful reconciliation!") + return reconcile.Result{RequeueAfter: time.Duration(share.RequeueAfterSecond) * time.Second}, nil +} + +func (r ConnectorsReconciler) getConnectorStatefulSet(connector *eventmeshoperatorv1.Connectors) *appsv1.StatefulSet { + replica := int32(connector.Spec.Size) + serviceName := fmt.Sprintf("%s-service", connector.Name) + label := getLabels(connector.Name) + + connectorDep := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: connector.Name, + Namespace: connector.Namespace, + Labels: label, + }, + Spec: appsv1.StatefulSetSpec{ + ServiceName: serviceName, + Replicas: &replica, + Selector: &metav1.LabelSelector{ + MatchLabels: label, + }, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: label, + }, + Spec: corev1.PodSpec{ + HostNetwork: connector.Spec.HostNetwork, + DNSPolicy: connector.Spec.DNSPolicy, + ServiceAccountName: connector.Spec.ServiceAccountName, + Affinity: connector.Spec.Affinity, + Tolerations: connector.Spec.Tolerations, + NodeSelector: connector.Spec.NodeSelector, + PriorityClassName: connector.Spec.PriorityClassName, + ImagePullSecrets: connector.Spec.ImagePullSecrets, + Containers: connector.Spec.ConnectorContainers, // Use all containers + Volumes: connector.Spec.Volumes, + SecurityContext: getConnectorPodSecurityContext(connector), + }, + }, + }, + } + + // Manually set security context for first container if needed + if len(connectorDep.Spec.Template.Spec.Containers) > 0 { + if connectorDep.Spec.Template.Spec.Containers[0].SecurityContext == nil { + connectorDep.Spec.Template.Spec.Containers[0].SecurityContext = getConnectorContainerSecurityContext(connector) + } + } + + _ = controllerutil.SetControllerReference(connector, connectorDep, r.Scheme) + + return connectorDep +} + +func (r ConnectorsReconciler) getConnectorService(connector *eventmeshoperatorv1.Connectors) *corev1.Service { + serviceName := fmt.Sprintf("%s-service", connector.Name) + label := getLabels(connector.Name) + + var ports []corev1.ServicePort + if len(connector.Spec.ConnectorContainers) > 0 { + for _, port := range connector.Spec.ConnectorContainers[0].Ports { + ports = append(ports, corev1.ServicePort{ + Name: port.Name, + Port: port.ContainerPort, + TargetPort: intstr.FromInt(int(port.ContainerPort)), + }) + } + } + // Fallback port if none + if len(ports) == 0 { + ports = append(ports, corev1.ServicePort{ + Name: "http", + Port: 8080, + TargetPort: intstr.FromInt(8080), + }) + } + + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceName, + Namespace: connector.Namespace, + Labels: label, + }, + Spec: corev1.ServiceSpec{ + ClusterIP: "None", // Headless + Selector: label, + Ports: ports, + }, + } + _ = controllerutil.SetControllerReference(connector, svc, r.Scheme) + return svc +} + +func getConnectorContainerSecurityContext(connector *eventmeshoperatorv1.Connectors) *corev1.SecurityContext { + var securityContext = corev1.SecurityContext{} + if connector.Spec.ContainerSecurityContext != nil { + securityContext = *connector.Spec.ContainerSecurityContext + } + return &securityContext +} + +func getLabels(name string) map[string]string { + return map[string]string{ + "app": "eventmesh-connector", + "instance": name, + } +} + +func getConnectorPodSecurityContext(connector *eventmeshoperatorv1.Connectors) *corev1.PodSecurityContext { + var securityContext = corev1.PodSecurityContext{} + if connector.Spec.PodSecurityContext != nil { + securityContext = *connector.Spec.PodSecurityContext + } + return &securityContext +} + +func getConnectorPodNames(pods []corev1.Pod) []string { + var podNames []string + for _, pod := range pods { + podNames = append(podNames, pod.Name) + } + return podNames +} diff --git a/eventmesh-operator/controllers/eventmesh_runtime/runtime_controller.go b/eventmesh-operator/controllers/eventmesh_runtime/runtime_controller.go new file mode 100644 index 0000000000..6d1a8e74e2 --- /dev/null +++ b/eventmesh-operator/controllers/eventmesh_runtime/runtime_controller.go @@ -0,0 +1,364 @@ +/* + * 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. + */ + +package eventmesh_runtime + +import ( + "context" + "fmt" + eventmeshoperatorv1 "github.com/apache/eventmesh/eventmesh-operator/api/v1" + "github.com/apache/eventmesh/eventmesh-operator/share" + "github.com/go-logr/logr" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "reflect" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + "strconv" + "time" +) + +// RuntimeReconciler reconciles a Runtime object +type RuntimeReconciler struct { + Client client.Client + Scheme *runtime.Scheme + Logger logr.Logger +} + +// SetupWithManager creates a new Runtime Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func SetupWithManager(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &RuntimeReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: mgr.GetLogger().WithName("runtime"), + } +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("runtime-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource runtime + err = c.Watch(&source.Kind{Type: &eventmeshoperatorv1.Runtime{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // Watch for changes to secondary resource Pods and requeue the owner runtime + err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &eventmeshoperatorv1.Runtime{}, + }) + if err != nil { + return err + } + + return nil +} + +//+kubebuilder:rbac:groups=eventmesh-operator.eventmesh,resources=runtimes,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=eventmesh-operator.eventmesh,resources=runtimes/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=eventmesh-operator.eventmesh,resources=runtimes/finalizers,verbs=update +//+kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="apps",resources=statefulsets,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +func (r *RuntimeReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { + r.Logger.Info("eventMeshRuntime start reconciling", + "Namespace", req.Namespace, "Name", req.Name) + + eventMeshRuntime := &eventmeshoperatorv1.Runtime{} + err := r.Client.Get(context.TODO(), req.NamespacedName, eventMeshRuntime) + if err != nil { + if errors.IsNotFound(err) { + r.Logger.Info("eventMeshRuntime resource not found. Ignoring since object must be deleted.") + return reconcile.Result{}, nil + } + r.Logger.Error(err, "Failed to get eventMeshRuntime") + return reconcile.Result{}, err + } + r.Logger.Info("get eventMeshRuntime object", "name", eventMeshRuntime.Name) + + var groupNum int + if eventMeshRuntime.Status.Size == 0 { + groupNum = eventMeshRuntime.Spec.Size + } else { + groupNum = eventMeshRuntime.Status.Size + } + + replicaPerGroup := eventMeshRuntime.Spec.ReplicaPerGroup + r.Logger.Info("GroupNum=" + strconv.Itoa(groupNum) + ", replicaPerGroup=" + strconv.Itoa(replicaPerGroup)) + + for groupIndex := 0; groupIndex < groupNum; groupIndex++ { + r.Logger.Info("Check eventMeshRuntime cluster " + strconv.Itoa(groupIndex+1) + "/" + strconv.Itoa(groupNum)) + + // 1. Reconcile Service + service := r.getEventMeshRuntimeService(eventMeshRuntime, groupIndex) + foundService := &corev1.Service{} + err = r.Client.Get(context.TODO(), types.NamespacedName{Name: service.Name, Namespace: service.Namespace}, foundService) + if err != nil && errors.IsNotFound(err) { + r.Logger.Info("Creating a new eventMeshRuntime Service.", "Service.Namespace", service.Namespace, "Service.Name", service.Name) + err = r.Client.Create(context.TODO(), service) + if err != nil { + r.Logger.Error(err, "Failed to create new Service", "Service.Namespace", service.Namespace, "Service.Name", service.Name) + return reconcile.Result{}, err + } + } else if err != nil { + r.Logger.Error(err, "Failed to get eventMeshRuntime Service.") + return reconcile.Result{}, err + } + + // 2. Reconcile StatefulSet + runtimeSts := r.getEventMeshRuntimeStatefulSet(eventMeshRuntime, groupIndex) + foundSts := &appsv1.StatefulSet{} + err = r.Client.Get(context.TODO(), types.NamespacedName{ + Name: runtimeSts.Name, + Namespace: runtimeSts.Namespace, + }, foundSts) + + if err != nil && errors.IsNotFound(err) { + r.Logger.Info("Creating a new eventMeshRuntime StatefulSet.", + "StatefulSet.Namespace", runtimeSts.Namespace, + "StatefulSet.Name", runtimeSts.Name) + err = r.Client.Create(context.TODO(), runtimeSts) + if err != nil { + r.Logger.Error(err, "Failed to create new StatefulSet", + "StatefulSet.Namespace", runtimeSts.Namespace, + "StatefulSet.Name", runtimeSts.Name) + return reconcile.Result{}, err + } + } else if err != nil { + r.Logger.Error(err, "Failed to get eventMeshRuntime StatefulSet.") + return reconcile.Result{}, err + } else { + // Update if needed + if eventMeshRuntime.Spec.AllowRestart { + // Simple update logic: overwrite spec + r.Logger.Info("Updating eventMeshRuntime StatefulSet", "Name", foundSts.Name) + runtimeSts.ResourceVersion = foundSts.ResourceVersion + err = r.Client.Update(context.TODO(), runtimeSts) + if err != nil { + r.Logger.Error(err, "Failed to update eventMeshRuntime StatefulSet", "Name", foundSts.Name) + return reconcile.Result{}, err + } + } + } + } + + podList := &corev1.PodList{} + labelSelector := labels.SelectorFromSet(getLabels(eventMeshRuntime.Name)) + listOps := &client.ListOptions{ + Namespace: eventMeshRuntime.Namespace, + LabelSelector: labelSelector, + } + err = r.Client.List(context.TODO(), podList, listOps) + if err != nil { + r.Logger.Error(err, "Failed to list pods.", + "eventMeshRuntime.Namespace", eventMeshRuntime.Namespace, "eventMeshRuntime.Name", eventMeshRuntime.Name) + return reconcile.Result{}, err + } + + podNames := getRuntimePodNames(podList.Items) + + // Update Status + var needsUpdate bool + if eventMeshRuntime.Spec.Size != eventMeshRuntime.Status.Size { + eventMeshRuntime.Status.Size = eventMeshRuntime.Spec.Size + needsUpdate = true + } + if !reflect.DeepEqual(podNames, eventMeshRuntime.Status.Nodes) { + eventMeshRuntime.Status.Nodes = podNames + needsUpdate = true + } + + if needsUpdate { + r.Logger.Info("Updating eventMeshRuntime status") + err = r.Client.Status().Update(context.TODO(), eventMeshRuntime) + if err != nil { + r.Logger.Error(err, "Failed to update eventMeshRuntime status.") + return reconcile.Result{}, err + } + } + + // Update global state + runningEventMeshRuntimeNum := getRunningRuntimeNum(podList.Items) + // We check if total running pods match expected total replicas + totalExpectedReplicas := groupNum * replicaPerGroup + if runningEventMeshRuntimeNum == totalExpectedReplicas { + // share.IsEventMeshRuntimeInitialized = true (Removed as per refactor) + } + + r.Logger.Info("Successful reconciliation!") + return reconcile.Result{RequeueAfter: time.Duration(share.RequeueAfterSecond) * time.Second}, nil +} + +func getRunningRuntimeNum(pods []corev1.Pod) int { + var num = 0 + for _, pod := range pods { + if reflect.DeepEqual(pod.Status.Phase, corev1.PodRunning) { + num++ + } + } + return num +} + +func getRuntimePodNames(pods []corev1.Pod) []string { + var podNames []string + for _, pod := range pods { + podNames = append(podNames, pod.Name) + } + return podNames +} + +func (r *RuntimeReconciler) getEventMeshRuntimeStatefulSet(runtime *eventmeshoperatorv1.Runtime, groupIndex int) *appsv1.StatefulSet { + // Naming: - + statefulSetName := fmt.Sprintf("%s-%d", runtime.Name, groupIndex) + serviceName := fmt.Sprintf("%s-%d-headless", runtime.Name, groupIndex) + + replicas := int32(runtime.Spec.ReplicaPerGroup) + label := getLabels(runtime.Name) + + deployment := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: statefulSetName, + Namespace: runtime.Namespace, + Labels: label, + }, + Spec: appsv1.StatefulSetSpec{ + ServiceName: serviceName, + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: label, + }, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: label, + }, + Spec: corev1.PodSpec{ + DNSPolicy: runtime.Spec.RuntimePodTemplate.Template.Spec.DNSPolicy, + Affinity: runtime.Spec.RuntimePodTemplate.Template.Spec.Affinity, + Tolerations: runtime.Spec.RuntimePodTemplate.Template.Spec.Tolerations, + NodeSelector: runtime.Spec.RuntimePodTemplate.Template.Spec.NodeSelector, + PriorityClassName: runtime.Spec.RuntimePodTemplate.Template.Spec.PriorityClassName, + HostNetwork: runtime.Spec.RuntimePodTemplate.Template.Spec.HostNetwork, + Containers: runtime.Spec.RuntimePodTemplate.Template.Spec.Containers, // Use all containers + Volumes: runtime.Spec.RuntimePodTemplate.Template.Spec.Volumes, + SecurityContext: getRuntimePodSecurityContext(runtime), + }, + }, + }, + } + // Manually set security context for the first container if not set, for backward compatibility or strict override + if len(deployment.Spec.Template.Spec.Containers) > 0 { + if deployment.Spec.Template.Spec.Containers[0].SecurityContext == nil { + deployment.Spec.Template.Spec.Containers[0].SecurityContext = getContainerSecurityContext(runtime) + } + } + + _ = controllerutil.SetControllerReference(runtime, deployment, r.Scheme) + return deployment +} + +func (r *RuntimeReconciler) getEventMeshRuntimeService(runtime *eventmeshoperatorv1.Runtime, groupIndex int) *corev1.Service { + serviceName := fmt.Sprintf("%s-%d-headless", runtime.Name, groupIndex) + label := getLabels(runtime.Name) + + var ports []corev1.ServicePort + // Extract ports from the first container + if len(runtime.Spec.RuntimePodTemplate.Template.Spec.Containers) > 0 { + for _, port := range runtime.Spec.RuntimePodTemplate.Template.Spec.Containers[0].Ports { + ports = append(ports, corev1.ServicePort{ + Name: port.Name, + Port: port.ContainerPort, + TargetPort: intstr.FromInt(int(port.ContainerPort)), + }) + } + } + // Fallback if no ports defined, though ideally CR should have them + if len(ports) == 0 { + ports = append(ports, corev1.ServicePort{ + Name: "grpc", + Port: 10000, + TargetPort: intstr.FromInt(10000), + }) + } + + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceName, + Namespace: runtime.Namespace, + Labels: label, + }, + Spec: corev1.ServiceSpec{ + ClusterIP: "None", // Headless Service + Selector: label, + Ports: ports, + }, + } + _ = controllerutil.SetControllerReference(runtime, svc, r.Scheme) + return svc +} + +func getRuntimePodSecurityContext(runtime *eventmeshoperatorv1.Runtime) *corev1.PodSecurityContext { + var securityContext = corev1.PodSecurityContext{} + if runtime.Spec.PodSecurityContext != nil { + securityContext = *runtime.Spec.PodSecurityContext + } + return &securityContext +} + +func getContainerSecurityContext(runtime *eventmeshoperatorv1.Runtime) *corev1.SecurityContext { + var securityContext = corev1.SecurityContext{} + if runtime.Spec.ContainerSecurityContext != nil { + securityContext = *runtime.Spec.ContainerSecurityContext + } + return &securityContext +} + +func getLabels(name string) map[string]string { + return map[string]string{ + "app": "eventmesh-runtime", + "instance": name, + } +} diff --git a/eventmesh-operator/controllers/suite_test.go b/eventmesh-operator/controllers/suite_test.go new file mode 100644 index 0000000000..5f4522eab7 --- /dev/null +++ b/eventmesh-operator/controllers/suite_test.go @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package controllers + +import ( + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + eventmeshoperatorv1 "github.com/apache/eventmesh/eventmesh-operator/api/v1" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = eventmeshoperatorv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/eventmesh-operator/eventmesh-operator.md b/eventmesh-operator/eventmesh-operator.md new file mode 100644 index 0000000000..cda91fcce9 --- /dev/null +++ b/eventmesh-operator/eventmesh-operator.md @@ -0,0 +1,185 @@ +## Environment + +### Prerequisite + +- docker +- golang +- kubernetes + +### Install + +- [Install the Operator SDK](https://v1-5-x.sdk.operatorframework.io/docs/installation/) + +## Build Operator: + +- Create an Operator Project + +``` +operator-sdk init --domain eventmesh --repo github.com/apache/eventmesh/eventmesh-operator + +Directory Structure: +. +├── Dockerfile +├── Makefile +├── PROJECT +├── README.md +├── config +│   ├── default +│   │   ├── kustomization.yaml +│   │   ├── manager_auth_proxy_patch.yaml +│   │   └── manager_config_patch.yaml +│   ├── manager +│   │   ├── kustomization.yaml +│   │   └── manager.yaml +│   ├── manifests +│   │   └── kustomization.yaml +│   ├── prometheus +│   │   ├── kustomization.yaml +│   │   └── monitor.yaml +│   ├── rbac +│   │   ├── auth_proxy_client_clusterrole.yaml +│   │   ├── auth_proxy_role.yaml +│   │   ├── auth_proxy_role_binding.yaml +│   │   ├── auth_proxy_service.yaml +│   │   ├── kustomization.yaml +│   │   ├── leader_election_role.yaml +│   │   ├── leader_election_role_binding.yaml +│   │   ├── role_binding.yaml +│   │   └── service_account.yaml +│   └── scorecard +│   ├── bases +│   │   └── config.yaml +│   ├── kustomization.yaml +│   └── patches +│   ├── basic.config.yaml +│   └── olm.config.yaml +├── go.mod +├── go.sum +├── hack +│   └── boilerplate.go.txt +└── main.go +``` +**Makefile**: make targets for building and deploying your controller +**PROJECT**: automatically generated project metadata. +**go.mod**: a new Go module matching our project, with basic dependencies +**config/default**: contains for starting the controller in a standard configuration. +**config/manager**: launch your controllers as pods in the cluster +**config/rbac**: permissions required to run your controllers under their own service account + +- Create api、resource、controller + +``` +operator-sdk create api --group eventmesh --version v1 --kind EventMeshOperator --resource --controller + +Directory Structure: +. +├── Dockerfile +├── Makefile +├── PROJECT +├── README.md +├── api +│   └── v1 +│   ├── eventmeshoperator_types.go +│   ├── groupversion_info.go +│   └── zz_generated.deepcopy.go +├── bin +│   └── controller-gen +├── config +│   ├── crd +│   │   ├── kustomization.yaml +│   │   ├── kustomizeconfig.yaml +│   │   └── patches +│   │   ├── cainjection_in_eventmeshoperators.yaml +│   │   └── webhook_in_eventmeshoperators.yaml +│   ├── default +│   │   ├── kustomization.yaml +│   │   ├── manager_auth_proxy_patch.yaml +│   │   └── manager_config_patch.yaml +│   ├── manager +│   │   ├── kustomization.yaml +│   │   └── manager.yaml +│   ├── manifests +│   │   └── kustomization.yaml +│   ├── prometheus +│   │   ├── kustomization.yaml +│   │   └── monitor.yaml +│   ├── rbac +│   │   ├── auth_proxy_client_clusterrole.yaml +│   │   ├── auth_proxy_role.yaml +│   │   ├── auth_proxy_role_binding.yaml +│   │   ├── auth_proxy_service.yaml +│   │   ├── eventmeshoperator_editor_role.yaml +│   │   ├── eventmeshoperator_viewer_role.yaml +│   │   ├── kustomization.yaml +│   │   ├── leader_election_role.yaml +│   │   ├── leader_election_role_binding.yaml +│   │   ├── role_binding.yaml +│   │   └── service_account.yaml +│   ├── samples +│   │   ├── grouptest_v1_eventmeshoperator.yaml +│   │   └── kustomization.yaml +│   └── scorecard +│   ├── bases +│   │   └── config.yaml +│   ├── kustomization.yaml +│   └── patches +│   ├── basic.config.yaml +│   └── olm.config.yaml +├── controllers +│   ├── eventmeshoperator_controller.go +│   └── suite_test.go +├── go.mod +├── go.sum +├── hack +│   └── boilerplate.go.txt +└── main.go +``` +**eventmeshoperator_types.go**: custom CRD corresponding struct place. +**groupversion_info.go**: groupVersion (GV) defines and registers CRD with Scheme. +**zz_generated.deepcopy.go**: GVR DeepCopy method automatically generated. +**crd**: the relevant Yaml collection for deploying CRD. +**default**: a default Yaml collection of the Operator is deployed using Kustomize, which is based on crd, rbac, and manager. +**manager**: deploy the associated Yaml collection of operators. +**prometheus**: the Operator runs and monitors the associated Yaml collections. +**rbac**: Yaml collections associated with RBAC permissions required for Operator deployment. +**samples**: deploy Yaml for a CR sample. +**controllers**: developers implement their own logic, and ventmeshoperator_controller.go is the file that completes the control logic. + +- Controller TODO +``` +func (r *EventMeshOperatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} +``` + +- Register to CRD: +``` +make generate +make manifests +``` + +- Builder IMG +``` +make docker-builder IMG= +make deploy IMG= +``` + +## EventMesh Components + +- EventMesh-runtime: Core Components, Runtime Modules + +- EventMesh-sdks: Supports HTTP, TCP, GRPC protocols + +- EventMesh-connectors: Connectors, Connecting Inserts + +- EventMesh-storage: Storage Module + +- EventMesh-workflow: EventMesh Workflow + +- EventMesh-dashboard: EventMesh Dashboard + +... \ No newline at end of file diff --git a/eventmesh-operator/go.mod b/eventmesh-operator/go.mod new file mode 100644 index 0000000000..d06c8bdffa --- /dev/null +++ b/eventmesh-operator/go.mod @@ -0,0 +1,89 @@ +// +// 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. +// + +module github.com/apache/eventmesh/eventmesh-operator + +go 1.23.0 + +require ( + github.com/go-logr/logr v1.2.3 + github.com/onsi/ginkgo/v2 v2.6.0 + github.com/onsi/gomega v1.24.1 + k8s.io/api v0.26.1 + k8s.io/apimachinery v0.26.1 + k8s.io/client-go v0.26.1 + sigs.k8s.io/controller-runtime v0.14.1 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/zapr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect + golang.org/x/time v0.3.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.26.0 // indirect + k8s.io/component-base v0.26.0 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace github.com/apache/eventmesh/eventmesh-operator/ => ./ diff --git a/eventmesh-operator/go.sum b/eventmesh-operator/go.sum new file mode 100644 index 0000000000..ad760123e8 --- /dev/null +++ b/eventmesh-operator/go.sum @@ -0,0 +1,618 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= +github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= +github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc= +github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ= +k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg= +k8s.io/apiextensions-apiserver v0.26.0 h1:Gy93Xo1eg2ZIkNX/8vy5xviVSxwQulsnUdQ00nEdpDo= +k8s.io/apiextensions-apiserver v0.26.0/go.mod h1:7ez0LTiyW5nq3vADtK6C3kMESxadD51Bh6uz3JOlqWQ= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU= +k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE= +k8s.io/component-base v0.26.0 h1:0IkChOCohtDHttmKuz+EP3j3+qKmV55rM9gIFTXA7Vs= +k8s.io/component-base v0.26.0/go.mod h1:lqHwlfV1/haa14F/Z5Zizk5QmzaVf23nQzCwVOQpfC8= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= +k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.14.1 h1:vThDes9pzg0Y+UbCPY3Wj34CGIYPgdmspPm2GIpxpzM= +sigs.k8s.io/controller-runtime v0.14.1/go.mod h1:GaRkrY8a7UZF0kqFFbUKG7n9ICiTY5T55P1RiE3UZlU= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/eventmesh-operator/hack/boilerplate.go.txt b/eventmesh-operator/hack/boilerplate.go.txt new file mode 100644 index 0000000000..d973dcedae --- /dev/null +++ b/eventmesh-operator/hack/boilerplate.go.txt @@ -0,0 +1,16 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/eventmesh-operator/main.go b/eventmesh-operator/main.go new file mode 100644 index 0000000000..ed1c4eb483 --- /dev/null +++ b/eventmesh-operator/main.go @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package main + +import ( + "flag" + "github.com/apache/eventmesh/eventmesh-operator/controllers/eventmesh_connectors" + "github.com/apache/eventmesh/eventmesh-operator/controllers/eventmesh_runtime" + "k8s.io/apimachinery/pkg/runtime" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + eventmeshoperatorv1 "github.com/apache/eventmesh/eventmesh-operator/api/v1" + //+kubebuilder:scaffold:imports +) + +//+kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(eventmeshoperatorv1.AddToScheme(scheme)) + //+kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var watchNamespace string + flag.StringVar(&watchNamespace, "watch-namespace", os.Getenv("WATCH_NAMESPACE"), "The namespace to watch, if not specified, all namespaces will be watched") + flag.StringVar(&metricsAddr, "metrics-bind-address", ":9020", "The address the metric endpoint binds to.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "bcdc2f43.eventmesh", + Namespace: watchNamespace, + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + // Setup all Controllers + if err := eventmesh_runtime.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to add eventmesh_runtime controller to manager") + os.Exit(1) + } + + if err := eventmesh_connectors.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to add eventmesh_connectors controller to manager") + os.Exit(1) + } + + //+kubebuilder:scaffold:builder + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/eventmesh-operator/share/share.go b/eventmesh-operator/share/share.go new file mode 100644 index 0000000000..a5b91c3559 --- /dev/null +++ b/eventmesh-operator/share/share.go @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package share + +const ( + // WaitForRuntimePodNameReadyInSecond is the time connector sleep for waiting runtime ready in second + WaitForRuntimePodNameReadyInSecond = 1 + // RequeueAfterSecond is a universal interval of the reconcile function + RequeueAfterSecond = 6 +) diff --git a/eventmesh-protocol-plugin/build.gradle b/eventmesh-protocol-plugin/build.gradle new file mode 100644 index 0000000000..d973dcedae --- /dev/null +++ b/eventmesh-protocol-plugin/build.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/build.gradle b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/build.gradle new file mode 100644 index 0000000000..4c2dd2f964 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/build.gradle @@ -0,0 +1,37 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-api") + implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-cloudevents") + implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-http") + + implementation "io.cloudevents:cloudevents-core" + implementation "io.cloudevents:cloudevents-json-jackson" + implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.networknt:json-schema-validator:1.5.6" + implementation "org.slf4j:slf4j-api" + implementation "org.apache.httpcomponents:httpclient" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.mockito:mockito-core' + testImplementation 'org.mockito:mockito-junit-jupiter' +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AClient.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AClient.java new file mode 100644 index 0000000000..b7d312e2c7 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AClient.java @@ -0,0 +1,585 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.protocol.a2a.model.AgentCard; + +import org.apache.http.HttpResponse; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * A2A Java SDK client for Agent developers. + * + *

Provides a simple API to: + *

    + *
  • Register and publish AgentCard
  • + *
  • Send A2A tasks to other agents via Gateway REST API
  • + *
  • Subscribe to and handle incoming A2A requests via transport
  • + *
  • Send heartbeat to keep agent card alive
  • + *
+ */ +public class A2AClient implements AutoCloseable { + + private static final Logger log = LoggerFactory.getLogger(A2AClient.class); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final String gatewayUrl; + private final String namespace; + private final String agentName; + private final AgentCard agentCard; + private final long heartbeatIntervalMs; + private final CloseableHttpClient httpClient; + + private volatile boolean started = false; + private ScheduledExecutorService heartbeatExecutor; + private RequestHandler requestHandler; + + private A2AMessageTransport transport; + private String requestSubscriptionId; + + A2AClient(Builder builder) { + this.gatewayUrl = builder.gatewayUrl; + this.namespace = builder.namespace; + this.agentName = builder.agentName; + this.agentCard = builder.agentCard; + this.heartbeatIntervalMs = builder.heartbeatIntervalMs; + RequestConfig config = RequestConfig.custom() + .setConnectTimeout(10_000) + .setSocketTimeout(builder.socketTimeoutMs) + .build(); + this.httpClient = HttpClients.custom().setDefaultRequestConfig(config).build(); + } + + public static Builder builder() { + return new Builder(); + } + + // ========================================================================= + // Lifecycle + // ========================================================================= + + public void start() throws Exception { + if (started) { + return; + } + registerAgentCard(); + startHeartbeat(); + started = true; + log.info("A2AClient started: agent={}, namespace={}", agentName, namespace); + } + + public void shutdown() throws Exception { + if (heartbeatExecutor != null) { + heartbeatExecutor.shutdownNow(); + } + if (transport != null && requestSubscriptionId != null) { + transport.unsubscribe(requestSubscriptionId); + requestSubscriptionId = null; + } + httpClient.close(); + started = false; + log.info("A2AClient shutdown: agent={}", agentName); + } + + @Override + public void close() throws Exception { + shutdown(); + } + + // ========================================================================= + // AgentCard Registration + // ========================================================================= + + public void registerAgentCard() throws Exception { + String[] parts = agentName.split("/"); + String orgId = parts.length >= 1 ? parts[0] : "default"; + String unitId = parts.length >= 2 ? parts[1] : "default"; + String agentId = parts.length >= 3 ? parts[2] : agentName; + + String url = String.format("%s/a2a/cards/card/%s/%s/%s", gatewayUrl, orgId, unitId, agentId); + String body = objectMapper.writeValueAsString(agentCard); + + HttpPost post = new HttpPost(url); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(body, StandardCharsets.UTF_8)); + + HttpResponse response = httpClient.execute(post); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode >= 400) { + String respBody = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : ""; + throw new RuntimeException("Failed to register agent card: " + statusCode + " " + respBody); + } + log.info("AgentCard registered: {} -> {}", agentName, statusCode); + } + + // ========================================================================= + // Heartbeat + // ========================================================================= + + private void startHeartbeat() { + heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "a2a-client-heartbeat"); + t.setDaemon(true); + return t; + }); + heartbeatExecutor.scheduleAtFixedRate(this::sendHeartbeat, + heartbeatIntervalMs, heartbeatIntervalMs, TimeUnit.MILLISECONDS); + } + + private void sendHeartbeat() { + try { + String[] parts = agentName.split("/"); + String orgId = parts.length >= 1 ? parts[0] : "default"; + String unitId = parts.length >= 2 ? parts[1] : "default"; + String agentId = parts.length >= 3 ? parts[2] : agentName; + + Map body = new HashMap<>(); + body.put("orgId", orgId); + body.put("unitId", unitId); + body.put("agentId", agentId); + + HttpPost post = new HttpPost(gatewayUrl + "/a2a/heartbeat"); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(objectMapper.writeValueAsString(body), StandardCharsets.UTF_8)); + + httpClient.execute(post); + log.debug("Heartbeat sent for agent: {}", agentName); + } catch (Exception e) { + log.warn("Heartbeat failed: {}", e.getMessage()); + } + } + + // ========================================================================= + // Task Operations (via Gateway REST) + // ========================================================================= + + public CompletableFuture sendTask(String targetAgent, String message) { + return CompletableFuture.supplyAsync(() -> { + try { + return sendTaskSync(targetAgent, message, null); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + /** + * Submits a task asynchronously. Returns the taskId immediately without waiting for agent response. + * Use {@link #getTaskStatus(String)} to poll for result. + */ + public String sendTaskAsync(String targetAgent, String message, String parentTaskId) throws Exception { + Map bodyMap = new HashMap<>(); + bodyMap.put("targetAgent", targetAgent); + bodyMap.put("message", message); + if (parentTaskId != null) { + bodyMap.put("parentTaskId", parentTaskId); + } + String body = objectMapper.writeValueAsString(bodyMap); + + HttpPost post = new HttpPost(gatewayUrl + "/a2a/tasks?mode=async"); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(body, StandardCharsets.UTF_8)); + + HttpResponse response = httpClient.execute(post); + int statusCode = response.getStatusLine().getStatusCode(); + String respBody = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : ""; + + if (statusCode >= 400) { + throw new RuntimeException("Task submission failed: " + statusCode + " " + respBody); + } + + TaskResult result = objectMapper.readValue(respBody, TaskResult.class); + return result.getTaskId(); + } + + public TaskResult sendTaskSync(String targetAgent, String message, String parentTaskId) throws Exception { + Map bodyMap = new HashMap<>(); + bodyMap.put("targetAgent", targetAgent); + bodyMap.put("message", message); + if (parentTaskId != null) { + bodyMap.put("parentTaskId", parentTaskId); + } + String body = objectMapper.writeValueAsString(bodyMap); + + HttpPost post = new HttpPost(gatewayUrl + "/a2a/tasks?mode=sync"); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(body, StandardCharsets.UTF_8)); + + HttpResponse response = httpClient.execute(post); + int statusCode = response.getStatusLine().getStatusCode(); + String respBody = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : ""; + + if (statusCode >= 400) { + throw new RuntimeException("Task submission failed: " + statusCode + " " + respBody); + } + + return objectMapper.readValue(respBody, TaskResult.class); + } + + public TaskResult getTaskStatus(String taskId) throws Exception { + HttpGet get = new HttpGet(gatewayUrl + "/a2a/tasks/" + taskId); + HttpResponse response = httpClient.execute(get); + String respBody = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : ""; + return objectMapper.readValue(respBody, TaskResult.class); + } + + public boolean cancelTask(String taskId) throws Exception { + HttpDelete delete = new HttpDelete(gatewayUrl + "/a2a/tasks/" + taskId); + HttpResponse response = httpClient.execute(delete); + return response.getStatusLine().getStatusCode() == 200; + } + + /** + * Subscribes to SSE status updates for a task via the /stream endpoint. + * + *

This method blocks until the stream ends (task reaches terminal state) or the + * consumer returns {@code false} to stop early. + * + * @param taskId the task ID to stream updates for + * @param consumer callback invoked for each SSE event; receives (taskId, state, data). + * Return {@code false} from the consumer to stop streaming. + * @throws Exception if the HTTP connection fails + */ + public void streamTaskStatus(String taskId, SseEventConsumer consumer) throws Exception { + HttpGet get = new HttpGet(gatewayUrl + "/a2a/tasks/" + taskId + "/stream"); + get.setHeader("Accept", "text/event-stream"); + + HttpResponse response = httpClient.execute(get); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + String body = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : ""; + throw new RuntimeException("SSE stream failed: " + statusCode + " " + body); + } + + try (java.io.InputStream is = response.getEntity().getContent(); + java.io.BufferedReader reader = new java.io.BufferedReader( + new java.io.InputStreamReader(is, StandardCharsets.UTF_8))) { + String line; + StringBuilder eventBuffer = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (line.isEmpty()) { + // Empty line = event boundary + if (eventBuffer.length() > 0) { + String json = eventBuffer.toString(); + if (json.startsWith("data: ")) { + json = json.substring(6); + } + try { + @SuppressWarnings("unchecked") + Map event = objectMapper.readValue(json, Map.class); + String eventTaskId = event.get("taskId") != null ? event.get("taskId").toString() : taskId; + String state = event.get("state") != null ? event.get("state").toString() : ""; + String data = event.get("data") != null ? event.get("data").toString() : null; + if (!consumer.onEvent(eventTaskId, state, data)) { + return; // Consumer requested stop + } + } catch (Exception e) { + log.warn("Failed to parse SSE event: {}", json, e); + } + eventBuffer.setLength(0); + } + } else if (line.startsWith(":")) { + // SSE comment / heartbeat line, ignore. + } else { + if (eventBuffer.length() > 0) { + eventBuffer.append("\n"); + } + eventBuffer.append(line); + } + } + } + } + + public List listAgents() throws Exception { + HttpGet get = new HttpGet(gatewayUrl + "/a2a/agents"); + HttpResponse response = httpClient.execute(get); + String respBody = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : "[]"; + List> cards = objectMapper.readValue(respBody, + new com.fasterxml.jackson.core.type.TypeReference>>() {}); + List names = new ArrayList<>(); + for (Map card : cards) { + Object name = card.get("name"); + if (name == null) { + name = card.get("id"); + } + if (name != null) { + names.add(name.toString()); + } + } + return names; + } + + // ========================================================================= + // Request Handler (for agent-to-agent via transport) + // ========================================================================= + + public void setRequestHandler(RequestHandler handler) { + this.requestHandler = handler; + } + + public void setTransport(A2AMessageTransport transport) throws Exception { + this.transport = transport; + String requestTopic = A2ATopicFactory.agentRequestTopic(namespace, agentName); + requestSubscriptionId = transport.subscribe(requestTopic, this::handleRequestMessage); + log.info("Subscribed to agent request topic: {}", requestTopic); + } + + private void handleRequestMessage(String topic, CloudEvent event) { + if (requestHandler == null) { + log.warn("Request received but no handler set. Dropping message on topic: {}", topic); + return; + } + + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse(topic); + if (parsed == null || !parsed.isRequest()) { + return; + } + + String taskId = event.getId(); + String message = event.getData() != null + ? new String(event.getData().toBytes(), StandardCharsets.UTF_8) : ""; + + log.info("Handling request: taskId={}, from={}", taskId, event.getSource()); + + try { + String result = requestHandler.handle(taskId, message); + + String gwId = gatewayIdFromSource(event); + String responseTopic = A2ATopicFactory.gatewayResponseTopic(namespace, gwId, taskId); + CloudEvent responseEvent = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withType(A2AProtocolConstants.CE_TYPE_PREFIX + "task.response") + .withSource(java.net.URI.create("agent/" + agentName)) + .withDataContentType("application/json") + .withData(result.getBytes(StandardCharsets.UTF_8)) + .withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, A2AProtocolConstants.OP_SEND_MESSAGE) + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL, "A2A") + .build(); + + transport.publish(responseTopic, responseEvent); + log.info("Response published: taskId={}, topic={}", taskId, responseTopic); + } catch (Exception e) { + log.error("Error handling request: taskId={}", taskId, e); + } + } + + private String gatewayIdFromSource(CloudEvent event) { + if (event.getSource() == null) { + return "default-gateway"; + } + String source = event.getSource().toString(); + if (source.startsWith("gateway/")) { + return source.substring("gateway/".length()); + } + return "default-gateway"; + } + + // ========================================================================= + // Builder + // ========================================================================= + + public static class Builder { + + private String gatewayUrl = "http://localhost:10105"; + private String namespace = "global"; + private String agentName; + private AgentCard agentCard; + private long heartbeatIntervalMs = 30_000L; + private int socketTimeoutMs = 0; + + public Builder gatewayUrl(String url) { + this.gatewayUrl = url; + return this; + } + + public Builder namespace(String namespace) { + this.namespace = namespace; + return this; + } + + public Builder agentName(String agentName) { + this.agentName = agentName; + return this; + } + + public Builder agentCard(AgentCard card) { + this.agentCard = card; + return this; + } + + public Builder heartbeatInterval(long intervalMs) { + this.heartbeatIntervalMs = intervalMs; + return this; + } + + public Builder socketTimeoutMs(int timeoutMs) { + this.socketTimeoutMs = timeoutMs; + return this; + } + + public A2AClient build() { + if (agentName == null) { + throw new IllegalArgumentException("agentName is required"); + } + if (agentCard == null) { + agentCard = AgentCard.builder().name(agentName).version("1.0.0").build(); + } + return new A2AClient(this); + } + } + + // ========================================================================= + // DTOs + // ========================================================================= + + @com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true) + public static class TaskResult { + + private String taskId; + private String state; + @com.fasterxml.jackson.annotation.JsonAlias("result") + private String data; + private String error; + private String targetAgent; + private String parentTaskId; + private long createdAt; + private long updatedAt; + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getTargetAgent() { + return targetAgent; + } + + public void setTargetAgent(String targetAgent) { + this.targetAgent = targetAgent; + } + + public String getParentTaskId() { + return parentTaskId; + } + + public void setParentTaskId(String parentTaskId) { + this.parentTaskId = parentTaskId; + } + + public long getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(long createdAt) { + this.createdAt = createdAt; + } + + public long getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(long updatedAt) { + this.updatedAt = updatedAt; + } + } + + /** + * Handler for incoming A2A task requests from agents. + */ + @FunctionalInterface + public interface RequestHandler { + + String handle(String taskId, String message) throws Exception; + } + + /** + * Consumer for SSE task status events. + */ + @FunctionalInterface + public interface SseEventConsumer { + + /** + * Called for each SSE event. + * + * @param taskId the task ID + * @param state the task state (SUBMITTED, WORKING, COMPLETED, FAILED, CANCELLED) + * @param data the event data (may be null) + * @return {@code true} to continue receiving events, {@code false} to stop + */ + boolean onEvent(String taskId, String state, String data); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AMessageTransport.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AMessageTransport.java new file mode 100644 index 0000000000..5856df9617 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AMessageTransport.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import io.cloudevents.CloudEvent; + +/** + * Abstracts the message transport layer for A2A communication. + * Implementations can use EventMesh producer/consumer, in-memory, or any other transport. + */ +public interface A2AMessageTransport { + + /** + * Publishes a CloudEvent to the given topic. + */ + void publish(String topic, CloudEvent event) throws Exception; + + /** + * Subscribes to a topic pattern. Returns a subscription ID. + * The callback is invoked for each matching message. + */ + String subscribe(String topicPattern, MessageCallback callback) throws Exception; + + /** + * Unsubscribes by subscription ID. + */ + void unsubscribe(String subscriptionId) throws Exception; + + /** + * Callback invoked when a message is received on a subscribed topic. + */ + @FunctionalInterface + interface MessageCallback { + void onMessage(String topic, CloudEvent event); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AProtocolConstants.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AProtocolConstants.java new file mode 100644 index 0000000000..1c168e85d8 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2AProtocolConstants.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +/** + * Standard Operations and Constants defined by A2A Protocol Specification. + * Reference: https://a2a-protocol.org/latest/specification/#3-a2a-protocol-operations + */ +public class A2AProtocolConstants { + + // Protocol version (per A2A spec) + public static final String PROTOCOL_VERSION = "0.3"; + + // Core Messaging + public static final String OP_SEND_MESSAGE = "message/send"; + public static final String OP_SEND_STREAMING_MESSAGE = "message/sendStream"; + + // Task Management + public static final String OP_GET_TASK = "task/get"; + public static final String OP_LIST_TASKS = "task/list"; + public static final String OP_CANCEL_TASK = "task/cancel"; + public static final String OP_SUBSCRIBE_TASK = "task/subscribe"; + + // Notifications + public static final String OP_NOTIFICATION_CONFIG_SET = "notification/config/set"; + public static final String OP_NOTIFICATION_CONFIG_GET = "notification/config/get"; + public static final String OP_NOTIFICATION_CONFIG_LIST = "notification/config/list"; + public static final String OP_NOTIFICATION_CONFIG_DELETE = "notification/config/delete"; + + // Agent Card / Discovery + public static final String OP_GET_AGENT_CARD = "agent/card/get"; + public static final String OP_REGISTER_AGENT_CARD = "agent/card/register"; + public static final String OP_DELETE_AGENT_CARD = "agent/card/delete"; + public static final String OP_LIST_AGENT_CARDS = "agent/card/list"; + public static final String OP_UPDATE_AGENT_CARD = "agent/card/update"; + + // Agent Status + public static final String STATUS_ONLINE = "online"; + public static final String STATUS_OFFLINE = "offline"; + + // CloudEvent extension keys (matching EMQX conventions) + public static final String CE_EXTENSION_A2A_STATUS = "a2astatus"; + public static final String CE_EXTENSION_A2A_STATUS_SOURCE = "a2astatussource"; + public static final String CE_EXTENSION_TARGET_AGENT = "targetagent"; + public static final String CE_EXTENSION_A2A_METHOD = "a2amethod"; + public static final String CE_EXTENSION_COLLABORATION_ID = "collaborationid"; + public static final String CE_EXTENSION_MCP_TYPE = "mcptype"; + public static final String CE_EXTENSION_PROTOCOL = "protocol"; + public static final String CE_EXTENSION_PROTOCOL_VERSION = "protocolversion"; + public static final String CE_EXTENSION_SEQ = "seq"; + + // Discovery topic components + public static final String TOPIC_NAMESPACE = "a2a"; + public static final String TOPIC_VERSION = "v1"; + public static final String TOPIC_DISCOVERY = "discovery"; + + // ID validation pattern (matching EMQX: ^[A-Za-z0-9._-]+$) + public static final String SEGMENT_ID_PATTERN = "^[A-Za-z0-9._-]+$"; + + // CloudEvent type prefix + public static final String CE_TYPE_PREFIX = "org.apache.eventmesh.a2a."; + + /** + * Checks if the method is a standard A2A Protocol operation. + */ + public static boolean isStandardOperation(String method) { + if (method == null) { + return false; + } + return method.startsWith("message/") + || method.startsWith("task/") + || method.startsWith("notification/") + || method.startsWith("agent/"); + } + + /** + * Checks if the method is an Agent Card operation. + */ + public static boolean isAgentCardOperation(String method) { + if (method == null) { + return false; + } + return method.startsWith("agent/card"); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2ATopicFactory.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2ATopicFactory.java new file mode 100644 index 0000000000..dbd299a1cf --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/A2ATopicFactory.java @@ -0,0 +1,347 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +/** + * Factory for generating standard A2A topic paths following the convention: + * + *

+ * {namespace}/a2a/v1/discovery/agentcards
+ * {namespace}/a2a/v1/discovery/gatewaycards
+ * {namespace}/a2a/v1/agent/request/{agentName}
+ * {namespace}/a2a/v1/agent/status/{agentName}/{taskId}
+ * {namespace}/a2a/v1/agent/response/{agentName}/{taskId}
+ * {namespace}/a2a/v1/gateway/request/{gatewayId}
+ * {namespace}/a2a/v1/gateway/status/{gatewayId}/{taskId}
+ * {namespace}/a2a/v1/gateway/response/{gatewayId}/{taskId}
+ * 
+ * + *

When namespace is {@link AgentIdentity#GLOBAL_NAMESPACE} ("global"), the + * namespace prefix is omitted (matching {@link AgentIdentity#discoveryTopic()}). + */ +public final class A2ATopicFactory { + + private static final String AGENT = "agent"; + private static final String GATEWAY = "gateway"; + private static final String REQUEST = "request"; + private static final String STATUS = "status"; + private static final String RESPONSE = "response"; + private static final String AGENTCARDS = "agentcards"; + private static final String GATEWAYCARDS = "gatewaycards"; + + private A2ATopicFactory() { + } + + // ------------------------------------------------------------------------- + // Discovery topics + // ------------------------------------------------------------------------- + + /** + * Topic for publishing/subscribing AgentCard discovery messages. + */ + public static String discoveryTopic(String namespace) { + return buildBase(namespace) + "/" + A2AProtocolConstants.TOPIC_DISCOVERY + "/" + AGENTCARDS; + } + + /** + * Topic for publishing/subscribing GatewayCard discovery messages. + */ + public static String gatewayDiscoveryTopic(String namespace) { + return buildBase(namespace) + "/" + A2AProtocolConstants.TOPIC_DISCOVERY + "/" + GATEWAYCARDS; + } + + // ------------------------------------------------------------------------- + // Agent topics + // ------------------------------------------------------------------------- + + /** + * Topic for sending a task request to a specific agent. + */ + public static String agentRequestTopic(String namespace, String agentName) { + validateSegment(agentName, "agentName"); + return buildBase(namespace) + "/" + AGENT + "/" + REQUEST + "/" + agentName; + } + + /** + * Topic for an agent to publish status updates for a specific task. + */ + public static String agentStatusTopic(String namespace, String agentName, String taskId) { + validateSegment(agentName, "agentName"); + validateSegment(taskId, "taskId"); + return buildBase(namespace) + "/" + AGENT + "/" + STATUS + "/" + agentName + "/" + taskId; + } + + /** + * Topic for an agent to publish the final response for a specific task. + */ + public static String agentResponseTopic(String namespace, String agentName, String taskId) { + validateSegment(agentName, "agentName"); + validateSegment(taskId, "taskId"); + return buildBase(namespace) + "/" + AGENT + "/" + RESPONSE + "/" + agentName + "/" + taskId; + } + + /** + * Wildcard topic to subscribe to all status updates from a specific agent. + */ + public static String agentStatusWildcardTopic(String namespace, String agentName) { + validateSegment(agentName, "agentName"); + return buildBase(namespace) + "/" + AGENT + "/" + STATUS + "/" + agentName + "/+"; + } + + /** + * Wildcard topic to subscribe to all responses from a specific agent. + */ + public static String agentResponseWildcardTopic(String namespace, String agentName) { + validateSegment(agentName, "agentName"); + return buildBase(namespace) + "/" + AGENT + "/" + RESPONSE + "/" + agentName + "/+"; + } + + // ------------------------------------------------------------------------- + // Gateway topics + // ------------------------------------------------------------------------- + + /** + * Topic for sending a task request to a specific gateway. + */ + public static String gatewayRequestTopic(String namespace, String gatewayId) { + validateSegment(gatewayId, "gatewayId"); + return buildBase(namespace) + "/" + GATEWAY + "/" + REQUEST + "/" + gatewayId; + } + + /** + * Topic for a gateway to receive status updates for a specific task. + */ + public static String gatewayStatusTopic(String namespace, String gatewayId, String taskId) { + validateSegment(gatewayId, "gatewayId"); + validateSegment(taskId, "taskId"); + return buildBase(namespace) + "/" + GATEWAY + "/" + STATUS + "/" + gatewayId + "/" + taskId; + } + + /** + * Topic for a gateway to receive the final response for a specific task. + */ + public static String gatewayResponseTopic(String namespace, String gatewayId, String taskId) { + validateSegment(gatewayId, "gatewayId"); + validateSegment(taskId, "taskId"); + return buildBase(namespace) + "/" + GATEWAY + "/" + RESPONSE + "/" + gatewayId + "/" + taskId; + } + + /** + * Wildcard topic for a gateway to subscribe to all status updates. + */ + public static String gatewayStatusWildcardTopic(String namespace, String gatewayId) { + validateSegment(gatewayId, "gatewayId"); + return buildBase(namespace) + "/" + GATEWAY + "/" + STATUS + "/" + gatewayId + "/+"; + } + + /** + * Wildcard topic for a gateway to subscribe to all responses. + */ + public static String gatewayResponseWildcardTopic(String namespace, String gatewayId) { + validateSegment(gatewayId, "gatewayId"); + return buildBase(namespace) + "/" + GATEWAY + "/" + RESPONSE + "/" + gatewayId + "/+"; + } + + // ------------------------------------------------------------------------- + // Parsing + // ------------------------------------------------------------------------- + + /** + * Parses an A2A topic and returns its components. + * + * @return parsed topic info, or {@code null} if not a valid A2A topic + */ + public static ParsedTopic parse(String topic) { + if (topic == null || topic.isEmpty()) { + return null; + } + String[] parts = topic.split("/"); + // Global: a2a/v1/{entity}/{action}/... = parts starting at index 0 + // Namespaced: {ns}/a2a/v1/{entity}/{action}/... = parts starting at index 1 + int offset; + String namespace; + if (parts.length >= 3 && A2AProtocolConstants.TOPIC_NAMESPACE.equals(parts[0]) + && A2AProtocolConstants.TOPIC_VERSION.equals(parts[1])) { + offset = 0; + namespace = AgentIdentity.GLOBAL_NAMESPACE; + } else if (parts.length >= 4 && A2AProtocolConstants.TOPIC_NAMESPACE.equals(parts[1]) + && A2AProtocolConstants.TOPIC_VERSION.equals(parts[2])) { + offset = 1; + namespace = parts[0]; + } else { + return null; + } + + // parts[offset] = "a2a", parts[offset+1] = "v1" + if (parts.length <= offset + 2) { + return null; + } + String segment3 = parts[offset + 2]; // discovery | agent | gateway + + if (A2AProtocolConstants.TOPIC_DISCOVERY.equals(segment3)) { + // a2a/v1/discovery/{agentcards|gatewaycards} + if (parts.length == offset + 4) { + String cardType = parts[offset + 3]; + if (AGENTCARDS.equals(cardType)) { + return new ParsedTopic(namespace, EntityType.DISCOVERY_AGENT, null, null, null); + } else if (GATEWAYCARDS.equals(cardType)) { + return new ParsedTopic(namespace, EntityType.DISCOVERY_GATEWAY, null, null, null); + } + } + return null; + } + + if (AGENT.equals(segment3)) { + // a2a/v1/agent/{request|status|response}/{agentName}[/{taskId}] + if (parts.length < offset + 5) { + return null; + } + String action = parts[offset + 3]; + String agentName = parts[offset + 4]; + String taskId = (parts.length >= offset + 6) ? parts[offset + 5] : null; + EntityType entityType; + if (REQUEST.equals(action)) { + entityType = EntityType.AGENT_REQUEST; + } else if (STATUS.equals(action)) { + entityType = EntityType.AGENT_STATUS; + } else if (RESPONSE.equals(action)) { + entityType = EntityType.AGENT_RESPONSE; + } else { + return null; + } + return new ParsedTopic(namespace, entityType, agentName, null, taskId); + } + + if (GATEWAY.equals(segment3)) { + // a2a/v1/gateway/{request|status|response}/{gatewayId}[/{taskId}] + if (parts.length < offset + 5) { + return null; + } + String action = parts[offset + 3]; + String gatewayId = parts[offset + 4]; + String taskId = (parts.length >= offset + 6) ? parts[offset + 5] : null; + EntityType entityType; + if (REQUEST.equals(action)) { + entityType = EntityType.GATEWAY_REQUEST; + } else if (STATUS.equals(action)) { + entityType = EntityType.GATEWAY_STATUS; + } else if (RESPONSE.equals(action)) { + entityType = EntityType.GATEWAY_RESPONSE; + } else { + return null; + } + return new ParsedTopic(namespace, entityType, null, gatewayId, taskId); + } + + return null; + } + + // ------------------------------------------------------------------------- + // Internal helpers + // ------------------------------------------------------------------------- + + private static String buildBase(String namespace) { + if (namespace == null || AgentIdentity.GLOBAL_NAMESPACE.equals(namespace)) { + return A2AProtocolConstants.TOPIC_NAMESPACE + "/" + A2AProtocolConstants.TOPIC_VERSION; + } + return namespace + "/" + A2AProtocolConstants.TOPIC_NAMESPACE + "/" + A2AProtocolConstants.TOPIC_VERSION; + } + + private static void validateSegment(String value, String name) { + if (value == null || !value.matches(A2AProtocolConstants.SEGMENT_ID_PATTERN)) { + throw new IllegalArgumentException( + "Invalid " + name + ": '" + value + "'. Must match " + A2AProtocolConstants.SEGMENT_ID_PATTERN); + } + } + + // ------------------------------------------------------------------------- + // Parsed topic result + // ------------------------------------------------------------------------- + + public enum EntityType { + DISCOVERY_AGENT, + DISCOVERY_GATEWAY, + AGENT_REQUEST, + AGENT_STATUS, + AGENT_RESPONSE, + GATEWAY_REQUEST, + GATEWAY_STATUS, + GATEWAY_RESPONSE + } + + public static class ParsedTopic { + + private final String namespace; + private final EntityType entityType; + private final String agentName; + private final String gatewayId; + private final String taskId; + + public ParsedTopic(String namespace, EntityType entityType, String agentName, + String gatewayId, String taskId) { + this.namespace = namespace; + this.entityType = entityType; + this.agentName = agentName; + this.gatewayId = gatewayId; + this.taskId = taskId; + } + + public String getNamespace() { + return namespace; + } + + public EntityType getEntityType() { + return entityType; + } + + public String getAgentName() { + return agentName; + } + + public String getGatewayId() { + return gatewayId; + } + + public String getTaskId() { + return taskId; + } + + public boolean isRequest() { + return entityType == EntityType.AGENT_REQUEST || entityType == EntityType.GATEWAY_REQUEST; + } + + public boolean isStatus() { + return entityType == EntityType.AGENT_STATUS || entityType == EntityType.GATEWAY_STATUS; + } + + public boolean isResponse() { + return entityType == EntityType.AGENT_RESPONSE || entityType == EntityType.GATEWAY_RESPONSE; + } + + public boolean isDiscovery() { + return entityType == EntityType.DISCOVERY_AGENT || entityType == EntityType.DISCOVERY_GATEWAY; + } + + @Override + public String toString() { + return "ParsedTopic{namespace='" + namespace + "', entityType=" + entityType + + ", agentName='" + agentName + "', gatewayId='" + gatewayId + + "', taskId='" + taskId + "'}"; + } + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/AgentCardValidator.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/AgentCardValidator.java new file mode 100644 index 0000000000..f226db9d3d --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/AgentCardValidator.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.SpecVersion; +import com.networknt.schema.ValidationMessage; + +import lombok.extern.slf4j.Slf4j; + +/** + * Validates Agent Card JSON against the A2A Agent Card JSON Schema. + */ +@Slf4j +public class AgentCardValidator { + + private static final String SCHEMA_RESOURCE = "/a2a/agent_card_schema.json"; + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final JsonSchema schema; + private final boolean schemaValidationEnabled; + + public AgentCardValidator(boolean schemaValidationEnabled) { + this.schemaValidationEnabled = schemaValidationEnabled; + this.schema = loadSchema(); + } + + public AgentCardValidator() { + this(true); + } + + private JsonSchema loadSchema() { + try (InputStream is = AgentCardValidator.class.getResourceAsStream(SCHEMA_RESOURCE)) { + if (is == null) { + log.warn("Agent card schema resource not found: {}, schema validation will be disabled", SCHEMA_RESOURCE); + return null; + } + JsonNode schemaNode = objectMapper.readTree(is); + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V6); + return factory.getSchema(schemaNode); + } catch (IOException e) { + log.warn("Failed to load agent card schema, validation will be disabled: {}", e.getMessage()); + return null; + } + } + + /** + * Validates an Agent Card JSON string. + * + * @param cardJson the card JSON string + * @return ValidationResult with success/failure and error messages + */ + public ValidationResult validate(String cardJson) { + if (cardJson == null || cardJson.isEmpty()) { + return ValidationResult.failure("Card JSON is null or empty"); + } + + if (!schemaValidationEnabled || schema == null) { + // Only check it's valid JSON object + try { + JsonNode node = objectMapper.readTree(cardJson); + if (!node.isObject()) { + return ValidationResult.failure("Card must be a JSON object"); + } + return ValidationResult.success(); + } catch (Exception e) { + return ValidationResult.failure("Card is not valid JSON: " + e.getMessage()); + } + } + + try { + JsonNode cardNode = objectMapper.readTree(cardJson); + if (!cardNode.isObject()) { + return ValidationResult.failure("Card must be a JSON object"); + } + Set messages = schema.validate(cardNode); + if (messages.isEmpty()) { + return ValidationResult.success(); + } + StringBuilder sb = new StringBuilder("Card schema validation failed: "); + for (ValidationMessage msg : messages) { + sb.append(msg.getMessage()).append("; "); + } + return ValidationResult.failure(sb.toString()); + } catch (IOException e) { + return ValidationResult.failure("Failed to parse card JSON: " + e.getMessage()); + } + } + + /** + * Validates that an ID segment matches the allowed pattern. + */ + public static boolean validateId(String id) { + return id != null && id.matches(A2AProtocolConstants.SEGMENT_ID_PATTERN); + } + + public static class ValidationResult { + + private final boolean valid; + private final String errorMessage; + + private ValidationResult(boolean valid, String errorMessage) { + this.valid = valid; + this.errorMessage = errorMessage; + } + + public static ValidationResult success() { + return new ValidationResult(true, null); + } + + public static ValidationResult failure(String errorMessage) { + return new ValidationResult(false, errorMessage); + } + + public boolean isValid() { + return valid; + } + + public String getErrorMessage() { + return errorMessage; + } + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/AgentIdentity.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/AgentIdentity.java new file mode 100644 index 0000000000..9677e6d5e8 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/AgentIdentity.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents the hierarchical identity of an A2A agent: org_id / unit_id / agent_id. + * Also provides discovery topic construction and parsing per the A2A protocol. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentIdentity implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final String GLOBAL_NAMESPACE = "global"; + public static final String TOPIC_NAMESPACE = "a2a"; + public static final String TOPIC_VERSION = "v1"; + public static final String TOPIC_DISCOVERY = "discovery"; + + private String orgId; + + private String unitId; + + private String agentId; + + private String namespace; + + public AgentIdentity(String orgId, String unitId, String agentId) { + this.orgId = orgId; + this.unitId = unitId; + this.agentId = agentId; + this.namespace = GLOBAL_NAMESPACE; + } + + /** + * Builds the discovery topic for this agent identity. + * Global namespace: a2a/v1/discovery/{orgId}/{unitId}/{agentId} + * Custom namespace: {namespace}/a2a/v1/discovery/{orgId}/{unitId}/{agentId} + */ + public String discoveryTopic() { + if (GLOBAL_NAMESPACE.equals(namespace)) { + return String.join("/", TOPIC_NAMESPACE, TOPIC_VERSION, TOPIC_DISCOVERY, orgId, unitId, agentId); + } + return String.join("/", namespace, TOPIC_NAMESPACE, TOPIC_VERSION, TOPIC_DISCOVERY, orgId, unitId, agentId); + } + + /** + * Parses a discovery topic string into an AgentIdentity. + * + * @param topic the discovery topic + * @return parsed AgentIdentity, or null if the topic does not match the expected pattern + */ + public static AgentIdentity fromDiscoveryTopic(String topic) { + if (topic == null) { + return null; + } + String[] parts = topic.split("/"); + // Global: a2a/v1/discovery/{org}/{unit}/{agent} = 6 parts + // Namespaced: {ns}/a2a/v1/discovery/{org}/{unit}/{agent} = 7 parts + if (parts.length == 6 + && TOPIC_NAMESPACE.equals(parts[0]) + && TOPIC_VERSION.equals(parts[1]) + && TOPIC_DISCOVERY.equals(parts[2])) { + return AgentIdentity.builder() + .namespace(GLOBAL_NAMESPACE) + .orgId(parts[3]) + .unitId(parts[4]) + .agentId(parts[5]) + .build(); + } + if (parts.length == 7 + && TOPIC_NAMESPACE.equals(parts[1]) + && TOPIC_VERSION.equals(parts[2]) + && TOPIC_DISCOVERY.equals(parts[3])) { + return AgentIdentity.builder() + .namespace(parts[0]) + .orgId(parts[4]) + .unitId(parts[5]) + .agentId(parts[6]) + .build(); + } + return null; + } + + /** + * Returns the composite client ID: orgId/unitId/agentId (matching EMQX's agent_card_clientid). + */ + public String clientId() { + return String.join("/", orgId, unitId, agentId); + } + + /** + * Validates that all ID segments match the allowed pattern: ^[A-Za-z0-9._-]+$ + */ + public boolean isValid() { + return isValidId(orgId) && isValidId(unitId) && isValidId(agentId); + } + + private static boolean isValidId(String id) { + return id != null && id.matches(A2AProtocolConstants.SEGMENT_ID_PATTERN); + } + + /** + * Checks if this identity matches a wildcard filter. + * Wildcard is represented by "+" (matching EMQX's MQTT wildcard convention). + */ + public boolean matchesFilter(String filterOrgId, String filterUnitId, String filterAgentId) { + return (filterOrgId == null || "+".equals(filterOrgId) || filterOrgId.equals(orgId)) + && (filterUnitId == null || "+".equals(filterUnitId) || filterUnitId.equals(unitId)) + && (filterAgentId == null || "+".equals(filterAgentId) || filterAgentId.equals(agentId)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AgentIdentity that = (AgentIdentity) o; + return Objects.equals(orgId, that.orgId) + && Objects.equals(unitId, that.unitId) + && Objects.equals(agentId, that.agentId) + && Objects.equals(namespace, that.namespace); + } + + @Override + public int hashCode() { + return Objects.hash(orgId, unitId, agentId, namespace); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/EnhancedA2AProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/EnhancedA2AProtocolAdaptor.java new file mode 100644 index 0000000000..fa906f32c2 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/EnhancedA2AProtocolAdaptor.java @@ -0,0 +1,458 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.protocol.api.ProtocolAdaptor; +import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; +import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * Enhanced A2A Protocol Adaptor that implements A2A (Agent-to-Agent) protocol over CloudEvents. + * + *

This adaptor supports: + * 1. Standard A2A JSON-RPC 2.0 messages (messaging, task, notification, agent card operations). + * 2. Agent Card registration and discovery via discovery topics. + * 3. Agent status metadata augmentation. + * 4. Delegation to standard CloudEvents/HTTP protocols. + */ +@Slf4j +public class EnhancedA2AProtocolAdaptor implements ProtocolAdaptor { + + private static final String PROTOCOL_TYPE = "A2A"; + private static final String PROTOCOL_VERSION = "2.0"; + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private ProtocolAdaptor cloudEventsAdaptor; + private ProtocolAdaptor httpAdaptor; + + private volatile boolean initialized = false; + + private AgentCardValidator cardValidator; + + public EnhancedA2AProtocolAdaptor() { + try { + this.cloudEventsAdaptor = ProtocolPluginFactory.getProtocolAdaptor("cloudevents"); + } catch (Exception e) { + log.warn("CloudEvents adaptor not available: {}", e.getMessage()); + this.cloudEventsAdaptor = null; + } + + try { + this.httpAdaptor = ProtocolPluginFactory.getProtocolAdaptor("http"); + } catch (Exception e) { + log.warn("HTTP adaptor not available: {}", e.getMessage()); + this.httpAdaptor = null; + } + } + + @Override + public void initialize() { + if (!initialized) { + log.info("Initializing Enhanced A2A Protocol Adaptor v{} (Agent Card Registry Support)", PROTOCOL_VERSION); + this.cardValidator = new AgentCardValidator(true); + if (cloudEventsAdaptor != null) { + log.info("Leveraging CloudEvents adaptor: {}", cloudEventsAdaptor.getClass().getSimpleName()); + } + initialized = true; + } + } + + @Override + public void destroy() { + if (initialized) { + log.info("Destroying Enhanced A2A Protocol Adaptor"); + initialized = false; + } + } + + @Override + public CloudEvent toCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { + try { + String content = protocol.toString(); + JsonNode node = null; + try { + if (content.contains("{")) { + node = objectMapper.readTree(content); + } + } catch (Exception ignored) { + // ignore + } + + if (node != null && node.has("jsonrpc") && "2.0".equals(node.get("jsonrpc").asText())) { + return convertA2AToCloudEvent(node, content); + } + + if (protocol.getClass().getName().contains("Http") && httpAdaptor != null) { + return httpAdaptor.toCloudEvent(protocol); + } else if (cloudEventsAdaptor != null) { + return cloudEventsAdaptor.toCloudEvent(protocol); + } else { + if (node != null && node.has("method")) { + return convertA2AToCloudEvent(node, content); + } + throw new ProtocolHandleException("Unknown protocol message format"); + } + + } catch (ProtocolHandleException e) { + throw e; + } catch (Exception e) { + throw new ProtocolHandleException("Failed to convert to CloudEvent", e); + } + } + + @Override + public List toBatchCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { + try { + String content = protocol.toString(); + JsonNode node = null; + try { + if (content.contains("[")) { + node = objectMapper.readTree(content); + } + } catch (Exception ignored) { + // ignore + } + + if (node != null && node.isArray()) { + List events = new ArrayList<>(); + for (JsonNode item : node) { + if (item.has("jsonrpc")) { + events.add(convertA2AToCloudEvent(item, item.toString())); + } + } + if (!events.isEmpty()) { + return events; + } + } + + if (cloudEventsAdaptor != null) { + try { + return cloudEventsAdaptor.toBatchCloudEvent(protocol); + } catch (Exception e) { + if (httpAdaptor != null) { + return httpAdaptor.toBatchCloudEvent(protocol); + } + } + } + + CloudEvent single = toCloudEvent(protocol); + return Collections.singletonList(single); + + } catch (ProtocolHandleException e) { + throw e; + } catch (Exception e) { + throw new ProtocolHandleException("Failed to convert batch to CloudEvents", e); + } + } + + @Override + public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws ProtocolHandleException { + try { + if (isA2ACloudEvent(cloudEvent)) { + return convertCloudEventToA2A(cloudEvent); + } + + String targetProtocol = getTargetProtocol(cloudEvent); + + switch (targetProtocol.toLowerCase()) { + case "http": + if (httpAdaptor != null) { + return httpAdaptor.fromCloudEvent(cloudEvent); + } + break; + case "cloudevents": + default: + if (cloudEventsAdaptor != null) { + return cloudEventsAdaptor.fromCloudEvent(cloudEvent); + } + break; + } + + return convertCloudEventToA2A(cloudEvent); + + } catch (Exception e) { + throw new ProtocolHandleException("Failed to convert from CloudEvent", e); + } + } + + @Override + public String getProtocolType() { + return PROTOCOL_TYPE; + } + + @Override + public String getVersion() { + return PROTOCOL_VERSION; + } + + @Override + public int getPriority() { + return 90; + } + + @Override + public boolean supportsBatchProcessing() { + return true; + } + + @Override + public Set getCapabilities() { + return createCapabilitiesSet( + "mcp-jsonrpc", + "agent-communication", + "workflow-orchestration", + "collaboration", + "agent-discovery", + "agent-card-registry", + "agent-status" + ); + } + + @Override + public boolean isValid(ProtocolTransportObject protocol) { + if (protocol == null) { + return false; + } + + try { + String content = protocol.toString(); + if (!content.contains("{")) { + return false; + } + + JsonNode node = objectMapper.readTree(content); + if (node.has("jsonrpc")) { + return true; + } + } catch (Exception e) { + // ignore + } + + if (cloudEventsAdaptor != null && cloudEventsAdaptor.isValid(protocol)) { + return true; + } + if (httpAdaptor != null && httpAdaptor.isValid(protocol)) { + return true; + } + + return false; + } + + private boolean isA2ACloudEvent(CloudEvent cloudEvent) { + return PROTOCOL_TYPE.equals(cloudEvent.getExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL)) + || cloudEvent.getType().startsWith(A2AProtocolConstants.CE_TYPE_PREFIX) + || cloudEvent.getExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD) != null; + } + + /** + * Converts an A2A JSON-RPC message to CloudEvent. + * Handles Agent Card operations with discovery topic routing. + */ + private CloudEvent convertA2AToCloudEvent(JsonNode node, String content) throws ProtocolHandleException { + try { + boolean isRequest = node.has("method"); + boolean isResponse = node.has("result") || node.has("error"); + + String id = node.has("id") ? node.get("id").asText() : generateMessageId(); + String ceType; + String mcpType; + String correlationId = null; + String eventId = isRequest ? id : generateMessageId(); + + CloudEventBuilder builder = CloudEventBuilder.v1() + .withSource(java.net.URI.create("eventmesh-a2a")) + .withData(content.getBytes(StandardCharsets.UTF_8)) + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL, PROTOCOL_TYPE) + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL_VERSION, PROTOCOL_VERSION); + + if (isRequest) { + String method = node.get("method").asText(); + mcpType = "request"; + + if (A2AProtocolConstants.isAgentCardOperation(method)) { + ceType = buildAgentCardCloudEventType(method); + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, method); + extractAgentCardRouting(node, builder, method); + } else if (A2AProtocolConstants.OP_SEND_STREAMING_MESSAGE.equals(method)) { + ceType = A2AProtocolConstants.CE_TYPE_PREFIX + method.replace("/", ".") + ".stream"; + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, method); + extractStandardRouting(node, builder); + } else { + ceType = A2AProtocolConstants.CE_TYPE_PREFIX + method.replace("/", ".") + ".req"; + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, method); + extractStandardRouting(node, builder); + } + } else if (isResponse) { + ceType = A2AProtocolConstants.CE_TYPE_PREFIX + "common.response"; + mcpType = "response"; + correlationId = id; + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_COLLABORATION_ID, correlationId); + } else { + ceType = A2AProtocolConstants.CE_TYPE_PREFIX + "unknown"; + mcpType = "unknown"; + } + + builder.withId(eventId) + .withType(ceType) + .withExtension(A2AProtocolConstants.CE_EXTENSION_MCP_TYPE, mcpType); + + return builder.build(); + + } catch (Exception e) { + throw new ProtocolHandleException("Failed to convert A2A message to CloudEvent", e); + } + } + + private String buildAgentCardCloudEventType(String method) { + return A2AProtocolConstants.CE_TYPE_PREFIX + method.replace("/", ".") + ".req"; + } + + /** + * Extracts routing for Agent Card operations. + * For register/update: route to discovery topic with org_id/unit_id/agent_id from params. + * For get/delete: route to discovery topic for lookup. + * For list: route to discovery topic with wildcard. + */ + private void extractAgentCardRouting(JsonNode node, CloudEventBuilder builder, String method) { + if (!node.has("params")) { + return; + } + JsonNode params = node.get("params"); + + String orgId = getTextParam(params, "org_id"); + String unitId = getTextParam(params, "unit_id"); + String agentId = getTextParam(params, "agent_id"); + + if (orgId != null && unitId != null && agentId != null) { + AgentIdentity identity = new AgentIdentity(orgId, unitId, agentId); + builder.withSubject(identity.discoveryTopic()); + } + + if (params.has("card")) { + // Validate card if validator is available + if (cardValidator != null) { + String cardJson = params.get("card").toString(); + AgentCardValidator.ValidationResult result = cardValidator.validate(cardJson); + if (!result.isValid()) { + log.warn("Agent card validation failed: {}", result.getErrorMessage()); + } + } + } + } + + private void extractStandardRouting(JsonNode node, CloudEventBuilder builder) { + if (!node.has("params")) { + return; + } + JsonNode params = node.get("params"); + + if (params.has("_topic")) { + builder.withSubject(params.get("_topic").asText()); + } else if (params.has("_agentId")) { + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_TARGET_AGENT, params.get("_agentId").asText()); + } + + if (params.has("_seq")) { + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_SEQ, params.get("_seq").asText()); + } + } + + private String getTextParam(JsonNode params, String key) { + if (params.has(key)) { + JsonNode val = params.get(key); + return val.isTextual() ? val.asText() : null; + } + return null; + } + + private ProtocolTransportObject convertCloudEventToA2A(CloudEvent cloudEvent) { + if (cloudEventsAdaptor != null) { + try { + return cloudEventsAdaptor.fromCloudEvent(cloudEvent); + } catch (Exception ignored) { + // ignore + } + } + + byte[] data = cloudEvent.getData() != null ? cloudEvent.getData().toBytes() : new byte[0]; + String content = new String(data, StandardCharsets.UTF_8); + return new SimpleA2AProtocolTransportObject(content, cloudEvent); + } + + private String getTargetProtocol(CloudEvent cloudEvent) { + if (cloudEvent == null) { + return "cloudevents"; + } + Object protocolDescObj = cloudEvent.getExtension("protocolDesc"); + if (protocolDescObj instanceof String) { + return (String) protocolDescObj; + } + String type = cloudEvent.getType(); + if (type != null && type.contains("http")) { + return "http"; + } + return "cloudevents"; + } + + private static class SimpleA2AProtocolTransportObject implements ProtocolTransportObject { + + private final String content; + private final CloudEvent sourceCloudEvent; + + public SimpleA2AProtocolTransportObject(String content, CloudEvent sourceCloudEvent) { + this.content = content; + this.sourceCloudEvent = sourceCloudEvent; + } + + @Override + public String toString() { + return content; + } + + public CloudEvent getSourceCloudEvent() { + return sourceCloudEvent; + } + } + + private Set createCapabilitiesSet(String... capabilities) { + Set result = new HashSet<>(); + Collections.addAll(result, capabilities); + return result; + } + + private String generateMessageId() { + return "a2a-" + System.currentTimeMillis() + "-" + Math.random(); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcError.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcError.java new file mode 100644 index 0000000000..dd770a9ce9 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcError.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.mcp; + +import java.io.Serializable; + +/** + * Standard JSON-RPC 2.0 Error object. + * Reference: https://www.jsonrpc.org/specification#error_object + */ +public class JsonRpcError implements Serializable { + + private int code; + private String message; + private Object data; + + public JsonRpcError() { + } + + public JsonRpcError(int code, String message, Object data) { + this.code = code; + this.message = message; + this.data = data; + } + + // Standard MCP/JSON-RPC Error Codes + public static final int PARSE_ERROR = -32700; + public static final int INVALID_REQUEST = -32600; + public static final int METHOD_NOT_FOUND = -32601; + public static final int INVALID_PARAMS = -32602; + public static final int INTERNAL_ERROR = -32603; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcRequest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcRequest.java new file mode 100644 index 0000000000..f299674abb --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcRequest.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.mcp; + +import java.io.Serializable; +import java.util.Map; + +/** + * Represents a standard JSON-RPC 2.0 Request object, aligned with MCP specifications. + */ +public class JsonRpcRequest implements Serializable { + + private String jsonrpc = "2.0"; + private String method; + private Map params; + private Object id; // Can be String, Number, or Null + + public JsonRpcRequest() { + } + + public JsonRpcRequest(String method, Map params, Object id) { + this.method = method; + this.params = params; + this.id = id; + } + + public String getJsonrpc() { + return jsonrpc; + } + + public void setJsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public Map getParams() { + return params; + } + + public void setParams(Map params) { + this.params = params; + } + + public Object getId() { + return id; + } + + public void setId(Object id) { + this.id = id; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcResponse.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcResponse.java new file mode 100644 index 0000000000..2c3d38c45c --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/JsonRpcResponse.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.mcp; + +import java.io.Serializable; + +/** + * Represents a standard JSON-RPC 2.0 Response object. + */ +public class JsonRpcResponse implements Serializable { + + private String jsonrpc = "2.0"; + private Object result; + private JsonRpcError error; + private Object id; + + public String getJsonrpc() { + return jsonrpc; + } + + public void setJsonrpc(String jsonrpc) { + this.jsonrpc = jsonrpc; + } + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + + public JsonRpcError getError() { + return error; + } + + public void setError(JsonRpcError error) { + this.error = error; + } + + public Object getId() { + return id; + } + + public void setId(Object id) { + this.id = id; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/McpMethods.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/McpMethods.java new file mode 100644 index 0000000000..6d42b2754a --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/mcp/McpMethods.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.mcp; + +/** + * Standard MCP Methods. + * Reference: https://modelcontextprotocol.io/docs/concepts/architecture + */ +public class McpMethods { + // Lifecycle + public static final String INITIALIZE = "initialize"; + public static final String INITIALIZED = "notifications/initialized"; + public static final String PING = "ping"; + + // Tools + public static final String TOOLS_LIST = "tools/list"; + public static final String TOOLS_CALL = "tools/call"; + + // Prompts + public static final String PROMPTS_LIST = "prompts/list"; + public static final String PROMPTS_GET = "prompts/get"; + + // Resources + public static final String RESOURCES_LIST = "resources/list"; + public static final String RESOURCES_READ = "resources/read"; + public static final String RESOURCES_SUBSCRIBE = "resources/subscribe"; + + // Sampling (Host-side) + public static final String SAMPLING_CREATE_MESSAGE = "sampling/createMessage"; + + public static boolean isMcpMethod(String method) { + if (method == null) { + return false; + } + return method.startsWith("tools/") + || method.startsWith("resources/") + || method.startsWith("prompts/") + || method.startsWith("sampling/") + || "initialize".equals(method) + || "ping".equals(method); + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCapabilities.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCapabilities.java new file mode 100644 index 0000000000..44322146ba --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCapabilities.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Defines optional capabilities supported by an agent. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentCapabilities implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean streaming; + + @JsonProperty("pushNotifications") + private Boolean pushNotifications; + + @JsonProperty("extendedAgentCard") + private Boolean extendedAgentCard; + + private List extensions; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCard.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCard.java new file mode 100644 index 0000000000..6f1787874c --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCard.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents an A2A Agent Card as defined by the A2A protocol specification. + * Reference: https://a2a-protocol.org/latest/specification/#agent-card + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentCard implements Serializable { + + private static final long serialVersionUID = 1L; + + private String name; + + private String description; + + private String version; + + @JsonProperty("supportedInterfaces") + private List supportedInterfaces; + + private AgentProvider provider; + + private AgentCapabilities capabilities; + + private List skills; + + private List signatures; + + @JsonProperty("securitySchemes") + private Map securitySchemes; + + @JsonProperty("securityRequirements") + private List securityRequirements; + + @JsonProperty("defaultInputModes") + private List defaultInputModes; + + @JsonProperty("defaultOutputModes") + private List defaultOutputModes; + + @JsonProperty("documentationUrl") + private String documentationUrl; + + @JsonProperty("iconUrl") + private String iconUrl; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCardSignature.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCardSignature.java new file mode 100644 index 0000000000..13cacbd4fc --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentCardSignature.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a JWS signature of an AgentCard (RFC 7515). + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentCardSignature implements Serializable { + + private static final long serialVersionUID = 1L; + + private String protect; + + private String signature; + + private Map header; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentExtension.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentExtension.java new file mode 100644 index 0000000000..ccb19a9c5e --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentExtension.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * A declaration of a protocol extension supported by an Agent. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentExtension implements Serializable { + + private static final long serialVersionUID = 1L; + + private String uri; + + private String description; + + private Boolean required; + + private Map params; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentInterface.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentInterface.java new file mode 100644 index 0000000000..d0f398951f --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentInterface.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Declares a combination of a target URL, transport and protocol version for interacting with the agent. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentInterface implements Serializable { + + private static final long serialVersionUID = 1L; + + private String url; + + @JsonProperty("protocolBinding") + private String protocolBinding; + + @JsonProperty("protocolVersion") + private String protocolVersion; + + private String tenant; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentProvider.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentProvider.java new file mode 100644 index 0000000000..72e53b39ef --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentProvider.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents the service provider of an agent. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentProvider implements Serializable { + + private static final long serialVersionUID = 1L; + + private String url; + + private String organization; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentSkill.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentSkill.java new file mode 100644 index 0000000000..0e484af21f --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/AgentSkill.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a distinct capability or function that an agent can perform. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AgentSkill implements Serializable { + + private static final long serialVersionUID = 1L; + + private String id; + + private String name; + + private String description; + + private List tags; + + private List examples; + + @JsonProperty("inputModes") + private List inputModes; + + @JsonProperty("outputModes") + private List outputModes; + + @JsonProperty("securityRequirements") + private List securityRequirements; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/SecurityRequirement.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/SecurityRequirement.java new file mode 100644 index 0000000000..cb8b05381f --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/SecurityRequirement.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Defines the security requirements for an agent. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SecurityRequirement implements Serializable { + + private static final long serialVersionUID = 1L; + + private Map schemes; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class StringList implements Serializable { + + private static final long serialVersionUID = 1L; + + private List list; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/SecurityScheme.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/SecurityScheme.java new file mode 100644 index 0000000000..381594232d --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/java/org/apache/eventmesh/protocol/a2a/model/SecurityScheme.java @@ -0,0 +1,255 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a.model; + +import java.io.Serializable; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Defines a security scheme that can be used to secure an agent's endpoints. + * Discriminated union type based on OpenAPI 3.2 Security Scheme Object. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SecurityScheme implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("apiKeySecurityScheme") + private APIKeySecurityScheme apiKeySecurityScheme; + + @JsonProperty("httpAuthSecurityScheme") + private HTTPAuthSecurityScheme httpAuthSecurityScheme; + + @JsonProperty("oauth2SecurityScheme") + private OAuth2SecurityScheme oauth2SecurityScheme; + + @JsonProperty("openIdConnectSecurityScheme") + private OpenIdConnectSecurityScheme openIdConnectSecurityScheme; + + @JsonProperty("mtlsSecurityScheme") + private MutualTlsSecurityScheme mtlsSecurityScheme; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class APIKeySecurityScheme implements Serializable { + + private static final long serialVersionUID = 1L; + + private String description; + private String location; + private String name; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class HTTPAuthSecurityScheme implements Serializable { + + private static final long serialVersionUID = 1L; + + private String description; + private String scheme; + + @JsonProperty("bearerFormat") + private String bearerFormat; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class OAuth2SecurityScheme implements Serializable { + + private static final long serialVersionUID = 1L; + + private String description; + private OAuthFlows flows; + + @JsonProperty("oauth2MetadataUrl") + private String oauth2MetadataUrl; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class OpenIdConnectSecurityScheme implements Serializable { + + private static final long serialVersionUID = 1L; + + private String description; + + @JsonProperty("openIdConnectUrl") + private String openIdConnectUrl; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class MutualTlsSecurityScheme implements Serializable { + + private static final long serialVersionUID = 1L; + + private String description; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class OAuthFlows implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("authorizationCode") + private AuthorizationCodeOAuthFlow authorizationCode; + + @JsonProperty("clientCredentials") + private ClientCredentialsOAuthFlow clientCredentials; + + @JsonProperty("deviceCode") + private DeviceCodeOAuthFlow deviceCode; + + @JsonProperty("implicit") + private ImplicitOAuthFlow implicit; + + @JsonProperty("password") + private PasswordOAuthFlow password; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class AuthorizationCodeOAuthFlow implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("authorizationUrl") + private String authorizationUrl; + + @JsonProperty("tokenUrl") + private String tokenUrl; + + @JsonProperty("refreshUrl") + private String refreshUrl; + + private Map scopes; + + @JsonProperty("pkceRequired") + private Boolean pkceRequired; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class ClientCredentialsOAuthFlow implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("tokenUrl") + private String tokenUrl; + + @JsonProperty("refreshUrl") + private String refreshUrl; + + private Map scopes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class DeviceCodeOAuthFlow implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("deviceAuthorizationUrl") + private String deviceAuthorizationUrl; + + @JsonProperty("tokenUrl") + private String tokenUrl; + + @JsonProperty("refreshUrl") + private String refreshUrl; + + private Map scopes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class ImplicitOAuthFlow implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("authorizationUrl") + private String authorizationUrl; + + @JsonProperty("refreshUrl") + private String refreshUrl; + + private Map scopes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class PasswordOAuthFlow implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("tokenUrl") + private String tokenUrl; + + @JsonProperty("refreshUrl") + private String refreshUrl; + + private Map scopes; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor new file mode 100644 index 0000000000..02cd9930f5 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor @@ -0,0 +1,16 @@ +# 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. + +a2a=org.apache.eventmesh.protocol.a2a.EnhancedA2AProtocolAdaptor \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/resources/a2a/agent_card_schema.json b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/resources/a2a/agent_card_schema.json new file mode 100644 index 0000000000..db9b4946f2 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/main/resources/a2a/agent_card_schema.json @@ -0,0 +1,732 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "A2A Agent Card", + "type": "object", + "required": [ + "name", + "description", + "supportedInterfaces", + "version", + "capabilities", + "defaultInputModes", + "defaultOutputModes", + "skills" + ], + "patternProperties": { + "^(supported_interfaces)$": { + "type": "array", + "description": "Ordered list of supported interfaces. The first entry is preferred.", + "items": { + "$ref": "#/definitions/AgentInterface" + } + }, + "^(documentation_url)$": { + "type": "string", + "description": "A URL providing additional documentation about the agent." + }, + "^(security_schemes)$": { + "type": "object", + "description": "The security scheme details used for authenticating with this agent.", + "additionalProperties": { + "$ref": "#/definitions/SecurityScheme" + }, + "propertyNames": { + "type": "string" + } + }, + "^(security_requirements)$": { + "type": "array", + "description": "Security requirements for contacting the agent.", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + }, + "^(default_input_modes)$": { + "type": "array", + "items": { "type": "string" }, + "description": "The set of interaction modes that the agent supports across all skills, defined as media types." + }, + "^(default_output_modes)$": { + "type": "array", + "items": { "type": "string" }, + "description": "The media types supported as outputs from this agent." + }, + "^(icon_url)$": { + "type": "string", + "description": "A URL to an icon for the agent." + } + }, + "properties": { + "name": { + "type": "string", + "description": "A human readable name for the agent." + }, + "description": { + "type": "string", + "description": "A human-readable description of the agent, assisting users and other agents in understanding its purpose." + }, + "supportedInterfaces": { + "type": "array", + "description": "Ordered list of supported interfaces. The first entry is preferred.", + "items": { + "$ref": "#/definitions/AgentInterface" + } + }, + "provider": { + "$ref": "#/definitions/AgentProvider" + }, + "version": { + "type": "string", + "description": "The version of the agent (e.g., \"1.0.0\")." + }, + "documentationUrl": { + "type": "string", + "description": "A URL providing additional documentation about the agent." + }, + "capabilities": { + "$ref": "#/definitions/AgentCapabilities" + }, + "securitySchemes": { + "type": "object", + "description": "The security scheme details used for authenticating with this agent.", + "additionalProperties": { + "$ref": "#/definitions/SecurityScheme" + }, + "propertyNames": { + "type": "string" + } + }, + "securityRequirements": { + "type": "array", + "description": "Security requirements for contacting the agent.", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + }, + "defaultInputModes": { + "type": "array", + "items": { "type": "string" }, + "description": "The set of interaction modes that the agent supports across all skills, defined as media types." + }, + "defaultOutputModes": { + "type": "array", + "items": { "type": "string" }, + "description": "The media types supported as outputs from this agent." + }, + "skills": { + "type": "array", + "description": "Skills represent the abilities of an agent.", + "items": { + "$ref": "#/definitions/AgentSkill" + } + }, + "signatures": { + "type": "array", + "description": "JSON Web Signatures computed for this AgentCard.", + "items": { + "$ref": "#/definitions/AgentCardSignature" + } + }, + "iconUrl": { + "type": "string", + "description": "A URL to an icon for the agent." + } + }, + "additionalProperties": false, + "definitions": { + "AgentInterface": { + "type": "object", + "description": "Declares a combination of a target URL, transport and protocol version for interacting with the agent.", + "required": ["url", "protocolBinding", "protocolVersion"], + "patternProperties": { + "^(protocol_binding)$": { + "type": "string", + "description": "The protocol binding supported at this URL (e.g., JSONRPC, GRPC, HTTP+JSON)." + }, + "^(protocol_version)$": { + "type": "string", + "description": "The version of the A2A protocol this interface exposes (e.g., \"0.3\", \"1.0\")." + } + }, + "properties": { + "url": { + "type": "string", + "description": "The URL where this interface is available." + }, + "protocolBinding": { + "type": "string", + "description": "The protocol binding supported at this URL (e.g., JSONRPC, GRPC, HTTP+JSON)." + }, + "tenant": { + "type": "string", + "description": "Tenant ID to be used in the request when calling the agent." + }, + "protocolVersion": { + "type": "string", + "description": "The version of the A2A protocol this interface exposes (e.g., \"0.3\", \"1.0\")." + } + }, + "additionalProperties": false + }, + "AgentProvider": { + "type": "object", + "description": "Represents the service provider of an agent.", + "required": ["url", "organization"], + "properties": { + "url": { + "type": "string", + "description": "A URL for the agent provider's website or relevant documentation." + }, + "organization": { + "type": "string", + "description": "The name of the agent provider's organization." + } + }, + "additionalProperties": false + }, + "AgentCapabilities": { + "type": "object", + "description": "Defines optional capabilities supported by an agent.", + "patternProperties": { + "^(push_notifications)$": { + "type": "boolean", + "description": "Indicates if the agent supports sending push notifications for asynchronous task updates." + }, + "^(extended_agent_card)$": { + "type": "boolean", + "description": "Indicates if the agent supports providing an extended agent card when authenticated." + } + }, + "properties": { + "streaming": { + "type": "boolean", + "description": "Indicates if the agent supports streaming responses." + }, + "pushNotifications": { + "type": "boolean", + "description": "Indicates if the agent supports sending push notifications for asynchronous task updates." + }, + "extensions": { + "type": "array", + "description": "A list of protocol extensions supported by the agent.", + "items": { + "$ref": "#/definitions/AgentExtension" + } + }, + "extendedAgentCard": { + "type": "boolean", + "description": "Indicates if the agent supports providing an extended agent card when authenticated." + } + }, + "additionalProperties": false + }, + "AgentExtension": { + "type": "object", + "description": "A declaration of a protocol extension supported by an Agent.", + "properties": { + "uri": { + "type": "string", + "description": "The unique URI identifying the extension." + }, + "description": { + "type": "string", + "description": "A human-readable description of how this agent uses the extension." + }, + "required": { + "type": "boolean", + "description": "If true, the client must understand and comply with the extension's requirements." + }, + "params": { + "type": "object", + "description": "Extension-specific configuration parameters." + } + }, + "additionalProperties": false + }, + "AgentSkill": { + "type": "object", + "description": "Represents a distinct capability or function that an agent can perform.", + "required": ["id", "name", "description", "tags"], + "patternProperties": { + "^(input_modes)$": { + "type": "array", + "items": { "type": "string" }, + "description": "The set of supported input media types for this skill, overriding the agent's defaults." + }, + "^(output_modes)$": { + "type": "array", + "items": { "type": "string" }, + "description": "The set of supported output media types for this skill, overriding the agent's defaults." + }, + "^(security_requirements)$": { + "type": "array", + "description": "Security schemes necessary for this skill.", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + } + }, + "properties": { + "id": { + "type": "string", + "description": "A unique identifier for the agent's skill." + }, + "name": { + "type": "string", + "description": "A human-readable name for the skill." + }, + "description": { + "type": "string", + "description": "A detailed description of the skill." + }, + "tags": { + "type": "array", + "items": { "type": "string" }, + "description": "A set of keywords describing the skill's capabilities." + }, + "examples": { + "type": "array", + "items": { "type": "string" }, + "description": "Example prompts or scenarios that this skill can handle." + }, + "inputModes": { + "type": "array", + "items": { "type": "string" }, + "description": "The set of supported input media types for this skill, overriding the agent's defaults." + }, + "outputModes": { + "type": "array", + "items": { "type": "string" }, + "description": "The set of supported output media types for this skill, overriding the agent's defaults." + }, + "securityRequirements": { + "type": "array", + "description": "Security schemes necessary for this skill.", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + } + }, + "additionalProperties": false + }, + "AgentCardSignature": { + "type": "object", + "description": "Represents a JWS signature of an AgentCard (RFC 7515).", + "required": ["protected", "signature"], + "properties": { + "protected": { + "type": "string", + "description": "The protected JWS header for the signature, base64url-encoded JSON object." + }, + "signature": { + "type": "string", + "description": "The computed signature, base64url-encoded." + }, + "header": { + "type": "object", + "description": "The unprotected JWS header values." + } + }, + "additionalProperties": false + }, + "SecurityRequirement": { + "type": "object", + "description": "Defines the security requirements for an agent.", + "properties": { + "schemes": { + "type": "object", + "description": "A map of security scheme names to the required scopes.", + "additionalProperties": { + "$ref": "#/definitions/StringList" + }, + "propertyNames": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "StringList": { + "type": "object", + "description": "A list of strings.", + "properties": { + "list": { + "type": "array", + "description": "The individual string values.", + "items": { "type": "string" } + } + }, + "additionalProperties": false + }, + "SecurityScheme": { + "type": "object", + "description": "Defines a security scheme that can be used to secure an agent's endpoints. This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object.", + "patternProperties": { + "^(api_key_security_scheme)$": { + "$ref": "#/definitions/APIKeySecurityScheme", + "description": "API key-based authentication." + }, + "^(http_auth_security_scheme)$": { + "$ref": "#/definitions/HTTPAuthSecurityScheme", + "description": "HTTP authentication (Basic, Bearer, etc.)." + }, + "^(oauth2_security_scheme)$": { + "$ref": "#/definitions/OAuth2SecurityScheme", + "description": "OAuth 2.0 authentication." + }, + "^(open_id_connect_security_scheme)$": { + "$ref": "#/definitions/OpenIdConnectSecurityScheme", + "description": "OpenID Connect authentication." + }, + "^(mtls_security_scheme)$": { + "$ref": "#/definitions/MutualTlsSecurityScheme", + "description": "Mutual TLS authentication." + } + }, + "properties": { + "apiKeySecurityScheme": { + "$ref": "#/definitions/APIKeySecurityScheme", + "description": "API key-based authentication." + }, + "httpAuthSecurityScheme": { + "$ref": "#/definitions/HTTPAuthSecurityScheme", + "description": "HTTP authentication (Basic, Bearer, etc.)." + }, + "oauth2SecurityScheme": { + "$ref": "#/definitions/OAuth2SecurityScheme", + "description": "OAuth 2.0 authentication." + }, + "openIdConnectSecurityScheme": { + "$ref": "#/definitions/OpenIdConnectSecurityScheme", + "description": "OpenID Connect authentication." + }, + "mtlsSecurityScheme": { + "$ref": "#/definitions/MutualTlsSecurityScheme", + "description": "Mutual TLS authentication." + } + }, + "additionalProperties": false + }, + "APIKeySecurityScheme": { + "type": "object", + "description": "Defines a security scheme using an API key.", + "properties": { + "description": { + "type": "string", + "description": "An optional description for the security scheme." + }, + "location": { + "type": "string", + "description": "The location of the API key. Valid values are \"query\", \"header\", or \"cookie\"." + }, + "name": { + "type": "string", + "description": "The name of the header, query, or cookie parameter to be used." + } + }, + "additionalProperties": false + }, + "HTTPAuthSecurityScheme": { + "type": "object", + "description": "Defines a security scheme using HTTP authentication.", + "patternProperties": { + "^(bearer_format)$": { + "type": "string", + "description": "A hint to identify how the bearer token is formatted (e.g., \"JWT\")." + } + }, + "properties": { + "description": { + "type": "string", + "description": "An optional description for the security scheme." + }, + "scheme": { + "type": "string", + "description": "The HTTP Authentication scheme (e.g., Bearer, Basic)." + }, + "bearerFormat": { + "type": "string", + "description": "A hint to identify how the bearer token is formatted (e.g., \"JWT\")." + } + }, + "additionalProperties": false + }, + "OAuth2SecurityScheme": { + "type": "object", + "description": "Defines a security scheme using OAuth 2.0.", + "patternProperties": { + "^(oauth2_metadata_url)$": { + "type": "string", + "description": "URL to the OAuth2 authorization server metadata (RFC 8414)." + } + }, + "properties": { + "description": { + "type": "string", + "description": "An optional description for the security scheme." + }, + "flows": { + "$ref": "#/definitions/OAuthFlows", + "description": "An object containing configuration information for the supported OAuth 2.0 flows." + }, + "oauth2MetadataUrl": { + "type": "string", + "description": "URL to the OAuth2 authorization server metadata (RFC 8414)." + } + }, + "additionalProperties": false + }, + "OpenIdConnectSecurityScheme": { + "type": "object", + "description": "Defines a security scheme using OpenID Connect.", + "patternProperties": { + "^(open_id_connect_url)$": { + "type": "string", + "description": "The OpenID Connect Discovery URL." + } + }, + "properties": { + "description": { + "type": "string", + "description": "An optional description for the security scheme." + }, + "openIdConnectUrl": { + "type": "string", + "description": "The OpenID Connect Discovery URL." + } + }, + "additionalProperties": false + }, + "MutualTlsSecurityScheme": { + "type": "object", + "description": "Defines a security scheme using mTLS authentication.", + "properties": { + "description": { + "type": "string", + "description": "An optional description for the security scheme." + } + }, + "additionalProperties": false + }, + "OAuthFlows": { + "type": "object", + "description": "Defines the configuration for the supported OAuth 2.0 flows.", + "patternProperties": { + "^(authorization_code)$": { + "$ref": "#/definitions/AuthorizationCodeOAuthFlow", + "description": "Configuration for the OAuth Authorization Code flow." + }, + "^(client_credentials)$": { + "$ref": "#/definitions/ClientCredentialsOAuthFlow", + "description": "Configuration for the OAuth Client Credentials flow." + }, + "^(device_code)$": { + "$ref": "#/definitions/DeviceCodeOAuthFlow", + "description": "Configuration for the OAuth Device Code flow." + } + }, + "properties": { + "authorizationCode": { + "$ref": "#/definitions/AuthorizationCodeOAuthFlow", + "description": "Configuration for the OAuth Authorization Code flow." + }, + "clientCredentials": { + "$ref": "#/definitions/ClientCredentialsOAuthFlow", + "description": "Configuration for the OAuth Client Credentials flow." + }, + "deviceCode": { + "$ref": "#/definitions/DeviceCodeOAuthFlow", + "description": "Configuration for the OAuth Device Code flow." + }, + "implicit": { + "$ref": "#/definitions/ImplicitOAuthFlow", + "description": "Deprecated: Use Authorization Code + PKCE instead." + }, + "password": { + "$ref": "#/definitions/PasswordOAuthFlow", + "description": "Deprecated: Use Authorization Code + PKCE or Device Code." + } + }, + "additionalProperties": false + }, + "AuthorizationCodeOAuthFlow": { + "type": "object", + "description": "Defines configuration details for the OAuth 2.0 Authorization Code flow.", + "patternProperties": { + "^(authorization_url)$": { + "type": "string", + "description": "The authorization URL to be used for this flow." + }, + "^(token_url)$": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "^(refresh_url)$": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + }, + "^(pkce_required)$": { + "type": "boolean", + "description": "Indicates if PKCE (RFC 7636) is required for this flow." + } + }, + "properties": { + "authorizationUrl": { + "type": "string", + "description": "The authorization URL to be used for this flow." + }, + "tokenUrl": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "refreshUrl": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + }, + "scopes": { + "type": "object", + "description": "The available scopes for the OAuth2 security scheme.", + "additionalProperties": { "type": "string" }, + "propertyNames": { "type": "string" } + }, + "pkceRequired": { + "type": "boolean", + "description": "Indicates if PKCE (RFC 7636) is required for this flow." + } + }, + "additionalProperties": false + }, + "ClientCredentialsOAuthFlow": { + "type": "object", + "description": "Defines configuration details for the OAuth 2.0 Client Credentials flow.", + "patternProperties": { + "^(token_url)$": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "^(refresh_url)$": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + } + }, + "properties": { + "tokenUrl": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "refreshUrl": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + }, + "scopes": { + "type": "object", + "description": "The available scopes for the OAuth2 security scheme.", + "additionalProperties": { "type": "string" }, + "propertyNames": { "type": "string" } + } + }, + "additionalProperties": false + }, + "DeviceCodeOAuthFlow": { + "type": "object", + "description": "Defines configuration details for the OAuth 2.0 Device Code flow (RFC 8628).", + "patternProperties": { + "^(device_authorization_url)$": { + "type": "string", + "description": "The device authorization endpoint URL." + }, + "^(token_url)$": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "^(refresh_url)$": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + } + }, + "properties": { + "deviceAuthorizationUrl": { + "type": "string", + "description": "The device authorization endpoint URL." + }, + "tokenUrl": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "refreshUrl": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + }, + "scopes": { + "type": "object", + "description": "The available scopes for the OAuth2 security scheme.", + "additionalProperties": { "type": "string" }, + "propertyNames": { "type": "string" } + } + }, + "additionalProperties": false + }, + "ImplicitOAuthFlow": { + "type": "object", + "description": "Deprecated: Use Authorization Code + PKCE instead.", + "patternProperties": { + "^(authorization_url)$": { + "type": "string", + "description": "The authorization URL to be used for this flow." + }, + "^(refresh_url)$": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + } + }, + "properties": { + "authorizationUrl": { + "type": "string", + "description": "The authorization URL to be used for this flow." + }, + "refreshUrl": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + }, + "scopes": { + "type": "object", + "description": "The available scopes for the OAuth2 security scheme.", + "additionalProperties": { "type": "string" }, + "propertyNames": { "type": "string" } + } + }, + "additionalProperties": false + }, + "PasswordOAuthFlow": { + "type": "object", + "description": "Deprecated: Use Authorization Code + PKCE or Device Code.", + "patternProperties": { + "^(token_url)$": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "^(refresh_url)$": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + } + }, + "properties": { + "tokenUrl": { + "type": "string", + "description": "The token URL to be used for this flow." + }, + "refreshUrl": { + "type": "string", + "description": "The URL to be used for obtaining refresh tokens." + }, + "scopes": { + "type": "object", + "description": "The available scopes for the OAuth2 security scheme.", + "additionalProperties": { "type": "string" }, + "propertyNames": { "type": "string" } + } + }, + "additionalProperties": false + } + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/A2ATopicFactoryTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/A2ATopicFactoryTest.java new file mode 100644 index 0000000000..a29d322db4 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/A2ATopicFactoryTest.java @@ -0,0 +1,335 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link A2ATopicFactory}. + */ +class A2ATopicFactoryTest { + + private static final String GLOBAL = "global"; + private static final String NS = "myorg"; + + // ========================================================================= + // Discovery topics + // ========================================================================= + + @Test + void testDiscoveryTopicGlobal() { + assertEquals("a2a/v1/discovery/agentcards", A2ATopicFactory.discoveryTopic(GLOBAL)); + } + + @Test + void testDiscoveryTopicNamespaced() { + assertEquals("myorg/a2a/v1/discovery/agentcards", A2ATopicFactory.discoveryTopic(NS)); + } + + @Test + void testGatewayDiscoveryTopicGlobal() { + assertEquals("a2a/v1/discovery/gatewaycards", A2ATopicFactory.gatewayDiscoveryTopic(GLOBAL)); + } + + @Test + void testGatewayDiscoveryTopicNamespaced() { + assertEquals("myorg/a2a/v1/discovery/gatewaycards", A2ATopicFactory.gatewayDiscoveryTopic(NS)); + } + + // ========================================================================= + // Agent topics + // ========================================================================= + + @Test + void testAgentRequestTopicGlobal() { + assertEquals("a2a/v1/agent/request/weather-agent", + A2ATopicFactory.agentRequestTopic(GLOBAL, "weather-agent")); + } + + @Test + void testAgentRequestTopicNamespaced() { + assertEquals("myorg/a2a/v1/agent/request/weather-agent", + A2ATopicFactory.agentRequestTopic(NS, "weather-agent")); + } + + @Test + void testAgentStatusTopic() { + assertEquals("a2a/v1/agent/status/weather-agent/task-123", + A2ATopicFactory.agentStatusTopic(GLOBAL, "weather-agent", "task-123")); + } + + @Test + void testAgentResponseTopic() { + assertEquals("a2a/v1/agent/response/weather-agent/task-123", + A2ATopicFactory.agentResponseTopic(GLOBAL, "weather-agent", "task-123")); + } + + @Test + void testAgentStatusWildcardTopic() { + assertEquals("a2a/v1/agent/status/weather-agent/+", + A2ATopicFactory.agentStatusWildcardTopic(GLOBAL, "weather-agent")); + } + + @Test + void testAgentResponseWildcardTopic() { + assertEquals("a2a/v1/agent/response/weather-agent/+", + A2ATopicFactory.agentResponseWildcardTopic(GLOBAL, "weather-agent")); + } + + // ========================================================================= + // Gateway topics + // ========================================================================= + + @Test + void testGatewayRequestTopic() { + assertEquals("a2a/v1/gateway/request/gw-1", + A2ATopicFactory.gatewayRequestTopic(GLOBAL, "gw-1")); + } + + @Test + void testGatewayStatusTopic() { + assertEquals("a2a/v1/gateway/status/gw-1/task-456", + A2ATopicFactory.gatewayStatusTopic(GLOBAL, "gw-1", "task-456")); + } + + @Test + void testGatewayResponseTopic() { + assertEquals("a2a/v1/gateway/response/gw-1/task-456", + A2ATopicFactory.gatewayResponseTopic(GLOBAL, "gw-1", "task-456")); + } + + @Test + void testGatewayStatusWildcardTopic() { + assertEquals("a2a/v1/gateway/status/gw-1/+", + A2ATopicFactory.gatewayStatusWildcardTopic(GLOBAL, "gw-1")); + } + + @Test + void testGatewayResponseWildcardTopic() { + assertEquals("a2a/v1/gateway/response/gw-1/+", + A2ATopicFactory.gatewayResponseWildcardTopic(GLOBAL, "gw-1")); + } + + // ========================================================================= + // Validation + // ========================================================================= + + @Test + void testInvalidAgentNameThrows() { + assertThrows(IllegalArgumentException.class, + () -> A2ATopicFactory.agentRequestTopic(GLOBAL, "agent with spaces")); + } + + @Test + void testInvalidTaskIdThrows() { + assertThrows(IllegalArgumentException.class, + () -> A2ATopicFactory.agentStatusTopic(GLOBAL, "agent-1", "task/with/slashes")); + } + + @Test + void testInvalidGatewayIdThrows() { + assertThrows(IllegalArgumentException.class, + () -> A2ATopicFactory.gatewayResponseTopic(GLOBAL, "gw#1", "task-1")); + } + + @Test + void testNullAgentNameThrows() { + assertThrows(IllegalArgumentException.class, + () -> A2ATopicFactory.agentRequestTopic(GLOBAL, null)); + } + + @Test + void testValidSpecialChars() { + // These should not throw: letters, digits, dots, underscores, hyphens + assertEquals("a2a/v1/agent/request/agent_1.v2-3", + A2ATopicFactory.agentRequestTopic(GLOBAL, "agent_1.v2-3")); + } + + // ========================================================================= + // Parsing + // ========================================================================= + + @Test + void testParseAgentRequestGlobal() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/agent/request/weather-agent"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.AGENT_REQUEST, parsed.getEntityType()); + assertEquals("weather-agent", parsed.getAgentName()); + assertEquals(GLOBAL, parsed.getNamespace()); + assertNull(parsed.getTaskId()); + assertTrue(parsed.isRequest()); + assertFalse(parsed.isStatus()); + assertFalse(parsed.isResponse()); + assertFalse(parsed.isDiscovery()); + } + + @Test + void testParseAgentStatusWithTaskId() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/agent/status/weather-agent/task-789"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.AGENT_STATUS, parsed.getEntityType()); + assertEquals("weather-agent", parsed.getAgentName()); + assertEquals("task-789", parsed.getTaskId()); + assertTrue(parsed.isStatus()); + } + + @Test + void testParseAgentResponse() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/agent/response/agent-a/task-001"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.AGENT_RESPONSE, parsed.getEntityType()); + assertTrue(parsed.isResponse()); + } + + @Test + void testParseGatewayResponse() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/gateway/response/gw-1/task-789"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.GATEWAY_RESPONSE, parsed.getEntityType()); + assertEquals("gw-1", parsed.getGatewayId()); + assertEquals("task-789", parsed.getTaskId()); + assertTrue(parsed.isResponse()); + } + + @Test + void testParseGatewayStatus() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/gateway/status/gw-1/task-789"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.GATEWAY_STATUS, parsed.getEntityType()); + assertTrue(parsed.isStatus()); + } + + @Test + void testParseGatewayRequest() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/gateway/request/gw-1"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.GATEWAY_REQUEST, parsed.getEntityType()); + assertEquals("gw-1", parsed.getGatewayId()); + assertTrue(parsed.isRequest()); + } + + @Test + void testParseDiscoveryAgent() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/discovery/agentcards"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.DISCOVERY_AGENT, parsed.getEntityType()); + assertTrue(parsed.isDiscovery()); + } + + @Test + void testParseDiscoveryGateway() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/discovery/gatewaycards"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.DISCOVERY_GATEWAY, parsed.getEntityType()); + assertTrue(parsed.isDiscovery()); + } + + @Test + void testParseNamespacedTopic() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("myorg/a2a/v1/agent/request/weather-agent"); + assertNotNull(parsed); + assertEquals("myorg", parsed.getNamespace()); + assertEquals(A2ATopicFactory.EntityType.AGENT_REQUEST, parsed.getEntityType()); + assertEquals("weather-agent", parsed.getAgentName()); + } + + @Test + void testParseNamespacedGatewayResponse() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("myorg/a2a/v1/gateway/response/gw-1/task-1"); + assertNotNull(parsed); + assertEquals("myorg", parsed.getNamespace()); + assertEquals(A2ATopicFactory.EntityType.GATEWAY_RESPONSE, parsed.getEntityType()); + assertEquals("gw-1", parsed.getGatewayId()); + assertEquals("task-1", parsed.getTaskId()); + } + + // ========================================================================= + // Invalid parsing + // ========================================================================= + + @Test + void testParseNullReturnsNull() { + assertNull(A2ATopicFactory.parse(null)); + } + + @Test + void testParseEmptyReturnsNull() { + assertNull(A2ATopicFactory.parse("")); + } + + @Test + void testParseNonA2ATopicReturnsNull() { + assertNull(A2ATopicFactory.parse("some/random/topic")); + } + + @Test + void testParseInvalidDiscoveryReturnsNull() { + assertNull(A2ATopicFactory.parse("a2a/v1/discovery/unknown")); + } + + @Test + void testParseInvalidActionReturnsNull() { + assertNull(A2ATopicFactory.parse("a2a/v1/agent/unknown/agent-1")); + } + + @Test + void testParseTooShortReturnsNull() { + assertNull(A2ATopicFactory.parse("a2a/v1")); + } + + // ========================================================================= + // Round-trip: generate then parse + // ========================================================================= + + @Test + void testRoundTripAgentRequest() { + String topic = A2ATopicFactory.agentRequestTopic(NS, "my-agent"); + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse(topic); + assertNotNull(parsed); + assertEquals(NS, parsed.getNamespace()); + assertEquals("my-agent", parsed.getAgentName()); + assertEquals(A2ATopicFactory.EntityType.AGENT_REQUEST, parsed.getEntityType()); + } + + @Test + void testRoundTripGatewayResponse() { + String topic = A2ATopicFactory.gatewayResponseTopic(NS, "gw-1", "task-abc"); + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse(topic); + assertNotNull(parsed); + assertEquals(NS, parsed.getNamespace()); + assertEquals("gw-1", parsed.getGatewayId()); + assertEquals("task-abc", parsed.getTaskId()); + assertEquals(A2ATopicFactory.EntityType.GATEWAY_RESPONSE, parsed.getEntityType()); + } + + @Test + void testParsedTopicToString() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/agent/request/test-agent"); + assertNotNull(parsed); + String str = parsed.toString(); + assertTrue(str.contains("agentName='test-agent'")); + assertTrue(str.contains("AGENT_REQUEST")); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/CloudEventsComprehensiveDemoTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/CloudEventsComprehensiveDemoTest.java new file mode 100644 index 0000000000..5e909e3b37 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/CloudEventsComprehensiveDemoTest.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +/** + * Comprehensive Demo Suite for Protocol 2: Native CloudEvents. + * Demonstrates how to achieve RPC, PubSub, and Streaming using raw CloudEvents without JSON-RPC wrappers. + */ +public class CloudEventsComprehensiveDemoTest { + + private EnhancedA2AProtocolAdaptor adaptor; + + @BeforeEach + public void setUp() { + adaptor = new EnhancedA2AProtocolAdaptor(); + adaptor.initialize(); + } + + /** + * Pattern 1: RPC (Request/Response) using Native CloudEvents + * + * Mechanism: + * - Request: Type ends with ".req", sets "mcptype"="request", "targetagent". + * - Response: Type ends with ".resp", sets "mcptype"="response", "collaborationid". + */ + @Test + public void demo_CE_RPC_Pattern() throws Exception { + String reqId = UUID.randomUUID().toString(); + String method = "tools/call"; + String targetAgent = "weather-service"; + + // 1. Client: Construct Request CloudEvent + CloudEvent requestEvent = CloudEventBuilder.v1() + .withId(reqId) + .withSource(URI.create("client-agent")) + .withType("org.apache.eventmesh.a2a.tools.call.req") // Convention: ..req + .withExtension("protocol", "A2A") + .withExtension("mcptype", "request") + .withExtension("a2amethod", method) + .withExtension("targetagent", targetAgent) // P2P Routing + .withData("application/json", "{\"city\":\"Shanghai\"}".getBytes(StandardCharsets.UTF_8)) + .build(); + + // 2. EventMesh: Ingress (Pass-through) + // Since input is already a CloudEvent, adaptor should pass it through or verify it. + // In this test, we simulate the "Transport -> Adaptor -> Core" flow using `fromCloudEvent` + // to verify the adaptor understands it as A2A protocol object. + ProtocolTransportObject transportObj = adaptor.fromCloudEvent(requestEvent); + + // Verify it didn't crash and preserved content + Assertions.assertNotNull(transportObj); + + // 3. Server: Construct Response CloudEvent + CloudEvent responseEvent = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("weather-service")) + .withType("org.apache.eventmesh.a2a.common.response") + .withExtension("protocol", "A2A") + .withExtension("mcptype", "response") + .withExtension("collaborationid", reqId) // Link back to Request ID + .withData("application/json", "{\"temp\":25}".getBytes(StandardCharsets.UTF_8)) + .build(); + + // 4. Verify Response Association + Assertions.assertEquals(reqId, responseEvent.getExtension("collaborationid")); + } + + /** + * Pattern 2: Pub/Sub (Broadcast) using Native CloudEvents + * + * Mechanism: + * - Set "subject" to the Topic. + * - Do NOT set "targetagent". + */ + @Test + public void demo_CE_PubSub_Pattern() throws Exception { + String topic = "market.crypto.btc"; + + // 1. Publisher: Construct Broadcast CloudEvent + CloudEvent pubEvent = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("market-data-feed")) + .withType("org.apache.eventmesh.a2a.market.update.req") + .withSubject(topic) // <--- Routing Key + .withExtension("protocol", "A2A") + .withExtension("mcptype", "request") // It's a request/notification + .withData("application/json", "{\"price\":90000}".getBytes(StandardCharsets.UTF_8)) + .build(); + + // 2. Verification + Assertions.assertEquals(topic, pubEvent.getSubject()); + Assertions.assertNull(pubEvent.getExtension("targetagent")); // Broadcast + + // In EventMesh Runtime, the Router will dispatch this to all queues bound to Subject "market.crypto.btc" + } + + /** + * Pattern 3: Streaming using Native CloudEvents + * + * Mechanism: + * - Type ends with ".stream". + * - Set "seq" extension. + */ + @Test + public void demo_CE_Streaming_Pattern() throws Exception { + String streamSessionId = UUID.randomUUID().toString(); + + // 1. Sender: Send Chunk 1 + CloudEvent chunk1 = CloudEventBuilder.v1() + .withId(streamSessionId) // Same ID for session, or new ID with grouping extension + .withSource(URI.create("file-server")) + .withType("org.apache.eventmesh.a2a.file.download.stream") // .stream suffix + .withExtension("protocol", "A2A") + .withExtension("mcptype", "request") + .withExtension("seq", "1") // <--- Ordering + .withExtension("targetagent", "downloader-client") + .withData("application/octet-stream", new byte[]{0x01, 0x02}) + .build(); + + // 2. Sender: Send Chunk 2 + CloudEvent chunk2 = CloudEventBuilder.v1() + .withId(streamSessionId) + .withSource(URI.create("file-server")) + .withType("org.apache.eventmesh.a2a.file.download.stream") + .withExtension("protocol", "A2A") + .withExtension("mcptype", "request") + .withExtension("seq", "2") + .withExtension("targetagent", "downloader-client") + .withData("application/octet-stream", new byte[]{0x03, 0x04}) + .build(); + + // 3. Verification + Assertions.assertEquals("1", chunk1.getExtension("seq")); + Assertions.assertEquals("2", chunk2.getExtension("seq")); + Assertions.assertEquals("org.apache.eventmesh.a2a.file.download.stream", chunk1.getType()); + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/EnhancedA2AProtocolAdaptorTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/EnhancedA2AProtocolAdaptorTest.java new file mode 100644 index 0000000000..de3cf83599 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/EnhancedA2AProtocolAdaptorTest.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class EnhancedA2AProtocolAdaptorTest { + + private EnhancedA2AProtocolAdaptor adaptor; + + @BeforeEach + public void setUp() { + adaptor = new EnhancedA2AProtocolAdaptor(); + adaptor.initialize(); + } + + @Test + public void testMcpRequestProcessing() throws ProtocolHandleException { + // Standard MCP JSON-RPC Request + String json = "{\"jsonrpc\": \"2.0\", \"method\": \"tools/call\", \"params\": {\"name\": \"weather\"}, \"id\": \"req-001\"}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("request", event.getExtension("mcptype")); + Assertions.assertEquals("tools/call", event.getExtension("a2amethod")); + Assertions.assertEquals("org.apache.eventmesh.a2a.tools.call.req", event.getType()); + Assertions.assertEquals("req-001", event.getId()); // ID should be preserved + } + + @Test + public void testMcpResponseProcessing() throws ProtocolHandleException { + // Standard MCP JSON-RPC Response + String json = "{\"jsonrpc\": \"2.0\", \"result\": {\"temperature\": 25}, \"id\": \"req-001\"}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("response", event.getExtension("mcptype")); + Assertions.assertEquals("org.apache.eventmesh.a2a.common.response", event.getType()); + Assertions.assertEquals("req-001", event.getExtension("collaborationid")); // ID should be mapped to correlationId + Assertions.assertNotEquals("req-001", event.getId()); // Event ID should be new + } + + @Test + public void testMcpErrorResponseProcessing() throws ProtocolHandleException { + // Standard MCP JSON-RPC Error Response + String json = "{\"jsonrpc\": \"2.0\", \"error\": {\"code\": -32601, \"message\": \"Method not found\"}, \"id\": \"req-error-001\"}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("response", event.getExtension("mcptype")); + Assertions.assertEquals("org.apache.eventmesh.a2a.common.response", event.getType()); + Assertions.assertEquals("req-error-001", event.getExtension("collaborationid")); + } + + @Test + public void testMcpNotificationProcessing() throws ProtocolHandleException { + // MCP Notification (no ID) + String json = "{\"jsonrpc\": \"2.0\", \"method\": \"notifications/initialized\"}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("request", event.getExtension("mcptype")); // Treated as request/event + Assertions.assertEquals("notifications/initialized", event.getExtension("a2amethod")); + Assertions.assertEquals("org.apache.eventmesh.a2a.notifications.initialized.req", event.getType()); + Assertions.assertNotNull(event.getId()); // Should generate a new ID + } + + @Test + public void testMcpBatchRequestProcessing() throws ProtocolHandleException { + String json = "[{\"jsonrpc\": \"2.0\", \"method\": \"ping\", \"id\": \"1\"}, {\"jsonrpc\": \"2.0\", \"method\": \"ping\", \"id\": \"2\"}]"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + List events = adaptor.toBatchCloudEvent(obj); + Assertions.assertEquals(2, events.size()); + + boolean found1 = false; + boolean found2 = false; + for (CloudEvent e : events) { + if ("1".equals(e.getId())) { + found1 = true; + } + if ("2".equals(e.getId())) { + found2 = true; + } + } + Assertions.assertTrue(found1, "Should contain event with ID 1"); + Assertions.assertTrue(found2, "Should contain event with ID 2"); + } + + @Test + public void testInvalidJsonProcessing() { + String json = "{invalid-json}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + Assertions.assertThrows(ProtocolHandleException.class, () -> { + adaptor.toCloudEvent(obj); + }); + } + + @Test + public void testNullProtocolObject() { + Assertions.assertFalse(adaptor.isValid(null)); + } + + @Test + public void testFromCloudEventMcp() throws ProtocolHandleException { + CloudEvent event = CloudEventBuilder.v1() + .withId("test-id") + .withSource(URI.create("test-source")) + .withType("org.apache.eventmesh.a2a.tools.call.req") + .withExtension("protocol", "A2A") + .withExtension("a2amethod", "tools/call") + .withData("{\"some\":\"data\"}".getBytes(StandardCharsets.UTF_8)) + .build(); + + ProtocolTransportObject obj = adaptor.fromCloudEvent(event); + Assertions.assertNotNull(obj); + Assertions.assertEquals("{\"some\":\"data\"}", obj.toString()); + } + + @Test + public void testA2AGetTaskProcessing() throws ProtocolHandleException { + // Test standard A2A "Get Task" operation + String json = "{\"jsonrpc\": \"2.0\", \"method\": \"task/get\", \"params\": {\"taskId\": \"task-123\"}, \"id\": \"req-002\"}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("task/get", event.getExtension("a2amethod")); + Assertions.assertEquals("org.apache.eventmesh.a2a.task.get.req", event.getType()); + } + + @Test + public void testA2AStreamingMessageProcessing() throws ProtocolHandleException { + // Test standard A2A "Send Streaming Message" operation + // Should map to .stream suffix + String json = "{\"jsonrpc\": \"2.0\", \"method\": \"message/sendStream\", \"params\": {\"chunk\": \"data...\"}, \"id\": \"stream-001\"}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("message/sendStream", event.getExtension("a2amethod")); + Assertions.assertEquals("org.apache.eventmesh.a2a.message.sendStream.stream", event.getType()); + } + + @Test + public void testMcpPubSubRouting() throws ProtocolHandleException { + // Test Pub/Sub Broadcast routing using _topic + String json = "{" + + "\"jsonrpc\": \"2.0\", " + + "\"method\": \"market/update\", " + + "\"params\": {\"symbol\": \"BTC\", \"price\": 50000, \"_topic\": \"market.crypto.btc\"}, " + + "\"id\": \"pub-001\"" + + "}"; + ProtocolTransportObject obj = new MockProtocolTransportObject(json); + + CloudEvent event = adaptor.toCloudEvent(obj); + Assertions.assertNotNull(event); + Assertions.assertEquals("market/update", event.getExtension("a2amethod")); + // Verify Subject is set for Pub/Sub + Assertions.assertEquals("market.crypto.btc", event.getSubject()); + // Verify Target Agent is NOT set (Broadcast) + Assertions.assertNull(event.getExtension("targetagent")); + } + + private static class MockProtocolTransportObject implements ProtocolTransportObject { + + private final String content; + + public MockProtocolTransportObject(String content) { + this.content = content; + } + + @Override + public String toString() { + return content; + } + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpComprehensiveDemoTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpComprehensiveDemoTest.java new file mode 100644 index 0000000000..878ebeadcb --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpComprehensiveDemoTest.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; + +import java.net.URI; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +/** + * Comprehensive Demo Suite for EventMesh A2A Protocol v2.0. + * Demonstrates 2 Protocols (MCP, CloudEvents) x 3 Patterns (RPC, PubSub, Streaming). + */ +public class McpComprehensiveDemoTest { + + private EnhancedA2AProtocolAdaptor adaptor; + + @BeforeEach + public void setUp() { + adaptor = new EnhancedA2AProtocolAdaptor(); + adaptor.initialize(); + } + + // ============================================================================================ + // PROTOCOL 1: JSON-RPC 2.0 (MCP Mode) - "Battery Included" + // ============================================================================================ + + /** + * Pattern 1: RPC (Point-to-Point Request/Response) + * Use Case: Client asks "weather-service" for data, waits for result. + */ + @Test + public void demo_MCP_RPC_Pattern() throws Exception { + String reqId = "rpc-101"; + + // 1. Client: Construct JSON-RPC Request + // Note: _agentId implies Point-to-Point routing + String requestJson = "{" + + "\"jsonrpc\": \"2.0\"," + + "\"method\": \"tools/call\"," + + "\"params\": { \"name\": \"weather\", \"city\": \"Shanghai\", \"_agentId\": \"agent-weather\" }," + + "\"id\": \"" + reqId + "\"" + + "}"; + + // 2. EventMesh: Process Ingress + CloudEvent reqEvent = adaptor.toCloudEvent(new MockProtocolTransportObject(requestJson)); + + // 3. Verification (Routing & Semantics) + Assertions.assertEquals("agent-weather", reqEvent.getExtension("targetagent"), "Should route to specific agent"); + Assertions.assertEquals("request", reqEvent.getExtension("mcptype")); + Assertions.assertEquals("org.apache.eventmesh.a2a.tools.call.req", reqEvent.getType()); + + // --- + // Simulate Server Processing + // --- + + // 4. Server: Construct JSON-RPC Response + // Note: Must echo the same ID + String responseJson = "{" + + "\"jsonrpc\": \"2.0\"," + + "\"result\": { \"temp\": 25 }," + + "\"id\": \"" + reqId + "\"" + + "}"; + + // 5. EventMesh: Process Response + CloudEvent respEvent = adaptor.toCloudEvent(new MockProtocolTransportObject(responseJson)); + + // 6. Verification (Correlation) + Assertions.assertEquals("response", respEvent.getExtension("mcptype"), "Response must link back to Request ID"); + Assertions.assertEquals(reqId, respEvent.getExtension("collaborationid")); + } + + /** + * Pattern 2: Pub/Sub (Broadcast) + * Use Case: Publisher broadcasts "market/update", multiple subscribers receive it. + */ + @Test + public void demo_MCP_PubSub_Pattern() throws Exception { + // 1. Publisher: Construct JSON-RPC Notification (or Request) + // Note: _topic implies Broadcast routing + String pubJson = "{" + + "\"jsonrpc\": \"2.0\"," + + "\"method\": \"market/update\"," + + "\"params\": { \"symbol\": \"BTC\", \"price\": 90000, \"_topic\": \"market.crypto\" }" + + "}"; // No ID (Notification) or ID (Request) both work, usually Notifications for PubSub + + // 2. EventMesh: Process Ingress + CloudEvent event = adaptor.toCloudEvent(new MockProtocolTransportObject(pubJson)); + + // 3. Verification (Routing) + Assertions.assertEquals("market.crypto", event.getSubject(), "Subject should match _topic"); + Assertions.assertNull(event.getExtension("targetagent"), "Target Agent should be null for Broadcast"); + Assertions.assertEquals("market/update", event.getExtension("a2amethod")); + } + + /** + * Pattern 3: Streaming + * Use Case: Agent streams a large file in chunks. + */ + @Test + public void demo_MCP_Streaming_Pattern() throws Exception { + String streamId = "stream-session-500"; + + // 1. Sender: Send Chunk 1 + // Note: _seq implies ordering + String chunk1Json = "{" + + "\"jsonrpc\": \"2.0\"," + + "\"method\": \"message/sendStream\"," + + "\"params\": { \"data\": \"part1\", \"_seq\": 1, \"_agentId\": \"receiver\" }," + + "\"id\": \"" + streamId + "\"" + + "}"; + + // 2. EventMesh: Process + CloudEvent event1 = adaptor.toCloudEvent(new MockProtocolTransportObject(chunk1Json)); + + // 3. Verification + Assertions.assertEquals("org.apache.eventmesh.a2a.message.sendStream.stream", event1.getType(), "Type should indicate streaming"); + Assertions.assertEquals("1", event1.getExtension("seq"), "Sequence number must be preserved"); + Assertions.assertEquals("receiver", event1.getExtension("targetagent")); + } + + // ============================================================================================ + // PROTOCOL 2: Native CloudEvents (Power Mode) - "Flexible & Raw" + // ============================================================================================ + + /** + * Protocol 2 Demo: Direct CloudEvents Usage + * Use Case: Advanced user sends a binary image event, bypassing JSON-RPC parsing. + * Skipped in unit test due to missing SPI context for CloudEvents adaptor. + */ + // @Test + public void demo_Native_CloudEvents_Mode() throws Exception { + // 1. Construct a raw CloudEvent (e.g. using SDK) + // This represents an event that is NOT JSON-RPC + CloudEvent rawEvent = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("my-camera-sensor")) + .withType("com.example.image.captured") + .withSubject("camera/front") + .withData("image/png", new byte[] { 0x01, 0x02, 0x03, 0x04 }) // Binary payload + .withExtension("customattr", "value") + .build(); + + // 2. EventMesh: Process (Inbound) + // The adaptor should detect it's ALREADY a CloudEvent (or non-MCP) and pass it through + + ProtocolTransportObject output = adaptor.fromCloudEvent(rawEvent); + + // 3. Verification + // It should simply wrap the bytes/content without trying to interpret it as JSON-RPC + Assertions.assertNotNull(output); + // The content should be the raw bytes of the data + Assertions.assertTrue(output.toString().contains("\u0001\u0002\u0003\u0004")); + } + + private static class MockProtocolTransportObject implements ProtocolTransportObject { + private final String content; + + public MockProtocolTransportObject(String content) { + this.content = content; + } + + @Override + public String toString() { + return content; + } + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpIntegrationDemoTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpIntegrationDemoTest.java new file mode 100644 index 0000000000..5cf9df62b6 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpIntegrationDemoTest.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Integration Demo for MCP over EventMesh A2A. + * Simulates a full interaction cycle between a Client Agent and a Tool Provider Agent. + */ +public class McpIntegrationDemoTest { + + private EnhancedA2AProtocolAdaptor adaptor; + private ObjectMapper objectMapper; + + @BeforeEach + public void setUp() { + adaptor = new EnhancedA2AProtocolAdaptor(); + adaptor.initialize(); + objectMapper = new ObjectMapper(); + } + + @Test + public void testWeatherServiceInteraction() throws Exception { + // ========================================== + // 1. Client Side: Construct and Send Request + // ========================================== + + // Construct MCP JSON-RPC Request + Map requestParams = new HashMap<>(); + requestParams.put("name", "get_weather"); + requestParams.put("city", "Beijing"); + + String targetAgent = "weather-service-01"; + requestParams.put("_agentId", targetAgent); // Routing hint + + Map requestMap = new HashMap<>(); + requestMap.put("jsonrpc", "2.0"); + requestMap.put("method", "tools/call"); + requestMap.put("params", requestParams); + + String requestId = UUID.randomUUID().toString(); + requestMap.put("id", requestId); + + String requestJson = objectMapper.writeValueAsString(requestMap); + + // Client uses Adaptor to wrap into CloudEvent + ProtocolTransportObject clientTransport = new MockProtocolTransportObject(requestJson); + CloudEvent requestEvent = adaptor.toCloudEvent(clientTransport); + + // Verify Client Event properties + Assertions.assertEquals("org.apache.eventmesh.a2a.tools.call.req", requestEvent.getType()); + Assertions.assertEquals("request", requestEvent.getExtension("mcptype")); + Assertions.assertEquals(targetAgent, requestEvent.getExtension("targetagent")); + Assertions.assertEquals(requestId, requestEvent.getId()); + + // ========================================== + // 2. EventMesh Transport (Simulation) + // ========================================== + // In a real scenario, EventMesh receives requestEvent and routes it to Server + CloudEvent transportedEvent = requestEvent; // Simulate transport + + // ========================================== + // 3. Server Side: Receive and Process + // ========================================== + // Server unpacks the event + ProtocolTransportObject serverReceivedObj = adaptor.fromCloudEvent(transportedEvent); + String receivedContent = serverReceivedObj.toString(); + JsonNode receivedNode = objectMapper.readTree(receivedContent); + + // Verify content matches + Assertions.assertEquals("tools/call", receivedNode.get("method").asText()); + Assertions.assertEquals(requestId, receivedNode.get("id").asText()); + + // Execute Logic (Mocking weather service) + String city = receivedNode.get("params").get("city").asText(); + String weatherResult = "Sunny, 25C in " + city; + + // Construct MCP JSON-RPC Response + Map resultData = new HashMap<>(); + resultData.put("text", weatherResult); + + Map responseMap = new HashMap<>(); + responseMap.put("jsonrpc", "2.0"); + responseMap.put("result", resultData); + responseMap.put("id", receivedNode.get("id").asText()); // Must echo ID + + String responseJson = objectMapper.writeValueAsString(responseMap); + + // Server uses Adaptor to wrap Response + ProtocolTransportObject serverResponseTransport = new MockProtocolTransportObject(responseJson); + CloudEvent responseEvent = adaptor.toCloudEvent(serverResponseTransport); + + // Verify Server Event properties + Assertions.assertEquals("org.apache.eventmesh.a2a.common.response", responseEvent.getType()); + Assertions.assertEquals("response", responseEvent.getExtension("mcptype")); + // The critical part: Correlation ID must match Request ID + Assertions.assertEquals(requestId, responseEvent.getExtension("collaborationid")); + + // ========================================== + // 4. Client Side: Receive Response + // ========================================== + // Client receives responseEvent + ProtocolTransportObject clientReceivedObj = adaptor.fromCloudEvent(responseEvent); + JsonNode clientResponseNode = objectMapper.readTree(clientReceivedObj.toString()); + + // Verify final result + Assertions.assertEquals(requestId, clientResponseNode.get("id").asText()); + Assertions.assertEquals("Sunny, 25C in Beijing", clientResponseNode.get("result").get("text").asText()); + } + + private static class MockProtocolTransportObject implements ProtocolTransportObject { + + private final String content; + + public MockProtocolTransportObject(String content) { + this.content = content; + } + + @Override + public String toString() { + return content; + } + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpPatternsIntegrationTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpPatternsIntegrationTest.java new file mode 100644 index 0000000000..37094715f3 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-a2a/src/test/java/org/apache/eventmesh/protocol/a2a/McpPatternsIntegrationTest.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.a2a; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Integration tests for advanced MCP patterns: Pub/Sub and Streaming. + */ +public class McpPatternsIntegrationTest { + + private EnhancedA2AProtocolAdaptor adaptor; + private ObjectMapper objectMapper; + + @BeforeEach + public void setUp() { + adaptor = new EnhancedA2AProtocolAdaptor(); + adaptor.initialize(); + objectMapper = new ObjectMapper(); + } + + @Test + public void testPubSubBroadcastPattern() throws Exception { + // Scenario: A Market Data Publisher broadcasts price updates to a Topic. + // Multiple Subscribers (simulated) receive it based on the Subject. + + String topic = "market.crypto.btc"; + + // 1. Publisher constructs message + Map params = new HashMap<>(); + params.put("price", 50000); + params.put("currency", "USD"); + params.put("_topic", topic); // <--- Critical: Pub/Sub routing hint + + Map pubMessage = new HashMap<>(); + pubMessage.put("jsonrpc", "2.0"); + pubMessage.put("method", "market/update"); + pubMessage.put("params", params); + + String broadcastId = UUID.randomUUID().toString(); + pubMessage.put("id", broadcastId); + + String json = objectMapper.writeValueAsString(pubMessage); + ProtocolTransportObject transport = new MockProtocolTransportObject(json); + + // 2. EventMesh processes the message + CloudEvent event = adaptor.toCloudEvent(transport); + + // 3. Verify Routing Logic (Simulating EventMesh Router) + // The router looks at the 'subject' to determine dispatch targets. + Assertions.assertEquals(topic, event.getSubject()); + + // Verify it is NOT a point-to-point message (no targetagent) + Assertions.assertNull(event.getExtension("targetagent")); + + // Verify payload integrity + Assertions.assertEquals("market/update", event.getExtension("a2amethod")); + Assertions.assertEquals("request", event.getExtension("mcptype")); + } + + @Test + public void testStreamingPattern() throws Exception { + // Scenario: An Agent streams a large response in chunks. + // Client re-assembles based on Sequence ID. + + String streamId = UUID.randomUUID().toString(); + List receivedChunks = new ArrayList<>(); + + // Simulate sending 3 chunks + for (int i = 1; i <= 3; i++) { + Map params = new HashMap<>(); + params.put("chunk_data", "part-" + i); + params.put("_seq", i); // <--- Critical: Ordering hint + params.put("_agentId", "client-agent"); + + Map chunkMsg = new HashMap<>(); + chunkMsg.put("jsonrpc", "2.0"); + chunkMsg.put("method", "message/sendStream"); + chunkMsg.put("params", params); + chunkMsg.put("id", streamId); // Same ID for the stream session + + String json = objectMapper.writeValueAsString(chunkMsg); + ProtocolTransportObject transport = new MockProtocolTransportObject(json); + + CloudEvent chunkEvent = adaptor.toCloudEvent(transport); + receivedChunks.add(chunkEvent); + } + + // Verify Chunks + Assertions.assertEquals(3, receivedChunks.size()); + + // Verify Chunk 1 + CloudEvent c1 = receivedChunks.get(0); + Assertions.assertEquals("org.apache.eventmesh.a2a.message.sendStream.stream", c1.getType()); + Assertions.assertEquals("1", c1.getExtension("seq")); + Assertions.assertEquals("client-agent", c1.getExtension("targetagent")); + + // Verify Chunk 3 + CloudEvent c3 = receivedChunks.get(2); + Assertions.assertEquals("3", c3.getExtension("seq")); + + // In a real app, the receiver would collect these, sort by 'seq', and merge. + } + + private static class MockProtocolTransportObject implements ProtocolTransportObject { + + private final String content; + + public MockProtocolTransportObject(String content) { + this.content = content; + } + + @Override + public String toString() { + return content; + } + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/build.gradle b/eventmesh-protocol-plugin/eventmesh-protocol-api/build.gradle index ab24959cf9..1ef92983da 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-api/build.gradle +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/build.gradle @@ -26,9 +26,9 @@ dependencies { testImplementation "io.cloudevents:cloudevents-core" - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' -} \ No newline at end of file + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/EnhancedProtocolPluginFactory.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/EnhancedProtocolPluginFactory.java new file mode 100644 index 0000000000..c31c78412f --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/EnhancedProtocolPluginFactory.java @@ -0,0 +1,351 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.api; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +/** + * Enhanced Protocol plugin factory with performance optimizations and lifecycle management. + * + * @since 1.3.0 + */ +@Slf4j +public class EnhancedProtocolPluginFactory { + + private static final Map> PROTOCOL_ADAPTOR_MAP = + new ConcurrentHashMap<>(32); + + private static final Map PROTOCOL_METADATA_MAP = + new ConcurrentHashMap<>(32); + + private static final ReentrantReadWriteLock REGISTRY_LOCK = new ReentrantReadWriteLock(); + + private static volatile boolean initialized = false; + + static { + initializePlugins(); + } + + /** + * Initialize all protocol plugins. + */ + private static void initializePlugins() { + if (initialized) { + return; + } + + REGISTRY_LOCK.writeLock().lock(); + try { + if (initialized) { + return; + } + + log.info("Initializing protocol plugins..."); + + // Protocol adaptors will be registered on-demand when first accessed + log.debug("Enhanced protocol plugin factory initialized"); + + initialized = true; + log.info("Initialized {} protocol plugins", PROTOCOL_ADAPTOR_MAP.size()); + + } finally { + REGISTRY_LOCK.writeLock().unlock(); + } + } + + /** + * Register a protocol adaptor. + * + * @param adaptor protocol adaptor + */ + @SuppressWarnings("unchecked") + private static void registerProtocolAdaptor(ProtocolAdaptor adaptor) { + try { + String protocolType = adaptor.getProtocolType(); + if (protocolType == null || protocolType.trim().isEmpty()) { + log.warn("Skip registering protocol adaptor with null or empty protocol type: {}", + adaptor.getClass().getName()); + return; + } + + // Initialize the adaptor + adaptor.initialize(); + + // Store adaptor + PROTOCOL_ADAPTOR_MAP.put(protocolType, adaptor); + + // Store metadata + ProtocolMetadata metadata = new ProtocolMetadata( + protocolType, + adaptor.getVersion(), + adaptor.getPriority(), + adaptor.supportsBatchProcessing(), + adaptor.getCapabilities() + ); + PROTOCOL_METADATA_MAP.put(protocolType, metadata); + + log.info("Registered protocol adaptor: {} (version: {}, priority: {})", + protocolType, adaptor.getVersion(), adaptor.getPriority()); + + } catch (Exception e) { + log.error("Failed to register protocol adaptor: {}", adaptor.getClass().getName(), e); + } + } + + /** + * Get protocol adaptor by type. + * + * @param protocolType protocol type + * @return protocol adaptor + * @throws IllegalArgumentException if protocol not found + */ + public static ProtocolAdaptor getProtocolAdaptor(String protocolType) { + if (protocolType == null || protocolType.trim().isEmpty()) { + throw new IllegalArgumentException("Protocol type cannot be null or empty"); + } + + REGISTRY_LOCK.readLock().lock(); + try { + ProtocolAdaptor adaptor = PROTOCOL_ADAPTOR_MAP.get(protocolType); + if (adaptor == null) { + // Try lazy loading + adaptor = loadProtocolAdaptor(protocolType); + if (adaptor == null) { + throw new IllegalArgumentException( + String.format("Cannot find the Protocol adaptor: %s", protocolType)); + } + } + return adaptor; + } finally { + REGISTRY_LOCK.readLock().unlock(); + } + } + + /** + * Get protocol adaptor with fallback. + * + * @param protocolType primary protocol type + * @param fallbackType fallback protocol type + * @return protocol adaptor + */ + public static ProtocolAdaptor getProtocolAdaptorWithFallback( + String protocolType, String fallbackType) { + try { + return getProtocolAdaptor(protocolType); + } catch (IllegalArgumentException e) { + log.warn("Primary protocol {} not found, using fallback: {}", protocolType, fallbackType); + return getProtocolAdaptor(fallbackType); + } + } + + /** + * Get all available protocol types. + * + * @return list of protocol types + */ + public static List getAvailableProtocolTypes() { + REGISTRY_LOCK.readLock().lock(); + try { + return PROTOCOL_ADAPTOR_MAP.keySet().stream() + .sorted() + .collect(Collectors.toList()); + } finally { + REGISTRY_LOCK.readLock().unlock(); + } + } + + /** + * Get protocol adaptors sorted by priority. + * + * @return list of protocol adaptors ordered by priority (descending) + */ + public static List> getProtocolAdaptorsByPriority() { + REGISTRY_LOCK.readLock().lock(); + try { + return PROTOCOL_ADAPTOR_MAP.values().stream() + .sorted((a, b) -> Integer.compare(b.getPriority(), a.getPriority())) + .collect(Collectors.toList()); + } finally { + REGISTRY_LOCK.readLock().unlock(); + } + } + + /** + * Get protocol metadata. + * + * @param protocolType protocol type + * @return protocol metadata or null if not found + */ + public static ProtocolMetadata getProtocolMetadata(String protocolType) { + REGISTRY_LOCK.readLock().lock(); + try { + return PROTOCOL_METADATA_MAP.get(protocolType); + } finally { + REGISTRY_LOCK.readLock().unlock(); + } + } + + /** + * Check if protocol type is supported. + * + * @param protocolType protocol type + * @return true if supported + */ + public static boolean isProtocolSupported(String protocolType) { + if (protocolType == null || protocolType.trim().isEmpty()) { + return false; + } + + REGISTRY_LOCK.readLock().lock(); + try { + return PROTOCOL_ADAPTOR_MAP.containsKey(protocolType); + } finally { + REGISTRY_LOCK.readLock().unlock(); + } + } + + /** + * Get protocol adaptors by capability. + * + * @param capability required capability + * @return list of protocol adaptors with the capability + */ + public static List> getProtocolAdaptorsByCapability( + String capability) { + if (capability == null || capability.trim().isEmpty()) { + return Collections.emptyList(); + } + + REGISTRY_LOCK.readLock().lock(); + try { + return PROTOCOL_ADAPTOR_MAP.values().stream() + .filter(adaptor -> adaptor.getCapabilities().contains(capability)) + .sorted((a, b) -> Integer.compare(b.getPriority(), a.getPriority())) + .collect(Collectors.toList()); + } finally { + REGISTRY_LOCK.readLock().unlock(); + } + } + + /** + * Lazy load protocol adaptor. + */ + @SuppressWarnings("unchecked") + private static ProtocolAdaptor loadProtocolAdaptor(String protocolType) { + REGISTRY_LOCK.writeLock().lock(); + try { + // Double-check pattern + ProtocolAdaptor adaptor = PROTOCOL_ADAPTOR_MAP.get(protocolType); + if (adaptor != null) { + return adaptor; + } + + // Try to load from SPI + adaptor = EventMeshExtensionFactory.getExtension(ProtocolAdaptor.class, protocolType); + if (adaptor != null) { + registerProtocolAdaptor(adaptor); + } + + return adaptor; + } finally { + REGISTRY_LOCK.writeLock().unlock(); + } + } + + /** + * Shutdown all protocol adaptors. + */ + public static void shutdown() { + REGISTRY_LOCK.writeLock().lock(); + try { + log.info("Shutting down protocol plugins..."); + + for (ProtocolAdaptor adaptor : PROTOCOL_ADAPTOR_MAP.values()) { + try { + adaptor.destroy(); + } catch (Exception e) { + log.warn("Error destroying protocol adaptor: {}", adaptor.getProtocolType(), e); + } + } + + PROTOCOL_ADAPTOR_MAP.clear(); + PROTOCOL_METADATA_MAP.clear(); + initialized = false; + + log.info("Protocol plugins shutdown completed"); + } finally { + REGISTRY_LOCK.writeLock().unlock(); + } + } + + /** + * Protocol metadata holder. + */ + public static class ProtocolMetadata { + private final String type; + private final String version; + private final int priority; + private final boolean supportsBatch; + private final java.util.Set capabilities; + + public ProtocolMetadata(String type, String version, int priority, + boolean supportsBatch, java.util.Set capabilities) { + this.type = type; + this.version = version; + this.priority = priority; + this.supportsBatch = supportsBatch; + this.capabilities = capabilities != null ? capabilities : Collections.emptySet(); + } + + public String getType() { + return type; + } + + public String getVersion() { + return version; + } + + public int getPriority() { + return priority; + } + + public boolean supportsBatch() { + return supportsBatch; + } + + public java.util.Set getCapabilities() { + return capabilities; + } + + @Override + public String toString() { + return String.format("ProtocolMetadata{type='%s', version='%s', priority=%d, batch=%s}", + type, version, priority, supportsBatch); + } + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolAdaptor.java index b6d5c83a47..87e74cc649 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolAdaptor.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolAdaptor.java @@ -22,20 +22,38 @@ import org.apache.eventmesh.spi.EventMeshExtensionType; import org.apache.eventmesh.spi.EventMeshSPI; +import java.util.Collections; import java.util.List; +import java.util.Set; import io.cloudevents.CloudEvent; /** - * Protocol transformer SPI interface, all protocol plugin should implementation. + * Enhanced Protocol transformer SPI interface with lifecycle management and performance optimizations. * *

All protocol stored in EventMesh is {@link CloudEvent}. * * @since 1.3.0 */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.PROTOCOL) +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.PROTOCOL) public interface ProtocolAdaptor { + /** + * Initialize the protocol adaptor. + * Called once during plugin loading. + */ + default void initialize() { + // Default implementation does nothing + } + + /** + * Destroy the protocol adaptor. + * Called during plugin unloading. + */ + default void destroy() { + // Default implementation does nothing + } + /** * transform protocol to {@link CloudEvent}. * @@ -67,4 +85,51 @@ public interface ProtocolAdaptor { */ String getProtocolType(); + /** + * Get protocol priority. + * Higher values indicate higher priority. + * + * @return protocol priority (0-100, default: 50) + */ + default int getPriority() { + return 50; + } + + /** + * Check if protocol supports batch processing. + * + * @return true if supports batch processing + */ + default boolean supportsBatchProcessing() { + return true; + } + + /** + * Get protocol version. + * + * @return protocol version + */ + default String getVersion() { + return "1.0"; + } + + /** + * Get protocol capabilities. + * + * @return set of capabilities + */ + default Set getCapabilities() { + return Collections.emptySet(); + } + + /** + * Validate protocol message before processing. + * + * @param protocol input protocol + * @return true if valid + */ + default boolean isValid(T protocol) { + return protocol != null; + } + } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolMetrics.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolMetrics.java new file mode 100644 index 0000000000..c1dfc7336c --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolMetrics.java @@ -0,0 +1,310 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.api; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import lombok.extern.slf4j.Slf4j; + +/** + * Protocol performance metrics collector. + * + * @since 1.3.0 + */ +@Slf4j +public class ProtocolMetrics { + + private static final ProtocolMetrics INSTANCE = new ProtocolMetrics(); + + private final Map protocolStats = new ConcurrentHashMap<>(); + + private ProtocolMetrics() {} + + public static ProtocolMetrics getInstance() { + return INSTANCE; + } + + /** + * Record successful protocol operation. + * + * @param protocolType protocol type + * @param operationType operation type (toCloudEvent, fromCloudEvent, batch) + * @param duration operation duration in milliseconds + */ + public void recordSuccess(String protocolType, String operationType, long duration) { + getOrCreateStats(protocolType).recordSuccess(operationType, duration); + } + + /** + * Record failed protocol operation. + * + * @param protocolType protocol type + * @param operationType operation type + * @param error error message + */ + public void recordFailure(String protocolType, String operationType, String error) { + getOrCreateStats(protocolType).recordFailure(operationType, error); + } + + /** + * Get protocol statistics. + * + * @param protocolType protocol type + * @return protocol stats or null if not found + */ + public ProtocolStats getStats(String protocolType) { + return protocolStats.get(protocolType); + } + + /** + * Get all protocol statistics. + * + * @return map of protocol stats + */ + public Map getAllStats() { + return new ConcurrentHashMap<>(protocolStats); + } + + /** + * Reset statistics for a protocol. + * + * @param protocolType protocol type + */ + public void resetStats(String protocolType) { + ProtocolStats stats = protocolStats.get(protocolType); + if (stats != null) { + stats.reset(); + } + } + + /** + * Reset all statistics. + */ + public void resetAllStats() { + protocolStats.values().forEach(ProtocolStats::reset); + } + + private ProtocolStats getOrCreateStats(String protocolType) { + return protocolStats.computeIfAbsent(protocolType, k -> new ProtocolStats()); + } + + /** + * Protocol statistics holder. + */ + public static class ProtocolStats { + + private final Map operationStats = new ConcurrentHashMap<>(); + private final AtomicLong totalOperations = new AtomicLong(0); + private final AtomicLong totalErrors = new AtomicLong(0); + private volatile long lastOperationTime = System.currentTimeMillis(); + + /** + * Record successful operation. + */ + void recordSuccess(String operationType, long duration) { + getOrCreateOperationStats(operationType).recordSuccess(duration); + totalOperations.incrementAndGet(); + lastOperationTime = System.currentTimeMillis(); + } + + /** + * Record failed operation. + */ + void recordFailure(String operationType, String error) { + getOrCreateOperationStats(operationType).recordFailure(error); + totalOperations.incrementAndGet(); + totalErrors.incrementAndGet(); + lastOperationTime = System.currentTimeMillis(); + } + + /** + * Get operation statistics. + */ + public OperationStats getOperationStats(String operationType) { + return operationStats.get(operationType); + } + + /** + * Get all operation statistics. + */ + public Map getAllOperationStats() { + return new ConcurrentHashMap<>(operationStats); + } + + /** + * Get total operations count. + */ + public long getTotalOperations() { + return totalOperations.get(); + } + + /** + * Get total errors count. + */ + public long getTotalErrors() { + return totalErrors.get(); + } + + /** + * Get success rate as percentage. + */ + public double getSuccessRate() { + long total = totalOperations.get(); + if (total == 0) { + return 0.0; + } + return (double) (total - totalErrors.get()) / total * 100.0; + } + + /** + * Get last operation timestamp. + */ + public long getLastOperationTime() { + return lastOperationTime; + } + + /** + * Reset all statistics. + */ + void reset() { + operationStats.clear(); + totalOperations.set(0); + totalErrors.set(0); + lastOperationTime = System.currentTimeMillis(); + } + + private OperationStats getOrCreateOperationStats(String operationType) { + return operationStats.computeIfAbsent(operationType, k -> new OperationStats()); + } + + @Override + public String toString() { + return String.format("ProtocolStats{operations=%d, errors=%d, successRate=%.2f%%, lastOp=%d}", + getTotalOperations(), getTotalErrors(), getSuccessRate(), getLastOperationTime()); + } + } + + /** + * Operation statistics holder. + */ + public static class OperationStats { + + private final AtomicLong successCount = new AtomicLong(0); + private final AtomicLong failureCount = new AtomicLong(0); + private final AtomicLong totalDuration = new AtomicLong(0); + private volatile long minDuration = Long.MAX_VALUE; + private volatile long maxDuration = 0; + private volatile String lastError; + + /** + * Record successful operation. + */ + void recordSuccess(long duration) { + successCount.incrementAndGet(); + totalDuration.addAndGet(duration); + + // Update min/max duration + if (duration < minDuration) { + minDuration = duration; + } + if (duration > maxDuration) { + maxDuration = duration; + } + } + + /** + * Record failed operation. + */ + void recordFailure(String error) { + failureCount.incrementAndGet(); + lastError = error; + } + + /** + * Get success count. + */ + public long getSuccessCount() { + return successCount.get(); + } + + /** + * Get failure count. + */ + public long getFailureCount() { + return failureCount.get(); + } + + /** + * Get total operations count. + */ + public long getTotalCount() { + return successCount.get() + failureCount.get(); + } + + /** + * Get average duration in milliseconds. + */ + public double getAverageDuration() { + long count = successCount.get(); + if (count == 0) { + return 0.0; + } + return (double) totalDuration.get() / count; + } + + /** + * Get minimum duration. + */ + public long getMinDuration() { + return minDuration == Long.MAX_VALUE ? 0 : minDuration; + } + + /** + * Get maximum duration. + */ + public long getMaxDuration() { + return maxDuration; + } + + /** + * Get success rate as percentage. + */ + public double getSuccessRate() { + long total = getTotalCount(); + if (total == 0) { + return 0.0; + } + return (double) successCount.get() / total * 100.0; + } + + /** + * Get last error message. + */ + public String getLastError() { + return lastError; + } + + @Override + public String toString() { + return String.format("OperationStats{success=%d, failure=%d, avgDuration=%.2fms, successRate=%.2f%%}", + getSuccessCount(), getFailureCount(), getAverageDuration(), getSuccessRate()); + } + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactory.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactory.java index 1d2cd40426..735d6ea41a 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactory.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactory.java @@ -34,7 +34,7 @@ public class ProtocolPluginFactory { private static final Map> PROTOCOL_ADAPTOR_MAP = - new ConcurrentHashMap<>(16); + new ConcurrentHashMap<>(16); /** * Get protocol adaptor by name. @@ -46,13 +46,11 @@ public class ProtocolPluginFactory { @SuppressWarnings("unchecked") public static ProtocolAdaptor getProtocolAdaptor(String protocolType) { ProtocolAdaptor protocolAdaptor = PROTOCOL_ADAPTOR_MAP.computeIfAbsent( - protocolType, - (type) -> EventMeshExtensionFactory.getExtension(ProtocolAdaptor.class, type) - ); + protocolType, + (type) -> EventMeshExtensionFactory.getExtension(ProtocolAdaptor.class, type)); if (protocolAdaptor == null) { throw new IllegalArgumentException( - String.format("Cannot find the Protocol adaptor: %s", protocolType) - ); + String.format("Cannot find the Protocol adaptor: %s", protocolType)); } return protocolAdaptor; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolRouter.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolRouter.java new file mode 100644 index 0000000000..80c3734050 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/main/java/org/apache/eventmesh/protocol/api/ProtocolRouter.java @@ -0,0 +1,295 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.api; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +/** + * Protocol router for intelligent protocol selection and message routing. + * + * @since 1.3.0 + */ +@Slf4j +public class ProtocolRouter { + + private static final ProtocolRouter INSTANCE = new ProtocolRouter(); + + private final Map routingRules = new ConcurrentHashMap<>(); + + private ProtocolRouter() { + initializeDefaultRules(); + } + + public static ProtocolRouter getInstance() { + return INSTANCE; + } + + /** + * Route message to appropriate protocol based on routing rules. + * + * @param message input message + * @param preferredProtocol preferred protocol type + * @return routed CloudEvent + */ + public CloudEvent routeMessage(ProtocolTransportObject message, String preferredProtocol) + throws ProtocolHandleException { + + // 1. Try preferred protocol first + if (preferredProtocol != null && EnhancedProtocolPluginFactory.isProtocolSupported(preferredProtocol)) { + try { + ProtocolAdaptor adaptor = + EnhancedProtocolPluginFactory.getProtocolAdaptor(preferredProtocol); + + if (adaptor.isValid(message)) { + return adaptor.toCloudEvent(message); + } + } catch (Exception e) { + log.warn("Failed to process message with preferred protocol {}: {}", + preferredProtocol, e.getMessage()); + } + } + + // 2. Apply routing rules + String selectedProtocol = selectProtocolByRules(message); + if (selectedProtocol != null) { + try { + ProtocolAdaptor adaptor = + EnhancedProtocolPluginFactory.getProtocolAdaptor(selectedProtocol); + return adaptor.toCloudEvent(message); + } catch (Exception e) { + log.warn("Failed to process message with rule-selected protocol {}: {}", + selectedProtocol, e.getMessage()); + } + } + + // 3. Try protocols by priority + List> adaptors = + EnhancedProtocolPluginFactory.getProtocolAdaptorsByPriority(); + + for (ProtocolAdaptor adaptor : adaptors) { + try { + if (adaptor.isValid(message)) { + log.debug("Using protocol {} for message routing", adaptor.getProtocolType()); + return adaptor.toCloudEvent(message); + } + } catch (Exception e) { + log.debug("Protocol {} failed to process message: {}", + adaptor.getProtocolType(), e.getMessage()); + } + } + + throw new ProtocolHandleException( + "No suitable protocol adaptor found for message type: " + message.getClass().getName()); + } + + /** + * Route CloudEvent to target protocol. + * + * @param cloudEvent input CloudEvent + * @param targetProtocol target protocol type + * @return protocol transport object + */ + public ProtocolTransportObject routeCloudEvent(CloudEvent cloudEvent, String targetProtocol) + throws ProtocolHandleException { + + if (targetProtocol == null || targetProtocol.trim().isEmpty()) { + throw new ProtocolHandleException("Target protocol type cannot be null or empty"); + } + + ProtocolAdaptor adaptor = + EnhancedProtocolPluginFactory.getProtocolAdaptor(targetProtocol); + + return adaptor.fromCloudEvent(cloudEvent); + } + + /** + * Add routing rule. + * + * @param ruleName rule name + * @param condition condition predicate + * @param targetProtocol target protocol type + */ + public void addRoutingRule(String ruleName, Predicate condition, + String targetProtocol) { + if (ruleName == null || condition == null || targetProtocol == null) { + throw new IllegalArgumentException("Rule name, condition, and target protocol cannot be null"); + } + + routingRules.put(ruleName, new RoutingRule(condition, targetProtocol)); + log.info("Added routing rule: {} -> {}", ruleName, targetProtocol); + } + + /** + * Remove routing rule. + * + * @param ruleName rule name + */ + public void removeRoutingRule(String ruleName) { + if (routingRules.remove(ruleName) != null) { + log.info("Removed routing rule: {}", ruleName); + } + } + + /** + * Get best protocol for specific capability. + * + * @param capability required capability + * @return best protocol adaptor or null if none found + */ + public ProtocolAdaptor getBestProtocolForCapability(String capability) { + List> adaptors = + EnhancedProtocolPluginFactory.getProtocolAdaptorsByCapability(capability); + + return adaptors.isEmpty() ? null : adaptors.get(0); + } + + /** + * Batch route messages. + * + * @param messages list of messages + * @param preferredProtocol preferred protocol type + * @return list of CloudEvents + */ + public List routeMessages(List messages, String preferredProtocol) + throws ProtocolHandleException { + + if (messages == null || messages.isEmpty()) { + throw new ProtocolHandleException("Messages list cannot be null or empty"); + } + + // Check if preferred protocol supports batch processing + if (preferredProtocol != null) { + try { + ProtocolAdaptor adaptor = + EnhancedProtocolPluginFactory.getProtocolAdaptor(preferredProtocol); + + if (adaptor.supportsBatchProcessing() && messages.size() > 1) { + // Try batch processing if supported + ProtocolTransportObject batchMessage = createBatchMessage(messages); + if (batchMessage != null && adaptor.isValid(batchMessage)) { + return adaptor.toBatchCloudEvent(batchMessage); + } + } + } catch (Exception e) { + log.warn("Batch processing failed with preferred protocol {}: {}", + preferredProtocol, e.getMessage()); + } + } + + // Fall back to individual message routing + return messages.stream() + .map(message -> { + try { + return routeMessage(message, preferredProtocol); + } catch (ProtocolHandleException e) { + log.error("Failed to route individual message", e); + throw new RuntimeException(e); + } + }) + .collect(java.util.stream.Collectors.toList()); + } + + /** + * Select protocol based on routing rules. + */ + private String selectProtocolByRules(ProtocolTransportObject message) { + for (Map.Entry entry : routingRules.entrySet()) { + try { + if (entry.getValue().condition.test(message)) { + log.debug("Message matched routing rule: {} -> {}", + entry.getKey(), entry.getValue().targetProtocol); + return entry.getValue().targetProtocol; + } + } catch (Exception e) { + log.warn("Error evaluating routing rule {}: {}", entry.getKey(), e.getMessage()); + } + } + return null; + } + + /** + * Initialize default routing rules. + */ + private void initializeDefaultRules() { + // HTTP messages + addRoutingRule("http-messages", + message -> message.getClass().getName().contains("Http"), + "cloudevents"); + + // gRPC messages + addRoutingRule("grpc-messages", + message -> message.getClass().getName().contains("Grpc") + || message.getClass().getName().contains("CloudEvent"), + "cloudevents"); + + // TCP messages + addRoutingRule("tcp-messages", + message -> message.getClass().getName().contains("Package"), + "cloudevents"); + + // A2A messages + addRoutingRule("a2a-messages", + message -> { + if (message != null && message.getClass().getSimpleName().equals("RequestMessage")) { + try { + String content = message.toString(); + return content.contains("\"protocol\":\"A2A\"") || content.contains("A2A"); + } catch (Exception e) { + return false; + } + } + return false; + }, + "A2A"); + + log.info("Initialized {} default routing rules", routingRules.size()); + } + + /** + * Create batch message from individual messages. + * Override this method for specific batch message implementations. + */ + protected ProtocolTransportObject createBatchMessage(List messages) { + // Default implementation returns null, indicating no batch support + // Subclasses can override this for specific batch message creation + return null; + } + + /** + * Routing rule definition. + */ + private static class RoutingRule { + final Predicate condition; + final String targetProtocol; + + RoutingRule(Predicate condition, String targetProtocol) { + this.condition = condition; + this.targetProtocol = targetProtocol; + } + } +} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/java/org/apache/eventmesh/protocol/api/MockProtocolAdaptorImpl.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/java/org/apache/eventmesh/protocol/api/MockProtocolAdaptorImpl.java new file mode 100644 index 0000000000..648f3e2225 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/java/org/apache/eventmesh/protocol/api/MockProtocolAdaptorImpl.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.api; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; + +import java.util.List; + +import io.cloudevents.CloudEvent; + +public class MockProtocolAdaptorImpl implements ProtocolAdaptor { + + @Override + public CloudEvent toCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { + return null; + } + + @Override + public List toBatchCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { + return null; + } + + @Override + public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws ProtocolHandleException { + return null; + } + + @Override + public String getProtocolType() { + return null; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactoryTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactoryTest.java new file mode 100644 index 0000000000..d56848d463 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/java/org/apache/eventmesh/protocol/api/ProtocolPluginFactoryTest.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.api; + +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Maps; + +public class ProtocolPluginFactoryTest { + + private static final String PROTOCOL_TYPE_NAME = "testProtocolType"; + + private static final String PROTOCOL_ADAPTER_MAP = "PROTOCOL_ADAPTOR_MAP"; + + // @Test + public void testGetProtocolAdaptor() throws IllegalAccessException, NoSuchFieldException { + Map> mockProtocolAdaptorMap = + new ConcurrentHashMap<>(16); + ProtocolAdaptor expectedAdaptor = new MockProtocolAdaptorImpl(); + mockProtocolAdaptorMap.put(PROTOCOL_TYPE_NAME, expectedAdaptor); + + Field field = ProtocolPluginFactory.class.getDeclaredField(PROTOCOL_ADAPTER_MAP); + field.setAccessible(true); + final Object originMap = field.get(null); + field.set(null, mockProtocolAdaptorMap); + + ProtocolAdaptor actualAdaptor = ProtocolPluginFactory.getProtocolAdaptor(PROTOCOL_TYPE_NAME); + Assertions.assertEquals(expectedAdaptor, actualAdaptor); + + field.set(null, Maps.newHashMap()); + ProtocolAdaptor adaptor = ProtocolPluginFactory.getProtocolAdaptor(PROTOCOL_TYPE_NAME); + Assertions.assertEquals(adaptor.getClass(), MockProtocolAdaptorImpl.class); + + field.set(null, originMap); + } + + @Test + public void testGetProtocolAdaptorThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> ProtocolPluginFactory.getProtocolAdaptor("empty_type_name")); + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor new file mode 100644 index 0000000000..6dd5895bff --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-api/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor @@ -0,0 +1,17 @@ +# +# 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. +# +testProtocolType=org.apache.eventmesh.protocol.api.MockProtocolAdaptorImpl \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/build.gradle b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/build.gradle index 9f3b904951..e6ffc372b9 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/build.gradle +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/build.gradle @@ -20,5 +20,15 @@ dependencies { implementation "io.cloudevents:cloudevents-core" implementation "com.google.guava:guava" implementation "io.cloudevents:cloudevents-json-jackson" - implementation "io.grpc:grpc-protobuf:1.17.1" + implementation ("io.grpc:grpc-protobuf:1.68.0") { + exclude group: "com.google.protobuf", module: "protobuf-java" + } + implementation("com.google.protobuf:protobuf-java:3.25.4") + implementation "io.cloudevents:cloudevents-protobuf" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolAdaptor.java index 5763e60ece..ddbfe44eca 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolAdaptor.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolAdaptor.java @@ -19,10 +19,9 @@ import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.BatchMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.BatchEventMeshCloudEventWrapper; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.RequestCode; @@ -30,18 +29,16 @@ import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; -import org.apache.eventmesh.protocol.cloudevents.resolver.grpc.GrpcMessageProtocolResolver; +import org.apache.eventmesh.protocol.cloudevents.resolver.grpc.GrpcEventMeshCloudEventProtocolResolver; import org.apache.eventmesh.protocol.cloudevents.resolver.http.SendMessageBatchProtocolResolver; import org.apache.eventmesh.protocol.cloudevents.resolver.http.SendMessageBatchV2ProtocolResolver; import org.apache.eventmesh.protocol.cloudevents.resolver.http.SendMessageRequestProtocolResolver; import org.apache.eventmesh.protocol.cloudevents.resolver.tcp.TcpMessageProtocolResolver; -import org.apache.commons.lang3.StringUtils; - -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import io.cloudevents.CloudEvent; import io.cloudevents.core.format.EventFormat; @@ -74,9 +71,9 @@ public CloudEvent toCloudEvent(ProtocolTransportObject cloudEvent) throws Protoc String requestCode = ((HttpCommand) cloudEvent).getRequestCode(); return deserializeHttpProtocol(requestCode, header, body); - } else if (cloudEvent instanceof SimpleMessageWrapper) { - SimpleMessage simpleMessage = ((SimpleMessageWrapper) cloudEvent).getMessage(); - return GrpcMessageProtocolResolver.buildEvent(simpleMessage); + } else if (cloudEvent instanceof EventMeshCloudEventWrapper) { + EventMeshCloudEventWrapper ce = (EventMeshCloudEventWrapper) cloudEvent; + return GrpcEventMeshCloudEventProtocolResolver.buildEvent(ce.getMessage()); } else { throw new ProtocolHandleException(String.format("protocol class: %s", cloudEvent.getClass())); } @@ -87,29 +84,27 @@ private CloudEvent deserializeTcpProtocol(Header header, String cloudEventJson) } private CloudEvent deserializeHttpProtocol(String requestCode, - org.apache.eventmesh.common.protocol.http.header.Header header, - Body body) throws ProtocolHandleException { - - if (String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()).equals(requestCode)) { - return SendMessageBatchProtocolResolver.buildEvent(header, body); - } else if (String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()).equals(requestCode)) { - return SendMessageBatchV2ProtocolResolver.buildEvent(header, body); - } else if (String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()).equals(requestCode)) { - return SendMessageRequestProtocolResolver.buildEvent(header, body); - } else if (String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()).equals(requestCode)) { - return SendMessageRequestProtocolResolver.buildEvent(header, body); - } else { - throw new ProtocolHandleException(String.format("unsupported requestCode: %s", requestCode)); + org.apache.eventmesh.common.protocol.http.header.Header header, + Body body) throws ProtocolHandleException { + + switch (RequestCode.get(Integer.parseInt(requestCode))) { + case MSG_BATCH_SEND: + return SendMessageBatchProtocolResolver.buildEvent(header, body); + case MSG_BATCH_SEND_V2: + return SendMessageBatchV2ProtocolResolver.buildEvent(header, body); + case MSG_SEND_SYNC: + case MSG_SEND_ASYNC: + return SendMessageRequestProtocolResolver.buildEvent(header, body); + default: + throw new ProtocolHandleException(String.format("unsupported requestCode: %s", requestCode)); } - } @Override - public List toBatchCloudEvent(ProtocolTransportObject protocol) - throws ProtocolHandleException { - if (protocol instanceof BatchMessageWrapper) { - BatchMessage batchMessage = ((BatchMessageWrapper) protocol).getMessage(); - return GrpcMessageProtocolResolver.buildBatchEvents(batchMessage); + public List toBatchCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { + if (protocol instanceof BatchEventMeshCloudEventWrapper) { + CloudEventBatch cloudEventBatch = ((BatchEventMeshCloudEventWrapper) protocol).getMessage(); + return GrpcEventMeshCloudEventProtocolResolver.buildBatchEvents(cloudEventBatch); } else { throw new ProtocolHandleException(String.format("protocol class: %s", protocol.getClass())); } @@ -117,36 +112,40 @@ public List toBatchCloudEvent(ProtocolTransportObject protocol) @Override public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws ProtocolHandleException { - String protocolDesc = cloudEvent.getExtension(Constants.PROTOCOL_DESC).toString(); - if (StringUtils.equals("http", protocolDesc)) { - HttpCommand httpCommand = new HttpCommand(); - Body body = new Body() { - final Map map = new HashMap<>(); - - @Override - public Map toMap() { - byte[] eventByte = - EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE).serialize(cloudEvent); - map.put("content", new String(eventByte, StandardCharsets.UTF_8)); - return map; - } - }; - body.toMap(); - httpCommand.setBody(body); - return httpCommand; - } else if (StringUtils.equals("tcp", protocolDesc)) { - Package pkg = new Package(); - String dataContentType = cloudEvent.getDataContentType(); - Preconditions.checkNotNull(dataContentType, "DateContentType cannot be null"); - EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(dataContentType); - Preconditions.checkNotNull(eventFormat, - String.format("DateContentType:%s is not supported", dataContentType)); - pkg.setBody(eventFormat.serialize(cloudEvent)); - return pkg; - } else if (StringUtils.equals("grpc", protocolDesc)) { - return GrpcMessageProtocolResolver.buildSimpleMessage(cloudEvent); - } else { - throw new ProtocolHandleException(String.format("Unsupported protocolDesc: %s", protocolDesc)); + Preconditions.checkNotNull(cloudEvent, "cloudEvent cannot be null"); + String protocolDesc = Objects.requireNonNull(cloudEvent.getExtension(Constants.PROTOCOL_DESC)).toString(); + switch (protocolDesc) { + case "http": + HttpCommand httpCommand = new HttpCommand(); + Body body = new Body() { + + final Map map = new HashMap<>(); + + @Override + public Map toMap() { + byte[] eventByte = + Objects.requireNonNull(EventFormatProvider.getInstance() + .resolveFormat(JsonFormat.CONTENT_TYPE)).serialize(cloudEvent); + map.put("content", new String(eventByte, Constants.DEFAULT_CHARSET)); + return map; + } + }; + body.toMap(); + httpCommand.setBody(body); + return httpCommand; + case "tcp": + Package pkg = new Package(); + String dataContentType = cloudEvent.getDataContentType(); + Preconditions.checkNotNull(dataContentType, "DateContentType cannot be null"); + EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(dataContentType); + Preconditions.checkNotNull(eventFormat, + String.format("DateContentType:%s is not supported", dataContentType)); + pkg.setBody(eventFormat.serialize(cloudEvent)); + return pkg; + case CloudEventsProtocolConstant.PROTOCOL_DESC_GRPC_CLOUD_EVENT: + return GrpcEventMeshCloudEventProtocolResolver.buildEventMeshCloudEvent(cloudEvent); + default: + throw new ProtocolHandleException(String.format("Unsupported protocolDesc: %s", protocolDesc)); } } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolConstant.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolConstant.java index 7c26920626..476430afa9 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolConstant.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/CloudEventsProtocolConstant.java @@ -19,5 +19,8 @@ public enum CloudEventsProtocolConstant { ; + public static final String PROTOCOL_NAME = "cloudevents"; + + public static final String PROTOCOL_DESC_GRPC_CLOUD_EVENT = "grpc-cloud-event"; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/WebHookProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/WebHookProtocolAdaptor.java deleted file mode 100644 index 691f0b81c8..0000000000 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/WebHookProtocolAdaptor.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.protocol.cloudevents; - -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.http.WebhookProtocolTransportObject; -import org.apache.eventmesh.protocol.api.ProtocolAdaptor; -import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class WebHookProtocolAdaptor implements ProtocolAdaptor { - - @Override - public CloudEvent toCloudEvent(WebhookProtocolTransportObject protocol) throws ProtocolHandleException { - return CloudEventBuilder.v1() - .withId(protocol.getCloudEventId()) - .withSubject(protocol.getCloudEventName()) - .withSource(URI.create(protocol.getCloudEventSource())) - .withDataContentType(protocol.getDataContentType()) - .withType(protocol.getEventType()) - .withData(protocol.getBody()) - .build(); - } - - @Override - public List toBatchCloudEvent(WebhookProtocolTransportObject protocol) throws ProtocolHandleException { - List cloudEventList = new ArrayList(); - return cloudEventList; - } - - @Override - public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws ProtocolHandleException { - return null; - } - - @Override - public String getProtocolType() { - return "webhookProtocolAdaptor"; - } - -} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/grpc/GrpcEventMeshCloudEventProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/grpc/GrpcEventMeshCloudEventProtocolResolver.java new file mode 100644 index 0000000000..ad48ad59dd --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/grpc/GrpcEventMeshCloudEventProtocolResolver.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.cloudevents.resolver.grpc; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.protobuf.ProtobufFormat; + +import com.google.protobuf.InvalidProtocolBufferException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GrpcEventMeshCloudEventProtocolResolver { + + private static final EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(ProtobufFormat.PROTO_CONTENT_TYPE); + + public static io.cloudevents.CloudEvent buildEvent(CloudEvent cloudEvent) { + return Objects.requireNonNull(eventFormat).deserialize(cloudEvent.toByteArray()); + } + + public static List buildBatchEvents(CloudEventBatch cloudEventBatch) { + if (cloudEventBatch == null || cloudEventBatch.getEventsCount() < 1) { + return new ArrayList<>(0); + } + return cloudEventBatch.getEventsList().stream().map(cloudEvent -> Objects.requireNonNull(eventFormat).deserialize(cloudEvent.toByteArray())) + .collect(Collectors.toList()); + } + + public static EventMeshCloudEventWrapper buildEventMeshCloudEvent(io.cloudevents.CloudEvent cloudEvent) { + if (cloudEvent == null) { + return new EventMeshCloudEventWrapper(null); + } + try { + return new EventMeshCloudEventWrapper(CloudEvent.parseFrom(Objects.requireNonNull(eventFormat).serialize(cloudEvent))); + } catch (InvalidProtocolBufferException e) { + log.error("Build Event Mesh CloudEvent from io.cloudevents.CloudEvent error", e); + } + return null; + } +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/grpc/GrpcMessageProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/grpc/GrpcMessageProtocolResolver.java deleted file mode 100644 index 6424c72482..0000000000 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/grpc/GrpcMessageProtocolResolver.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.protocol.cloudevents.resolver.grpc; - -import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; - -import org.apache.commons.lang3.StringUtils; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import io.cloudevents.CloudEvent; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.provider.EventFormatProvider; - -public class GrpcMessageProtocolResolver { - - public static CloudEvent buildEvent(SimpleMessage message) { - String cloudEventJson = message.getContent(); - - String contentType = message.getPropertiesOrDefault(ProtocolKey.CONTENT_TYPE, "application/cloudevents+json"); - EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(contentType); - CloudEvent event = eventFormat.deserialize(cloudEventJson.getBytes(StandardCharsets.UTF_8)); - - RequestHeader header = message.getHeader(); - String env = StringUtils.isEmpty(header.getEnv()) ? event.getExtension(ProtocolKey.ENV).toString() : header.getEnv(); - String idc = StringUtils.isEmpty(header.getIdc()) ? event.getExtension(ProtocolKey.IDC).toString() : header.getIdc(); - String ip = StringUtils.isEmpty(header.getIp()) ? event.getExtension(ProtocolKey.IP).toString() : header.getIp(); - String pid = StringUtils.isEmpty(header.getPid()) ? event.getExtension(ProtocolKey.PID).toString() : header.getPid(); - String sys = StringUtils.isEmpty(header.getSys()) ? event.getExtension(ProtocolKey.SYS).toString() : header.getSys(); - - String language = StringUtils.isEmpty(header.getLanguage()) - ? event.getExtension(ProtocolKey.LANGUAGE).toString() : header.getLanguage(); - - String protocolType = StringUtils.isEmpty(header.getProtocolType()) - ? event.getExtension(ProtocolKey.PROTOCOL_TYPE).toString() : header.getProtocolType(); - - String protocolDesc = StringUtils.isEmpty(header.getProtocolDesc()) - ? event.getExtension(ProtocolKey.PROTOCOL_DESC).toString() : header.getProtocolDesc(); - - String protocolVersion = StringUtils.isEmpty(header.getProtocolVersion()) - ? event.getExtension(ProtocolKey.PROTOCOL_VERSION).toString() : header.getProtocolVersion(); - - String uniqueId = StringUtils.isEmpty(message.getUniqueId()) - ? event.getExtension(ProtocolKey.UNIQUE_ID).toString() : message.getUniqueId(); - - String seqNum = StringUtils.isEmpty(message.getSeqNum()) - ? event.getExtension(ProtocolKey.SEQ_NUM).toString() : message.getSeqNum(); - - String topic = StringUtils.isEmpty(message.getTopic()) ? event.getSubject() : message.getTopic(); - - String username = StringUtils.isEmpty(header.getUsername()) ? event.getExtension(ProtocolKey.USERNAME).toString() : header.getUsername(); - String passwd = StringUtils.isEmpty(header.getPassword()) ? event.getExtension(ProtocolKey.PASSWD).toString() : header.getPassword(); - String ttl = StringUtils.isEmpty(message.getTtl()) ? event.getExtension(ProtocolKey.TTL).toString() : message.getTtl(); - - String producerGroup = StringUtils.isEmpty(message.getProducerGroup()) - ? event.getExtension(ProtocolKey.PRODUCERGROUP).toString() : message.getProducerGroup(); - - CloudEventBuilder eventBuilder; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - eventBuilder = CloudEventBuilder.v1(event); - } else { - eventBuilder = CloudEventBuilder.v03(event); - } - - eventBuilder.withSubject(topic) - .withExtension(ProtocolKey.ENV, env) - .withExtension(ProtocolKey.IDC, idc) - .withExtension(ProtocolKey.IP, ip) - .withExtension(ProtocolKey.PID, pid) - .withExtension(ProtocolKey.SYS, sys) - .withExtension(ProtocolKey.USERNAME, username) - .withExtension(ProtocolKey.PASSWD, passwd) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(ProtocolKey.SEQ_NUM, seqNum) - .withExtension(ProtocolKey.UNIQUE_ID, uniqueId) - .withExtension(ProtocolKey.PRODUCERGROUP, producerGroup) - .withExtension(ProtocolKey.TTL, ttl); - - message.getPropertiesMap().forEach((k, v) -> eventBuilder.withExtension(k, v)); - - return eventBuilder.build(); - } - - public static SimpleMessageWrapper buildSimpleMessage(CloudEvent cloudEvent) { - String env = cloudEvent.getExtension(ProtocolKey.ENV) == null ? "env" : cloudEvent.getExtension(ProtocolKey.ENV).toString(); - String idc = cloudEvent.getExtension(ProtocolKey.IDC) == null ? "idc" : cloudEvent.getExtension(ProtocolKey.IDC).toString(); - String ip = cloudEvent.getExtension(ProtocolKey.IP) == null ? "127.0.0.1" : cloudEvent.getExtension(ProtocolKey.IP).toString(); - String pid = cloudEvent.getExtension(ProtocolKey.PID) == null ? "123" : cloudEvent.getExtension(ProtocolKey.PID).toString(); - String sys = cloudEvent.getExtension(ProtocolKey.SYS) == null ? "sys123" : cloudEvent.getExtension(ProtocolKey.SYS).toString(); - String userName = cloudEvent.getExtension(ProtocolKey.USERNAME) == null ? "user" : cloudEvent.getExtension(ProtocolKey.USERNAME).toString(); - String passwd = cloudEvent.getExtension(ProtocolKey.PASSWD) == null ? "pass" : cloudEvent.getExtension(ProtocolKey.PASSWD).toString(); - String language = cloudEvent.getExtension(ProtocolKey.LANGUAGE) == null ? "JAVA" : cloudEvent.getExtension(ProtocolKey.LANGUAGE).toString(); - String protocol = cloudEvent.getExtension(ProtocolKey.PROTOCOL_TYPE) == null ? "protocol" : - cloudEvent.getExtension(ProtocolKey.PROTOCOL_TYPE).toString(); - String protocolDesc = cloudEvent.getExtension(ProtocolKey.PROTOCOL_DESC) == null ? "protocolDesc" : - cloudEvent.getExtension(ProtocolKey.PROTOCOL_DESC).toString(); - String protocolVersion = cloudEvent.getExtension(ProtocolKey.PROTOCOL_VERSION) == null ? "1.0" : - cloudEvent.getExtension(ProtocolKey.PROTOCOL_VERSION).toString(); - String seqNum = cloudEvent.getExtension(ProtocolKey.SEQ_NUM) == null ? "" : cloudEvent.getExtension(ProtocolKey.SEQ_NUM).toString(); - String uniqueId = cloudEvent.getExtension(ProtocolKey.UNIQUE_ID) == null ? "" : cloudEvent.getExtension(ProtocolKey.UNIQUE_ID).toString(); - String producerGroup = cloudEvent.getExtension(ProtocolKey.PRODUCERGROUP) == null ? "producerGroup" : - cloudEvent.getExtension(ProtocolKey.PRODUCERGROUP).toString(); - String ttl = cloudEvent.getExtension(ProtocolKey.TTL) == null ? "3000" : cloudEvent.getExtension(ProtocolKey.TTL).toString(); - - RequestHeader header = RequestHeader.newBuilder() - .setEnv(env).setIdc(idc) - .setIp(ip).setPid(pid) - .setSys(sys).setUsername(userName).setPassword(passwd) - .setLanguage(language).setProtocolType(protocol) - .setProtocolDesc(protocolDesc).setProtocolVersion(protocolVersion) - .build(); - - String contentType = cloudEvent.getDataContentType(); - EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(contentType); - - SimpleMessage.Builder messageBuilder = SimpleMessage.newBuilder() - .setHeader(header) - .setContent(new String(eventFormat.serialize(cloudEvent), StandardCharsets.UTF_8)) - .setProducerGroup(producerGroup) - .setSeqNum(seqNum) - .setUniqueId(uniqueId) - .setTopic(cloudEvent.getSubject()) - .setTtl(ttl) - .putProperties(ProtocolKey.CONTENT_TYPE, contentType); - - for (String key : cloudEvent.getExtensionNames()) { - messageBuilder.putProperties(key, cloudEvent.getExtension(key).toString()); - } - - SimpleMessage simpleMessage = messageBuilder.build(); - - return new SimpleMessageWrapper(simpleMessage); - } - - public static List buildBatchEvents(BatchMessage batchMessage) { - List cloudEvents = new ArrayList<>(); - - RequestHeader header = batchMessage.getHeader(); - - for (BatchMessage.MessageItem item : batchMessage.getMessageItemList()) { - String cloudEventJson = item.getContent(); - - String contentType = item.getPropertiesOrDefault(ProtocolKey.CONTENT_TYPE, "application/cloudevents+json"); - EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(contentType); - CloudEvent event = eventFormat.deserialize(cloudEventJson.getBytes(StandardCharsets.UTF_8)); - - String env = StringUtils.isEmpty(header.getEnv()) ? event.getExtension(ProtocolKey.ENV).toString() : header.getEnv(); - String idc = StringUtils.isEmpty(header.getIdc()) ? event.getExtension(ProtocolKey.IDC).toString() : header.getIdc(); - String ip = StringUtils.isEmpty(header.getIp()) ? event.getExtension(ProtocolKey.IP).toString() : header.getIp(); - String pid = StringUtils.isEmpty(header.getPid()) ? event.getExtension(ProtocolKey.PID).toString() : header.getPid(); - String sys = StringUtils.isEmpty(header.getSys()) ? event.getExtension(ProtocolKey.SYS).toString() : header.getSys(); - - String language = StringUtils.isEmpty(header.getLanguage()) - ? event.getExtension(ProtocolKey.LANGUAGE).toString() : header.getLanguage(); - - String protocolType = StringUtils.isEmpty(header.getProtocolType()) - ? event.getExtension(ProtocolKey.PROTOCOL_TYPE).toString() : header.getProtocolType(); - - String protocolDesc = StringUtils.isEmpty(header.getProtocolDesc()) - ? event.getExtension(ProtocolKey.PROTOCOL_DESC).toString() : header.getProtocolDesc(); - - String protocolVersion = StringUtils.isEmpty(header.getProtocolVersion()) - ? event.getExtension(ProtocolKey.PROTOCOL_VERSION).toString() : header.getProtocolVersion(); - - String username = StringUtils.isEmpty(header.getUsername()) ? event.getExtension(ProtocolKey.USERNAME).toString() : header.getUsername(); - String passwd = StringUtils.isEmpty(header.getPassword()) ? event.getExtension(ProtocolKey.PASSWD).toString() : header.getPassword(); - - String seqNum = StringUtils.isEmpty(item.getSeqNum()) ? event.getExtension(ProtocolKey.SEQ_NUM).toString() : item.getSeqNum(); - String uniqueId = StringUtils.isEmpty(item.getUniqueId()) ? event.getExtension(ProtocolKey.UNIQUE_ID).toString() : item.getUniqueId(); - - String topic = StringUtils.isEmpty(batchMessage.getTopic()) ? event.getSubject() : batchMessage.getTopic(); - - String producerGroup = StringUtils.isEmpty(batchMessage.getProducerGroup()) - ? event.getExtension(ProtocolKey.PRODUCERGROUP).toString() : batchMessage.getProducerGroup(); - String ttl = StringUtils.isEmpty(item.getTtl()) ? event.getExtension(ProtocolKey.TTL).toString() : item.getTtl(); - - CloudEventBuilder eventBuilder; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - eventBuilder = CloudEventBuilder.v1(event); - } else { - eventBuilder = CloudEventBuilder.v03(event); - } - - eventBuilder.withSubject(topic) - .withExtension(ProtocolKey.ENV, env) - .withExtension(ProtocolKey.IDC, idc) - .withExtension(ProtocolKey.IP, ip) - .withExtension(ProtocolKey.PID, pid) - .withExtension(ProtocolKey.SYS, sys) - .withExtension(ProtocolKey.USERNAME, username) - .withExtension(ProtocolKey.PASSWD, passwd) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(ProtocolKey.SEQ_NUM, seqNum) - .withExtension(ProtocolKey.UNIQUE_ID, uniqueId) - .withExtension(ProtocolKey.PRODUCERGROUP, producerGroup) - .withExtension(ProtocolKey.TTL, ttl); - - item.getPropertiesMap().forEach((k, v) -> eventBuilder.withExtension(k, v)); - - cloudEvents.add(eventBuilder.build()); - } - return cloudEvents; - } -} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchProtocolResolver.java index d27fdcdb1c..bdf0b96ada 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchProtocolResolver.java @@ -23,6 +23,7 @@ import io.cloudevents.CloudEvent; public class SendMessageBatchProtocolResolver { + public static CloudEvent buildEvent(Header header, Body body) { return null; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchV2ProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchV2ProtocolResolver.java index 095095f3fe..8d8b0b2d94 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchV2ProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageBatchV2ProtocolResolver.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.protocol.cloudevents.resolver.http; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; @@ -27,7 +28,7 @@ import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; +import java.util.Objects; import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; @@ -36,6 +37,7 @@ import io.cloudevents.jackson.JsonFormat; public class SendMessageBatchV2ProtocolResolver { + public static CloudEvent buildEvent(Header header, Body body) throws ProtocolHandleException { try { SendMessageBatchV2RequestHeader sendMessageBatchV2RequestHeader = (SendMessageBatchV2RequestHeader) header; @@ -60,44 +62,25 @@ public static CloudEvent buildEvent(Header header, Body body) throws ProtocolHan String content = sendMessageBatchV2RequestBody.getMsg(); CloudEvent event = null; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - event = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); - event = CloudEventBuilder.from(event) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP, producerGroup) - .build(); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - event = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); + if (StringUtils.equalsAny(protocolVersion, SpecVersion.V1.toString(), SpecVersion.V03.toString())) { + event = Objects.requireNonNull(EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE)) + .deserialize(content.getBytes(Constants.DEFAULT_CHARSET)); event = CloudEventBuilder.from(event) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP, producerGroup) - .build(); + .withExtension(ProtocolKey.REQUEST_CODE, code) + .withExtension(ProtocolKey.ClientInstanceKey.ENV.getKey(), env) + .withExtension(ProtocolKey.ClientInstanceKey.IDC.getKey(), idc) + .withExtension(ProtocolKey.ClientInstanceKey.IP.getKey(), ip) + .withExtension(ProtocolKey.ClientInstanceKey.PID.getKey(), pid) + .withExtension(ProtocolKey.ClientInstanceKey.SYS.getKey(), sys) + .withExtension(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), username) + .withExtension(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), passwd) + .withExtension(ProtocolKey.VERSION, version.getVersion()) + .withExtension(ProtocolKey.LANGUAGE, language) + .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) + .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) + .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) + .withExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP, producerGroup) + .build(); } return event; } catch (Exception e) { diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageRequestProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageRequestProtocolResolver.java index 8bfde60d32..a803312591 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageRequestProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/http/SendMessageRequestProtocolResolver.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.protocol.cloudevents.resolver.http; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; @@ -27,7 +28,7 @@ import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; +import java.util.Objects; import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; @@ -61,44 +62,25 @@ public static CloudEvent buildEvent(Header header, Body body) throws ProtocolHan String content = sendMessageRequestBody.getContent(); CloudEvent event = null; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - event = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); - event = CloudEventBuilder.v1(event) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageRequestBody.PRODUCERGROUP, producerGroup) - .build(); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - event = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); - event = CloudEventBuilder.v03(event) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageRequestBody.PRODUCERGROUP, producerGroup) - .build(); + if (StringUtils.equalsAny(protocolVersion, SpecVersion.V1.toString(), SpecVersion.V03.toString())) { + event = Objects.requireNonNull(EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE)) + .deserialize(content.getBytes(Constants.DEFAULT_CHARSET)); + event = CloudEventBuilder.from(event) + .withExtension(ProtocolKey.REQUEST_CODE, code) + .withExtension(ProtocolKey.ClientInstanceKey.ENV.getKey(), env) + .withExtension(ProtocolKey.ClientInstanceKey.IDC.getKey(), idc) + .withExtension(ProtocolKey.ClientInstanceKey.IP.getKey(), ip) + .withExtension(ProtocolKey.ClientInstanceKey.PID.getKey(), pid) + .withExtension(ProtocolKey.ClientInstanceKey.SYS.getKey(), sys) + .withExtension(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), username) + .withExtension(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), passwd) + .withExtension(ProtocolKey.VERSION, version.getVersion()) + .withExtension(ProtocolKey.LANGUAGE, language) + .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) + .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) + .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) + .withExtension(SendMessageRequestBody.PRODUCERGROUP, producerGroup) + .build(); } return event; } catch (Exception e) { diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/tcp/TcpMessageProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/tcp/TcpMessageProtocolResolver.java index 82b338882d..32315938df 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/tcp/TcpMessageProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/java/org/apache/eventmesh/protocol/cloudevents/resolver/tcp/TcpMessageProtocolResolver.java @@ -38,48 +38,38 @@ public class TcpMessageProtocolResolver { public static CloudEvent buildEvent(Header header, String cloudEventJson) - throws ProtocolHandleException { - CloudEventBuilder cloudEventBuilder; + throws ProtocolHandleException { + final CloudEventBuilder cloudEventBuilder; String protocolType = header.getProperty(Constants.PROTOCOL_TYPE).toString(); String protocolVersion = header.getProperty(Constants.PROTOCOL_VERSION).toString(); String protocolDesc = header.getProperty(Constants.PROTOCOL_DESC).toString(); - if (StringUtils.isBlank(protocolType) - || StringUtils.isBlank(protocolVersion) - || StringUtils.isBlank(protocolDesc)) { + if (StringUtils.isAnyBlank(protocolType, protocolVersion, protocolDesc)) { throw new ProtocolHandleException( - String.format("invalid protocol params protocolType %s|protocolVersion %s|protocolDesc %s", - protocolType, protocolVersion, protocolDesc)); + String.format("invalid protocol params protocolType %s|protocolVersion %s|protocolDesc %s", + protocolType, protocolVersion, protocolDesc)); + } + + if (StringUtils.isBlank(cloudEventJson)) { + throw new ProtocolHandleException( + String.format("invalid method params cloudEventJson %s", cloudEventJson)); } if (!StringUtils.equals(CloudEventsProtocolConstant.PROTOCOL_NAME, protocolType)) { throw new ProtocolHandleException(String.format("Unsupported protocolType: %s", protocolType)); } - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { + if (StringUtils.equalsAny(protocolVersion, SpecVersion.V1.toString(), SpecVersion.V03.toString())) { // todo:resolve different format EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); Preconditions - .checkNotNull(eventFormat, String.format("EventFormat: %s is not supported", JsonFormat.CONTENT_TYPE)); + .checkNotNull(eventFormat, "EventFormat: %s is not supported", JsonFormat.CONTENT_TYPE); CloudEvent event = eventFormat.deserialize(cloudEventJson.getBytes(StandardCharsets.UTF_8)); - cloudEventBuilder = CloudEventBuilder.v1(event); - for (String propKey : header.getProperties().keySet()) { - cloudEventBuilder.withExtension(propKey, header.getProperty(propKey).toString()); - } - - return cloudEventBuilder.build(); - - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - // todo:resolve different format - CloudEvent event = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(cloudEventJson.getBytes(StandardCharsets.UTF_8)); - cloudEventBuilder = CloudEventBuilder.v03(event); - - for (String propKey : header.getProperties().keySet()) { - cloudEventBuilder.withExtension(propKey, header.getProperty(propKey).toString()); - } - + cloudEventBuilder = CloudEventBuilder.from(event); + header.getProperties().forEach((k, v) -> { + cloudEventBuilder.withExtension(k, v.toString()); + }); return cloudEventBuilder.build(); } else { throw new ProtocolHandleException(String.format("Unsupported protocolVersion: %s", protocolVersion)); diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor index e38fb694c9..7892308089 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor +++ b/eventmesh-protocol-plugin/eventmesh-protocol-cloudevents/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.protocol.api.ProtocolAdaptor @@ -13,5 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -cloudevents=org.apache.eventmesh.protocol.cloudevents.CloudEventsProtocolAdaptor -webhookProtocolAdaptor=org.apache.eventmesh.protocol.cloudevents.WebHookProtocolAdaptor \ No newline at end of file +cloudevents=org.apache.eventmesh.protocol.cloudevents.CloudEventsProtocolAdaptor \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-grpc/build.gradle b/eventmesh-protocol-plugin/eventmesh-protocol-grpc/build.gradle index 72c17de017..5929c72136 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-grpc/build.gradle +++ b/eventmesh-protocol-plugin/eventmesh-protocol-grpc/build.gradle @@ -17,24 +17,26 @@ plugins { id 'java' - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.9.4' } repositories { mavenCentral() } -def grpcVersion = '1.17.1' // CURRENT_GRPC_VERSION -def protobufVersion = '3.5.1' +def grpcVersion = '1.68.0' +def protobufVersion = '3.25.4' def protocVersion = protobufVersion dependencies { - implementation "io.grpc:grpc-protobuf:${grpcVersion}" + implementation ("io.grpc:grpc-protobuf:${grpcVersion}") { + exclude group: "com.google.protobuf", module: "protobuf-java" + } + implementation("com.google.protobuf:protobuf-java:${protobufVersion}") implementation "io.grpc:grpc-stub:${grpcVersion}" implementation "com.google.protobuf:protobuf-java-util:${protobufVersion}" implementation "javax.annotation:javax.annotation-api:1.3.2" - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' + testImplementation 'org.junit.jupiter:junit-jupiter' } protobuf { @@ -48,7 +50,3 @@ protobuf { } } } - -test { - useJUnitPlatform() -} \ No newline at end of file diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-cloudevents.proto b/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-cloudevents.proto new file mode 100644 index 0000000000..37e07a0b40 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-cloudevents.proto @@ -0,0 +1,86 @@ +/* + * 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. + */ + + + +/** + * CloudEvent Protobuf Format + * + * - Required context attributes are explicitly represented. + * - Optional and Extension context attributes are carried in a map structure. + * - Data may be represented as binary, text, or protobuf messages. + */ + +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option java_package = "org.apache.eventmesh.common.protocol.grpc.cloudevents"; +option java_multiple_files = true; +option java_outer_classname = "EventMeshCloudEvents"; + + +message CloudEvent { + + // -- CloudEvent Context Attributes + + // Required Attributes + string id = 1; + string source = 2; // URI-reference + string spec_version = 3; + string type = 4; + + // Optional & Extension Attributes + map attributes = 5; + + // -- CloudEvent Data (Bytes, Text, or Proto) + oneof data { + bytes binary_data = 6; + string text_data = 7; + google.protobuf.Any proto_data = 8; + } + + /** + * The CloudEvent specification defines + * seven attribute value types... + */ + + message CloudEventAttributeValue { + + oneof attr { + bool ce_boolean = 1; + int32 ce_integer = 2; + string ce_string = 3; + bytes ce_bytes = 4; + string ce_uri = 5; + string ce_uri_ref = 6; + google.protobuf.Timestamp ce_timestamp = 7; + } + } +} + +/** + * CloudEvent Protobuf Batch Format + * + */ + +message CloudEventBatch { + repeated CloudEvent events = 1; +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-service.proto b/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-service.proto new file mode 100644 index 0000000000..99d57bc514 --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-service.proto @@ -0,0 +1,58 @@ +/* + * 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. + */ +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "google/protobuf/empty.proto"; +import "eventmesh-cloudevents.proto"; + +option java_package = "org.apache.eventmesh.common.protocol.grpc.cloudevents"; +option java_multiple_files = true; +option java_outer_classname = "EventMeshGrpcService"; + + +service PublisherService { + //publish event + rpc publish(CloudEvent) returns (CloudEvent); + + //publish event with reply + rpc requestReply(CloudEvent) returns (CloudEvent); + + //publish event one way + rpc publishOneWay(CloudEvent) returns (google.protobuf.Empty); + + // publish batch event + rpc batchPublish(CloudEventBatch) returns (CloudEvent); + + //publish batch event one way + rpc batchPublishOneWay(CloudEventBatch) returns (google.protobuf.Empty); +} + +service ConsumerService { + // The subscribed event will be delivered by invoking the webhook url in the Subscription + rpc subscribe(CloudEvent) returns (CloudEvent); + + // The subscribed event will be delivered through stream of Message + rpc subscribeStream(stream CloudEvent) returns (stream CloudEvent); + + rpc unsubscribe(CloudEvent) returns (CloudEvent); +} + +service HeartbeatService { + rpc heartbeat(CloudEvent) returns (CloudEvent); +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-http/build.gradle b/eventmesh-protocol-plugin/eventmesh-protocol-http/build.gradle index 9f3b904951..d219c5dc03 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-http/build.gradle +++ b/eventmesh-protocol-plugin/eventmesh-protocol-http/build.gradle @@ -20,5 +20,8 @@ dependencies { implementation "io.cloudevents:cloudevents-core" implementation "com.google.guava:guava" implementation "io.cloudevents:cloudevents-json-jackson" - implementation "io.grpc:grpc-protobuf:1.17.1" + implementation ("io.grpc:grpc-protobuf:1.68.0") { + exclude group: "com.google.protobuf", module: "protobuf-java" + } + implementation("com.google.protobuf:protobuf-java:3.25.4") } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptor.java index ad7ff7f5d7..08c4718825 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptor.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptor.java @@ -17,6 +17,11 @@ package org.apache.eventmesh.protocol.http; +import static org.apache.eventmesh.protocol.http.HttpProtocolConstant.CONSTANTS_KEY_BODY; +import static org.apache.eventmesh.protocol.http.HttpProtocolConstant.CONSTANTS_KEY_HEADERS; +import static org.apache.eventmesh.protocol.http.HttpProtocolConstant.CONSTANTS_KEY_METHOD; +import static org.apache.eventmesh.protocol.http.HttpProtocolConstant.CONSTANTS_KEY_PATH; + import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; @@ -27,9 +32,11 @@ import org.apache.eventmesh.protocol.http.resolver.HttpRequestProtocolResolver; import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import io.cloudevents.CloudEvent; @@ -71,12 +78,11 @@ private CloudEvent deserializeProtocol(String requestURI, HttpEventWrapper httpE @Override public List toBatchCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { - return null; + return Collections.emptyList(); } @Override public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws ProtocolHandleException { - String protocolDesc = cloudEvent.getExtension(Constants.PROTOCOL_DESC).toString(); HttpEventWrapper httpEventWrapper = new HttpEventWrapper(); Map sysHeaderMap = new HashMap<>(); // ce attributes @@ -91,20 +97,25 @@ public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws Prot } httpEventWrapper.setSysHeaderMap(sysHeaderMap); // ce data - Map dataContentMap = JsonUtils.deserialize(new String(cloudEvent.getData().toBytes()), - new TypeReference>() {}); - - String requestHeader = JsonUtils.serialize(dataContentMap.get("headers")); - byte[] requestBody = JsonUtils.serialize(dataContentMap.get("body")).getBytes(StandardCharsets.UTF_8); - Map requestHeaderMap = JsonUtils.deserialize(requestHeader, new TypeReference>() { - }); - String requestURI = dataContentMap.get("path").toString(); - String httpMethod = dataContentMap.get("method").toString(); - - httpEventWrapper.setHeaderMap(requestHeaderMap); - httpEventWrapper.setBody(requestBody); - httpEventWrapper.setRequestURI(requestURI); - httpEventWrapper.setHttpMethod(httpMethod); + if (cloudEvent.getData() != null) { + Map dataContentMap = JsonUtils.parseTypeReferenceObject( + new String(Objects.requireNonNull(cloudEvent.getData()).toBytes(), Constants.DEFAULT_CHARSET), + new TypeReference>() { + }); + String requestHeader = JsonUtils.toJSONString( + Objects.requireNonNull(dataContentMap, "Headers must not be null").get(CONSTANTS_KEY_HEADERS)); + byte[] requestBody = Objects.requireNonNull( + JsonUtils.toJSONString(dataContentMap.get(CONSTANTS_KEY_BODY)), "Body must not be null").getBytes(StandardCharsets.UTF_8); + Map requestHeaderMap = JsonUtils.parseTypeReferenceObject(requestHeader, new TypeReference>() { + }); + String requestURI = dataContentMap.get(CONSTANTS_KEY_PATH).toString(); + String httpMethod = dataContentMap.get(CONSTANTS_KEY_METHOD).toString(); + + httpEventWrapper.setHeaderMap(requestHeaderMap); + httpEventWrapper.setBody(requestBody); + httpEventWrapper.setRequestURI(requestURI); + httpEventWrapper.setHttpMethod(httpMethod); + } return httpEventWrapper; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolConstant.java b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolConstant.java index 0e70bd7d5a..08c17ade37 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolConstant.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/HttpProtocolConstant.java @@ -19,13 +19,12 @@ public enum HttpProtocolConstant { ; - public static final String PROTOCOL_NAME = "http"; - public static final String DATA_CONTENT_TYPE = "application/json"; + public static final String PROTOCOL_NAME = "http"; public static final String CONSTANTS_DEFAULT_SOURCE = "/"; public static final String CONSTANTS_DEFAULT_TYPE = "http_request"; - public static final String CONSTANTS_DEFAULT_SUBJECT = "TOPIC-HTTP-REQUEST"; + public static final String CONSTANTS_DEFAULT_SUBJECT = ""; public static final String CONSTANTS_KEY_ID = "id"; public static final String CONSTANTS_KEY_SOURCE = "source"; @@ -35,4 +34,9 @@ public enum HttpProtocolConstant { public static final String CONSTANTS_KEY_BODY = "body"; public static final String CONSTANTS_KEY_PATH = "path"; public static final String CONSTANTS_KEY_METHOD = "method"; + + public static final String DATA_CONTENT_TYPE = "Content-Type"; + + public static final String APPLICATION_JSON = "application/json"; + public static final String PROTOBUF = "application/x-protobuf"; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/resolver/HttpRequestProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/resolver/HttpRequestProtocolResolver.java index d3b5b547fb..258723d3c0 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/resolver/HttpRequestProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/main/java/org/apache/eventmesh/protocol/http/resolver/HttpRequestProtocolResolver.java @@ -27,6 +27,7 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.UUID; @@ -48,50 +49,59 @@ public static CloudEvent buildEvent(HttpEventWrapper httpEventWrapper) throws Pr String id = sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_ID, UUID.randomUUID()).toString(); - String source = - sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_SOURCE, HttpProtocolConstant.CONSTANTS_DEFAULT_SOURCE).toString(); + String source = sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_SOURCE, + HttpProtocolConstant.CONSTANTS_DEFAULT_SOURCE).toString(); - String type = sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_TYPE, HttpProtocolConstant.CONSTANTS_DEFAULT_TYPE).toString(); + String type = sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_TYPE, + HttpProtocolConstant.CONSTANTS_DEFAULT_TYPE).toString(); - String subject = - sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_SUBJECT, HttpProtocolConstant.CONSTANTS_DEFAULT_SUBJECT).toString(); + String subject = sysHeaderMap.getOrDefault(HttpProtocolConstant.CONSTANTS_KEY_SUBJECT, + HttpProtocolConstant.CONSTANTS_DEFAULT_SUBJECT).toString(); + String dataContentType = requestHeaderMap.getOrDefault(HttpProtocolConstant.DATA_CONTENT_TYPE, + HttpProtocolConstant.APPLICATION_JSON).toString(); // with attributes builder.withId(id) .withType(type) .withSource(URI.create(HttpProtocolConstant.CONSTANTS_KEY_SOURCE + ":" + source)) .withSubject(subject) - .withDataContentType(HttpProtocolConstant.DATA_CONTENT_TYPE); + .withDataContentType(dataContentType); // with extensions - for (String extensionKey : sysHeaderMap.keySet()) { - if (StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_ID, extensionKey) - || StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_SOURCE, extensionKey) - || StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_TYPE, extensionKey) - || StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_SUBJECT, extensionKey)) { + for (Map.Entry extension : sysHeaderMap.entrySet()) { + if (StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_ID, extension.getKey()) + || StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_SOURCE, extension.getKey()) + || StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_TYPE, extension.getKey()) + || StringUtils.equals(HttpProtocolConstant.CONSTANTS_KEY_SUBJECT, extension.getKey())) { continue; } - String lowerExtensionKey = extensionKey.toLowerCase(); - builder.withExtension(lowerExtensionKey, sysHeaderMap.get(extensionKey).toString()); + String lowerExtensionKey = extension.getKey().toLowerCase(Locale.getDefault()); + builder.withExtension(lowerExtensionKey, sysHeaderMap.get(extension.getKey()).toString()); } byte[] requestBody = httpEventWrapper.getBody(); - Map requestBodyMap = JsonUtils.deserialize(new String(requestBody), new TypeReference>() { - }); - - String requestURI = httpEventWrapper.getRequestURI(); - - Map data = new HashMap<>(); - data.put(HttpProtocolConstant.CONSTANTS_KEY_HEADERS, requestHeaderMap); - data.put(HttpProtocolConstant.CONSTANTS_KEY_BODY, requestBodyMap); - data.put(HttpProtocolConstant.CONSTANTS_KEY_PATH, requestURI); - data.put(HttpProtocolConstant.CONSTANTS_KEY_METHOD, httpEventWrapper.getHttpMethod()); - // with data - builder = builder.withData(JsonUtils.serialize(data).getBytes(StandardCharsets.UTF_8)); + if (StringUtils.equals(dataContentType, HttpProtocolConstant.APPLICATION_JSON)) { + Map requestBodyMap = JsonUtils.parseTypeReferenceObject(new String(requestBody), + new TypeReference>() { + }); + + String requestURI = httpEventWrapper.getRequestURI(); + + Map data = new HashMap<>(); + data.put(HttpProtocolConstant.CONSTANTS_KEY_HEADERS, requestHeaderMap); + data.put(HttpProtocolConstant.CONSTANTS_KEY_BODY, requestBodyMap); + data.put(HttpProtocolConstant.CONSTANTS_KEY_PATH, requestURI); + data.put(HttpProtocolConstant.CONSTANTS_KEY_METHOD, httpEventWrapper.getHttpMethod()); + // with data + builder = builder.withData(JsonUtils.toJSONString(data).getBytes(StandardCharsets.UTF_8)); + } else if (StringUtils.equals(dataContentType, HttpProtocolConstant.PROTOBUF)) { + // with data + builder = builder.withData(requestBody); + } return builder.build(); } catch (Exception e) { - throw new ProtocolHandleException(e.getMessage(), e.getCause()); + throw new ProtocolHandleException(e.getMessage(), e); } } } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/test/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptorTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/test/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptorTest.java index c7ead7d312..b01c6d5503 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-http/src/test/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptorTest.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-http/src/test/java/org/apache/eventmesh/protocol/http/HttpProtocolAdaptorTest.java @@ -21,19 +21,19 @@ import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class HttpProtocolAdaptorTest { @Test public void loadPlugin() { ProtocolAdaptor protocolAdaptor = - ProtocolPluginFactory.getProtocolAdaptor(HttpProtocolConstant.PROTOCOL_NAME); + ProtocolPluginFactory.getProtocolAdaptor(HttpProtocolConstant.PROTOCOL_NAME); - Assert.assertNotNull(protocolAdaptor); - Assert.assertEquals( - HttpProtocolConstant.PROTOCOL_NAME, protocolAdaptor.getProtocolType()); - Assert.assertEquals(HttpProtocolAdaptor.class, protocolAdaptor.getClass()); + Assertions.assertNotNull(protocolAdaptor); + Assertions.assertEquals( + HttpProtocolConstant.PROTOCOL_NAME, protocolAdaptor.getProtocolType()); + Assertions.assertEquals(HttpProtocolAdaptor.class, protocolAdaptor.getClass()); } -} \ No newline at end of file +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/build.gradle b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/build.gradle index b20c6837a3..3f15d199ff 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/build.gradle +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/build.gradle @@ -18,8 +18,18 @@ dependencies { implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-api") implementation "io.cloudevents:cloudevents-core" - implementation "io.grpc:grpc-protobuf:1.17.1" + implementation ("io.grpc:grpc-protobuf:1.68.0") { + exclude group: "com.google.protobuf", module: "protobuf-java" + } + implementation("com.google.protobuf:protobuf-java:3.25.4") + implementation "io.cloudevents:cloudevents-protobuf" testImplementation project(":eventmesh-protocol-plugin:eventmesh-protocol-api") testImplementation "io.cloudevents:cloudevents-core" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptor.java index df60c39604..8f1f6af786 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptor.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptor.java @@ -18,11 +18,11 @@ package org.apache.eventmesh.protocol.meshmessage; import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.BatchMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.BatchEventMeshCloudEventWrapper; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.RequestCode; @@ -32,21 +32,21 @@ import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; -import org.apache.eventmesh.protocol.meshmessage.resolver.grpc.GrpcMessageProtocolResolver; +import org.apache.eventmesh.protocol.meshmessage.resolver.grpc.GrpcEventMeshCloudEventProtocolResolver; import org.apache.eventmesh.protocol.meshmessage.resolver.http.SendMessageBatchProtocolResolver; import org.apache.eventmesh.protocol.meshmessage.resolver.http.SendMessageBatchV2ProtocolResolver; import org.apache.eventmesh.protocol.meshmessage.resolver.http.SendMessageRequestProtocolResolver; import org.apache.eventmesh.protocol.meshmessage.resolver.tcp.TcpMessageProtocolResolver; -import org.apache.commons.lang3.StringUtils; - -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import io.cloudevents.CloudEvent; +import com.google.common.base.Preconditions; + public class MeshMessageProtocolAdaptor implements ProtocolAdaptor { @Override @@ -62,48 +62,42 @@ public CloudEvent toCloudEvent(ProtocolTransportObject protocol) throws Protocol org.apache.eventmesh.common.protocol.http.header.Header header = ((HttpCommand) protocol).getHeader(); Body body = ((HttpCommand) protocol).getBody(); String requestCode = ((HttpCommand) protocol).getRequestCode(); - return deserializeHttpProtocol(requestCode, header, body); - } else if (protocol instanceof SimpleMessageWrapper) { - SimpleMessage message = ((SimpleMessageWrapper) protocol).getMessage(); - return deserializeGrpcProtocol(message); + } else if (protocol instanceof EventMeshCloudEventWrapper) { + EventMeshCloudEventWrapper wrapper = (EventMeshCloudEventWrapper) protocol; + return GrpcEventMeshCloudEventProtocolResolver.buildEvent(wrapper.getMessage()); } else { throw new ProtocolHandleException(String.format("protocol class: %s", protocol.getClass())); } } - private CloudEvent deserializeGrpcProtocol(SimpleMessage message) - throws ProtocolHandleException { - return GrpcMessageProtocolResolver.buildEvent(message); - } - private CloudEvent deserializeTcpProtocol(Header header, String bodyJson) throws ProtocolHandleException { - return TcpMessageProtocolResolver.buildEvent(header, JsonUtils.deserialize(bodyJson, EventMeshMessage.class)); + return TcpMessageProtocolResolver.buildEvent(header, JsonUtils.parseObject(bodyJson, EventMeshMessage.class)); } private CloudEvent deserializeHttpProtocol(String requestCode, - org.apache.eventmesh.common.protocol.http.header.Header header, - Body body) throws ProtocolHandleException { - - if (String.valueOf(RequestCode.MSG_BATCH_SEND.getRequestCode()).equals(requestCode)) { - return SendMessageBatchProtocolResolver.buildEvent(header, body); - } else if (String.valueOf(RequestCode.MSG_BATCH_SEND_V2.getRequestCode()).equals(requestCode)) { - return SendMessageBatchV2ProtocolResolver.buildEvent(header, body); - } else if (String.valueOf(RequestCode.MSG_SEND_SYNC.getRequestCode()).equals(requestCode)) { - return SendMessageRequestProtocolResolver.buildEvent(header, body); - } else if (String.valueOf(RequestCode.MSG_SEND_ASYNC.getRequestCode()).equals(requestCode)) { - return SendMessageRequestProtocolResolver.buildEvent(header, body); - } else { - throw new ProtocolHandleException(String.format("unsupported requestCode: %s", requestCode)); + org.apache.eventmesh.common.protocol.http.header.Header header, + Body body) throws ProtocolHandleException { + + switch (RequestCode.get(Integer.parseInt(requestCode))) { + case MSG_BATCH_SEND: + return SendMessageBatchProtocolResolver.buildEvent(header, body); + case MSG_BATCH_SEND_V2: + return SendMessageBatchV2ProtocolResolver.buildEvent(header, body); + case MSG_SEND_SYNC: + case MSG_SEND_ASYNC: + return SendMessageRequestProtocolResolver.buildEvent(header, body); + default: + throw new ProtocolHandleException(String.format("unsupported requestCode: %s", requestCode)); } } @Override public List toBatchCloudEvent(ProtocolTransportObject protocol) throws ProtocolHandleException { - if (protocol instanceof BatchMessageWrapper) { - BatchMessage batchMessage = ((BatchMessageWrapper) protocol).getMessage(); - return GrpcMessageProtocolResolver.buildBatchEvents(batchMessage); + if (protocol instanceof BatchEventMeshCloudEventWrapper) { + CloudEventBatch cloudEventBatch = ((BatchEventMeshCloudEventWrapper) protocol).getMessage(); + return GrpcEventMeshCloudEventProtocolResolver.buildBatchEvents(cloudEventBatch); } else { throw new ProtocolHandleException(String.format("protocol class: %s", protocol.getClass())); } @@ -111,33 +105,45 @@ public List toBatchCloudEvent(ProtocolTransportObject protocol) thro @Override public ProtocolTransportObject fromCloudEvent(CloudEvent cloudEvent) throws ProtocolHandleException { - String protocolDesc = cloudEvent.getExtension(Constants.PROTOCOL_DESC).toString(); - - if (StringUtils.equals("http", protocolDesc)) { - HttpCommand httpCommand = new HttpCommand(); - Body body = new Body() { - final Map map = new HashMap<>(); - - @Override - public Map toMap() { - map.put("content", new String(cloudEvent.getData().toBytes(), StandardCharsets.UTF_8)); - return map; - } - }; - body.toMap(); - httpCommand.setBody(body); - return httpCommand; - } else if (StringUtils.equals("grpc", protocolDesc)) { - return GrpcMessageProtocolResolver.buildSimpleMessage(cloudEvent); - } else if (StringUtils.equals("tcp", protocolDesc)) { - return TcpMessageProtocolResolver.buildEventMeshMessage(cloudEvent); - } else { - throw new ProtocolHandleException(String.format("Unsupported protocolDesc: %s", protocolDesc)); + validateCloudEvent(cloudEvent); + String protocolDesc = + cloudEvent.getExtension(Constants.PROTOCOL_DESC) == null ? null : cloudEvent.getExtension(Constants.PROTOCOL_DESC).toString(); + + switch (Objects.requireNonNull(protocolDesc)) { + case Constants.PROTOCOL_DESC_HTTP: + HttpCommand httpCommand = new HttpCommand(); + Body body = new Body() { + + final Map map = new HashMap<>(); + + @Override + public Map toMap() { + if (cloudEvent.getData() == null) { + return map; + } + map.put(MeshMessageProtocolConstant.PROTOCOL_KEY_CONTENT, + new String(cloudEvent.getData().toBytes(), Constants.DEFAULT_CHARSET)); + return map; + } + }; + body.toMap(); + httpCommand.setBody(body); + return httpCommand; + case Constants.PROTOCOL_DESC_TCP: + return TcpMessageProtocolResolver.buildEventMeshMessage(cloudEvent); + case Constants.PROTOCOL_DESC_GRPC_CLOUD_EVENT: + return GrpcEventMeshCloudEventProtocolResolver.buildEventMeshCloudEvent(cloudEvent); + default: + throw new ProtocolHandleException(String.format("Unsupported protocolDesc: %s", protocolDesc)); } } @Override public String getProtocolType() { - return MeshMessageProtocolConstant.PROTOCOL_NAME; + return EventMeshProtocolType.EVENT_MESH_MESSAGE.protocolTypeName(); + } + + private void validateCloudEvent(CloudEvent cloudEvent) { + Preconditions.checkNotNull(cloudEvent, "CloudEvent cannot be null"); } } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolConstant.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolConstant.java index 0a667f63f0..ac9f3d6e46 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolConstant.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolConstant.java @@ -19,5 +19,8 @@ public enum MeshMessageProtocolConstant { ; + public static final String PROTOCOL_NAME = "eventmeshmessage"; + + public static final String PROTOCOL_KEY_CONTENT = "content"; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/grpc/GrpcEventMeshCloudEventProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/grpc/GrpcEventMeshCloudEventProtocolResolver.java new file mode 100644 index 0000000000..19a1cbc43e --- /dev/null +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/grpc/GrpcEventMeshCloudEventProtocolResolver.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.protocol.meshmessage.resolver.grpc; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.protobuf.ProtobufFormat; + +import com.google.protobuf.InvalidProtocolBufferException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GrpcEventMeshCloudEventProtocolResolver { + + private static final EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(ProtobufFormat.PROTO_CONTENT_TYPE); + + public static io.cloudevents.CloudEvent buildEvent(CloudEvent cloudEvent) { + if (cloudEvent == null) { + return null; + } + io.cloudevents.CloudEvent event = eventFormat.deserialize(cloudEvent.toByteArray()); + return event; + } + + public static EventMeshCloudEventWrapper buildEventMeshCloudEvent(io.cloudevents.CloudEvent cloudEvent) { + if (cloudEvent == null) { + return new EventMeshCloudEventWrapper(null); + } + try { + return new EventMeshCloudEventWrapper(CloudEvent.parseFrom(eventFormat.serialize(cloudEvent))); + } catch (InvalidProtocolBufferException e) { + log.error("Build Event Mesh CloudEvent from io.cloudevents.CloudEvent error", e); + } + return null; + } + + public static List buildBatchEvents(CloudEventBatch cloudEventBatch) { + if (cloudEventBatch == null || cloudEventBatch.getEventsCount() < 1) { + return new ArrayList<>(0); + } + return cloudEventBatch.getEventsList().stream().map(cloudEvent -> eventFormat.deserialize(cloudEvent.toByteArray())) + .collect(Collectors.toList()); + } + +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/grpc/GrpcMessageProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/grpc/GrpcMessageProtocolResolver.java deleted file mode 100644 index 47b4278ca7..0000000000 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/grpc/GrpcMessageProtocolResolver.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.protocol.meshmessage.resolver.grpc; - -import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage.MessageItem; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; - -import org.apache.commons.lang3.StringUtils; - -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import io.cloudevents.CloudEvent; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class GrpcMessageProtocolResolver { - - public static CloudEvent buildEvent(SimpleMessage message) throws ProtocolHandleException { - try { - RequestHeader requestHeader = message.getHeader(); - - String protocolType = requestHeader.getProtocolType(); - String protocolDesc = requestHeader.getProtocolDesc(); - String protocolVersion = requestHeader.getProtocolVersion(); - - String env = requestHeader.getEnv(); - String idc = requestHeader.getIdc(); - String ip = requestHeader.getIp(); - String pid = requestHeader.getPid(); - String sys = requestHeader.getSys(); - String username = requestHeader.getUsername(); - String passwd = requestHeader.getPassword(); - String language = requestHeader.getLanguage(); - - String content = message.getContent(); - - CloudEvent event = null; - CloudEventBuilder cloudEventBuilder; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v1(); - - cloudEventBuilder = cloudEventBuilder.withId(message.getSeqNum()) - .withSubject(message.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.ENV, env) - .withExtension(ProtocolKey.IDC, idc) - .withExtension(ProtocolKey.IP, ip) - .withExtension(ProtocolKey.PID, pid) - .withExtension(ProtocolKey.SYS, sys) - .withExtension(ProtocolKey.USERNAME, username) - .withExtension(ProtocolKey.PASSWD, passwd) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(ProtocolKey.SEQ_NUM, message.getSeqNum()) - .withExtension(ProtocolKey.UNIQUE_ID, message.getUniqueId()) - .withExtension(ProtocolKey.PRODUCERGROUP, message.getProducerGroup()) - .withExtension(ProtocolKey.TTL, message.getTtl()); - - for (Map.Entry entry : message.getPropertiesMap().entrySet()) { - cloudEventBuilder.withExtension(entry.getKey(), entry.getValue()); - } - if (StringUtils.isNotEmpty(message.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(ProtocolKey.TAG, message.getTag()); - } - event = cloudEventBuilder.build(); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v03(); - cloudEventBuilder = cloudEventBuilder.withId(message.getSeqNum()) - .withSubject(message.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.ENV, env) - .withExtension(ProtocolKey.IDC, idc) - .withExtension(ProtocolKey.IP, ip) - .withExtension(ProtocolKey.PID, pid) - .withExtension(ProtocolKey.SYS, sys) - .withExtension(ProtocolKey.USERNAME, username) - .withExtension(ProtocolKey.PASSWD, passwd) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(ProtocolKey.SEQ_NUM, message.getSeqNum()) - .withExtension(ProtocolKey.UNIQUE_ID, message.getUniqueId()) - .withExtension(ProtocolKey.PRODUCERGROUP, message.getProducerGroup()) - .withExtension(ProtocolKey.TTL, message.getTtl()); - - for (Map.Entry entry : message.getPropertiesMap().entrySet()) { - cloudEventBuilder.withExtension(entry.getKey(), entry.getValue()); - } - if (StringUtils.isNotEmpty(message.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(ProtocolKey.TAG, message.getTag()); - } - event = cloudEventBuilder.build(); - } - return event; - } catch (Exception e) { - throw new ProtocolHandleException(e.getMessage(), e.getCause()); - } - } - - public static List buildBatchEvents(BatchMessage message) { - List events = new LinkedList<>(); - RequestHeader requestHeader = message.getHeader(); - - String protocolType = requestHeader.getProtocolType(); - String protocolDesc = requestHeader.getProtocolDesc(); - String protocolVersion = requestHeader.getProtocolVersion(); - - String env = requestHeader.getEnv(); - String idc = requestHeader.getIdc(); - String ip = requestHeader.getIp(); - String pid = requestHeader.getPid(); - String sys = requestHeader.getSys(); - String username = requestHeader.getUsername(); - String passwd = requestHeader.getPassword(); - String language = requestHeader.getLanguage(); - - for (MessageItem item : message.getMessageItemList()) { - String content = item.getContent(); - - CloudEvent event = null; - CloudEventBuilder cloudEventBuilder; - - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v1(); - - cloudEventBuilder = cloudEventBuilder.withId(item.getSeqNum()) - .withSubject(message.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.ENV, env) - .withExtension(ProtocolKey.IDC, idc) - .withExtension(ProtocolKey.IP, ip) - .withExtension(ProtocolKey.PID, pid) - .withExtension(ProtocolKey.SYS, sys) - .withExtension(ProtocolKey.USERNAME, username) - .withExtension(ProtocolKey.PASSWD, passwd) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(ProtocolKey.SEQ_NUM, item.getSeqNum()) - .withExtension(ProtocolKey.UNIQUE_ID, item.getUniqueId()) - .withExtension(ProtocolKey.PRODUCERGROUP, message.getProducerGroup()) - .withExtension(ProtocolKey.TTL, item.getTtl()); - - for (Map.Entry entry : item.getPropertiesMap().entrySet()) { - cloudEventBuilder.withExtension(entry.getKey(), entry.getValue()); - } - if (StringUtils.isNotEmpty(item.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(ProtocolKey.TAG, item.getTag()); - } - event = cloudEventBuilder.build(); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v03(); - cloudEventBuilder = cloudEventBuilder.withId(item.getSeqNum()) - .withSubject(message.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.ENV, env) - .withExtension(ProtocolKey.IDC, idc) - .withExtension(ProtocolKey.IP, ip) - .withExtension(ProtocolKey.PID, pid) - .withExtension(ProtocolKey.SYS, sys) - .withExtension(ProtocolKey.USERNAME, username) - .withExtension(ProtocolKey.PASSWD, passwd) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(ProtocolKey.SEQ_NUM, item.getSeqNum()) - .withExtension(ProtocolKey.UNIQUE_ID, item.getUniqueId()) - .withExtension(ProtocolKey.PRODUCERGROUP, message.getProducerGroup()) - .withExtension(ProtocolKey.TTL, item.getTtl()); - - for (Map.Entry entry : item.getPropertiesMap().entrySet()) { - cloudEventBuilder.withExtension(entry.getKey(), entry.getValue()); - } - if (StringUtils.isNotEmpty(item.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(ProtocolKey.TAG, item.getTag()); - } - event = cloudEventBuilder.build(); - } - events.add(event); - } - - return events; - } - - public static SimpleMessageWrapper buildSimpleMessage(CloudEvent cloudEvent) { - String env = cloudEvent.getExtension(ProtocolKey.ENV) == null ? "env" : cloudEvent.getExtension(ProtocolKey.ENV).toString(); - String idc = cloudEvent.getExtension(ProtocolKey.IDC) == null ? "idc" : cloudEvent.getExtension(ProtocolKey.IDC).toString(); - String ip = cloudEvent.getExtension(ProtocolKey.IP) == null ? "ip" : cloudEvent.getExtension(ProtocolKey.IP).toString(); - String pid = cloudEvent.getExtension(ProtocolKey.PID) == null ? "33" : cloudEvent.getExtension(ProtocolKey.PID).toString(); - String sys = cloudEvent.getExtension(ProtocolKey.SYS) == null ? "sys" : cloudEvent.getExtension(ProtocolKey.SYS).toString(); - String userName = cloudEvent.getExtension(ProtocolKey.USERNAME) == null ? "user" : cloudEvent.getExtension(ProtocolKey.USERNAME).toString(); - String passwd = cloudEvent.getExtension(ProtocolKey.PASSWD) == null ? "pass" : cloudEvent.getExtension(ProtocolKey.PASSWD).toString(); - String language = cloudEvent.getExtension(ProtocolKey.LANGUAGE) == null ? "JAVA" : cloudEvent.getExtension(ProtocolKey.LANGUAGE).toString(); - String protocol = cloudEvent.getExtension(ProtocolKey.PROTOCOL_TYPE) == null ? "" : - cloudEvent.getExtension(ProtocolKey.PROTOCOL_TYPE).toString(); - String protocolDesc = cloudEvent.getExtension(ProtocolKey.PROTOCOL_DESC) == null ? "" : - cloudEvent.getExtension(ProtocolKey.PROTOCOL_DESC).toString(); - String protocolVersion = cloudEvent.getExtension(ProtocolKey.PROTOCOL_VERSION) == null ? "" : - cloudEvent.getExtension(ProtocolKey.PROTOCOL_VERSION).toString(); - String seqNum = cloudEvent.getExtension(ProtocolKey.SEQ_NUM) == null ? "" : cloudEvent.getExtension(ProtocolKey.SEQ_NUM).toString(); - String uniqueId = cloudEvent.getExtension(ProtocolKey.UNIQUE_ID) == null ? "" : cloudEvent.getExtension(ProtocolKey.UNIQUE_ID).toString(); - String producerGroup = cloudEvent.getExtension(ProtocolKey.PRODUCERGROUP) == null ? "" : - cloudEvent.getExtension(ProtocolKey.PRODUCERGROUP).toString(); - String ttl = cloudEvent.getExtension(ProtocolKey.TTL) == null ? "4000" : cloudEvent.getExtension(ProtocolKey.TTL).toString(); - - RequestHeader header = RequestHeader.newBuilder() - .setEnv(env).setIdc(idc) - .setIp(ip).setPid(pid) - .setSys(sys).setUsername(userName).setPassword(passwd) - .setLanguage(language).setProtocolType(protocol) - .setProtocolDesc(protocolDesc).setProtocolVersion(protocolVersion) - .build(); - - SimpleMessage.Builder messageBuilder = SimpleMessage.newBuilder() - .setHeader(header) - .setContent(new String(cloudEvent.getData().toBytes(), StandardCharsets.UTF_8)) - .setProducerGroup(producerGroup) - .setSeqNum(seqNum) - .setUniqueId(uniqueId) - .setTopic(cloudEvent.getSubject()) - .setTtl(ttl); - - for (String key : cloudEvent.getExtensionNames()) { - messageBuilder.putProperties(key, cloudEvent.getExtension(key).toString()); - } - - SimpleMessage simpleMessage = messageBuilder.build(); - - return new SimpleMessageWrapper(simpleMessage); - } -} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchProtocolResolver.java index e5762dc354..e71487b118 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchProtocolResolver.java @@ -23,6 +23,7 @@ import io.cloudevents.CloudEvent; public class SendMessageBatchProtocolResolver { + public static CloudEvent buildEvent(Header header, Body body) { return null; } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchV2ProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchV2ProtocolResolver.java index eefe660a37..d7197b6a95 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchV2ProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageBatchV2ProtocolResolver.java @@ -17,11 +17,11 @@ package org.apache.eventmesh.protocol.meshmessage.resolver.http; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.header.Header; import org.apache.eventmesh.common.protocol.http.header.message.SendMessageBatchV2RequestHeader; import org.apache.eventmesh.protocol.api.exception.ProtocolHandleException; @@ -29,96 +29,53 @@ import org.apache.commons.lang3.StringUtils; import java.net.URI; -import java.nio.charset.StandardCharsets; import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; public class SendMessageBatchV2ProtocolResolver { + public static CloudEvent buildEvent(Header header, Body body) throws ProtocolHandleException { try { SendMessageBatchV2RequestHeader sendMessageBatchV2RequestHeader = (SendMessageBatchV2RequestHeader) header; SendMessageBatchV2RequestBody sendMessageBatchV2RequestBody = (SendMessageBatchV2RequestBody) body; - String protocolType = sendMessageBatchV2RequestHeader.getProtocolType(); - String protocolDesc = sendMessageBatchV2RequestHeader.getProtocolDesc(); - String protocolVersion = sendMessageBatchV2RequestHeader.getProtocolVersion(); - - String code = sendMessageBatchV2RequestHeader.getCode(); - String env = sendMessageBatchV2RequestHeader.getEnv(); - String idc = sendMessageBatchV2RequestHeader.getIdc(); - String ip = sendMessageBatchV2RequestHeader.getIp(); - String pid = sendMessageBatchV2RequestHeader.getPid(); - String sys = sendMessageBatchV2RequestHeader.getSys(); - String username = sendMessageBatchV2RequestHeader.getUsername(); - String passwd = sendMessageBatchV2RequestHeader.getPasswd(); - ProtocolVersion version = sendMessageBatchV2RequestHeader.getVersion(); - String language = sendMessageBatchV2RequestHeader.getLanguage(); - - String content = sendMessageBatchV2RequestBody.getMsg(); - - CloudEvent event = null; - CloudEventBuilder cloudEventBuilder; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v1(); + CloudEventBuilder cloudEventBuilder = CloudEventBuilder.fromSpecVersion( + SpecVersion.parse(sendMessageBatchV2RequestHeader.getProtocolVersion())); - cloudEventBuilder = cloudEventBuilder.withId(sendMessageBatchV2RequestBody.getBizSeqNo()) - .withSubject(sendMessageBatchV2RequestBody.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageBatchV2RequestBody.BIZSEQNO, sendMessageBatchV2RequestBody.getBizSeqNo()) - .withExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP, sendMessageBatchV2RequestBody.getProducerGroup()) - .withExtension(SendMessageBatchV2RequestBody.TTL, sendMessageBatchV2RequestBody.getTtl()); - if (StringUtils.isNotEmpty(sendMessageBatchV2RequestBody.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(SendMessageRequestBody.TAG, sendMessageBatchV2RequestBody.getTag()); - } - event = cloudEventBuilder.build(); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v03(); - cloudEventBuilder = cloudEventBuilder.withId(sendMessageBatchV2RequestBody.getBizSeqNo()) - .withSubject(sendMessageBatchV2RequestBody.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageBatchV2RequestBody.BIZSEQNO, sendMessageBatchV2RequestBody.getBizSeqNo()) - .withExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP, sendMessageBatchV2RequestBody.getProducerGroup()) - .withExtension(SendMessageBatchV2RequestBody.TTL, sendMessageBatchV2RequestBody.getTtl()); - if (StringUtils.isNotEmpty(sendMessageBatchV2RequestBody.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(SendMessageRequestBody.TAG, sendMessageBatchV2RequestBody.getTag()); - } - event = cloudEventBuilder.build(); - } - return event; + return getBuildCloudEvent(sendMessageBatchV2RequestHeader, sendMessageBatchV2RequestBody, cloudEventBuilder); } catch (Exception e) { throw new ProtocolHandleException(e.getMessage(), e.getCause()); } } + + private static CloudEvent getBuildCloudEvent(SendMessageBatchV2RequestHeader sendMessageBatchV2RequestHeader, + SendMessageBatchV2RequestBody sendMessageBatchV2RequestBody, CloudEventBuilder cloudEventBuilder) { + cloudEventBuilder = cloudEventBuilder.withId(sendMessageBatchV2RequestBody.getBizSeqNo()) + .withSubject(sendMessageBatchV2RequestBody.getTopic()) + .withType("eventmeshmessage") + .withSource(URI.create("/")) + .withData(sendMessageBatchV2RequestBody.getMsg().getBytes(Constants.DEFAULT_CHARSET)) + .withExtension(ProtocolKey.REQUEST_CODE, sendMessageBatchV2RequestHeader.getCode()) + .withExtension(ProtocolKey.ClientInstanceKey.ENV.getKey(), sendMessageBatchV2RequestHeader.getEnv()) + .withExtension(ProtocolKey.ClientInstanceKey.IDC.getKey(), sendMessageBatchV2RequestHeader.getIdc()) + .withExtension(ProtocolKey.ClientInstanceKey.IP.getKey(), sendMessageBatchV2RequestHeader.getIp()) + .withExtension(ProtocolKey.ClientInstanceKey.PID.getKey(), sendMessageBatchV2RequestHeader.getPid()) + .withExtension(ProtocolKey.ClientInstanceKey.SYS.getKey(), sendMessageBatchV2RequestHeader.getSys()) + .withExtension(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), sendMessageBatchV2RequestHeader.getUsername()) + .withExtension(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), sendMessageBatchV2RequestHeader.getPasswd()) + .withExtension(ProtocolKey.VERSION, sendMessageBatchV2RequestHeader.getVersion().getVersion()) + .withExtension(ProtocolKey.LANGUAGE, sendMessageBatchV2RequestHeader.getLanguage()) + .withExtension(ProtocolKey.PROTOCOL_TYPE, sendMessageBatchV2RequestHeader.getProtocolType()) + .withExtension(ProtocolKey.PROTOCOL_DESC, sendMessageBatchV2RequestHeader.getProtocolDesc()) + .withExtension(ProtocolKey.PROTOCOL_VERSION, sendMessageBatchV2RequestHeader.getProtocolVersion()) + .withExtension(SendMessageBatchV2RequestBody.BIZSEQNO, sendMessageBatchV2RequestBody.getBizSeqNo()) + .withExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP, sendMessageBatchV2RequestBody.getProducerGroup()) + .withExtension(SendMessageBatchV2RequestBody.TTL, sendMessageBatchV2RequestBody.getTtl()); + if (StringUtils.isNotEmpty(sendMessageBatchV2RequestBody.getTag())) { + cloudEventBuilder = cloudEventBuilder.withExtension(SendMessageRequestBody.TAG, sendMessageBatchV2RequestBody.getTag()); + } + return cloudEventBuilder.build(); + } } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageRequestProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageRequestProtocolResolver.java index 215f2e38ce..2ad417cf5d 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageRequestProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/http/SendMessageRequestProtocolResolver.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.protocol.meshmessage.resolver.http; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; @@ -28,7 +29,6 @@ import org.apache.commons.lang3.StringUtils; import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.Map; import io.cloudevents.CloudEvent; @@ -61,56 +61,22 @@ public static CloudEvent buildEvent(Header header, Body body) throws ProtocolHan CloudEvent event = null; CloudEventBuilder cloudEventBuilder; - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v1(); + if (StringUtils.equalsAny(protocolVersion, SpecVersion.V1.toString(), SpecVersion.V03.toString())) { + cloudEventBuilder = CloudEventBuilder.fromSpecVersion(SpecVersion.parse(protocolVersion)); cloudEventBuilder = cloudEventBuilder.withId(sendMessageRequestBody.getBizSeqNo()) .withSubject(sendMessageRequestBody.getTopic()) .withType("eventmeshmessage") .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) + .withData(content.getBytes(Constants.DEFAULT_CHARSET)) .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) - .withExtension(ProtocolKey.VERSION, version.getVersion()) - .withExtension(ProtocolKey.LANGUAGE, language) - .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) - .withExtension(ProtocolKey.PROTOCOL_DESC, protocolDesc) - .withExtension(ProtocolKey.PROTOCOL_VERSION, protocolVersion) - .withExtension(SendMessageRequestBody.BIZSEQNO, sendMessageRequestBody.getBizSeqNo()) - .withExtension(SendMessageRequestBody.UNIQUEID, sendMessageRequestBody.getUniqueId()) - .withExtension(SendMessageRequestBody.PRODUCERGROUP, - sendMessageRequestBody.getProducerGroup()) - .withExtension(SendMessageRequestBody.TTL, sendMessageRequestBody.getTtl()); - if (StringUtils.isNotEmpty(sendMessageRequestBody.getTag())) { - cloudEventBuilder = cloudEventBuilder.withExtension(SendMessageRequestBody.TAG, sendMessageRequestBody.getTag()); - } - if (sendMessageRequestBody.getExtFields() != null && sendMessageRequestBody.getExtFields().size() > 0) { - for (Map.Entry entry : sendMessageRequestBody.getExtFields().entrySet()) { - cloudEventBuilder = cloudEventBuilder.withExtension(entry.getKey(), entry.getValue()); - } - } - event = cloudEventBuilder.build(); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v03(); - cloudEventBuilder = cloudEventBuilder.withId(sendMessageRequestBody.getBizSeqNo()) - .withSubject(sendMessageRequestBody.getTopic()) - .withType("eventmeshmessage") - .withSource(URI.create("/")) - .withData(content.getBytes(StandardCharsets.UTF_8)) - .withExtension(ProtocolKey.REQUEST_CODE, code) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, env) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, idc) - .withExtension(ProtocolKey.ClientInstanceKey.IP, ip) - .withExtension(ProtocolKey.ClientInstanceKey.PID, pid) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, sys) - .withExtension(ProtocolKey.ClientInstanceKey.USERNAME, username) - .withExtension(ProtocolKey.ClientInstanceKey.PASSWD, passwd) + .withExtension(ProtocolKey.ClientInstanceKey.ENV.getKey(), env) + .withExtension(ProtocolKey.ClientInstanceKey.IDC.getKey(), idc) + .withExtension(ProtocolKey.ClientInstanceKey.IP.getKey(), ip) + .withExtension(ProtocolKey.ClientInstanceKey.PID.getKey(), pid) + .withExtension(ProtocolKey.ClientInstanceKey.SYS.getKey(), sys) + .withExtension(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), username) + .withExtension(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), passwd) .withExtension(ProtocolKey.VERSION, version.getVersion()) .withExtension(ProtocolKey.LANGUAGE, language) .withExtension(ProtocolKey.PROTOCOL_TYPE, protocolType) diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/tcp/TcpMessageProtocolResolver.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/tcp/TcpMessageProtocolResolver.java index 6e199cad9e..48b94696c9 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/tcp/TcpMessageProtocolResolver.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/main/java/org/apache/eventmesh/protocol/meshmessage/resolver/tcp/TcpMessageProtocolResolver.java @@ -27,9 +27,9 @@ import org.apache.commons.lang3.StringUtils; import java.net.URI; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; @@ -37,20 +37,16 @@ public class TcpMessageProtocolResolver { - public static CloudEvent buildEvent(Header header, EventMeshMessage message) throws ProtocolHandleException { - CloudEventBuilder cloudEventBuilder; String protocolType = header.getProperty(Constants.PROTOCOL_TYPE).toString(); String protocolVersion = header.getProperty(Constants.PROTOCOL_VERSION).toString(); String protocolDesc = header.getProperty(Constants.PROTOCOL_DESC).toString(); - if (StringUtils.isBlank(protocolType) - || StringUtils.isBlank(protocolVersion) - || StringUtils.isBlank(protocolDesc)) { + if (StringUtils.isAnyBlank(protocolType, protocolVersion, protocolDesc)) { throw new ProtocolHandleException(String.format("invalid protocol params protocolType %s|protocolVersion %s|protocolDesc %s", - protocolType, protocolVersion, protocolDesc)); + protocolType, protocolVersion, protocolDesc)); } if (!StringUtils.equals(MeshMessageProtocolConstant.PROTOCOL_NAME, protocolType)) { @@ -58,39 +54,37 @@ public static CloudEvent buildEvent(Header header, EventMeshMessage message) thr } String topic = message.getTopic(); - String content = message.getBody(); - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v1(); - - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - cloudEventBuilder = CloudEventBuilder.v03(); - + if (StringUtils.equalsAny(protocolVersion, SpecVersion.V1.toString(), SpecVersion.V03.toString())) { + cloudEventBuilder = CloudEventBuilder.fromSpecVersion(SpecVersion.parse(protocolVersion)); } else { throw new ProtocolHandleException(String.format("Unsupported protocolVersion: %s", protocolVersion)); } - cloudEventBuilder = cloudEventBuilder - .withId(header.getSeq()) - .withSource(URI.create("/")) - .withType("eventmeshmessage") - .withSubject(topic) - .withData(content.getBytes(StandardCharsets.UTF_8)); + cloudEventBuilder.withId(header.getSeq()) + .withSource(URI.create("/")) + .withType("eventmeshmessage") + .withSubject(topic) + .withData(content.getBytes(Constants.DEFAULT_CHARSET)); - for (String propKey : header.getProperties().keySet()) { + if (message.getHeaders().containsKey(Constants.DATA_CONTENT_TYPE)) { + cloudEventBuilder.withDataContentType(message.getHeaders().get(Constants.DATA_CONTENT_TYPE)); + } + + for (Map.Entry prop : header.getProperties().entrySet()) { try { - cloudEventBuilder.withExtension(propKey, header.getProperty(propKey).toString()); + cloudEventBuilder.withExtension(prop.getKey(), prop.getValue().toString()); } catch (Exception e) { - throw new ProtocolHandleException(String.format("Abnormal propKey: %s", propKey), e); + throw new ProtocolHandleException(String.format("Abnormal propKey: %s", prop.getKey()), e); } } - for (String propKey : message.getProperties().keySet()) { + for (Map.Entry prop : message.getProperties().entrySet()) { try { - cloudEventBuilder.withExtension(propKey, message.getProperties().get(propKey)); + cloudEventBuilder.withExtension(prop.getKey(), prop.getValue()); } catch (Exception e) { - throw new ProtocolHandleException(String.format("Abnormal propKey: %s", propKey), e); + throw new ProtocolHandleException(String.format("Abnormal propKey: %s", prop.getKey()), e); } } @@ -101,17 +95,21 @@ public static CloudEvent buildEvent(Header header, EventMeshMessage message) thr public static Package buildEventMeshMessage(CloudEvent cloudEvent) { EventMeshMessage eventMeshMessage = new EventMeshMessage(); eventMeshMessage.setTopic(cloudEvent.getSubject()); - eventMeshMessage.setBody(new String(cloudEvent.getData().toBytes(), StandardCharsets.UTF_8)); + eventMeshMessage.setBody(new String(Objects.requireNonNull(cloudEvent.getData()).toBytes(), Constants.DEFAULT_CHARSET)); Map prop = new HashMap<>(); - for (String extKey : cloudEvent.getExtensionNames()) { - prop.put(extKey, cloudEvent.getExtension(extKey).toString()); - } + cloudEvent.getExtensionNames().forEach(k -> { + prop.put(k, Objects.requireNonNull(cloudEvent.getExtension(k)).toString()); + }); eventMeshMessage.setProperties(prop); Package pkg = new Package(); pkg.setBody(eventMeshMessage); + if (!StringUtils.isBlank(cloudEvent.getDataContentType())) { + eventMeshMessage.getHeaders().put(Constants.DATA_CONTENT_TYPE, cloudEvent.getDataContentType()); + } + return pkg; } } diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/test/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptorTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/test/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptorTest.java index d67c58071a..4e1eac7d84 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/test/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptorTest.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-meshmessage/src/test/java/org/apache/eventmesh/protocol/meshmessage/MeshMessageProtocolAdaptorTest.java @@ -21,23 +21,22 @@ import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class MeshMessageProtocolAdaptorTest { @Test public void loadPlugin() { ProtocolAdaptor protocolAdaptor = - ProtocolPluginFactory.getProtocolAdaptor(MeshMessageProtocolConstant.PROTOCOL_NAME); - Assert.assertNotNull(protocolAdaptor); + ProtocolPluginFactory.getProtocolAdaptor(MeshMessageProtocolConstant.PROTOCOL_NAME); + Assertions.assertNotNull(protocolAdaptor); - Assert.assertEquals( - MeshMessageProtocolConstant.PROTOCOL_NAME, protocolAdaptor.getProtocolType() - ); + Assertions.assertEquals( + MeshMessageProtocolConstant.PROTOCOL_NAME, protocolAdaptor.getProtocolType()); } @Test public void getProtocolType() { } -} \ No newline at end of file +} diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/main/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptor.java b/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/main/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptor.java index 0e2d525049..7ddc76ea0e 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/main/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptor.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/main/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptor.java @@ -27,8 +27,7 @@ import io.openmessaging.api.Message; /** - * OpenMessage protocol adaptor, used to transform protocol between - * {@link CloudEvent} with {@link Message}. + * OpenMessage protocol adaptor, used to transform protocol between {@link CloudEvent} with {@link Message}. * * @since 1.3.0 */ diff --git a/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/test/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptorTest.java b/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/test/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptorTest.java index b0c49707fa..62d46d7155 100644 --- a/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/test/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptorTest.java +++ b/eventmesh-protocol-plugin/eventmesh-protocol-openmessage/src/test/java/org/apache/eventmesh/protocol/openmessage/OpenMessageProtocolAdaptorTest.java @@ -21,20 +21,19 @@ import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class OpenMessageProtocolAdaptorTest { @Test public void loadPlugin() { ProtocolAdaptor protocolAdaptor = - ProtocolPluginFactory.getProtocolAdaptor(OpenMessageProtocolConstant.PROTOCOL_NAME); + ProtocolPluginFactory.getProtocolAdaptor(OpenMessageProtocolConstant.PROTOCOL_NAME); - Assert.assertNotNull(protocolAdaptor); - Assert.assertEquals( - OpenMessageProtocolConstant.PROTOCOL_NAME, protocolAdaptor.getProtocolType() - ); - Assert.assertEquals(OpenMessageProtocolAdaptor.class, protocolAdaptor.getClass()); + Assertions.assertNotNull(protocolAdaptor); + Assertions.assertEquals( + OpenMessageProtocolConstant.PROTOCOL_NAME, protocolAdaptor.getProtocolType()); + Assertions.assertEquals(OpenMessageProtocolAdaptor.class, protocolAdaptor.getClass()); } -} \ No newline at end of file +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/RegistryService.java b/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/RegistryService.java deleted file mode 100644 index c38bf7a4a4..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/registry/RegistryService.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.api.registry; - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.spi.EventMeshExtensionType; -import org.apache.eventmesh.spi.EventMeshSPI; - -import java.util.List; -import java.util.Map; - -/** - * RegistryService - */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.REGISTRY) -public interface RegistryService { - - void init() throws RegistryException; - - void start() throws RegistryException; - - void shutdown() throws RegistryException; - - List findEventMeshInfoByCluster(String clusterName) throws RegistryException; - - List findAllEventMeshInfo() throws RegistryException; - - Map> findEventMeshClientDistributionData( - String clusterName, String group, String purpose) throws RegistryException; - - void registerMetadata(Map metadataMap); - - boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws RegistryException; - - boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws RegistryException; -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-consul/build.gradle b/eventmesh-registry-plugin/eventmesh-registry-consul/build.gradle deleted file mode 100644 index 53d7f67b4c..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-consul/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -dependencies { - implementation 'com.ecwid.consul:consul-api:1.4.5' - implementation 'org.apache.httpcomponents:httpclient:4.5.13' - implementation project(":eventmesh-registry-plugin:eventmesh-registry-api") - implementation project(":eventmesh-common") - testImplementation "org.mockito:mockito-core" -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-consul/gradle.properties b/eventmesh-registry-plugin/eventmesh-registry-consul/gradle.properties deleted file mode 100644 index 3ed992f06e..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-consul/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# 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. -# - -pluginType=registry -pluginName=consul \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/java/org/apache/eventmesh/registry/consul/service/ConsulRegistryService.java b/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/java/org/apache/eventmesh/registry/consul/service/ConsulRegistryService.java deleted file mode 100644 index 36b3c2814c..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/java/org/apache/eventmesh/registry/consul/service/ConsulRegistryService.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.registry.consul.service; - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.RegistryService; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.ConsulRawClient; -import com.ecwid.consul.v1.agent.model.NewService; -import com.ecwid.consul.v1.agent.model.Service; -import com.ecwid.consul.v1.health.HealthServicesRequest; -import com.ecwid.consul.v1.health.model.HealthService; - -public class ConsulRegistryService implements RegistryService { - - public static final String IP_PORT_SEPARATOR = ":"; - - private static final Logger logger = LoggerFactory.getLogger(ConsulRegistryService.class); - - private static final AtomicBoolean INIT_STATUS = new AtomicBoolean(false); - - private static final AtomicBoolean START_STATUS = new AtomicBoolean(false); - - private String consulHost; - - private String consulPort; - - private ConsulClient consulClient; - - private String token; - - @Override - public void init() throws RegistryException { - if (INIT_STATUS.compareAndSet(false, true)) { - for (String key : ConfigurationContextUtil.KEYS) { - CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); - if (null != commonConfiguration) { - String namesrvAddr = commonConfiguration.namesrvAddr; - if (StringUtils.isBlank(namesrvAddr)) { - throw new RegistryException("namesrvAddr cannot be null"); - } - String[] addr = namesrvAddr.split(":"); - if (addr.length != 2) { - throw new RegistryException("Illegal namesrvAddr"); - } - this.consulHost = addr[0]; - this.consulPort = addr[1]; - break; - } - } - } - } - - @Override - public void start() throws RegistryException { - consulClient = new ConsulClient(new ConsulRawClient(consulHost, Integer.parseInt(consulPort))); - } - - @Override - public void shutdown() throws RegistryException { - INIT_STATUS.compareAndSet(true, false); - START_STATUS.compareAndSet(true, false); - consulClient = null; - } - - @Override - public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws RegistryException { - try { - String[] ipPort = eventMeshRegisterInfo.getEndPoint().split(IP_PORT_SEPARATOR); - NewService service = new NewService(); - service.setPort(Integer.parseInt(ipPort[1])); - service.setAddress(ipPort[0]); - service.setName(eventMeshRegisterInfo.getEventMeshName()); - service.setId(eventMeshRegisterInfo.getEventMeshClusterName() + "-" + eventMeshRegisterInfo.getEventMeshName()); - consulClient.agentServiceRegister(service, token); - } catch (Exception e) { - throw new RegistryException(e.getMessage()); - } - logger.info("EventMesh successfully registered to consul"); - return true; - } - - @Override - public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws RegistryException { - try { - consulClient.agentServiceDeregister(eventMeshUnRegisterInfo.getEventMeshClusterName() + "-" + eventMeshUnRegisterInfo.getEventMeshName(), - token); - } catch (Exception e) { - throw new RegistryException(e.getMessage()); - } - logger.info("EventMesh successfully unregistered to consul"); - return true; - } - - @Override - public List findEventMeshInfoByCluster(String clusterName) throws RegistryException { - HealthServicesRequest request = HealthServicesRequest.newBuilder().setPassing(true).setToken(token).build(); - List healthServices = consulClient.getHealthServices(clusterName, request).getValue(); - List eventMeshDataInfos = new ArrayList<>(); - healthServices.forEach(healthService -> { - HealthService.Service service = healthService.getService(); - String[] split = service.getId().split("-"); - eventMeshDataInfos.add(new EventMeshDataInfo(split[0], split[1], service.getAddress() + ":" + service.getPort(), 0, service.getMeta())); - }); - return eventMeshDataInfos; - } - - @Override - public List findAllEventMeshInfo() throws RegistryException { - Map agentServices = consulClient.getAgentServices().getValue(); - List eventMeshDataInfos = new ArrayList<>(); - agentServices.forEach((k, v) -> { - String[] split = v.getId().split("-"); - eventMeshDataInfos.add(new EventMeshDataInfo(split[0], split[1], v.getAddress() + ":" + v.getPort(), 0, v.getMeta())); - }); - return eventMeshDataInfos; - } - - @Override - public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) - throws RegistryException { - return Collections.emptyMap(); - } - - @Override - public void registerMetadata(Map metadataMap) { - - } - - public ConsulClient getConsulClient() { - return consulClient; - } -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService b/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService deleted file mode 100644 index d18efe974c..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-consul/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -consul=org.apache.eventmesh.registry.consul.service.ConsulRegistryService \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-consul/src/test/java/ConsulRegistryServiceTest.java b/eventmesh-registry-plugin/eventmesh-registry-consul/src/test/java/ConsulRegistryServiceTest.java deleted file mode 100644 index 96932e7dd0..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-consul/src/test/java/ConsulRegistryServiceTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - */ - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; -import org.apache.eventmesh.registry.consul.service.ConsulRegistryService; - -import java.lang.reflect.Field; -import java.util.List; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class ConsulRegistryServiceTest { - - @Mock - private EventMeshRegisterInfo eventMeshRegisterInfo; - @Mock - private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; - - private ConsulRegistryService consulRegistryService; - - @Before - public void registryTest() { - consulRegistryService = new ConsulRegistryService(); - CommonConfiguration configuration = new CommonConfiguration(null); - ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.HTTP, configuration); - configuration.namesrvAddr = "127.0.0.1:8500"; - Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); - Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); - Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8500"); - - Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); - Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); - } - - @After - public void after() { - consulRegistryService.shutdown(); - } - - @Test - public void testInit() { - consulRegistryService.init(); - consulRegistryService.start(); - Assert.assertNotNull(consulRegistryService.getConsulClient()); - } - - @Test - public void testStart() { - consulRegistryService.init(); - consulRegistryService.start(); - Assert.assertNotNull(consulRegistryService.getConsulClient()); - } - - @Test - public void testShutdown() throws NoSuchFieldException, IllegalAccessException { - consulRegistryService.init(); - consulRegistryService.start(); - consulRegistryService.shutdown(); - Assert.assertNull(consulRegistryService.getConsulClient()); - Class consulRegistryServiceClass = ConsulRegistryService.class; - Field initStatus = consulRegistryServiceClass.getDeclaredField("INIT_STATUS"); - initStatus.setAccessible(true); - Object initStatusField = initStatus.get(consulRegistryService); - - Field startStatus = consulRegistryServiceClass.getDeclaredField("START_STATUS"); - startStatus.setAccessible(true); - Object startStatusField = startStatus.get(consulRegistryService); - - - Assert.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); - Assert.assertFalse((Boolean.parseBoolean(startStatusField.toString()))); - } - - @Test(expected = RegistryException.class) - public void testRegister() { - consulRegistryService.init(); - consulRegistryService.start(); - consulRegistryService.register(eventMeshRegisterInfo); - List eventmesh = consulRegistryService.findEventMeshInfoByCluster("eventmesh"); - Assert.assertEquals(1, eventmesh.size()); - } - - @Test(expected = RegistryException.class) - public void testUnRegister() { - consulRegistryService.init(); - consulRegistryService.start(); - consulRegistryService.unRegister(eventMeshUnRegisterInfo); - List eventmesh = consulRegistryService.findEventMeshInfoByCluster("eventmesh"); - Assert.assertEquals(0, eventmesh.size()); - } - - @Test(expected = RegistryException.class) - public void findEventMeshInfoByCluster() { - consulRegistryService.init(); - consulRegistryService.start(); - consulRegistryService.register(eventMeshRegisterInfo); - List eventmesh = consulRegistryService.findEventMeshInfoByCluster("eventmesh"); - Assert.assertEquals(1, eventmesh.size()); - consulRegistryService.unRegister(eventMeshUnRegisterInfo); - } -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/build.gradle b/eventmesh-registry-plugin/eventmesh-registry-etcd/build.gradle deleted file mode 100644 index 153c7555b3..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -dependencies { - implementation ("io.etcd:jetcd-core:0.3.0") - implementation project(":eventmesh-registry-plugin:eventmesh-registry-api") - implementation project(":eventmesh-common") - testImplementation "org.mockito:mockito-core" -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/gradle.properties b/eventmesh-registry-plugin/eventmesh-registry-etcd/gradle.properties deleted file mode 100644 index 325b28af4a..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# 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. -# - -pluginType=registry -pluginName=etcd \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/service/EtcdRegistryService.java b/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/service/EtcdRegistryService.java deleted file mode 100644 index 58c78f34a9..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/java/org/apache/eventmesh/registry/etcd/service/EtcdRegistryService.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.registry.etcd.service; - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.RegistryService; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.ThreadPoolFactory; -import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.registry.etcd.constant.EtcdConstant; -import org.apache.eventmesh.registry.etcd.factory.EtcdClientFactory; - -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.etcd.jetcd.ByteSequence; -import io.etcd.jetcd.Client; -import io.etcd.jetcd.KeyValue; -import io.etcd.jetcd.options.GetOption; -import io.etcd.jetcd.options.PutOption; - -public class EtcdRegistryService implements RegistryService { - - private static final Logger logger = LoggerFactory.getLogger(EtcdRegistryService.class); - - private static final AtomicBoolean INIT_STATUS = new AtomicBoolean(false); - - private static final AtomicBoolean START_STATUS = new AtomicBoolean(false); - - private static final String KEY_PREFIX = EtcdConstant.KEY_SEPARATOR + "eventMesh" + EtcdConstant.KEY_SEPARATOR + "registry" - + EtcdConstant.KEY_SEPARATOR; - - private String serverAddr; - - private String username; - - private String password; - - private Client etcdClient; - - private Map eventMeshRegisterInfoMap; - - private ScheduledExecutorService etcdRegistryMonitorExecutorService; - - @Override - public void init() throws RegistryException { - boolean update = INIT_STATUS.compareAndSet(false, true); - if (!update) { - return; - } - eventMeshRegisterInfoMap = new HashMap<>(ConfigurationContextUtil.KEYS.size()); - for (String key : ConfigurationContextUtil.KEYS) { - CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); - if (null == commonConfiguration) { - continue; - } - if (StringUtils.isBlank(commonConfiguration.namesrvAddr)) { - throw new RegistryException("namesrvAddr cannot be null"); - } - this.serverAddr = commonConfiguration.namesrvAddr; - this.username = commonConfiguration.eventMeshRegistryPluginUsername; - this.password = commonConfiguration.eventMeshRegistryPluginPassword; - break; - } - etcdRegistryMonitorExecutorService = ThreadPoolFactory.createSingleScheduledExecutor( - "EtcdRegistryMonitorThread" - ); - } - - @Override - public void start() throws RegistryException { - boolean update = START_STATUS.compareAndSet(false, true); - if (!update) { - return; - } - try { - Properties properties = new Properties(); - properties.setProperty(EtcdConstant.SERVER_ADDR, serverAddr); - properties.setProperty(EtcdConstant.USERNAME, username); - properties.setProperty(EtcdConstant.PASSWORD, password); - this.etcdClient = EtcdClientFactory.createClient(properties); - - etcdRegistryMonitorExecutorService.scheduleAtFixedRate(new EventMeshEtcdRegisterMonitor(), - 15000L, 15000L, TimeUnit.MILLISECONDS); - } catch (Exception e) { - logger.error("[EtcdRegistryService][start] error", e); - throw new RegistryException(e.getMessage()); - } - } - - @Override - public void shutdown() throws RegistryException { - INIT_STATUS.compareAndSet(true, false); - START_STATUS.compareAndSet(true, false); - try { - if (etcdClient != null) { - etcdClient.close(); - } - if (etcdRegistryMonitorExecutorService != null && !etcdRegistryMonitorExecutorService.isShutdown()) { - etcdRegistryMonitorExecutorService.shutdown(); - } - } catch (Exception e) { - logger.error("[EtcdRegistryService][shutdown] error", e); - throw new RegistryException(e.getMessage()); - } - logger.info("EtcdRegistryService closed"); - } - - @Override - public List findEventMeshInfoByCluster(String clusterName) throws RegistryException { - List eventMeshDataInfoList = new ArrayList<>(); - - try { - String keyPrefix = clusterName == null ? KEY_PREFIX : KEY_PREFIX + EtcdConstant.KEY_SEPARATOR + clusterName; - ByteSequence keyByteSequence = ByteSequence.from(keyPrefix.getBytes()); - GetOption getOption = GetOption.newBuilder().withPrefix(keyByteSequence).build(); - List keyValues = etcdClient.getKVClient().get(keyByteSequence, getOption).get().getKvs(); - - if (CollectionUtils.isNotEmpty(keyValues)) { - for (KeyValue kv : keyValues) { - EventMeshDataInfo eventMeshDataInfo = JsonUtils.deserialize(new String(kv.getValue().getBytes()), EventMeshDataInfo.class); - eventMeshDataInfoList.add(eventMeshDataInfo); - } - } - } catch (Exception e) { - logger.error("[EtcdRegistryService][findEventMeshInfoByCluster] error, clusterName: {}", clusterName, e); - throw new RegistryException(e.getMessage()); - } - return eventMeshDataInfoList; - } - - @Override - public List findAllEventMeshInfo() throws RegistryException { - try { - return findEventMeshInfoByCluster(null); - } catch (Exception e) { - logger.error("[EtcdRegistryService][findEventMeshInfoByCluster] error", e); - throw new RegistryException(e.getMessage()); - } - } - - @Override - public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) - throws RegistryException { - // todo find metadata - return null; - } - - @Override - public void registerMetadata(Map metadataMap) { - for (Map.Entry eventMeshRegisterInfo : eventMeshRegisterInfoMap.entrySet()) { - EventMeshRegisterInfo registerInfo = eventMeshRegisterInfo.getValue(); - registerInfo.setMetadata(metadataMap); - this.register(registerInfo); - } - } - - @Override - public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws RegistryException { - String eventMeshClusterName = eventMeshRegisterInfo.getEventMeshClusterName(); - String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); - String endPoint = eventMeshRegisterInfo.getEndPoint(); - try { - ByteSequence etcdKey = getEtcdKey(eventMeshClusterName, eventMeshName, endPoint); - EventMeshDataInfo eventMeshDataInfo = - new EventMeshDataInfo(eventMeshClusterName, eventMeshName, - endPoint, System.currentTimeMillis(), eventMeshRegisterInfo.getMetadata()); - ByteSequence etcdValue = ByteSequence.from(JsonUtils.serialize(eventMeshDataInfo).getBytes()); - etcdClient.getKVClient().put(etcdKey, etcdValue, PutOption.newBuilder().withLeaseId(getLeaseId()).build()); - eventMeshRegisterInfoMap.put(eventMeshName, eventMeshRegisterInfo); - - logger.info("EventMesh successfully registered to etcd, eventMeshClusterName: {}, eventMeshName: {}", - eventMeshClusterName, eventMeshName); - return true; - } catch (Exception e) { - logger.error("[EtcdRegistryService][register] error, eventMeshClusterName: {}, eventMeshName: {}", - eventMeshClusterName, eventMeshName, e); - throw new RegistryException(e.getMessage()); - } - } - - @Override - public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws RegistryException { - String eventMeshClusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); - String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); - try { - ByteSequence etcdKey = getEtcdKey(eventMeshClusterName, eventMeshName, - eventMeshUnRegisterInfo.getEndPoint()); - etcdClient.getKVClient().delete(etcdKey); - eventMeshRegisterInfoMap.remove(eventMeshName); - logger.info("EventMesh successfully logout to etcd, eventMeshClusterName: {}, eventMeshName: {}", - eventMeshClusterName, eventMeshName); - return true; - } catch (Exception e) { - logger.error("[EtcdRegistryService][unRegister] error, eventMeshClusterName: {}, eventMeshName: {}", - eventMeshClusterName, eventMeshName, e); - throw new RegistryException(e.getMessage()); - } - } - - public Client getEtcdClient() { - return etcdClient; - } - - public long getLeaseId() { - return EtcdClientFactory.getLeaseId(serverAddr); - } - - private ByteSequence getEtcdKey(String eventMeshClusterName, String eventMeshName, String endPoint) { - StringBuilder etcdKey = new StringBuilder(KEY_PREFIX).append(eventMeshClusterName); - if (StringUtils.isNoneBlank(eventMeshName)) { - etcdKey.append(EtcdConstant.KEY_SEPARATOR).append(eventMeshName); - } - if (StringUtils.isNoneBlank(endPoint)) { - etcdKey.append(EtcdConstant.KEY_SEPARATOR).append(endPoint); - } - return ByteSequence.from(etcdKey.toString().getBytes()); - } - - /** - * check the registered services if alive - */ - private class EventMeshEtcdRegisterMonitor implements Runnable { - - @Override - public void run() { - if (eventMeshRegisterInfoMap.size() > 0) { - for (Map.Entry eventMeshRegisterInfoEntry : eventMeshRegisterInfoMap.entrySet()) { - EventMeshRegisterInfo eventMeshRegisterInfo = eventMeshRegisterInfoEntry.getValue(); - ByteSequence etcdKey = getEtcdKey(eventMeshRegisterInfo.getEventMeshClusterName(), - eventMeshRegisterInfo.getEventMeshName(), eventMeshRegisterInfo.getEndPoint()); - List keyValues = null; - try { - keyValues = etcdClient.getKVClient().get(etcdKey).get().getKvs(); - } catch (InterruptedException | ExecutionException e) { - logger.error("get etcdKey[{}] failed", etcdKey, e); - } - if (CollectionUtils.isEmpty(keyValues)) { - logger.warn("eventMeshRegisterInfo [{}] is not matched in Etcd , try to register again", - eventMeshRegisterInfo.getEventMeshName()); - EtcdClientFactory.renewalLeaseId(EtcdClientFactory.getEtcdLeaseId(serverAddr)); - register(eventMeshRegisterInfo); - } - } - } - } - } -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService b/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService deleted file mode 100644 index 56730d9290..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -etcd=org.apache.eventmesh.registry.etcd.service.EtcdRegistryService \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdRegistryServiceTest.java b/eventmesh-registry-plugin/eventmesh-registry-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdRegistryServiceTest.java deleted file mode 100644 index 5aaaeaf6e4..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-etcd/src/test/java/org/apache/eventmesh/registry/etcd/service/EtcdRegistryServiceTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.registry.etcd.service; - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; - -import java.lang.reflect.Field; -import java.util.List; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class EtcdRegistryServiceTest { - - @Mock - private EventMeshRegisterInfo eventMeshRegisterInfo; - @Mock - private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; - - private EtcdRegistryService etcdRegistryService; - - @Before - public void setUp() { - etcdRegistryService = new EtcdRegistryService(); - CommonConfiguration configuration = new CommonConfiguration(null); - configuration.namesrvAddr = "127.0.0.1:2379"; - ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.HTTP, configuration); - - // Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); - // Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); - // Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:2379"); - // - // Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); - // Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); - // Mockito.when(eventMeshUnRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:2379"); - } - - @After - public void after() { - etcdRegistryService.shutdown(); - } - - - @Test - public void testInit() { - etcdRegistryService.init(); - } - - @Test(expected = RegistryException.class) - public void testStart() { - etcdRegistryService.init(); - etcdRegistryService.start(); - Assert.assertNotNull(etcdRegistryService); - - } - - @Test(expected = RegistryException.class) - public void testShutdown() throws NoSuchFieldException, IllegalAccessException { - etcdRegistryService.init(); - etcdRegistryService.start(); - etcdRegistryService.shutdown(); - - Class etcdRegistryServiceClass = EtcdRegistryService.class; - Field initStatus = etcdRegistryServiceClass.getDeclaredField("INIT_STATUS"); - initStatus.setAccessible(true); - Object initStatusField = initStatus.get(etcdRegistryService); - - Field startStatus = etcdRegistryServiceClass.getDeclaredField("START_STATUS"); - startStatus.setAccessible(true); - Object startStatusField = startStatus.get(etcdRegistryService); - - } - - @Test(expected = RegistryException.class) - public void testRegister() { - etcdRegistryService.init(); - etcdRegistryService.start(); - etcdRegistryService.register(eventMeshRegisterInfo); - } - - @Test(expected = RegistryException.class) - public void testFindEventMeshInfo() { - etcdRegistryService.init(); - etcdRegistryService.start(); - etcdRegistryService.register(eventMeshRegisterInfo); - List eventMeshDataInfoList = etcdRegistryService.findAllEventMeshInfo(); - } - - @Test(expected = RegistryException.class) - public void testUnRegister() { - etcdRegistryService.init(); - etcdRegistryService.start(); - etcdRegistryService.unRegister(eventMeshUnRegisterInfo); - } - -} \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-nacos/build.gradle b/eventmesh-registry-plugin/eventmesh-registry-nacos/build.gradle deleted file mode 100644 index a0492d7479..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-nacos/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -dependencies { - implementation "com.alibaba.nacos:nacos-client:2.0.4" - implementation project(":eventmesh-registry-plugin:eventmesh-registry-api") - implementation project(":eventmesh-common") - testImplementation "org.mockito:mockito-core" -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-nacos/gradle.properties b/eventmesh-registry-plugin/eventmesh-registry-nacos/gradle.properties deleted file mode 100644 index dc23fa1f66..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-nacos/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# 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. -# - -pluginType=registry -pluginName=nacos \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/service/NacosRegistryService.java b/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/service/NacosRegistryService.java deleted file mode 100644 index 956f6eb629..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/service/NacosRegistryService.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.registry.nacos.service; - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.RegistryService; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; -import org.apache.eventmesh.registry.nacos.constant.NacosConstant; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.NamingService; -import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.client.naming.NacosNamingService; -import com.alibaba.nacos.common.utils.CollectionUtils; - -public class NacosRegistryService implements RegistryService { - - private static final Logger logger = LoggerFactory.getLogger(NacosRegistryService.class); - - private static final AtomicBoolean INIT_STATUS = new AtomicBoolean(false); - - private static final AtomicBoolean START_STATUS = new AtomicBoolean(false); - - private String serverAddr; - - private String username; - - private String password; - - private NamingService namingService; - - private Map eventMeshRegisterInfoMap; - - @Override - public void init() throws RegistryException { - boolean update = INIT_STATUS.compareAndSet(false, true); - if (!update) { - return; - } - eventMeshRegisterInfoMap = new HashMap<>(ConfigurationContextUtil.KEYS.size()); - for (String key : ConfigurationContextUtil.KEYS) { - CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); - if (null == commonConfiguration) { - continue; - } - if (StringUtils.isBlank(commonConfiguration.namesrvAddr)) { - throw new RegistryException("namesrvAddr cannot be null"); - } - this.serverAddr = commonConfiguration.namesrvAddr; - this.username = commonConfiguration.eventMeshRegistryPluginUsername; - this.password = commonConfiguration.eventMeshRegistryPluginPassword; - break; - } - } - - @Override - public void start() throws RegistryException { - boolean update = START_STATUS.compareAndSet(false, true); - if (!update) { - return; - } - try { - Properties properties = new Properties(); - properties.setProperty(NacosConstant.SERVER_ADDR, serverAddr); - properties.setProperty(NacosConstant.USERNAME, username); - properties.setProperty(NacosConstant.PASSWORD, password); - namingService = new NacosNamingService(properties); - } catch (NacosException e) { - logger.error("[NacosRegistryService][start] error", e); - throw new RegistryException(e.getMessage()); - } - } - - @Override - public void shutdown() throws RegistryException { - INIT_STATUS.compareAndSet(true, false); - START_STATUS.compareAndSet(true, false); - try { - namingService.shutDown(); - } catch (NacosException e) { - logger.error("[NacosRegistryService][shutdown] error", e); - throw new RegistryException(e.getMessage()); - } - logger.info("NacosRegistryService close"); - } - - @Override - public List findEventMeshInfoByCluster(String clusterName) throws RegistryException { - List eventMeshDataInfoList = new ArrayList<>(); - for (String key : ConfigurationContextUtil.KEYS) { - CommonConfiguration configuration = ConfigurationContextUtil.get(key); - if (Objects.isNull(configuration)) { - continue; - } - String eventMeshName = configuration.eventMeshName; - try { - List instances = - namingService.selectInstances(eventMeshName + "-" + key, configuration.eventMeshCluster, Collections.singletonList(clusterName), - true); - if (CollectionUtils.isEmpty(instances)) { - continue; - } - for (Instance instance : instances) { - EventMeshDataInfo eventMeshDataInfo = - new EventMeshDataInfo(instance.getClusterName(), instance.getServiceName(), - instance.getIp() + ":" + instance.getPort(), 0L, instance.getMetadata()); - eventMeshDataInfoList.add(eventMeshDataInfo); - } - } catch (NacosException e) { - logger.error("[NacosRegistryService][findEventMeshInfoByCluster] error", e); - throw new RegistryException(e.getMessage()); - } - - } - return eventMeshDataInfoList; - } - - @Override - public List findAllEventMeshInfo() throws RegistryException { - List eventMeshDataInfoList = new ArrayList<>(); - for (String key : ConfigurationContextUtil.KEYS) { - CommonConfiguration configuration = ConfigurationContextUtil.get(key); - if (Objects.isNull(configuration)) { - continue; - } - String eventMeshName = configuration.eventMeshName; - try { - List instances = - namingService.selectInstances(eventMeshName + "-" + key, key + "-" + NacosConstant.GROUP, null, - true); - if (CollectionUtils.isEmpty(instances)) { - continue; - } - for (Instance instance : instances) { - EventMeshDataInfo eventMeshDataInfo = - new EventMeshDataInfo(instance.getClusterName(), instance.getServiceName(), - instance.getIp() + ":" + instance.getPort(), 0L, instance.getMetadata()); - eventMeshDataInfoList.add(eventMeshDataInfo); - } - } catch (NacosException e) { - logger.error("[NacosRegistryService][findEventMeshInfoByCluster] error", e); - throw new RegistryException(e.getMessage()); - } - - } - return eventMeshDataInfoList; - } - - @Override - public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) - throws RegistryException { - // todo find metadata - return null; - } - - @Override - public void registerMetadata(Map metadataMap) { - for (Map.Entry eventMeshRegisterInfo : eventMeshRegisterInfoMap.entrySet()) { - EventMeshRegisterInfo registerInfo = eventMeshRegisterInfo.getValue(); - registerInfo.setMetadata(metadataMap); - this.register(registerInfo); - } - } - - @Override - public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws RegistryException { - try { - String[] ipPort = eventMeshRegisterInfo.getEndPoint().split(NacosConstant.IP_PORT_SEPARATOR); - String eventMeshClusterName = eventMeshRegisterInfo.getEventMeshClusterName(); - Map metadata = eventMeshRegisterInfo.getMetadata(); - - Instance instance = new Instance(); - instance.setIp(ipPort[0]); - instance.setPort(Integer.parseInt(ipPort[1])); - instance.setWeight(1.0); - instance.setClusterName(eventMeshClusterName); - instance.setMetadata(metadata); - - String eventMeshName = eventMeshRegisterInfo.getEventMeshName(); - namingService.registerInstance(eventMeshName, eventMeshRegisterInfo.getProtocolType() + "-" + NacosConstant.GROUP, instance); - eventMeshRegisterInfoMap.put(eventMeshName, eventMeshRegisterInfo); - } catch (NacosException e) { - logger.error("[NacosRegistryService][register] error", e); - throw new RegistryException(e.getMessage()); - } - logger.info("EventMesh successfully registered to nacos"); - return true; - } - - @Override - public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws RegistryException { - String[] ipPort = eventMeshUnRegisterInfo.getEndPoint().split(NacosConstant.IP_PORT_SEPARATOR); - try { - Instance instance = new Instance(); - instance.setIp(ipPort[0]); - instance.setPort(Integer.parseInt(ipPort[1])); - String eventMeshName = eventMeshUnRegisterInfo.getEventMeshName(); - String eventMeshClusterName = eventMeshUnRegisterInfo.getEventMeshClusterName(); - instance.setClusterName(eventMeshClusterName); - namingService.deregisterInstance(eventMeshName, eventMeshUnRegisterInfo.getProtocolType() + "-" + NacosConstant.GROUP, instance); - } catch (NacosException e) { - logger.error("[NacosRegistryService][unRegister] error", e); - throw new RegistryException(e.getMessage()); - } - logger.info("EventMesh successfully logout to nacos"); - return true; - } - - public String getServerAddr() { - return serverAddr; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public NamingService getNamingService() { - return namingService; - } -} diff --git a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService b/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService deleted file mode 100644 index 3d28c7c18d..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.registry.RegistryService +++ /dev/null @@ -1,16 +0,0 @@ -# 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. - -nacos=org.apache.eventmesh.registry.nacos.service.NacosRegistryService \ No newline at end of file diff --git a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/test/java/org/apache/eventmesh/registry/nacos/service/NacosRegistryServiceTest.java b/eventmesh-registry-plugin/eventmesh-registry-nacos/src/test/java/org/apache/eventmesh/registry/nacos/service/NacosRegistryServiceTest.java deleted file mode 100644 index 9499128930..0000000000 --- a/eventmesh-registry-plugin/eventmesh-registry-nacos/src/test/java/org/apache/eventmesh/registry/nacos/service/NacosRegistryServiceTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.registry.nacos.service; - -import org.apache.eventmesh.api.exception.RegistryException; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; - -import java.lang.reflect.Field; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class NacosRegistryServiceTest { - - @Mock - private EventMeshRegisterInfo eventMeshRegisterInfo; - @Mock - private EventMeshUnRegisterInfo eventMeshUnRegisterInfo; - - private NacosRegistryService nacosRegistryService; - - @Before - public void setUp() { - nacosRegistryService = new NacosRegistryService(); - CommonConfiguration configuration = new CommonConfiguration(null); - configuration.namesrvAddr = "127.0.0.1"; - configuration.eventMeshRegistryPluginPassword = "nacos"; - configuration.eventMeshRegistryPluginUsername = "nacos"; - ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.HTTP, configuration); - - Mockito.when(eventMeshRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); - Mockito.when(eventMeshRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); - Mockito.when(eventMeshRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); - - Mockito.when(eventMeshUnRegisterInfo.getEventMeshClusterName()).thenReturn("eventmesh"); - Mockito.when(eventMeshUnRegisterInfo.getEventMeshName()).thenReturn("eventmesh"); - Mockito.when(eventMeshUnRegisterInfo.getEndPoint()).thenReturn("127.0.0.1:8848"); - } - - @After - public void after() { - nacosRegistryService.shutdown(); - } - - - @Test - public void testInit() { - nacosRegistryService.init(); - nacosRegistryService.start(); - Assert.assertNotNull(nacosRegistryService.getServerAddr()); - } - - @Test - public void testStart() { - nacosRegistryService.init(); - nacosRegistryService.start(); - Assert.assertNotNull(nacosRegistryService.getNamingService()); - - } - - @Test - public void testShutdown() throws NoSuchFieldException, IllegalAccessException { - nacosRegistryService.init(); - nacosRegistryService.start(); - nacosRegistryService.shutdown(); - - Class nacosRegistryServiceClass = NacosRegistryService.class; - Field initStatus = nacosRegistryServiceClass.getDeclaredField("INIT_STATUS"); - initStatus.setAccessible(true); - Object initStatusField = initStatus.get(nacosRegistryService); - - Field startStatus = nacosRegistryServiceClass.getDeclaredField("START_STATUS"); - startStatus.setAccessible(true); - Object startStatusField = startStatus.get(nacosRegistryService); - - - Assert.assertFalse((Boolean.parseBoolean(initStatusField.toString()))); - Assert.assertFalse((Boolean.parseBoolean(startStatusField.toString()))); - } - - @Test(expected = RegistryException.class) - public void testRegister() { - nacosRegistryService.init(); - nacosRegistryService.start(); - nacosRegistryService.register(eventMeshRegisterInfo); - } - - @Test(expected = RegistryException.class) - public void testUnRegister() { - nacosRegistryService.init(); - nacosRegistryService.start(); - nacosRegistryService.unRegister(eventMeshUnRegisterInfo); - } - -} \ No newline at end of file diff --git a/eventmesh-registry/.gitignore b/eventmesh-registry/.gitignore new file mode 100644 index 0000000000..b63da4551b --- /dev/null +++ b/eventmesh-registry/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/eventmesh-registry/build.gradle b/eventmesh-registry/build.gradle new file mode 100644 index 0000000000..d973dcedae --- /dev/null +++ b/eventmesh-registry/build.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/eventmesh-registry/eventmesh-registry-api/build.gradle b/eventmesh-registry/eventmesh-registry-api/build.gradle new file mode 100644 index 0000000000..c0546b6169 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/build.gradle @@ -0,0 +1,25 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-spi") + implementation project(":eventmesh-common") + implementation "com.alibaba.nacos:nacos-client" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/NotifyEvent.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/NotifyEvent.java new file mode 100644 index 0000000000..fdef6a3285 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/NotifyEvent.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry; + +import java.util.List; + +import lombok.Getter; + +public class NotifyEvent { + + public NotifyEvent() { + + } + + public NotifyEvent(List instances) { + this(instances, false); + } + + public NotifyEvent(List instances, boolean isIncrement) { + this.isIncrement = isIncrement; + this.instances = instances; + } + + + // means whether it is an increment data + @Getter + private boolean isIncrement; + + @Getter + private List instances; +} diff --git a/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/QueryInstances.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/QueryInstances.java new file mode 100644 index 0000000000..c8c7d61f4d --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/QueryInstances.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Data; + +@Data +public class QueryInstances { + + private String serviceName; + private boolean health; + private Map extFields = new HashMap<>(); +} diff --git a/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegisterServerInfo.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegisterServerInfo.java new file mode 100644 index 0000000000..0bf411c037 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegisterServerInfo.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@ToString +public class RegisterServerInfo { + + // different implementations will have different formats + @Getter + @Setter + private String serviceName; + + @Getter + @Setter + private String address; + + @Getter + @Setter + private boolean health; + @Getter + private Map metadata = new HashMap<>(); + @Getter + private Map extFields = new HashMap<>(); + + public void setMetadata(Map metadata) { + if (metadata == null) { + this.metadata.clear(); + return; + } + + this.metadata = metadata; + } + + public void addMetadata(String key, String value) { + this.metadata.put(key, value); + } + + public void setExtFields(Map extFields) { + if (extFields == null) { + this.extFields.clear(); + return; + } + + this.extFields = extFields; + } + + public void addExtFields(String key, Object value) { + this.extFields.put(key, value); + } +} diff --git a/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryFactory.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryFactory.java new file mode 100644 index 0000000000..d757781c2b --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryFactory.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry; + +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.HashMap; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RegistryFactory { + + private static final Map META_CACHE = new HashMap<>(16); + + public static RegistryService getInstance(String registryPluginType) { + return META_CACHE.computeIfAbsent(registryPluginType, RegistryFactory::registryBuilder); + } + + private static RegistryService registryBuilder(String registryPluginType) { + RegistryService registryServiceExt = EventMeshExtensionFactory.getExtension(RegistryService.class, registryPluginType); + if (registryServiceExt == null) { + String errorMsg = "can't load the registry plugin, please check."; + log.error(errorMsg); + throw new RuntimeException(errorMsg); + } + log.info("build registry plugin [{}] by type [{}] success", registryServiceExt.getClass().getSimpleName(), + registryPluginType); + return registryServiceExt; + } +} diff --git a/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryListener.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryListener.java new file mode 100644 index 0000000000..81445fbe20 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryListener.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry; + +/** + * RegistryListener + */ +public interface RegistryListener { + + void onChange(NotifyEvent event) throws Exception; +} diff --git a/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryService.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryService.java new file mode 100644 index 0000000000..63243cd339 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/RegistryService.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry; + + +import org.apache.eventmesh.registry.exception.RegistryException; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +import java.util.List; + +/** + * RegistryService + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.REGISTRY) +public interface RegistryService { + void init() throws RegistryException; + + void shutdown() throws RegistryException; + + void subscribe(RegistryListener registryListener, String serviceName); + + void unsubscribe(RegistryListener registryListener, String serviceName); + + List selectInstances(QueryInstances serverInfo); + + boolean register(RegisterServerInfo registerInfo) throws RegistryException; + + boolean unRegister(RegisterServerInfo registerInfo) throws RegistryException; +} diff --git a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/exception/RegistryException.java b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/exception/RegistryException.java similarity index 93% rename from eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/exception/RegistryException.java rename to eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/exception/RegistryException.java index 893f8ff25c..1aa61bd246 100644 --- a/eventmesh-registry-plugin/eventmesh-registry-api/src/main/java/org/apache/eventmesh/api/exception/RegistryException.java +++ b/eventmesh-registry/eventmesh-registry-api/src/main/java/org/apache/eventmesh/registry/exception/RegistryException.java @@ -15,13 +15,9 @@ * limitations under the License. */ -package org.apache.eventmesh.api.exception; +package org.apache.eventmesh.registry.exception; -/** - * RegistryException - */ public class RegistryException extends RuntimeException { - public RegistryException(String message) { super(message); } diff --git a/eventmesh-registry/eventmesh-registry-nacos/build.gradle b/eventmesh-registry/eventmesh-registry-nacos/build.gradle new file mode 100644 index 0000000000..d371f23812 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-nacos/build.gradle @@ -0,0 +1,25 @@ +/* + * 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. + */ + +dependencies { + implementation "com.alibaba.nacos:nacos-client" + implementation project(":eventmesh-registry:eventmesh-registry-api") + implementation project(":eventmesh-common") + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' +} \ No newline at end of file diff --git a/eventmesh-registry/eventmesh-registry-nacos/gradle.properties b/eventmesh-registry/eventmesh-registry-nacos/gradle.properties new file mode 100644 index 0000000000..cf067e20bf --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-nacos/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# + +pluginType=registryCenter +pluginName=nacos \ No newline at end of file diff --git a/eventmesh-registry/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/NacosDiscoveryService.java b/eventmesh-registry/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/NacosDiscoveryService.java new file mode 100644 index 0000000000..54d9d8b9d3 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/NacosDiscoveryService.java @@ -0,0 +1,312 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry.nacos; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.registry.NotifyEvent; +import org.apache.eventmesh.registry.QueryInstances; +import org.apache.eventmesh.registry.RegisterServerInfo; +import org.apache.eventmesh.registry.RegistryListener; +import org.apache.eventmesh.registry.RegistryService; +import org.apache.eventmesh.registry.exception.RegistryException; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.AbstractEventListener; +import com.alibaba.nacos.api.naming.listener.Event; +import com.alibaba.nacos.api.naming.listener.EventListener; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.client.naming.utils.UtilAndComs; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class NacosDiscoveryService implements RegistryService { + + private final AtomicBoolean initFlag = new AtomicBoolean(false); + + private NacosRegistryConfiguration nacosConf; + + private NamingService namingService; + + private final Map> listeners = new HashMap<>(); + + private static final Executor notifyExecutor = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(20), r -> { + Thread t = new Thread(r); + t.setName("org.apache.eventmesh.registry.nacos.executor"); + t.setDaemon(true); + return t; + }, new ThreadPoolExecutor.DiscardOldestPolicy() + ); + + private final Lock lock = new ReentrantLock(); + + + @Override + public void init() throws RegistryException { + if (!initFlag.compareAndSet(false, true)) { + return; + } + nacosConf = ConfigService.getInstance().buildConfigInstance(NacosRegistryConfiguration.class); + if (nacosConf == null) { + log.info("nacos registry configuration is null"); + } + Properties properties = buildProperties(); + // registry + try { + this.namingService = NacosFactory.createNamingService(properties); + } catch (NacosException e) { + log.error("[NacosRegistryService][start] error", e); + throw new RegistryException(e.getMessage()); + } + } + + private Properties buildProperties() { + Properties properties = new Properties(); + if (nacosConf == null) { + return properties; + } + properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosConf.getRegistryAddr()); + properties.setProperty(PropertyKeyConst.USERNAME, nacosConf.getEventMeshRegistryPluginUsername()); + properties.setProperty(PropertyKeyConst.PASSWORD, nacosConf.getEventMeshRegistryPluginPassword()); + + String endpoint = nacosConf.getEndpoint(); + if (Objects.nonNull(endpoint) && endpoint.contains(":")) { + int index = endpoint.indexOf(":"); + properties.put(PropertyKeyConst.ENDPOINT, endpoint.substring(0, index)); + properties.put(PropertyKeyConst.ENDPOINT_PORT, endpoint.substring(index + 1)); + } else { + Optional.ofNullable(endpoint).ifPresent(value -> properties.put(PropertyKeyConst.ENDPOINT, endpoint)); + String endpointPort = nacosConf.getEndpointPort(); + Optional.ofNullable(endpointPort).ifPresent(value -> properties.put(PropertyKeyConst.ENDPOINT_PORT, + endpointPort)); + } + String accessKey = nacosConf.getAccessKey(); + Optional.ofNullable(accessKey).ifPresent(value -> properties.put(PropertyKeyConst.ACCESS_KEY, accessKey)); + String secretKey = nacosConf.getSecretKey(); + Optional.ofNullable(secretKey).ifPresent(value -> properties.put(PropertyKeyConst.SECRET_KEY, secretKey)); + String clusterName = nacosConf.getClusterName(); + Optional.ofNullable(clusterName).ifPresent(value -> properties.put(PropertyKeyConst.CLUSTER_NAME, clusterName)); + String logFileName = nacosConf.getLogFileName(); + Optional.ofNullable(logFileName).ifPresent(value -> properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, + logFileName)); + String logLevel = nacosConf.getLogLevel(); + Optional.ofNullable(logLevel).ifPresent(value -> properties.put(UtilAndComs.NACOS_NAMING_LOG_LEVEL, logLevel)); + Integer pollingThreadCount = nacosConf.getPollingThreadCount(); + Optional.ofNullable(pollingThreadCount).ifPresent(value -> properties.put(PropertyKeyConst.NAMING_POLLING_THREAD_COUNT, pollingThreadCount)); + String namespace = nacosConf.getNamespace(); + Optional.ofNullable(namespace).ifPresent(value -> properties.put(PropertyKeyConst.NAMESPACE, namespace)); + return properties; + } + + @Override + public void shutdown() throws RegistryException { + if (this.namingService != null) { + try { + namingService.shutDown(); + } catch (NacosException e) { + log.warn("shutdown nacos naming service fail", e); + } + } + } + + @Override + public void subscribe(RegistryListener listener, String serviceName) { + lock.lock(); + try { + ServiceInfo serviceInfo = ServiceInfo.fromKey(serviceName); + Map eventListenerMap = listeners.computeIfAbsent(serviceName, + k -> new HashMap<>()); + if (eventListenerMap.containsKey(listener)) { + log.warn("already use same listener subscribe service name {}", serviceName); + return; + } + EventListener eventListener = new AbstractEventListener() { + @Override + public Executor getExecutor() { + return notifyExecutor; + } + + @Override + public void onEvent(Event event) { + if (!(event instanceof NamingEvent)) { + log.warn("received notify event type isn't not as expected"); + return; + } + try { + NamingEvent namingEvent = (NamingEvent) event; + List instances = namingEvent.getInstances(); + List list = new ArrayList<>(); + if (instances != null) { + for (Instance instance : instances) { + RegisterServerInfo info = new RegisterServerInfo(); + info.setAddress(instance.getIp() + ":" + instance.getPort()); + info.setMetadata(instance.getMetadata()); + info.setHealth(instance.isHealthy()); + info.setServiceName( + ServiceInfo.getKey(NamingUtils.getGroupedName(namingEvent.getServiceName(), + namingEvent.getGroupName()), + namingEvent.getClusters())); + list.add(info); + } + } + listener.onChange(new NotifyEvent(list)); + } catch (Exception e) { + log.warn(""); + } + } + }; + List clusters; + if (serviceInfo.getClusters() == null || serviceInfo.getClusters().isEmpty()) { + clusters = new ArrayList<>(); + } else { + clusters = Arrays.stream(serviceInfo.getClusters().split(",")).collect(Collectors.toList()); + } + namingService.subscribe(serviceInfo.getName(), serviceInfo.getGroupName(), clusters, eventListener); + eventListenerMap.put(listener, eventListener); + } catch (Exception e) { + log.error("subscribe service name {} fail", serviceName, e); + } finally { + lock.unlock(); + } + } + + @Override + public void unsubscribe(RegistryListener registryListener, String serviceName) { + lock.lock(); + try { + ServiceInfo serviceInfo = ServiceInfo.fromKey(serviceName); + Map map = listeners.get(serviceName); + if (map == null) { + return; + } + List clusters; + if (serviceInfo.getClusters() == null || serviceInfo.getClusters().isEmpty()) { + clusters = new ArrayList<>(); + } else { + clusters = Arrays.stream(serviceInfo.getClusters().split(",")).collect(Collectors.toList()); + } + EventListener eventListener = map.get(registryListener); + namingService.unsubscribe(serviceInfo.getName(), serviceInfo.getGroupName(), clusters, eventListener); + map.remove(registryListener); + } catch (Exception e) { + log.error("unsubscribe service name {} fail", serviceName, e); + } finally { + lock.unlock(); + } + } + + @Override + public List selectInstances(QueryInstances queryInstances) { + ArrayList list = new ArrayList<>(); + try { + ServiceInfo serviceInfo = ServiceInfo.fromKey(queryInstances.getServiceName()); + ArrayList clusters = new ArrayList<>(); + if (StringUtils.isNotBlank(serviceInfo.getClusters())) { + clusters.addAll(Arrays.asList(serviceInfo.getClusters().split(","))); + } + List instances = namingService.selectInstances(serviceInfo.getName(), + serviceInfo.getGroupName(), clusters, + queryInstances.isHealth()); + if (instances != null) { + instances.forEach(x -> { + RegisterServerInfo instanceInfo = new RegisterServerInfo(); + instanceInfo.setMetadata(x.getMetadata()); + instanceInfo.setHealth(x.isHealthy()); + instanceInfo.setAddress(x.getIp() + ":" + x.getPort()); + instanceInfo.setServiceName( + ServiceInfo.getKey(NamingUtils.getGroupedName(x.getServiceName(), + serviceInfo.getGroupName()), x.getClusterName())); + list.add(instanceInfo); + }); + } + return list; + } catch (Exception e) { + log.error("select instance by query {} from nacos fail", queryInstances, e); + return list; + } + } + + @Override + public boolean register(RegisterServerInfo eventMeshRegisterInfo) throws RegistryException { + try { + String[] ipPort = eventMeshRegisterInfo.getAddress().split(":"); + if (ipPort.length < 2) { + return false; + } + ServiceInfo serviceInfo = ServiceInfo.fromKey(eventMeshRegisterInfo.getServiceName()); + Instance instance = new Instance(); + instance.setClusterName(serviceInfo.getClusters()); + instance.setEnabled(true); + instance.setEphemeral(true); + instance.setHealthy(eventMeshRegisterInfo.isHealth()); + instance.setWeight(1.0); + instance.setIp(ipPort[0]); + instance.setPort(Integer.parseInt(ipPort[1])); + instance.setMetadata(eventMeshRegisterInfo.getMetadata()); + namingService.registerInstance(serviceInfo.getName(), serviceInfo.getGroupName(), instance); + return true; + } catch (Exception e) { + log.error("register instance service {} fail", eventMeshRegisterInfo, e); + return false; + } + } + + @Override + public boolean unRegister(RegisterServerInfo eventMeshRegisterInfo) throws RegistryException { + try { + String[] ipPort = eventMeshRegisterInfo.getAddress().split(":"); + if (ipPort.length < 2) { + return false; + } + ServiceInfo serviceInfo = ServiceInfo.fromKey(eventMeshRegisterInfo.getServiceName()); + namingService.deregisterInstance(serviceInfo.getName(), serviceInfo.getGroupName(), ipPort[0], + Integer.parseInt(ipPort[1]), + serviceInfo.getClusters()); + return true; + } catch (Exception e) { + log.error("unregister instance service {} fail", eventMeshRegisterInfo, e); + return false; + } + } +} diff --git a/eventmesh-registry/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/NacosRegistryConfiguration.java b/eventmesh-registry/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/NacosRegistryConfiguration.java new file mode 100644 index 0000000000..7c908c9424 --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-nacos/src/main/java/org/apache/eventmesh/registry/nacos/NacosRegistryConfiguration.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.registry.nacos; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.client.naming.utils.UtilAndComs; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(prefix = "eventMesh.registry.nacos") +public class NacosRegistryConfiguration extends CommonConfiguration { + + @ConfigField(field = PropertyKeyConst.ENDPOINT) + private String endpoint; + + @ConfigField(field = PropertyKeyConst.ENDPOINT_PORT) + private String endpointPort; + + @ConfigField(field = PropertyKeyConst.ACCESS_KEY) + private String accessKey; + + @ConfigField(field = PropertyKeyConst.SECRET_KEY) + private String secretKey; + + @ConfigField(field = PropertyKeyConst.CLUSTER_NAME) + private String clusterName; + + @ConfigField(field = PropertyKeyConst.NAMESPACE) + private String namespace; + + @ConfigField(field = PropertyKeyConst.NAMING_POLLING_THREAD_COUNT) + private Integer pollingThreadCount = Runtime.getRuntime().availableProcessors() / 2 + 1; + + @ConfigField(field = UtilAndComs.NACOS_NAMING_LOG_NAME) + private String logFileName; + + @ConfigField(field = UtilAndComs.NACOS_NAMING_LOG_LEVEL) + private String logLevel; + +} diff --git a/eventmesh-registry/eventmesh-registry-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.registry.RegistryService b/eventmesh-registry/eventmesh-registry-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.registry.RegistryService new file mode 100644 index 0000000000..3301d56e5e --- /dev/null +++ b/eventmesh-registry/eventmesh-registry-nacos/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.registry.RegistryService @@ -0,0 +1,16 @@ +# 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. + +nacos=org.apache.eventmesh.registry.nacos.NacosDiscoveryService \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-api/build.gradle b/eventmesh-retry/eventmesh-retry-api/build.gradle new file mode 100644 index 0000000000..228d23f595 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/build.gradle @@ -0,0 +1,30 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-common") + implementation project(":eventmesh-spi") + + implementation 'io.cloudevents:cloudevents-core' + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'org.junit.jupiter:junit-jupiter' +} \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/AbstractRetryer.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/AbstractRetryer.java new file mode 100644 index 0000000000..0b6ddf844b --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/AbstractRetryer.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.retry.api.timer.HashedWheelTimer; +import org.apache.eventmesh.retry.api.timer.Timer; +import org.apache.eventmesh.retry.api.timer.TimerTask; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractRetryer implements Retryer { + + private volatile Timer timer; + + private static final int MAX_PENDING_TIMEOUTS = 10000; + + @Override + public void newTimeout(TimerTask timerTask, long delay, TimeUnit timeUnit) { + log.debug("[HASHED-WHEEL-TIMER] executed! taskClass={}, nowTime={}", + timeUnit.getClass().getName(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + timer.newTimeout(timerTask, delay, timeUnit); + } + + @Override + public void start() { + if (timer == null) { + synchronized (this) { + if (timer == null) { + timer = new HashedWheelTimer( + new EventMeshThreadFactory("failback-cluster-timer", true), + 1, + TimeUnit.SECONDS, 512, MAX_PENDING_TIMEOUTS); + } + } + } + log.info("EventMesh retryer started......"); + } + + @Override + public void shutdown() { + timer.stop(); + log.info("EventMesh retryer shutdown......"); + } + + @Override + public long getPendingTimeouts() { + if (timer == null) { + return 0; + } + return timer.pendingTimeouts(); + } + + @Override + public void printState() { + if (timer == null) { + log.warn("No HashedWheelTimer is provided!"); + return; + } + HashedWheelTimer hashedWheelTimer = (HashedWheelTimer) timer; + + log.info("[Retry-HashedWheelTimer] state=================="); + log.info("Running :{}", !hashedWheelTimer.isStop()); + log.info("Pending Timeouts: {} | Cancelled Timeouts: {}", hashedWheelTimer.pendingTimeouts(), hashedWheelTimer.cancelledTimeouts()); + log.info("========================================"); + } +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/Retryer.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/Retryer.java new file mode 100644 index 0000000000..82634e1739 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/Retryer.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api; + +import org.apache.eventmesh.retry.api.timer.TimerTask; + +import java.util.concurrent.TimeUnit; + +/** + * Retryer interface. + */ +public interface Retryer { + + void start(); + + void shutdown(); + + long getPendingTimeouts(); + + void printState(); + + void newTimeout(TimerTask timerTask, long delay, TimeUnit timeUnit); + +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/conf/RetryConfiguration.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/conf/RetryConfiguration.java new file mode 100644 index 0000000000..351a06fd39 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/conf/RetryConfiguration.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api.conf; + +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.protocol.SubscriptionMode; + +import io.cloudevents.CloudEvent; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class RetryConfiguration { + + private CloudEvent event; + + private String consumerGroupName; + + private Producer producer; + + private String topic; + + private SubscriptionMode subscriptionMode; +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/strategy/RetryStrategy.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/strategy/RetryStrategy.java new file mode 100644 index 0000000000..739be171b8 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/strategy/RetryStrategy.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api.strategy; + +import org.apache.eventmesh.retry.api.conf.RetryConfiguration; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * Retry strategy. + */ +@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.RETRY) +public interface RetryStrategy { + + void retry(RetryConfiguration configuration); +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/HashedWheelTimer.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/HashedWheelTimer.java new file mode 100644 index 0000000000..6c82bfdcb6 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/HashedWheelTimer.java @@ -0,0 +1,798 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api.timer; + +import static org.apache.eventmesh.common.Constants.OS_NAME_KEY; +import static org.apache.eventmesh.common.Constants.OS_WIN_PREFIX; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link Timer} optimized for approximated I/O timeout scheduling. + * + *

Tick Duration

+ *

+ * As described with 'approximated', this timer does not execute the scheduled + * {@link TimerTask} on time. {@link HashedWheelTimer}, on every tick, will + * check if there are any {@link TimerTask}s behind the schedule and execute + * them. + *

+ * You can increase or decrease the accuracy of the execution timing by + * specifying smaller or larger tick duration in the constructor. In most + * network applications, I/O timeout does not need to be accurate. Therefore, + * the default tick duration is 100 milliseconds, and you will not need to try + * different configurations in most cases. + * + *

Ticks per Wheel (Wheel Size)

+ *

+ * {@link HashedWheelTimer} maintains a data structure called 'wheel'. + * To put simply, a wheel is a hash table of {@link TimerTask}s whose hash + * function is 'deadline of the task'. The default number of ticks per wheel + * (i.e. the size of the wheel) is 512. You could specify a larger value + * if you are going to schedule a lot of timeouts. + * + *

Do not create many instances.

+ *

+ * {@link HashedWheelTimer} creates a new thread whenever it is instantiated and + * started. Therefore, you should make sure to create only one instance and + * share it across your application. One of the common mistakes, that makes + * your application unresponsive, is to create a new instance for every connection. + * + *

Implementation Details

+ *

+ * {@link HashedWheelTimer} is based on + * George Varghese and + * Tony Lauck's paper, + * 'Hashed + * and Hierarchical Timing Wheels: data structures to efficiently implement a + * timer facility'. More comprehensive slides are located + * here. + */ +public class HashedWheelTimer implements Timer { + + private static final Logger logger = LoggerFactory.getLogger(HashedWheelTimer.class); + + private static final AtomicInteger INSTANCE_COUNTER = new AtomicInteger(); + private static final AtomicBoolean WARNED_TOO_MANY_INSTANCES = new AtomicBoolean(); + private static final int INSTANCE_COUNT_LIMIT = 64; + private static final AtomicIntegerFieldUpdater WORKER_STATE_UPDATER = + AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimer.class, "workerState"); + + private final Worker worker = new Worker(); + private final Thread workerThread; + + private static final int WORKER_STATE_INIT = 0; + private static final int WORKER_STATE_STARTED = 1; + private static final int WORKER_STATE_SHUTDOWN = 2; + + /** + * 0 - init, 1 - started, 2 - shut down + */ + @SuppressWarnings({"unused", "FieldMayBeFinal"}) + private volatile int workerState; + + private final long tickDuration; + private final HashedWheelBucket[] wheel; + private final int mask; + private final CountDownLatch startTimeInitialized = new CountDownLatch(1); + private final Queue timeouts = new LinkedBlockingQueue<>(); + private final Queue cancelledTimeouts = new LinkedBlockingQueue<>(); + private final AtomicLong pendingTimeouts = new AtomicLong(0); + private final long maxPendingTimeouts; + + private volatile long startTime; + + /** + * Creates a new timer with the default thread factory + * ({@link Executors#defaultThreadFactory()}), default tick duration, and + * default number of ticks per wheel. + */ + public HashedWheelTimer() { + this(Executors.defaultThreadFactory()); + } + + /** + * Creates a new timer with the default thread factory + * ({@link Executors#defaultThreadFactory()}) and default number of ticks + * per wheel. + * + * @param tickDuration the duration between tick + * @param unit the time unit of the {@code tickDuration} + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code tickDuration} is <= 0 + */ + public HashedWheelTimer(long tickDuration, TimeUnit unit) { + this(Executors.defaultThreadFactory(), tickDuration, unit); + } + + /** + * Creates a new timer with the default thread factory + * ({@link Executors#defaultThreadFactory()}). + * + * @param tickDuration the duration between tick + * @param unit the time unit of the {@code tickDuration} + * @param ticksPerWheel the size of the wheel + * @throws NullPointerException if {@code unit} is {@code null} + * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0 + */ + public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) { + this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel); + } + + /** + * Creates a new timer with the default tick duration and default number of + * ticks per wheel. + * + * @param threadFactory a {@link ThreadFactory} that creates a + * background {@link Thread} which is dedicated to + * {@link TimerTask} execution. + * @throws NullPointerException if {@code threadFactory} is {@code null} + */ + public HashedWheelTimer(ThreadFactory threadFactory) { + this(threadFactory, 100, TimeUnit.MILLISECONDS); + } + + /** + * Creates a new timer with the default number of ticks per wheel. + * + * @param threadFactory a {@link ThreadFactory} that creates a + * background {@link Thread} which is dedicated to + * {@link TimerTask} execution. + * @param tickDuration the duration between tick + * @param unit the time unit of the {@code tickDuration} + * @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null} + * @throws IllegalArgumentException if {@code tickDuration} is <= 0 + */ + public HashedWheelTimer( + ThreadFactory threadFactory, long tickDuration, TimeUnit unit) { + this(threadFactory, tickDuration, unit, 512); + } + + /** + * Creates a new timer. + * + * @param threadFactory a {@link ThreadFactory} that creates a + * background {@link Thread} which is dedicated to + * {@link TimerTask} execution. + * @param tickDuration the duration between tick + * @param unit the time unit of the {@code tickDuration} + * @param ticksPerWheel the size of the wheel + * @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null} + * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0 + */ + public HashedWheelTimer( + ThreadFactory threadFactory, + long tickDuration, TimeUnit unit, int ticksPerWheel) { + this(threadFactory, tickDuration, unit, ticksPerWheel, -1); + } + + /** + * Creates a new timer. + * + * @param threadFactory a {@link ThreadFactory} that creates a + * background {@link Thread} which is dedicated to + * {@link TimerTask} execution. + * @param tickDuration the duration between tick + * @param unit the time unit of the {@code tickDuration} + * @param ticksPerWheel the size of the wheel + * @param maxPendingTimeouts The maximum number of pending timeouts after which call to + * {@code newTimeout} will result in + * {@link RejectedExecutionException} + * being thrown. No maximum pending timeouts limit is assumed if + * this value is 0 or negative. + * @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null} + * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0 + */ + public HashedWheelTimer( + ThreadFactory threadFactory, + long tickDuration, TimeUnit unit, int ticksPerWheel, + long maxPendingTimeouts) { + + if (threadFactory == null) { + throw new NullPointerException("threadFactory"); + } + if (unit == null) { + throw new NullPointerException("unit"); + } + if (tickDuration <= 0) { + throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration); + } + if (ticksPerWheel <= 0) { + throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel); + } + + // Normalize ticksPerWheel to power of two and initialize the wheel. + wheel = createWheel(ticksPerWheel); + mask = wheel.length - 1; + + // Convert tickDuration to nanos. + this.tickDuration = unit.toNanos(tickDuration); + + // Prevent overflow. + if (this.tickDuration >= Long.MAX_VALUE / wheel.length) { + throw new IllegalArgumentException(String.format( + "tickDuration: %d (expected: 0 < tickDuration in nanos < %d", + tickDuration, Long.MAX_VALUE / wheel.length)); + } + workerThread = threadFactory.newThread(worker); + + this.maxPendingTimeouts = maxPendingTimeouts; + + if (INSTANCE_COUNTER.incrementAndGet() > INSTANCE_COUNT_LIMIT && WARNED_TOO_MANY_INSTANCES.compareAndSet(false, true)) { + reportTooManyInstances(); + } + } + + private static HashedWheelBucket[] createWheel(int ticksPerWheel) { + if (ticksPerWheel <= 0) { + throw new IllegalArgumentException( + "ticksPerWheel must be greater than 0: " + ticksPerWheel); + } + if (ticksPerWheel > 1073741824) { + throw new IllegalArgumentException( + "ticksPerWheel may not be greater than 2^30: " + ticksPerWheel); + } + + ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel); + HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel]; + for (int i = 0; i < wheel.length; i++) { + wheel[i] = new HashedWheelBucket(); + } + return wheel; + } + + private static int normalizeTicksPerWheel(int ticksPerWheel) { + int normalizedTicksPerWheel = ticksPerWheel - 1; + normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 1; + normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 2; + normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 4; + normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 8; + normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 16; + return normalizedTicksPerWheel + 1; + } + + /** + * Starts the background thread explicitly. The background thread will + * start automatically on demand even if you did not call this method. + * + * @throws IllegalStateException if this timer has been + * {@linkplain #stop() stopped} already + */ + public void start() { + switch (WORKER_STATE_UPDATER.get(this)) { + case WORKER_STATE_INIT: + if (WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_INIT, WORKER_STATE_STARTED)) { + workerThread.start(); + } + break; + case WORKER_STATE_STARTED: + break; + case WORKER_STATE_SHUTDOWN: + throw new IllegalStateException("cannot be started once stopped"); + default: + throw new Error("Invalid WorkerState"); + } + + // Wait until the startTime is initialized by the worker. + while (startTime == 0) { + try { + startTimeInitialized.await(); + } catch (InterruptedException ignore) { + // Ignore - it will be ready very soon. + } + } + } + + @Override + public Set stop() { + if (Thread.currentThread() == workerThread) { + throw new IllegalStateException( + HashedWheelTimer.class.getSimpleName() + ".stop() cannot be called from " + TimerTask.class.getSimpleName()); + } + + if (!WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) { + // workerState can be 0 or 2 at this moment - let it always be 2. + if (WORKER_STATE_UPDATER.getAndSet(this, WORKER_STATE_SHUTDOWN) != WORKER_STATE_SHUTDOWN) { + INSTANCE_COUNTER.decrementAndGet(); + } + + return Collections.emptySet(); + } + + try { + boolean interrupted = false; + while (workerThread.isAlive()) { + workerThread.interrupt(); + try { + workerThread.join(100); + } catch (InterruptedException ignored) { + interrupted = true; + } + } + + if (interrupted) { + Thread.currentThread().interrupt(); + } + } finally { + INSTANCE_COUNTER.decrementAndGet(); + } + return worker.unprocessedTimeouts(); + } + + @Override + public boolean isStop() { + return WORKER_STATE_SHUTDOWN == WORKER_STATE_UPDATER.get(this); + } + + @Override + public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { + if (task == null) { + throw new NullPointerException("task"); + } + if (unit == null) { + throw new NullPointerException("unit"); + } + + long pendingTimeoutsCount = pendingTimeouts.incrementAndGet(); + + if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) { + pendingTimeouts.decrementAndGet(); + throw new RejectedExecutionException("Number of pending timeouts (" + + pendingTimeoutsCount + ") is greater than or equal to maximum allowed pending " + + "timeouts (" + maxPendingTimeouts + ")"); + } + + start(); + + // Add the timeout to the timeout queue which will be processed on the next tick. + // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket. + long deadline = System.nanoTime() + unit.toNanos(delay) - startTime; + + // Guard against overflow. + if (delay > 0 && deadline < 0) { + deadline = Long.MAX_VALUE; + } + HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline); + timeouts.add(timeout); + return timeout; + } + + /** + * Returns the number of pending timeouts of this {@link Timer}. + */ + public long pendingTimeouts() { + return pendingTimeouts.get(); + } + + /** + * Returns the number of cancelled timeouts of this {@link Timer}. + */ + public long cancelledTimeouts() { + return cancelledTimeouts.size(); + } + + private static void reportTooManyInstances() { + logger.error("You are creating too many HashedWheelTimer instances. is a shared resource that must be reused across the JVM, " + + "so that only a few instances are created."); + } + + private final class Worker implements Runnable { + + private final Set unprocessedTimeouts = new HashSet(); + + private long tick; + + @Override + public void run() { + // Initialize the startTime. + startTime = System.nanoTime(); + if (startTime == 0) { + // We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized. + startTime = 1; + } + + // Notify the other threads waiting for the initialization at start(). + startTimeInitialized.countDown(); + + do { + final long deadline = waitForNextTick(); + if (deadline > 0) { + int idx = (int) (tick & mask); + processCancelledTasks(); + HashedWheelBucket bucket = + wheel[idx]; + transferTimeoutsToBuckets(); + bucket.expireTimeouts(deadline); + tick++; + } + } while (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_STARTED); + + // Fill the unprocessedTimeouts so we can return them from stop() method. + for (HashedWheelBucket bucket : wheel) { + bucket.clearTimeouts(unprocessedTimeouts); + } + for (;;) { + HashedWheelTimeout timeout = timeouts.poll(); + if (timeout == null) { + break; + } + if (!timeout.isCancelled()) { + unprocessedTimeouts.add(timeout); + } + } + processCancelledTasks(); + } + + private void transferTimeoutsToBuckets() { + // transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just + // adds new timeouts in a loop. + for (int i = 0; i < 100000; i++) { + HashedWheelTimeout timeout = timeouts.poll(); + if (timeout == null) { + // all processed + break; + } + if (timeout.state() == HashedWheelTimeout.ST_CANCELLED) { + // Was cancelled in the meantime. + continue; + } + + long calculated = timeout.deadline / tickDuration; + timeout.remainingRounds = (calculated - tick) / wheel.length; + + // Ensure we don't schedule for past. + final long ticks = Math.max(calculated, tick); + int stopIndex = (int) (ticks & mask); + + HashedWheelBucket bucket = wheel[stopIndex]; + bucket.addTimeout(timeout); + } + } + + private void processCancelledTasks() { + for (;;) { + HashedWheelTimeout timeout = cancelledTimeouts.poll(); + if (timeout == null) { + // all processed + break; + } + try { + timeout.remove(); + } catch (Throwable t) { + logger.warn("An exception was thrown while process a cancellation task", t); + } + } + } + + /** + * calculate goal nanoTime from startTime and current tick number, + * then wait until that goal has been reached. + * + * @return Long.MIN_VALUE if received a shutdown request, + * current time otherwise (with Long.MIN_VALUE changed by +1) + */ + private long waitForNextTick() { + long deadline = tickDuration * (tick + 1); + + for (;;) { + final long currentTime = System.nanoTime() - startTime; + long sleepTimeMs = (deadline - currentTime + 999999) / 1000000; + + if (sleepTimeMs <= 0) { + if (currentTime == Long.MIN_VALUE) { + return -Long.MAX_VALUE; + } else { + return currentTime; + } + } + if (isWindows()) { + sleepTimeMs = sleepTimeMs / 10 * 10; + } + + try { + Thread.sleep(sleepTimeMs); + } catch (InterruptedException ignored) { + if (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_SHUTDOWN) { + return Long.MIN_VALUE; + } + } + } + } + + Set unprocessedTimeouts() { + return Collections.unmodifiableSet(unprocessedTimeouts); + } + } + + private static final class HashedWheelTimeout implements Timeout { + + private static final int ST_INIT = 0; + private static final int ST_CANCELLED = 1; + private static final int ST_EXPIRED = 2; + private static final AtomicIntegerFieldUpdater STATE_UPDATER = + AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimeout.class, "state"); + + private final HashedWheelTimer timer; + private final TimerTask task; + private final long deadline; + + private volatile int state = ST_INIT; + + /** + * RemainingRounds will be calculated and set by Worker.transferTimeoutsToBuckets() before the + * HashedWheelTimeout will be added to the correct HashedWheelBucket. + */ + long remainingRounds; + + /** + * This will be used to chain timeouts in HashedWheelTimerBucket via a double-linked-list. + * As only the workerThread will act on it there is no need for synchronization / volatile. + */ + HashedWheelTimeout next; + HashedWheelTimeout prev; + + /** + * The bucket to which the timeout was added + */ + HashedWheelBucket bucket; + + HashedWheelTimeout(HashedWheelTimer timer, TimerTask task, long deadline) { + this.timer = timer; + this.task = task; + this.deadline = deadline; + } + + @Override + public Timer timer() { + return timer; + } + + @Override + public TimerTask task() { + return task; + } + + @Override + public boolean cancel() { + // only update the state it will be removed from HashedWheelBucket on next tick. + if (!compareAndSetState(ST_INIT, ST_CANCELLED)) { + return false; + } + // If a task should be canceled we put this to another queue which will be processed on each tick. + // So this means that we will have a GC latency of max. 1 tick duration which is good enough. This way we + // can make again use of our LinkedBlockingQueue and so minimize the locking / overhead as much as possible. + timer.cancelledTimeouts.add(this); + return true; + } + + void remove() { + HashedWheelBucket bucket = this.bucket; + if (bucket != null) { + bucket.remove(this); + } else { + timer.pendingTimeouts.decrementAndGet(); + } + } + + public boolean compareAndSetState(int expected, int state) { + return STATE_UPDATER.compareAndSet(this, expected, state); + } + + public int state() { + return state; + } + + @Override + public boolean isCancelled() { + return state() == ST_CANCELLED; + } + + @Override + public boolean isExpired() { + return state() == ST_EXPIRED; + } + + public void expire() { + if (!compareAndSetState(ST_INIT, ST_EXPIRED)) { + return; + } + + try { + task.run(); + task.setExecuteTimeHook(System.currentTimeMillis()); + } catch (Throwable t) { + logger.warn("An exception was thrown by " + TimerTask.class.getSimpleName() + '.', t); + } + } + + @Override + public String toString() { + final long currentTime = System.nanoTime(); + long remaining = deadline - currentTime + timer.startTime; + String simpleClassName = getClass().getSimpleName(); + + StringBuilder buf = new StringBuilder(192) + .append(simpleClassName) + .append('(') + .append("deadline: "); + if (remaining > 0) { + buf.append(remaining) + .append(" ns later"); + } else if (remaining < 0) { + buf.append(-remaining) + .append(" ns ago"); + } else { + buf.append("now"); + } + + if (isCancelled()) { + buf.append(", cancelled"); + } + + return buf.append(", task: ") + .append(task()) + .append(')') + .toString(); + } + } + + /** + * Bucket that stores HashedWheelTimeouts. These are stored in a linked-list like datastructure to allow easy + * removal of HashedWheelTimeouts in the middle. Also the HashedWheelTimeout act as nodes themself and so no + * extra object creation is needed. + */ + private static final class HashedWheelBucket { + + /** + * Used for the linked-list datastructure + */ + private HashedWheelTimeout head; + private HashedWheelTimeout tail; + + /** + * Add {@link HashedWheelTimeout} to this bucket. + */ + void addTimeout(HashedWheelTimeout timeout) { + assert timeout.bucket == null; + timeout.bucket = this; + if (head == null) { + head = tail = timeout; + } else { + tail.next = timeout; + timeout.prev = tail; + tail = timeout; + } + } + + /** + * Expire all {@link HashedWheelTimeout}s for the given {@code deadline}. + */ + void expireTimeouts(long deadline) { + HashedWheelTimeout timeout = head; + + // process all timeouts + while (timeout != null) { + HashedWheelTimeout next = timeout.next; + if (timeout.remainingRounds <= 0) { + next = remove(timeout); + if (timeout.deadline <= deadline) { + timeout.expire(); + } else { + // The timeout was placed into a wrong slot. This should never happen. + throw new IllegalStateException(String.format( + "timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline)); + } + } else if (timeout.isCancelled()) { + next = remove(timeout); + } else { + timeout.remainingRounds--; + } + timeout = next; + } + } + + public HashedWheelTimeout remove(HashedWheelTimeout timeout) { + HashedWheelTimeout next = timeout.next; + // remove timeout that was either processed or cancelled by updating the linked-list + if (timeout.prev != null) { + timeout.prev.next = next; + } + if (timeout.next != null) { + timeout.next.prev = timeout.prev; + } + + if (timeout == head) { + // if timeout is also the tail we need to adjust the entry too + if (timeout == tail) { + tail = null; + head = null; + } else { + head = next; + } + } else if (timeout == tail) { + // if the timeout is the tail modify the tail to be the prev node. + tail = timeout.prev; + } + // null out prev, next and bucket to allow for GC. + timeout.prev = null; + timeout.next = null; + timeout.bucket = null; + timeout.timer.pendingTimeouts.decrementAndGet(); + return next; + } + + /** + * Clear this bucket and return all not expired / cancelled {@link Timeout}s. + */ + void clearTimeouts(Set set) { + for (;;) { + HashedWheelTimeout timeout = pollTimeout(); + if (timeout == null) { + return; + } + if (timeout.isExpired() || timeout.isCancelled()) { + continue; + } + set.add(timeout); + } + } + + private HashedWheelTimeout pollTimeout() { + HashedWheelTimeout head = this.head; + if (head == null) { + return null; + } + HashedWheelTimeout next = head.next; + if (next == null) { + tail = this.head = null; + } else { + this.head = next; + next.prev = null; + } + + // null out prev and next to allow for GC. + head.next = null; + head.prev = null; + head.bucket = null; + return head; + } + } + + private static final boolean IS_OS_WINDOWS = System.getProperty(OS_NAME_KEY, "").toLowerCase(Locale.US).contains(OS_WIN_PREFIX); + + private boolean isWindows() { + return IS_OS_WINDOWS; + } +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/Timeout.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/Timeout.java new file mode 100644 index 0000000000..e6485ff511 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/Timeout.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api.timer; + +/** + * A handle associated with a {@link TimerTask} that is returned by a + * {@link Timer}. + */ +public interface Timeout { + + /** + * Returns the {@link Timer} that created this handle. + */ + Timer timer(); + + /** + * Returns the {@link TimerTask} which is associated with this handle. + */ + TimerTask task(); + + /** + * Returns {@code true} if and only if the {@link TimerTask} associated + * with this handle has been expired. + */ + boolean isExpired(); + + /** + * Returns {@code true} if and only if the {@link TimerTask} associated + * with this handle has been cancelled. + */ + boolean isCancelled(); + + /** + * Attempts to cancel the {@link TimerTask} associated with this handle. + * If the task has been executed or cancelled already, it will return with + * no side effect. + * + * @return True if the cancellation completed successfully, otherwise false + */ + boolean cancel(); +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/Timer.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/Timer.java new file mode 100644 index 0000000000..50d1ce06a8 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/Timer.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api.timer; + +import java.util.Set; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * Schedules {@link TimerTask}s for one-time future execution in a background + * thread. + */ +public interface Timer { + + /** + * Schedules the specified {@link TimerTask} for one-time execution after + * the specified delay. + * + * @return a handle which is associated with the specified task + * @throws IllegalStateException if this timer has been {@linkplain #stop() stopped} already + * @throws RejectedExecutionException if the pending timeouts are too many and creating new timeout + * can cause instability in the system. + */ + Timeout newTimeout(TimerTask task, long delay, TimeUnit unit); + + /** + * Releases all resources acquired by this {@link Timer} and cancels all + * tasks which were scheduled but not executed yet. + * + * @return the handles associated with the tasks which were canceled by + * this method + */ + Set stop(); + + /** + * the timer is stop + * + * @return true for stop + */ + boolean isStop(); + + /** + * the pending timeouts + * @return count of pending timeout + */ + long pendingTimeouts(); +} diff --git a/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/TimerTask.java b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/TimerTask.java new file mode 100644 index 0000000000..879481454e --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-api/src/main/java/org/apache/eventmesh/retry/api/timer/TimerTask.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.api.timer; + +import java.util.concurrent.TimeUnit; + +/** + * A task which is executed after the delay specified with + * {@link Timer#newTimeout(TimerTask, long, TimeUnit)} (TimerTask, long, TimeUnit)}. + */ +public interface TimerTask { + + /** + * Executed after the delay specified with + * {@link Timer#newTimeout(TimerTask, long, TimeUnit)}. + */ + void run() throws Exception; + + /** + * Hook method to set the execute time. + * @param executeTime execute time + */ + void setExecuteTimeHook(long executeTime); +} diff --git a/eventmesh-retry/eventmesh-retry-rocketmq/build.gradle b/eventmesh-retry/eventmesh-retry-rocketmq/build.gradle new file mode 100644 index 0000000000..883081271c --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-rocketmq/build.gradle @@ -0,0 +1,55 @@ +/* + * 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. + */ + +List rocketmq = [ + "org.apache.rocketmq:rocketmq-client:$rocketmq_version", + "org.apache.rocketmq:rocketmq-broker:$rocketmq_version", + "org.apache.rocketmq:rocketmq-common:$rocketmq_version", + "org.apache.rocketmq:rocketmq-store:$rocketmq_version", + "org.apache.rocketmq:rocketmq-namesrv:$rocketmq_version", + "org.apache.rocketmq:rocketmq-tools:$rocketmq_version", + "org.apache.rocketmq:rocketmq-remoting:$rocketmq_version", + "org.apache.rocketmq:rocketmq-logging:$rocketmq_version", + "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", + "org.apache.rocketmq:rocketmq-filter:$rocketmq_version", + "org.apache.rocketmq:rocketmq-acl:$rocketmq_version", + "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", +] + +dependencies { + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-rocketmq") + /* + * The exclusions can be removed after this issue is fixed: + * https://github.com/apache/rocketmq/issues/5347 + */ + rocketmq.each { + implementation(it) { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } + } + implementation project(":eventmesh-retry:eventmesh-retry-api") + implementation project(":eventmesh-common") + + implementation 'io.cloudevents:cloudevents-core' + implementation 'io.cloudevents:cloudevents-json-jackson' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'org.junit.jupiter:junit-jupiter' +} \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties b/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties new file mode 100644 index 0000000000..5114e05231 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-rocketmq/gradle.properties @@ -0,0 +1,19 @@ +# 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. +# + +rocketmq_version=4.9.5 +pluginType=retry +pluginName=rocketmq \ No newline at end of file diff --git a/eventmesh-retry/eventmesh-retry-rocketmq/src/main/java/org/apache/eventmesh/retry/rocketmq/RocketMQRetryStrategyImpl.java b/eventmesh-retry/eventmesh-retry-rocketmq/src/main/java/org/apache/eventmesh/retry/rocketmq/RocketMQRetryStrategyImpl.java new file mode 100644 index 0000000000..9d817eec50 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-rocketmq/src/main/java/org/apache/eventmesh/retry/rocketmq/RocketMQRetryStrategyImpl.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.retry.rocketmq; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.retry.api.conf.RetryConfiguration; +import org.apache.eventmesh.retry.api.strategy.RetryStrategy; + +import org.apache.rocketmq.common.MixAll; + +import java.util.Objects; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RocketMQRetryStrategyImpl implements RetryStrategy { + + @Override + public void retry(RetryConfiguration configuration) { + sendMessageBack(configuration); + } + + @SneakyThrows + private void sendMessageBack(final RetryConfiguration configuration) { + CloudEvent event = configuration.getEvent(); + String topic = configuration.getTopic(); + String consumerGroupName = configuration.getConsumerGroupName(); + String retryTopicName = MixAll.getRetryTopic(consumerGroupName); + + String bizSeqNo = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey())).toString(); + String uniqueId = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey())).toString(); + CloudEvent retryEvent = CloudEventBuilder.from(event) + .withExtension(ProtocolKey.TOPIC, topic) + .withSubject(retryTopicName) + .build(); + Producer producer = configuration.getProducer(); + producer.publish(retryEvent, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + log.info("consumer:{} consume success,, bizSeqno:{}, uniqueId:{}", + consumerGroupName, bizSeqNo, uniqueId); + } + + @Override + public void onException(OnExceptionContext context) { + log.warn("consumer:{} consume fail, sendMessageBack, bizSeqno:{}, uniqueId:{}", + consumerGroupName, bizSeqNo, uniqueId, context.getException()); + } + }); + } +} diff --git a/eventmesh-retry/eventmesh-retry-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.retry.api.strategy.RetryStrategy b/eventmesh-retry/eventmesh-retry-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.retry.api.strategy.RetryStrategy new file mode 100644 index 0000000000..71c2006e92 --- /dev/null +++ b/eventmesh-retry/eventmesh-retry-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.retry.api.strategy.RetryStrategy @@ -0,0 +1,16 @@ +# 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. + +rocketmq=org.apache.eventmesh.retry.rocketmq.RocketMQRetryStrategyImpl \ No newline at end of file diff --git a/eventmesh-runtime-v2/bin/start-v2.sh b/eventmesh-runtime-v2/bin/start-v2.sh new file mode 100644 index 0000000000..fc67c29d3e --- /dev/null +++ b/eventmesh-runtime-v2/bin/start-v2.sh @@ -0,0 +1,200 @@ +#!/bin/bash +# +# Licensed to 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. Apache Software Foundation (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. + +#=========================================================================================== +# Java Environment Setting +#=========================================================================================== +set -e +# Server configuration may be inconsistent, add these configurations to avoid garbled code problems +export LANG=en_US.UTF-8 +export LC_CTYPE=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +TMP_JAVA_HOME="/customize/your/java/home/here" + +# Detect operating system. +OS=$(uname) + +function is_java8_or_11 { + local _java="$1" + [[ -x "$_java" ]] || return 1 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' || "$("$_java" -version 2>&1)" =~ 'java version "11' || "$("$_java" -version 2>&1)" =~ 'openjdk version "11' ]] || return 2 + return 0 +} + +function extract_java_version { + local _java="$1" + local version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{if ($1 == 1 && $2 == 8) print "8"; else if ($1 == 11) print "11"; else print "unknown"}') + echo "$version" +} + +# 0(not running), 1(is running) +#function is_proxyRunning { +# local _pid="$1" +# local pid=`ps ax | grep -i 'org.apache.eventmesh.runtime.boot.EventMeshStartup' |grep java | grep -v grep | awk '{print $1}'|grep $_pid` +# if [ -z "$pid" ] ; then +# return 0 +# else +# return 1 +# fi +#} + +function get_pid { + local ppid="" + if [ -f ${EVENTMESH_HOME}/bin/pid.file ]; then + ppid=$(cat ${EVENTMESH_HOME}/bin/pid.file) + # If the process does not exist, it indicates that the previous process terminated abnormally. + if [ ! -d /proc/$ppid ]; then + # Remove the residual file. + rm ${EVENTMESH_HOME}/bin/pid.file + echo -e "ERROR\t EventMesh process had already terminated unexpectedly before, please check log output." + ppid="" + fi + else + if [[ $OS =~ Msys ]]; then + # There is a Bug on Msys that may not be able to kill the identified process + ppid=`jps -v | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # Known problem: grep Java may not be able to accurately identify Java processes + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + if [ $DOCKER ]; then + # No need to exclude root user in Docker containers. + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_HOME | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | awk -F ' ' {'print $2'}) + else + # It is required to identify the process as accurately as possible on Linux. + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_HOME | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | grep -Ev "^root" | awk -F ' ' {'print $2'}) + fi + fi + fi + echo "$ppid"; +} + +#=========================================================================================== +# Locate Java Executable +#=========================================================================================== + +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8_or_11 "$TMP_JAVA_HOME/bin/java"; then + JAVA="$TMP_JAVA_HOME/bin/java" + JAVA_VERSION=$(extract_java_version "$TMP_JAVA_HOME/bin/java") +elif [[ -d "$JAVA_HOME" ]] && is_java8_or_11 "$JAVA_HOME/bin/java"; then + JAVA="$JAVA_HOME/bin/java" + JAVA_VERSION=$(extract_java_version "$JAVA_HOME/bin/java") +elif is_java8_or_11 "$(which java)"; then + JAVA="$(which java)" + JAVA_VERSION=$(extract_java_version "$(which java)") +else + echo -e "ERROR\t Java 8 or 11 not found, operation abort." + exit 9; +fi + +echo "EventMesh using Java version: $JAVA_VERSION, path: $JAVA" + +EVENTMESH_HOME=$(cd "$(dirname "$0")/.." && pwd) +export EVENTMESH_HOME + +EVENTMESH_LOG_HOME="${EVENTMESH_HOME}/logs" +export EVENTMESH_LOG_HOME + +echo -e "EVENTMESH_HOME : ${EVENTMESH_HOME}\nEVENTMESH_LOG_HOME : ${EVENTMESH_LOG_HOME}" + +function make_logs_dir { + if [ ! -e "${EVENTMESH_LOG_HOME}" ]; then mkdir -p "${EVENTMESH_LOG_HOME}"; fi +} + +error_exit () +{ + echo -e "ERROR\t $1 !!" + exit 1 +} + +export JAVA_HOME + +#=========================================================================================== +# JVM Configuration +#=========================================================================================== +#if [ $1 = "prd" -o $1 = "benchmark" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms2048M -Xmx4096M -Xmn2048m -XX:SurvivorRatio=4" +#elif [ $1 = "sit" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms256M -Xmx512M -Xmn256m -XX:SurvivorRatio=4" +#elif [ $1 = "dev" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms128M -Xmx256M -Xmn128m -XX:SurvivorRatio=4" +#fi + +GC_LOG_FILE="${EVENTMESH_LOG_HOME}/eventmesh_gc_%p.log" + +#JAVA_OPT="${JAVA_OPT} -server -Xms2048M -Xmx4096M -Xmn2048m -XX:SurvivorRatio=4" +JAVA_OPT=`cat ${EVENTMESH_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` +JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" +JAVA_OPT="${JAVA_OPT} -verbose:gc" +if [[ "$JAVA_VERSION" == "8" ]]; then + # Set JAVA_OPT for Java 8 + JAVA_OPT="${JAVA_OPT} -Xloggc:${GC_LOG_FILE} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" + JAVA_OPT="${JAVA_OPT} -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +elif [[ "$JAVA_VERSION" == "11" ]]; then + # Set JAVA_OPT for Java 11 + XLOG_PARAM="time,level,tags:filecount=5,filesize=30m" + JAVA_OPT="${JAVA_OPT} -Xlog:gc*:${GC_LOG_FILE}:${XLOG_PARAM}" + JAVA_OPT="${JAVA_OPT} -Xlog:safepoint:${GC_LOG_FILE}:${XLOG_PARAM} -Xlog:ergo*=debug:${GC_LOG_FILE}:${XLOG_PARAM}" +fi +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${EVENTMESH_LOG_HOME} -XX:ErrorFile=${EVENTMESH_LOG_HOME}/hs_err_%p.log" +JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" +JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" +JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" +JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking" +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dio.netty.allocator.type=pooled" +JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom" +JAVA_OPT="${JAVA_OPT} -Dlog4j.configurationFile=${EVENTMESH_HOME}/conf/log4j2.xml" +JAVA_OPT="${JAVA_OPT} -Deventmesh.log.home=${EVENTMESH_LOG_HOME}" +JAVA_OPT="${JAVA_OPT} -DconfPath=${EVENTMESH_HOME}/conf" +JAVA_OPT="${JAVA_OPT} -Dlog4j2.AsyncQueueFullPolicy=Discard" +JAVA_OPT="${JAVA_OPT} -Drocketmq.client.logUseSlf4j=true" +JAVA_OPT="${JAVA_OPT} -DeventMeshPluginDir=${EVENTMESH_HOME}/plugin" + +#if [ -f "pid.file" ]; then +# pid=`cat pid.file` +# if ! is_proxyRunning "$pid"; then +# echo "proxy is running already" +# exit 9; +# else +# echo "err pid$pid, rm pid.file" +# rm pid.file +# fi +#fi + +pid=$(get_pid) +if [[ $pid == "ERROR"* ]]; then + echo -e "${pid}" + exit 9 +fi +if [ -n "$pid" ]; then + echo -e "ERROR\t The server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9 +fi + +make_logs_dir + +echo "Using Java version: $JAVA_VERSION, path: $JAVA" >> ${EVENTMESH_LOG_HOME}/eventmesh.out + +EVENTMESH_MAIN=org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter +if [ $DOCKER ]; then + $JAVA $JAVA_OPT -classpath ${EVENTMESH_HOME}/conf:${EVENTMESH_HOME}/apps/*:${EVENTMESH_HOME}/lib/* $EVENTMESH_MAIN >> ${EVENTMESH_LOG_HOME}/eventmesh.out +else + $JAVA $JAVA_OPT -classpath ${EVENTMESH_HOME}/conf:${EVENTMESH_HOME}/apps/*:${EVENTMESH_HOME}/lib/* $EVENTMESH_MAIN >> ${EVENTMESH_LOG_HOME}/eventmesh.out 2>&1 & +echo $!>${EVENTMESH_HOME}/bin/pid.file +fi +exit 0 diff --git a/eventmesh-runtime-v2/bin/stop-v2.sh b/eventmesh-runtime-v2/bin/stop-v2.sh new file mode 100644 index 0000000000..177ae1e129 --- /dev/null +++ b/eventmesh-runtime-v2/bin/stop-v2.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# +# Licensed to 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. Apache Software Foundation (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. + +# Detect operating system +OS=$(uname) + +EVENTMESH_HOME=`cd $(dirname $0)/.. && pwd` + +export EVENTMESH_HOME + +function get_pid { + local ppid="" + if [ -f ${EVENTMESH_HOME}/bin/pid.file ]; then + ppid=$(cat ${EVENTMESH_HOME}/bin/pid.file) + # If the process does not exist, it indicates that the previous process terminated abnormally. + if [ ! -d /proc/$ppid ]; then + # Remove the residual file and return an error status. + rm ${EVENTMESH_HOME}/bin/pid.file + echo -e "ERROR\t EventMesh process had already terminated unexpectedly before, please check log output." + ppid="" + fi + else + if [[ $OS =~ Msys ]]; then + # There is a Bug on Msys that may not be able to kill the identified process + ppid=`jps -v | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | grep java | grep -v grep | awk -F ' ' {'print $1'}` + elif [[ $OS =~ Darwin ]]; then + # Known problem: grep Java may not be able to accurately identify Java processes + ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + else + # It is required to identify the process as accurately as possible on Linux + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_HOME | grep -i "org.apache.eventmesh.runtime.boot.RuntimeInstanceStarter" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + fi + fi + echo "$ppid"; +} + +pid=$(get_pid) +if [[ $pid == "ERROR"* ]]; then + echo -e "${pid}" + exit 9 +fi +if [ -z "$pid" ];then + echo -e "ERROR\t No EventMesh server running." + exit 9 +fi + +kill ${pid} +echo "Send shutdown request to EventMesh(${pid}) OK" + +[[ $OS =~ Msys ]] && PS_PARAM=" -W " +stop_timeout=60 +for no in $(seq 1 $stop_timeout); do + if ps $PS_PARAM -p "$pid" 2>&1 > /dev/null; then + if [ $no -lt $stop_timeout ]; then + echo "[$no] server shutting down ..." + sleep 1 + continue + fi + + echo "shutdown server timeout, kill process: $pid" + kill -9 $pid; sleep 1; break; + echo "`date +'%Y-%m-%-d %H:%M:%S'` , pid : [$pid] , error message : abnormal shutdown which can not be closed within 60s" > ../logs/shutdown.error + else + echo "shutdown server ok!"; break; + fi +done + +if [ -f "pid.file" ]; then + rm pid.file +fi + + diff --git a/eventmesh-runtime-v2/build.gradle b/eventmesh-runtime-v2/build.gradle new file mode 100644 index 0000000000..74b9759b10 --- /dev/null +++ b/eventmesh-runtime-v2/build.gradle @@ -0,0 +1,54 @@ +/* + * 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. + */ + +plugins { + id 'java' +} + +group 'org.apache.eventmesh' +version '1.10.0-release' + +repositories { + mavenCentral() +} + +dependencies { + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + api project (":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api") + api project (":eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-admin") + implementation project(":eventmesh-openconnect:eventmesh-openconnect-java") + implementation project(":eventmesh-common") + implementation project(":eventmesh-connectors:eventmesh-connector-canal") + implementation project(":eventmesh-connectors:eventmesh-connector-http") + implementation project(":eventmesh-function:eventmesh-function-api") + implementation project(":eventmesh-function:eventmesh-function-filter") + implementation project(":eventmesh-function:eventmesh-function-transformer") + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-meta:eventmesh-meta-nacos") + implementation project(":eventmesh-registry:eventmesh-registry-api") + implementation project(":eventmesh-registry:eventmesh-registry-nacos") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-standalone") + + implementation "io.grpc:grpc-core" + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty" + implementation "io.grpc:grpc-netty-shaded" +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/Runtime.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/Runtime.java new file mode 100644 index 0000000000..608ef96da7 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/Runtime.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime; + +/** + * Runtime + */ +public interface Runtime { + + void init() throws Exception; + + void start() throws Exception; + + void stop() throws Exception; + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/RuntimeFactory.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/RuntimeFactory.java new file mode 100644 index 0000000000..ed273030d9 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/RuntimeFactory.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime; + +/** + * RuntimeFactory + */ +public interface RuntimeFactory extends AutoCloseable { + + void init() throws Exception; + + Runtime createRuntime(RuntimeInstanceConfig runtimeInstanceConfig); + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/RuntimeInstanceConfig.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/RuntimeInstanceConfig.java new file mode 100644 index 0000000000..caa5330fe3 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/RuntimeInstanceConfig.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.enums.ComponentType; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(path = "classPath://runtime.yaml") +public class RuntimeInstanceConfig { + + private boolean registryEnabled; + + private String registryServerAddr; + + private String registryPluginType; + + private String storagePluginType; + + private String adminServiceName; + + private String adminServiceAddr; + + private ComponentType componentType; + + private String runtimeInstanceId; + + private String runtimeInstanceName; + + private String runtimeInstanceDesc; + + private String runtimeInstanceVersion; + + private String runtimeInstanceConfig; + + private String runtimeInstanceStatus; + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/boot/RuntimeInstance.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/boot/RuntimeInstance.java new file mode 100644 index 0000000000..beb1d1eedc --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/boot/RuntimeInstance.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.registry.QueryInstances; +import org.apache.eventmesh.registry.RegisterServerInfo; +import org.apache.eventmesh.registry.RegistryFactory; +import org.apache.eventmesh.registry.RegistryService; +import org.apache.eventmesh.runtime.Runtime; +import org.apache.eventmesh.runtime.RuntimeFactory; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; +import org.apache.eventmesh.runtime.connector.ConnectorRuntimeFactory; +import org.apache.eventmesh.runtime.function.FunctionRuntimeFactory; +import org.apache.eventmesh.runtime.mesh.MeshRuntimeFactory; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RuntimeInstance { + + private String adminServiceAddr; + + private Map adminServerInfoMap = new HashMap<>(); + + private RegistryService registryService; + + private Runtime runtime; + + private RuntimeFactory runtimeFactory; + + private final RuntimeInstanceConfig runtimeInstanceConfig; + + private volatile boolean isStarted = false; + + public RuntimeInstance(RuntimeInstanceConfig runtimeInstanceConfig) { + this.runtimeInstanceConfig = runtimeInstanceConfig; + if (runtimeInstanceConfig.isRegistryEnabled()) { + this.registryService = RegistryFactory.getInstance(runtimeInstanceConfig.getRegistryPluginType()); + } + } + + public void init() throws Exception { + if (registryService != null) { + registryService.init(); + QueryInstances queryInstances = new QueryInstances(); + queryInstances.setServiceName(runtimeInstanceConfig.getAdminServiceName()); + queryInstances.setHealth(true); + List adminServerRegisterInfoList = registryService.selectInstances(queryInstances); + if (!adminServerRegisterInfoList.isEmpty()) { + adminServiceAddr = getRandomAdminServerAddr(adminServerRegisterInfoList); + } else { + throw new RuntimeException("admin server address is empty, please check"); + } + // use registry adminServiceAddr value replace config + runtimeInstanceConfig.setAdminServiceAddr(adminServiceAddr); + } else { + adminServiceAddr = runtimeInstanceConfig.getAdminServiceAddr(); + } + + runtimeFactory = initRuntimeFactory(runtimeInstanceConfig); + runtime = runtimeFactory.createRuntime(runtimeInstanceConfig); + runtime.init(); + } + + public void start() throws Exception { + if (StringUtils.isBlank(adminServiceAddr)) { + throw new RuntimeException("admin server address is empty, please check"); + } else { + if (registryService != null) { + registryService.subscribe((event) -> { + log.info("runtime receive registry event: {}", event); + List registerServerInfoList = event.getInstances(); + Map registerServerInfoMap = new HashMap<>(); + for (RegisterServerInfo registerServerInfo : registerServerInfoList) { + registerServerInfoMap.put(registerServerInfo.getAddress(), registerServerInfo); + } + if (!registerServerInfoMap.isEmpty()) { + adminServerInfoMap = registerServerInfoMap; + updateAdminServerAddr(); + } + }, runtimeInstanceConfig.getAdminServiceName()); + } + runtime.start(); + isStarted = true; + } + } + + public void shutdown() throws Exception { + runtime.stop(); + } + + private void updateAdminServerAddr() throws Exception { + if (isStarted) { + if (!adminServerInfoMap.containsKey(adminServiceAddr)) { + adminServiceAddr = getRandomAdminServerAddr(adminServerInfoMap); + log.info("admin server address changed to: {}", adminServiceAddr); + shutdown(); + start(); + } + } else { + adminServiceAddr = getRandomAdminServerAddr(adminServerInfoMap); + } + } + + private String getRandomAdminServerAddr(Map adminServerInfoMap) { + ArrayList addresses = new ArrayList<>(adminServerInfoMap.keySet()); + Random random = new Random(); + int randomIndex = random.nextInt(addresses.size()); + return addresses.get(randomIndex); + } + + private String getRandomAdminServerAddr(List adminServerRegisterInfoList) { + Random random = new Random(); + int randomIndex = random.nextInt(adminServerRegisterInfoList.size()); + return adminServerRegisterInfoList.get(randomIndex).getAddress(); + } + + private RuntimeFactory initRuntimeFactory(RuntimeInstanceConfig runtimeInstanceConfig) { + switch (runtimeInstanceConfig.getComponentType()) { + case CONNECTOR: + return new ConnectorRuntimeFactory(); + case FUNCTION: + return new FunctionRuntimeFactory(); + case MESH: + return new MeshRuntimeFactory(); + default: + throw new RuntimeException("unsupported runtime type: " + runtimeInstanceConfig.getComponentType()); + } + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/boot/RuntimeInstanceStarter.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/boot/RuntimeInstanceStarter.java new file mode 100644 index 0000000000..0881521879 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/boot/RuntimeInstanceStarter.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; +import org.apache.eventmesh.runtime.util.BannerUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RuntimeInstanceStarter { + + public static void main(String[] args) { + try { + RuntimeInstanceConfig runtimeInstanceConfig = ConfigService.getInstance().buildConfigInstance(RuntimeInstanceConfig.class); + RuntimeInstance runtimeInstance = new RuntimeInstance(runtimeInstanceConfig); + BannerUtil.generateBanner(); + runtimeInstance.init(); + runtimeInstance.start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + log.info("runtime shutting down hook begin."); + long start = System.currentTimeMillis(); + runtimeInstance.shutdown(); + long end = System.currentTimeMillis(); + log.info("runtime shutdown cost {}ms", end - start); + } catch (Exception e) { + log.error("exception when shutdown {}", e.getMessage(), e); + } + })); + } catch (Throwable e) { + log.error("runtime start fail {}.", e.getMessage(), e); + System.exit(-1); + } + + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntime.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntime.java new file mode 100644 index 0000000000..92e78256ec --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntime.java @@ -0,0 +1,546 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.connector; + +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.api.factory.StoragePluginFactory; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.config.connector.offset.OffsetStorageConfig; +import org.apache.eventmesh.common.enums.ConnectorStage; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc.AdminServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc.AdminServiceStub; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.request.FetchJobRequest; +import org.apache.eventmesh.common.remote.response.FetchJobResponse; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.factory.ConnectorPluginFactory; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendExceptionContext; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendMessageCallback; +import org.apache.eventmesh.openconnect.offsetmgmt.api.callback.SendResult; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.RecordOffsetManagement; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.DefaultOffsetManagementServiceImpl; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetManagementService; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetStorageReaderImpl; +import org.apache.eventmesh.openconnect.offsetmgmt.api.storage.OffsetStorageWriterImpl; +import org.apache.eventmesh.openconnect.util.ConfigUtil; +import org.apache.eventmesh.runtime.Runtime; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; +import org.apache.eventmesh.runtime.service.health.HealthService; +import org.apache.eventmesh.runtime.service.monitor.MonitorService; +import org.apache.eventmesh.runtime.service.monitor.SinkMonitor; +import org.apache.eventmesh.runtime.service.monitor.SourceMonitor; +import org.apache.eventmesh.runtime.service.status.StatusService; +import org.apache.eventmesh.runtime.service.verify.VerifyService; +import org.apache.eventmesh.runtime.util.RuntimeUtils; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ConnectorRuntime implements Runtime { + + private RuntimeInstanceConfig runtimeInstanceConfig; + + private ConnectorRuntimeConfig connectorRuntimeConfig; + + private ManagedChannel channel; + + private AdminServiceStub adminServiceStub; + + private AdminServiceBlockingStub adminServiceBlockingStub; + + private Source sourceConnector; + + private Sink sinkConnector; + + private OffsetStorageWriterImpl offsetStorageWriter; + + private OffsetStorageReaderImpl offsetStorageReader; + + private OffsetManagementService offsetManagementService; + + private RecordOffsetManagement offsetManagement; + + private volatile RecordOffsetManagement.CommittableOffsets committableOffsets; + + private Producer producer; + + private Consumer consumer; + + private final ExecutorService sourceService = ThreadPoolFactory.createSingleExecutor("eventMesh-sourceService"); + + private final ExecutorService sinkService = ThreadPoolFactory.createSingleExecutor("eventMesh-sinkService"); + + + private final BlockingQueue queue; + + private volatile boolean isRunning = false; + + private volatile boolean isFailed = false; + + public static final String CALLBACK_EXTENSION = "callBackExtension"; + + private String adminServerAddr; + + private HealthService healthService; + + private MonitorService monitorService; + + private SourceMonitor sourceMonitor; + + private SinkMonitor sinkMonitor; + + private VerifyService verifyService; + + private StatusService statusService; + + + public ConnectorRuntime(RuntimeInstanceConfig runtimeInstanceConfig) { + this.runtimeInstanceConfig = runtimeInstanceConfig; + this.queue = new LinkedBlockingQueue<>(1000); + } + + @Override + public void init() throws Exception { + + initAdminService(); + + initStorageService(); + + initStatusService(); + + initConnectorService(); + + initMonitorService(); + + initHealthService(); + + initVerfiyService(); + + } + + private void initAdminService() { + adminServerAddr = RuntimeUtils.getRandomAdminServerAddr(runtimeInstanceConfig.getAdminServiceAddr()); + // create gRPC channel + channel = ManagedChannelBuilder.forTarget(adminServerAddr) + .usePlaintext() + .enableRetry() + .maxRetryAttempts(3) + .build(); + + adminServiceStub = AdminServiceGrpc.newStub(channel).withWaitForReady(); + + adminServiceBlockingStub = AdminServiceGrpc.newBlockingStub(channel).withWaitForReady(); + + } + + private void initStorageService() { + // TODO: init producer & consumer + producer = StoragePluginFactory.getMeshMQProducer(runtimeInstanceConfig.getStoragePluginType()); + + consumer = StoragePluginFactory.getMeshMQPushConsumer(runtimeInstanceConfig.getStoragePluginType()); + + } + + private void initStatusService() { + statusService = new StatusService(adminServiceStub, adminServiceBlockingStub); + } + + private void initConnectorService() throws Exception { + + connectorRuntimeConfig = ConfigService.getInstance().buildConfigInstance(ConnectorRuntimeConfig.class); + + FetchJobResponse jobResponse = fetchJobConfig(); + log.info("fetch job config from admin server: {}", JsonUtils.toJSONString(jobResponse)); + + if (jobResponse == null) { + isFailed = true; + stop(); + throw new RuntimeException("fetch job config fail"); + } + + connectorRuntimeConfig.setSourceConnectorType(jobResponse.getTransportType().getSrc().getName()); + connectorRuntimeConfig.setSourceConnectorDesc(jobResponse.getConnectorConfig().getSourceConnectorDesc()); + connectorRuntimeConfig.setSourceConnectorConfig(jobResponse.getConnectorConfig().getSourceConnectorConfig()); + + connectorRuntimeConfig.setSinkConnectorType(jobResponse.getTransportType().getDst().getName()); + connectorRuntimeConfig.setSinkConnectorDesc(jobResponse.getConnectorConfig().getSinkConnectorDesc()); + connectorRuntimeConfig.setSinkConnectorConfig(jobResponse.getConnectorConfig().getSinkConnectorConfig()); + + // spi load offsetMgmtService + this.offsetManagement = new RecordOffsetManagement(); + this.committableOffsets = RecordOffsetManagement.CommittableOffsets.EMPTY; + OffsetStorageConfig offsetStorageConfig = new OffsetStorageConfig(); + offsetStorageConfig.setOffsetStorageAddr(connectorRuntimeConfig.getRuntimeConfig().get("offsetStorageAddr").toString()); + offsetStorageConfig.setOffsetStorageType(connectorRuntimeConfig.getRuntimeConfig().get("offsetStoragePluginType").toString()); + offsetStorageConfig.setDataSourceType(jobResponse.getTransportType().getSrc()); + offsetStorageConfig.setDataSinkType(jobResponse.getTransportType().getDst()); + Map offsetStorageExtensions = new HashMap<>(); + offsetStorageExtensions.put("jobId", connectorRuntimeConfig.getJobID()); + offsetStorageConfig.setExtensions(offsetStorageExtensions); + + this.offsetManagementService = Optional.ofNullable(offsetStorageConfig).map(OffsetStorageConfig::getOffsetStorageType) + .map(storageType -> EventMeshExtensionFactory.getExtension(OffsetManagementService.class, storageType)) + .orElse(new DefaultOffsetManagementServiceImpl()); + this.offsetManagementService.initialize(offsetStorageConfig); + this.offsetStorageWriter = new OffsetStorageWriterImpl(offsetManagementService); + this.offsetStorageReader = new OffsetStorageReaderImpl(offsetManagementService); + + ConnectorCreateService sourceConnectorCreateService = + ConnectorPluginFactory.createConnector(connectorRuntimeConfig.getSourceConnectorType() + "-Source"); + sourceConnector = (Source) sourceConnectorCreateService.create(); + + SourceConfig sourceConfig = (SourceConfig) ConfigUtil.parse(connectorRuntimeConfig.getSourceConnectorConfig(), sourceConnector.configClass()); + SourceConnectorContext sourceConnectorContext = new SourceConnectorContext(); + sourceConnectorContext.setSourceConfig(sourceConfig); + sourceConnectorContext.setRuntimeConfig(connectorRuntimeConfig.getRuntimeConfig()); + sourceConnectorContext.setJobType(jobResponse.getType()); + sourceConnectorContext.setOffsetStorageReader(offsetStorageReader); + if (CollectionUtils.isNotEmpty(jobResponse.getPosition())) { + sourceConnectorContext.setRecordPositionList(jobResponse.getPosition()); + } + sourceConnector.init(sourceConnectorContext); + + ConnectorCreateService sinkConnectorCreateService = + ConnectorPluginFactory.createConnector(connectorRuntimeConfig.getSinkConnectorType() + "-Sink"); + sinkConnector = (Sink) sinkConnectorCreateService.create(); + + SinkConfig sinkConfig = (SinkConfig) ConfigUtil.parse(connectorRuntimeConfig.getSinkConnectorConfig(), sinkConnector.configClass()); + SinkConnectorContext sinkConnectorContext = new SinkConnectorContext(); + sinkConnectorContext.setSinkConfig(sinkConfig); + sinkConnectorContext.setRuntimeConfig(connectorRuntimeConfig.getRuntimeConfig()); + sinkConnectorContext.setJobType(jobResponse.getType()); + sinkConnector.init(sinkConnectorContext); + + statusService.reportJobStatus(connectorRuntimeConfig.getJobID(), JobState.INIT); + + } + + private FetchJobResponse fetchJobConfig() { + String jobId = connectorRuntimeConfig.getJobID(); + FetchJobRequest jobRequest = new FetchJobRequest(); + jobRequest.setJobID(jobId); + + Metadata metadata = Metadata.newBuilder().setType(FetchJobRequest.class.getSimpleName()).build(); + + Payload request = Payload.newBuilder().setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(jobRequest)))).build()) + .build(); + Payload response = adminServiceBlockingStub.invoke(request); + if (response.getMetadata().getType().equals(FetchJobResponse.class.getSimpleName())) { + return JsonUtils.parseObject(response.getBody().getValue().toStringUtf8(), FetchJobResponse.class); + } + return null; + } + + private void initMonitorService() { + monitorService = new MonitorService(adminServiceStub, adminServiceBlockingStub); + sourceMonitor = new SourceMonitor(connectorRuntimeConfig.getTaskID(), connectorRuntimeConfig.getJobID(), IPUtils.getLocalAddress()); + monitorService.registerMonitor(sourceMonitor); + sinkMonitor = new SinkMonitor(connectorRuntimeConfig.getTaskID(), connectorRuntimeConfig.getJobID(), IPUtils.getLocalAddress()); + monitorService.registerMonitor(sinkMonitor); + } + + private void initHealthService() { + healthService = new HealthService(adminServiceStub, adminServiceBlockingStub, connectorRuntimeConfig); + } + + private void initVerfiyService() { + verifyService = new VerifyService(adminServiceStub, adminServiceBlockingStub, connectorRuntimeConfig); + } + + @Override + public void start() throws Exception { + // start offsetMgmtService + offsetManagementService.start(); + + monitorService.start(); + + healthService.start(); + + isRunning = true; + // start sinkService + sinkService.execute(() -> { + try { + startSinkConnector(); + } catch (Exception e) { + isFailed = true; + log.error("sink connector start fail", e.getStackTrace()); + try { + this.stop(); + } catch (Exception ex) { + log.error("Failed to stop after exception", ex); + } + } finally { + System.exit(-1); + } + }); + // start sourceService + sourceService.execute(() -> { + try { + startSourceConnector(); + } catch (Exception e) { + isFailed = true; + log.error("source connector start fail", e); + try { + this.stop(); + } catch (Exception ex) { + log.error("Failed to stop after exception", ex); + } + } finally { + System.exit(-1); + } + }); + + statusService.reportJobStatus(connectorRuntimeConfig.getJobID(), JobState.RUNNING); + } + + @Override + public void stop() throws Exception { + log.info("ConnectorRuntime start stop"); + isRunning = false; + if (isFailed) { + statusService.reportJobStatus(connectorRuntimeConfig.getJobID(), JobState.FAIL); + } else { + statusService.reportJobStatus(connectorRuntimeConfig.getJobID(), JobState.COMPLETE); + } + sourceConnector.stop(); + sinkConnector.stop(); + monitorService.stop(); + healthService.stop(); + sourceService.shutdown(); + sinkService.shutdown(); + verifyService.stop(); + statusService.stop(); + if (channel != null && !channel.isShutdown()) { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + log.info("ConnectorRuntime stopped"); + } + + private void startSourceConnector() throws Exception { + sourceConnector.start(); + while (isRunning) { + long sourceStartTime = System.currentTimeMillis(); + List connectorRecordList = sourceConnector.poll(); + long sinkStartTime = System.currentTimeMillis(); + // TODO: use producer pub record to storage replace below + if (connectorRecordList != null && !connectorRecordList.isEmpty()) { + for (ConnectRecord record : connectorRecordList) { + // check recordUniqueId + if (record.getExtensions() == null || !record.getExtensions().containsKey("recordUniqueId")) { + record.addExtension("recordUniqueId", record.getRecordId()); + } + + // set a callback for this record + // if used the memory storage callback will be triggered after sink put success + record.setCallback(new SendMessageCallback() { + @Override + public void onSuccess(SendResult result) { + log.debug("send record to sink callback success, record: {}", record); + long sinkEndTime = System.currentTimeMillis(); + sinkMonitor.recordProcess(sinkEndTime - sinkStartTime); + // commit record + sourceConnector.commit(record); + if (record.getPosition() != null) { + Optional submittedRecordPosition = prepareToUpdateRecordOffset(record); + submittedRecordPosition.ifPresent(RecordOffsetManagement.SubmittedPosition::ack); + log.debug("start wait all messages to commit"); + offsetManagement.awaitAllMessages(5000, TimeUnit.MILLISECONDS); + // update & commit offset + updateCommittableOffsets(); + commitOffsets(); + } + Optional callback = + Optional.ofNullable(record.getExtensionObj(CALLBACK_EXTENSION)).map(v -> (SendMessageCallback) v); + callback.ifPresent(cb -> cb.onSuccess(convertToSendResult(record))); + } + + @Override + public void onException(SendExceptionContext sendExceptionContext) { + isFailed = true; + // handle exception + sourceConnector.onException(record); + log.error("send record to sink callback exception, process will shut down, record: {}", record, + sendExceptionContext.getCause()); + try { + stop(); + } catch (Exception e) { + log.error("Failed to stop after exception", e); + } + } + }); + + queue.put(record); + long sourceEndTime = System.currentTimeMillis(); + sourceMonitor.recordProcess(sourceEndTime - sourceStartTime); + + // if enabled incremental data reporting consistency check + if (connectorRuntimeConfig.enableIncrementalDataConsistencyCheck) { + verifyService.reportVerifyRequest(record, ConnectorStage.SOURCE); + } + + } + } + } + } + + private SendResult convertToSendResult(ConnectRecord record) { + SendResult result = new SendResult(); + result.setMessageId(record.getRecordId()); + if (StringUtils.isNotEmpty(record.getExtension("topic"))) { + result.setTopic(record.getExtension("topic")); + } + return result; + } + + + public Optional prepareToUpdateRecordOffset(ConnectRecord record) { + return Optional.of(this.offsetManagement.submitRecord(record.getPosition())); + } + + public void updateCommittableOffsets() { + RecordOffsetManagement.CommittableOffsets newOffsets = offsetManagement.committableOffsets(); + synchronized (this) { + this.committableOffsets = this.committableOffsets.updatedWith(newOffsets); + } + } + + public boolean commitOffsets() { + log.info("Start Committing offsets"); + + long timeout = System.currentTimeMillis() + 5000L; + + RecordOffsetManagement.CommittableOffsets offsetsToCommit; + synchronized (this) { + offsetsToCommit = this.committableOffsets; + this.committableOffsets = RecordOffsetManagement.CommittableOffsets.EMPTY; + } + + if (committableOffsets.isEmpty()) { + log.debug( + "Either no records were produced since the last offset commit, " + + "or every record has been filtered out by a transformation or dropped due to transformation or conversion errors."); + // We continue with the offset commit process here instead of simply returning immediately + // in order to invoke SourceTask::commit and record metrics for a successful offset commit + } else { + log.info("{} Committing offsets for {} acknowledged messages", this, committableOffsets.numCommittableMessages()); + if (committableOffsets.hasPending()) { + log.debug( + "{} There are currently {} pending messages spread across {} source partitions whose offsets will not be committed." + + " The source partition with the most pending messages is {}, with {} pending messages", + this, + committableOffsets.numUncommittableMessages(), committableOffsets.numDeques(), committableOffsets.largestDequePartition(), + committableOffsets.largestDequeSize()); + } else { + log.debug( + "{} There are currently no pending messages for this offset commit; " + + "all messages dispatched to the task's producer since the last commit have been acknowledged", + this); + } + } + + // write offset to memory + offsetsToCommit.offsets().forEach(offsetStorageWriter::writeOffset); + + // begin flush + if (!offsetStorageWriter.beginFlush()) { + return true; + } + + // using offsetManagementService to persist offset + Future flushFuture = offsetStorageWriter.doFlush(); + try { + flushFuture.get(Math.max(timeout - System.currentTimeMillis(), 0), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.warn("{} Flush of offsets interrupted, cancelling", this); + offsetStorageWriter.cancelFlush(); + return false; + } catch (ExecutionException e) { + log.error("{} Flush of offsets threw an unexpected exception: ", this, e); + offsetStorageWriter.cancelFlush(); + return false; + } catch (TimeoutException e) { + log.error("{} Timed out waiting to flush offsets to storage; will try again on next flush interval with latest offsets", this); + offsetStorageWriter.cancelFlush(); + return false; + } + return true; + } + + private void startSinkConnector() throws Exception { + sinkConnector.start(); + while (isRunning) { + // TODO: use consumer sub from storage to replace below + ConnectRecord connectRecord = null; + try { + connectRecord = queue.poll(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("poll connect record error", e); + } + if (connectRecord == null) { + continue; + } + List connectRecordList = new ArrayList<>(); + connectRecordList.add(connectRecord); + sinkConnector.put(connectRecordList); + // if enabled incremental data reporting consistency check + if (connectorRuntimeConfig.enableIncrementalDataConsistencyCheck) { + verifyService.reportVerifyRequest(connectRecord, ConnectorStage.SINK); + } + } + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntimeConfig.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntimeConfig.java new file mode 100644 index 0000000000..ab6fc3aaf5 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntimeConfig.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.connector; + +import org.apache.eventmesh.common.config.Config; + +import java.util.Map; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Config(path = "classPath://connector.yaml") +public class ConnectorRuntimeConfig { + + private String connectorRuntimeInstanceId; + + private String taskID; + + private String jobID; + + private String region; + + private Map runtimeConfig; + + private String sourceConnectorType; + + private String sourceConnectorDesc; + + private Map sourceConnectorConfig; + + private String sinkConnectorType; + + private String sinkConnectorDesc; + + private Map sinkConnectorConfig; + + public boolean enableIncrementalDataConsistencyCheck = true; + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntimeFactory.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntimeFactory.java new file mode 100644 index 0000000000..d1ec2ff4e9 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorRuntimeFactory.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.connector; + +import org.apache.eventmesh.runtime.Runtime; +import org.apache.eventmesh.runtime.RuntimeFactory; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; + +public class ConnectorRuntimeFactory implements RuntimeFactory { + + @Override + public void init() throws Exception { + + } + + @Override + public Runtime createRuntime(RuntimeInstanceConfig runtimeInstanceConfig) { + return new ConnectorRuntime(runtimeInstanceConfig); + } + + @Override + public void close() throws Exception { + + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntime.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntime.java new file mode 100644 index 0000000000..4a68001909 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntime.java @@ -0,0 +1,503 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.function; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.config.connector.SinkConfig; +import org.apache.eventmesh.common.config.connector.SourceConfig; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc.AdminServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc.AdminServiceStub; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.exception.ErrorCode; +import org.apache.eventmesh.common.remote.job.JobType; +import org.apache.eventmesh.common.remote.request.FetchJobRequest; +import org.apache.eventmesh.common.remote.request.ReportHeartBeatRequest; +import org.apache.eventmesh.common.remote.request.ReportJobRequest; +import org.apache.eventmesh.common.remote.response.FetchJobResponse; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.function.api.AbstractEventMeshFunctionChain; +import org.apache.eventmesh.function.api.EventMeshFunction; +import org.apache.eventmesh.function.filter.pattern.Pattern; +import org.apache.eventmesh.function.filter.patternbuild.PatternBuilder; +import org.apache.eventmesh.function.transformer.Transformer; +import org.apache.eventmesh.function.transformer.TransformerBuilder; +import org.apache.eventmesh.function.transformer.TransformerType; +import org.apache.eventmesh.openconnect.api.ConnectorCreateService; +import org.apache.eventmesh.openconnect.api.connector.SinkConnectorContext; +import org.apache.eventmesh.openconnect.api.connector.SourceConnectorContext; +import org.apache.eventmesh.openconnect.api.factory.ConnectorPluginFactory; +import org.apache.eventmesh.openconnect.api.sink.Sink; +import org.apache.eventmesh.openconnect.api.source.Source; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.openconnect.util.ConfigUtil; +import org.apache.eventmesh.runtime.Runtime; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FunctionRuntime implements Runtime { + + private final RuntimeInstanceConfig runtimeInstanceConfig; + + private ManagedChannel channel; + + private AdminServiceStub adminServiceStub; + + private AdminServiceBlockingStub adminServiceBlockingStub; + + StreamObserver responseObserver; + + StreamObserver requestObserver; + + private final LinkedBlockingQueue queue; + + private FunctionRuntimeConfig functionRuntimeConfig; + + private AbstractEventMeshFunctionChain functionChain; + + private Sink sinkConnector; + + private Source sourceConnector; + + private final ExecutorService sourceService = ThreadPoolFactory.createSingleExecutor("eventMesh-sourceService"); + + private final ExecutorService sinkService = ThreadPoolFactory.createSingleExecutor("eventMesh-sinkService"); + + private final ScheduledExecutorService heartBeatExecutor = Executors.newSingleThreadScheduledExecutor(); + + private volatile boolean isRunning = false; + + private volatile boolean isFailed = false; + + private String adminServerAddr; + + + public FunctionRuntime(RuntimeInstanceConfig runtimeInstanceConfig) { + this.runtimeInstanceConfig = runtimeInstanceConfig; + this.queue = new LinkedBlockingQueue<>(1000); + } + + + @Override + public void init() throws Exception { + // load function runtime config from local file + this.functionRuntimeConfig = ConfigService.getInstance().buildConfigInstance(FunctionRuntimeConfig.class); + + // init admin service + initAdminService(); + + // get remote config from admin service and update local config + getAndUpdateRemoteConfig(); + + // init connector service + initConnectorService(); + + // report status to admin server + reportJobRequest(functionRuntimeConfig.getJobID(), JobState.INIT); + } + + private void initAdminService() { + adminServerAddr = getRandomAdminServerAddr(runtimeInstanceConfig.getAdminServiceAddr()); + // create gRPC channel + channel = ManagedChannelBuilder.forTarget(adminServerAddr).usePlaintext().build(); + + adminServiceStub = AdminServiceGrpc.newStub(channel).withWaitForReady(); + + adminServiceBlockingStub = AdminServiceGrpc.newBlockingStub(channel).withWaitForReady(); + + responseObserver = new StreamObserver() { + @Override + public void onNext(Payload response) { + log.info("runtime receive message: {} ", response); + } + + @Override + public void onError(Throwable t) { + log.error("runtime receive error message: {}", t.getMessage()); + } + + @Override + public void onCompleted() { + log.info("runtime finished receive message and completed"); + } + }; + + requestObserver = adminServiceStub.invokeBiStream(responseObserver); + } + + private String getRandomAdminServerAddr(String adminServerAddrList) { + String[] addresses = adminServerAddrList.split(";"); + if (addresses.length == 0) { + throw new IllegalArgumentException("Admin server address list is empty"); + } + Random random = new Random(); + int randomIndex = random.nextInt(addresses.length); + return addresses[randomIndex]; + } + + private void getAndUpdateRemoteConfig() { + String jobId = functionRuntimeConfig.getJobID(); + FetchJobRequest jobRequest = new FetchJobRequest(); + jobRequest.setJobID(jobId); + + Metadata metadata = Metadata.newBuilder().setType(FetchJobRequest.class.getSimpleName()).build(); + + Payload request = Payload.newBuilder().setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(jobRequest)))).build()) + .build(); + Payload response = adminServiceBlockingStub.invoke(request); + FetchJobResponse jobResponse = null; + if (response.getMetadata().getType().equals(FetchJobResponse.class.getSimpleName())) { + jobResponse = JsonUtils.parseObject(response.getBody().getValue().toStringUtf8(), FetchJobResponse.class); + } + + if (jobResponse == null || jobResponse.getErrorCode() != ErrorCode.SUCCESS) { + if (jobResponse != null) { + log.error("Failed to get remote config from admin server. ErrorCode: {}, Response: {}", + jobResponse.getErrorCode(), jobResponse); + } else { + log.error("Failed to get remote config from admin server. "); + } + isFailed = true; + try { + stop(); + } catch (Exception e) { + log.error("Failed to stop after exception", e); + } + throw new RuntimeException("Failed to get remote config from admin server."); + } + + // update local config + // source + functionRuntimeConfig.setSourceConnectorType(jobResponse.getTransportType().getSrc().getName()); + functionRuntimeConfig.setSourceConnectorDesc(jobResponse.getConnectorConfig().getSourceConnectorDesc()); + functionRuntimeConfig.setSourceConnectorConfig(jobResponse.getConnectorConfig().getSourceConnectorConfig()); + + // sink + functionRuntimeConfig.setSinkConnectorType(jobResponse.getTransportType().getDst().getName()); + functionRuntimeConfig.setSinkConnectorDesc(jobResponse.getConnectorConfig().getSinkConnectorDesc()); + functionRuntimeConfig.setSinkConnectorConfig(jobResponse.getConnectorConfig().getSinkConnectorConfig()); + + // TODO: update functionConfigs + + } + + + private void initConnectorService() throws Exception { + final JobType jobType = (JobType) functionRuntimeConfig.getRuntimeConfig().get("jobType"); + + // create sink connector + ConnectorCreateService sinkConnectorCreateService = + ConnectorPluginFactory.createConnector(functionRuntimeConfig.getSinkConnectorType() + "-Sink"); + this.sinkConnector = (Sink) sinkConnectorCreateService.create(); + + // parse sink config and init sink connector + SinkConfig sinkConfig = (SinkConfig) ConfigUtil.parse(functionRuntimeConfig.getSinkConnectorConfig(), sinkConnector.configClass()); + SinkConnectorContext sinkConnectorContext = new SinkConnectorContext(); + sinkConnectorContext.setSinkConfig(sinkConfig); + sinkConnectorContext.setRuntimeConfig(functionRuntimeConfig.getRuntimeConfig()); + sinkConnectorContext.setJobType(jobType); + sinkConnector.init(sinkConnectorContext); + + // create source connector + ConnectorCreateService sourceConnectorCreateService = + ConnectorPluginFactory.createConnector(functionRuntimeConfig.getSourceConnectorType() + "-Source"); + this.sourceConnector = (Source) sourceConnectorCreateService.create(); + + // parse source config and init source connector + SourceConfig sourceConfig = (SourceConfig) ConfigUtil.parse(functionRuntimeConfig.getSourceConnectorConfig(), sourceConnector.configClass()); + SourceConnectorContext sourceConnectorContext = new SourceConnectorContext(); + sourceConnectorContext.setSourceConfig(sourceConfig); + sourceConnectorContext.setRuntimeConfig(functionRuntimeConfig.getRuntimeConfig()); + sourceConnectorContext.setJobType(jobType); + + sourceConnector.init(sourceConnectorContext); + } + + private void reportJobRequest(String jobId, JobState jobState) { + ReportJobRequest reportJobRequest = new ReportJobRequest(); + reportJobRequest.setJobID(jobId); + reportJobRequest.setState(jobState); + Metadata metadata = Metadata.newBuilder() + .setType(ReportJobRequest.class.getSimpleName()) + .build(); + Payload payload = Payload.newBuilder() + .setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(reportJobRequest)))) + .build()) + .build(); + requestObserver.onNext(payload); + } + + + @Override + public void start() throws Exception { + this.isRunning = true; + + // build function chain + this.functionChain = buildFunctionChain(functionRuntimeConfig.getFunctionConfigs()); + + // start heart beat + this.heartBeatExecutor.scheduleAtFixedRate(() -> { + + ReportHeartBeatRequest heartBeat = new ReportHeartBeatRequest(); + heartBeat.setAddress(IPUtils.getLocalAddress()); + heartBeat.setReportedTimeStamp(String.valueOf(System.currentTimeMillis())); + heartBeat.setJobID(functionRuntimeConfig.getJobID()); + + Metadata metadata = Metadata.newBuilder().setType(ReportHeartBeatRequest.class.getSimpleName()).build(); + + Payload request = Payload.newBuilder().setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(heartBeat)))).build()) + .build(); + + requestObserver.onNext(request); + }, 5, 5, TimeUnit.SECONDS); + + // start sink service + this.sinkService.execute(() -> { + try { + startSinkConnector(); + } catch (Exception e) { + isFailed = true; + log.error("Sink Connector [{}] failed to start.", sinkConnector.name(), e); + try { + this.stop(); + } catch (Exception ex) { + log.error("Failed to stop after exception", ex); + } + throw new RuntimeException(e); + } + }); + + // start source service + this.sourceService.execute(() -> { + try { + startSourceConnector(); + } catch (Exception e) { + isFailed = true; + log.error("Source Connector [{}] failed to start.", sourceConnector.name(), e); + try { + this.stop(); + } catch (Exception ex) { + log.error("Failed to stop after exception", ex); + } + throw new RuntimeException(e); + } + }); + + reportJobRequest(functionRuntimeConfig.getJobID(), JobState.RUNNING); + } + + private StringEventMeshFunctionChain buildFunctionChain(List> functionConfigs) { + StringEventMeshFunctionChain functionChain = new StringEventMeshFunctionChain(); + + // build function chain + for (Map functionConfig : functionConfigs) { + String functionType = String.valueOf(functionConfig.getOrDefault("functionType", "")); + if (StringUtils.isEmpty(functionType)) { + throw new IllegalArgumentException("'functionType' is required for function"); + } + + // build function based on functionType + EventMeshFunction function; + switch (functionType) { + case "filter": + function = buildFilter(functionConfig); + break; + case "transformer": + function = buildTransformer(functionConfig); + break; + default: + throw new IllegalArgumentException( + "Invalid functionType: '" + functionType + "'. Supported functionType: 'filter', 'transformer'"); + } + + // add function to functionChain + functionChain.addLast(function); + } + + return functionChain; + } + + + @SuppressWarnings("unchecked") + private Pattern buildFilter(Map functionConfig) { + // get condition from attributes + Object condition = functionConfig.get("condition"); + if (condition == null) { + throw new IllegalArgumentException("'condition' is required for filter function"); + } + if (condition instanceof String) { + return PatternBuilder.build(String.valueOf(condition)); + } else if (condition instanceof Map) { + return PatternBuilder.build((Map) condition); + } else { + throw new IllegalArgumentException("Invalid condition"); + } + } + + private Transformer buildTransformer(Map functionConfig) { + // get transformerType from attributes + String transformerTypeStr = String.valueOf(functionConfig.getOrDefault("transformerType", "")).toLowerCase(); + TransformerType transformerType = TransformerType.getItem(transformerTypeStr); + if (transformerType == null) { + throw new IllegalArgumentException( + "Invalid transformerType: '" + transformerTypeStr + + "'. Supported transformerType: 'constant', 'template', 'original' (case insensitive)"); + } + + // build transformer + Transformer transformer = null; + + switch (transformerType) { + case CONSTANT: + // check value + String content = String.valueOf(functionConfig.getOrDefault("content", "")); + if (StringUtils.isEmpty(content)) { + throw new IllegalArgumentException("'content' is required for constant transformer"); + } + transformer = TransformerBuilder.buildConstantTransformer(content); + break; + case TEMPLATE: + // check value and template + Object valueMap = functionConfig.get("valueMap"); + String template = String.valueOf(functionConfig.getOrDefault("template", "")); + if (valueMap == null || StringUtils.isEmpty(template)) { + throw new IllegalArgumentException("'valueMap' and 'template' are required for template transformer"); + } + transformer = TransformerBuilder.buildTemplateTransFormer(valueMap, template); + break; + case ORIGINAL: + // ORIGINAL transformer does not need any parameter + break; + default: + throw new IllegalArgumentException( + "Invalid transformerType: '" + transformerType + "', supported transformerType: 'CONSTANT', 'TEMPLATE', 'ORIGINAL'"); + } + + return transformer; + } + + + private void startSinkConnector() throws Exception { + // start sink connector + this.sinkConnector.start(); + + // try to get data from queue and send it. + while (this.isRunning) { + ConnectRecord connectRecord = null; + try { + connectRecord = queue.poll(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + log.error("Failed to poll data from queue.", e); + Thread.currentThread().interrupt(); + } + + // send data if not null + if (connectRecord != null) { + sinkConnector.put(Collections.singletonList(connectRecord)); + } + } + } + + private void startSourceConnector() throws Exception { + // start source connector + this.sourceConnector.start(); + + // try to get data from source connector and handle it. + while (this.isRunning) { + List connectorRecordList = sourceConnector.poll(); + + // handle data + if (connectorRecordList != null && !connectorRecordList.isEmpty()) { + for (ConnectRecord connectRecord : connectorRecordList) { + if (connectRecord == null || connectRecord.getData() == null) { + // If data is null, just put it into queue. + this.queue.put(connectRecord); + } else { + // Apply function chain to data + String data = functionChain.apply((String) connectRecord.getData()); + if (data != null) { + if (log.isDebugEnabled()) { + log.debug("Function chain applied. Original data: {}, Transformed data: {}", connectRecord.getData(), data); + } + connectRecord.setData(data); + this.queue.put(connectRecord); + } else if (log.isDebugEnabled()) { + log.debug("Data filtered out by function chain. Original data: {}", connectRecord.getData()); + } + } + } + } + } + } + + + @Override + public void stop() throws Exception { + log.info("FunctionRuntime is stopping..."); + + isRunning = false; + + if (isFailed) { + reportJobRequest(functionRuntimeConfig.getJobID(), JobState.FAIL); + } else { + reportJobRequest(functionRuntimeConfig.getJobID(), JobState.COMPLETE); + } + + sinkConnector.stop(); + sourceConnector.stop(); + sinkService.shutdown(); + sourceService.shutdown(); + heartBeatExecutor.shutdown(); + + requestObserver.onCompleted(); + if (channel != null && !channel.isShutdown()) { + channel.shutdown(); + } + + log.info("FunctionRuntime stopped."); + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntimeConfig.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntimeConfig.java new file mode 100644 index 0000000000..4d57c83e82 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntimeConfig.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.function; + +import org.apache.eventmesh.common.config.Config; + +import java.util.List; +import java.util.Map; + + +import lombok.Data; + +@Data +@Config(path = "classPath://function.yaml") +public class FunctionRuntimeConfig { + + private String functionRuntimeInstanceId; + + private String taskID; + + private String jobID; + + private String region; + + private Map runtimeConfig; + + private String sourceConnectorType; + + private String sourceConnectorDesc; + + private Map sourceConnectorConfig; + + private String sinkConnectorType; + + private String sinkConnectorDesc; + + private Map sinkConnectorConfig; + + private List> functionConfigs; + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntimeFactory.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntimeFactory.java new file mode 100644 index 0000000000..40346e272f --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/FunctionRuntimeFactory.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.function; + +import org.apache.eventmesh.runtime.Runtime; +import org.apache.eventmesh.runtime.RuntimeFactory; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; + +public class FunctionRuntimeFactory implements RuntimeFactory { + + @Override + public void init() throws Exception { + + } + + @Override + public Runtime createRuntime(RuntimeInstanceConfig runtimeInstanceConfig) { + return new FunctionRuntime(runtimeInstanceConfig); + } + + @Override + public void close() throws Exception { + + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/StringEventMeshFunctionChain.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/StringEventMeshFunctionChain.java new file mode 100644 index 0000000000..0035999ecb --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/function/StringEventMeshFunctionChain.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.function; + +import org.apache.eventmesh.function.api.AbstractEventMeshFunctionChain; +import org.apache.eventmesh.function.api.EventMeshFunction; + +/** + * ConnectRecord Function Chain. + */ +public class StringEventMeshFunctionChain extends AbstractEventMeshFunctionChain { + + @Override + public String apply(String content) { + for (EventMeshFunction function : functions) { + if (content == null) { + break; + } + content = function.apply(content); + } + return content; + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/ConnectorManager.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/ConnectorManager.java new file mode 100644 index 0000000000..2354a350db --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/ConnectorManager.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.manager; + +public class ConnectorManager { +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/FunctionManager.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/FunctionManager.java new file mode 100644 index 0000000000..8c88be9986 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/FunctionManager.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.manager; + +public class FunctionManager { +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/MeshManager.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/MeshManager.java new file mode 100644 index 0000000000..cc67b9fb40 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/manager/MeshManager.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.manager; + +public class MeshManager { +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntime.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntime.java new file mode 100644 index 0000000000..eb186c7658 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntime.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.mesh; + +import org.apache.eventmesh.runtime.Runtime; + +public class MeshRuntime implements Runtime { + + @Override + public void init() throws Exception { + + } + + @Override + public void start() throws Exception { + + } + + @Override + public void stop() throws Exception { + + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntimeConfig.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntimeConfig.java new file mode 100644 index 0000000000..cd21eb1a11 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntimeConfig.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.mesh; + +public class MeshRuntimeConfig { +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntimeFactory.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntimeFactory.java new file mode 100644 index 0000000000..32a3f2e38e --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/mesh/MeshRuntimeFactory.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.mesh; + +import org.apache.eventmesh.runtime.Runtime; +import org.apache.eventmesh.runtime.RuntimeFactory; +import org.apache.eventmesh.runtime.RuntimeInstanceConfig; + +public class MeshRuntimeFactory implements RuntimeFactory { + + @Override + public void init() throws Exception { + + } + + @Override + public Runtime createRuntime(RuntimeInstanceConfig runtimeInstanceConfig) { + return null; + } + + @Override + public void close() throws Exception { + + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/meta/MetaStorage.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/meta/MetaStorage.java new file mode 100644 index 0000000000..41da6994f7 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/meta/MetaStorage.java @@ -0,0 +1,148 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.meta; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MetaStorage { + + private static final Map META_CACHE = new HashMap<>(16); + + private MetaService metaService; + + private final AtomicBoolean inited = new AtomicBoolean(false); + + private final AtomicBoolean started = new AtomicBoolean(false); + + private final AtomicBoolean shutdown = new AtomicBoolean(false); + + private MetaStorage() { + + } + + public static MetaStorage getInstance(String metaPluginType) { + return META_CACHE.computeIfAbsent(metaPluginType, MetaStorage::metaStorageBuilder); + } + + private static MetaStorage metaStorageBuilder(String metaPluginType) { + MetaService metaServiceExt = EventMeshExtensionFactory.getExtension(MetaService.class, metaPluginType); + if (metaServiceExt == null) { + String errorMsg = "can't load the metaService plugin, please check."; + log.error(errorMsg); + throw new RuntimeException(errorMsg); + } + MetaStorage metaStorage = new MetaStorage(); + metaStorage.metaService = metaServiceExt; + + return metaStorage; + } + + public void init() throws MetaException { + if (!inited.compareAndSet(false, true)) { + return; + } + metaService.init(); + } + + public void start() throws MetaException { + if (!started.compareAndSet(false, true)) { + return; + } + metaService.start(); + } + + public void shutdown() throws MetaException { + inited.compareAndSet(true, false); + started.compareAndSet(true, false); + if (!shutdown.compareAndSet(false, true)) { + return; + } + synchronized (this) { + metaService.shutdown(); + } + } + + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + return metaService.findEventMeshInfoByCluster(clusterName); + } + + public List findAllEventMeshInfo() throws MetaException { + return metaService.findAllEventMeshInfo(); + } + + public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) + throws MetaException { + return metaService.findEventMeshClientDistributionData(clusterName, group, purpose); + } + + public void registerMetadata(Map metadata) { + metaService.registerMetadata(metadata); + } + + public void updateMetaData(Map metadata) { + metaService.updateMetaData(metadata); + } + + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + return metaService.register(eventMeshRegisterInfo); + } + + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + return metaService.unRegister(eventMeshUnRegisterInfo); + } + + public List findEventMeshServicePubTopicInfos() throws Exception { + return metaService.findEventMeshServicePubTopicInfos(); + } + + public EventMeshAppSubTopicInfo findEventMeshAppSubTopicInfo(String group) throws Exception { + return metaService.findEventMeshAppSubTopicInfoByGroup(group); + } + + public Map getMetaData(String key, boolean fuzzyEnabled) { + return metaService.getMetaData(key, fuzzyEnabled); + } + + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) throws Exception { + metaService.getMetaDataWithListener(metaServiceListener, key); + } + + public AtomicBoolean getInited() { + return inited; + } + + public AtomicBoolean getStarted() { + return started; + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/health/HealthService.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/health/HealthService.java new file mode 100644 index 0000000000..54f924874b --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/health/HealthService.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.service.health; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.request.ReportHeartBeatRequest; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.connector.ConnectorRuntimeConfig; + +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HealthService { + + private final ScheduledExecutorService scheduler; + + private StreamObserver requestObserver; + + private StreamObserver responseObserver; + + private AdminServiceGrpc.AdminServiceStub adminServiceStub; + + private AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub; + + private ConnectorRuntimeConfig connectorRuntimeConfig; + + + public HealthService(AdminServiceGrpc.AdminServiceStub adminServiceStub, AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub, + ConnectorRuntimeConfig connectorRuntimeConfig) { + this.adminServiceStub = adminServiceStub; + this.adminServiceBlockingStub = adminServiceBlockingStub; + this.connectorRuntimeConfig = connectorRuntimeConfig; + + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + + responseObserver = new StreamObserver() { + @Override + public void onNext(Payload response) { + log.debug("health service receive message: {}|{} ", response.getMetadata(), response.getBody()); + } + + @Override + public void onError(Throwable t) { + log.error("health service receive error message: {}", t.getMessage()); + } + + @Override + public void onCompleted() { + log.info("health service finished receive message and completed"); + } + }; + requestObserver = this.adminServiceStub.invokeBiStream(responseObserver); + } + + public void start() { + this.healthReport(); + } + + public void healthReport() { + scheduler.scheduleAtFixedRate(() -> { + ReportHeartBeatRequest heartBeat = new ReportHeartBeatRequest(); + heartBeat.setAddress(IPUtils.getLocalAddress()); + heartBeat.setReportedTimeStamp(String.valueOf(System.currentTimeMillis())); + heartBeat.setJobID(connectorRuntimeConfig.getJobID()); + + Metadata metadata = Metadata.newBuilder().setType(ReportHeartBeatRequest.class.getSimpleName()).build(); + + Payload request = Payload.newBuilder().setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(heartBeat)))).build()) + .build(); + + requestObserver.onNext(request); + }, 5, 5, TimeUnit.SECONDS); + } + + + public void stop() { + scheduler.shutdown(); + if (requestObserver != null) { + requestObserver.onCompleted(); + } + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/MonitorService.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/MonitorService.java new file mode 100644 index 0000000000..f5af7596c3 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/MonitorService.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.service.monitor; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.request.ReportMonitorRequest; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.api.monitor.Monitor; +import org.apache.eventmesh.openconnect.api.monitor.MonitorRegistry; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MonitorService { + + private final ScheduledExecutorService scheduler; + + private StreamObserver requestObserver; + + private StreamObserver responseObserver; + + private AdminServiceGrpc.AdminServiceStub adminServiceStub; + + private AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub; + + + public MonitorService(AdminServiceGrpc.AdminServiceStub adminServiceStub, AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub) { + this.adminServiceStub = adminServiceStub; + this.adminServiceBlockingStub = adminServiceBlockingStub; + + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + + responseObserver = new StreamObserver() { + @Override + public void onNext(Payload response) { + log.debug("monitor service receive message: {}|{} ", response.getMetadata(), response.getBody()); + } + + @Override + public void onError(Throwable t) { + log.error("monitor service receive error message: {}", t.getMessage()); + } + + @Override + public void onCompleted() { + log.info("monitor service finished receive message and completed"); + } + }; + requestObserver = this.adminServiceStub.invokeBiStream(responseObserver); + } + + public void registerMonitor(Monitor monitor) { + MonitorRegistry.registerMonitor(monitor); + } + + public void start() { + this.startReporting(); + } + + public void startReporting() { + scheduler.scheduleAtFixedRate(() -> { + List monitors = MonitorRegistry.getMonitors(); + for (Monitor monitor : monitors) { + monitor.printMetrics(); + reportToAdminService(monitor); + } + }, 5, 30, TimeUnit.SECONDS); + } + + private void reportToAdminService(Monitor monitor) { + ReportMonitorRequest request = new ReportMonitorRequest(); + if (monitor instanceof SourceMonitor) { + SourceMonitor sourceMonitor = (SourceMonitor) monitor; + request.setTaskID(sourceMonitor.getTaskId()); + request.setJobID(sourceMonitor.getJobId()); + request.setAddress(sourceMonitor.getIp()); + request.setConnectorStage(sourceMonitor.getConnectorStage()); + request.setTotalReqNum(sourceMonitor.getTotalRecordNum().longValue()); + request.setTotalTimeCost(sourceMonitor.getTotalTimeCost().longValue()); + request.setMaxTimeCost(sourceMonitor.getMaxTimeCost().longValue()); + request.setAvgTimeCost(sourceMonitor.getAverageTime()); + request.setTps(sourceMonitor.getTps()); + } else if (monitor instanceof SinkMonitor) { + SinkMonitor sinkMonitor = (SinkMonitor) monitor; + request.setTaskID(sinkMonitor.getTaskId()); + request.setJobID(sinkMonitor.getJobId()); + request.setAddress(sinkMonitor.getIp()); + request.setConnectorStage(sinkMonitor.getConnectorStage()); + request.setTotalReqNum(sinkMonitor.getTotalRecordNum().longValue()); + request.setTotalTimeCost(sinkMonitor.getTotalTimeCost().longValue()); + request.setMaxTimeCost(sinkMonitor.getMaxTimeCost().longValue()); + request.setAvgTimeCost(sinkMonitor.getAverageTime()); + request.setTps(sinkMonitor.getTps()); + } else { + throw new IllegalArgumentException("Unsupported monitor: " + monitor); + } + + Metadata metadata = Metadata.newBuilder() + .setType(ReportMonitorRequest.class.getSimpleName()) + .build(); + Payload payload = Payload.newBuilder() + .setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(request)))) + .build()) + .build(); + requestObserver.onNext(payload); + } + + public void stop() { + scheduler.shutdown(); + if (requestObserver != null) { + requestObserver.onCompleted(); + } + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/SinkMonitor.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/SinkMonitor.java new file mode 100644 index 0000000000..b27b44da7c --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/SinkMonitor.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.service.monitor; + +import org.apache.eventmesh.common.enums.ConnectorStage; +import org.apache.eventmesh.openconnect.api.monitor.AbstractConnectorMonitor; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@Setter +public class SinkMonitor extends AbstractConnectorMonitor { + + private String connectorStage = ConnectorStage.SINK.name(); + + public SinkMonitor(String taskId, String jobId, String ip) { + super(taskId, jobId, ip); + } + + @Override + public void recordProcess(long timeCost) { + super.recordProcess(timeCost); + } + + @Override + public void recordProcess(int recordCount, long timeCost) { + super.recordProcess(recordCount, timeCost); + } + + @Override + public void printMetrics() { + super.printMetrics(); + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/SourceMonitor.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/SourceMonitor.java new file mode 100644 index 0000000000..3895c8df14 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/monitor/SourceMonitor.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.service.monitor; + +import org.apache.eventmesh.common.enums.ConnectorStage; +import org.apache.eventmesh.openconnect.api.monitor.AbstractConnectorMonitor; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@Setter +public class SourceMonitor extends AbstractConnectorMonitor { + + private String connectorStage = ConnectorStage.SOURCE.name(); + + public SourceMonitor(String taskId, String jobId, String ip) { + super(taskId, jobId, ip); + } + + @Override + public void recordProcess(int recordCount, long timeCost) { + super.recordProcess(recordCount, timeCost); + } + + @Override + public void printMetrics() { + super.printMetrics(); + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/status/StatusService.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/status/StatusService.java new file mode 100644 index 0000000000..e40686f575 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/status/StatusService.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.service.status; + +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.JobState; +import org.apache.eventmesh.common.remote.request.ReportJobRequest; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.util.Objects; + +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class StatusService { + + private StreamObserver requestObserver; + + private StreamObserver responseObserver; + + private AdminServiceGrpc.AdminServiceStub adminServiceStub; + + private AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub; + + + public StatusService(AdminServiceGrpc.AdminServiceStub adminServiceStub, AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub) { + this.adminServiceStub = adminServiceStub; + this.adminServiceBlockingStub = adminServiceBlockingStub; + + responseObserver = new StreamObserver() { + @Override + public void onNext(Payload response) { + log.debug("health service receive message: {}|{} ", response.getMetadata(), response.getBody()); + } + + @Override + public void onError(Throwable t) { + log.error("health service receive error message: {}", t.getMessage()); + } + + @Override + public void onCompleted() { + log.info("health service finished receive message and completed"); + } + }; + requestObserver = this.adminServiceStub.invokeBiStream(responseObserver); + } + + public void reportJobStatus(String jobId, JobState jobState) { + ReportJobRequest reportJobRequest = new ReportJobRequest(); + reportJobRequest.setJobID(jobId); + reportJobRequest.setState(jobState); + reportJobRequest.setAddress(IPUtils.getLocalAddress()); + Metadata metadata = Metadata.newBuilder() + .setType(ReportJobRequest.class.getSimpleName()) + .build(); + Payload payload = Payload.newBuilder() + .setMetadata(metadata) + .setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(reportJobRequest)))) + .build()) + .build(); + log.info("report job state request: {}", JsonUtils.toJSONString(reportJobRequest)); + requestObserver.onNext(payload); + } + + public void stop() { + if (requestObserver != null) { + requestObserver.onCompleted(); + } + } +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/verify/VerifyService.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/verify/VerifyService.java new file mode 100644 index 0000000000..8bcb72199c --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/service/verify/VerifyService.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.service.verify; + +import org.apache.eventmesh.common.enums.ConnectorStage; +import org.apache.eventmesh.common.protocol.grpc.adminserver.AdminServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Metadata; +import org.apache.eventmesh.common.protocol.grpc.adminserver.Payload; +import org.apache.eventmesh.common.remote.request.ReportVerifyRequest; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.openconnect.offsetmgmt.api.data.ConnectRecord; +import org.apache.eventmesh.runtime.connector.ConnectorRuntimeConfig; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import io.grpc.stub.StreamObserver; + +import com.google.protobuf.Any; +import com.google.protobuf.UnsafeByteOperations; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class VerifyService { + + private final ExecutorService reportVerifyExecutor; + + private StreamObserver requestObserver; + + private StreamObserver responseObserver; + + private AdminServiceGrpc.AdminServiceStub adminServiceStub; + + private AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub; + + private ConnectorRuntimeConfig connectorRuntimeConfig; + + + public VerifyService(AdminServiceGrpc.AdminServiceStub adminServiceStub, AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub, + ConnectorRuntimeConfig connectorRuntimeConfig) { + this.adminServiceStub = adminServiceStub; + this.adminServiceBlockingStub = adminServiceBlockingStub; + this.connectorRuntimeConfig = connectorRuntimeConfig; + + this.reportVerifyExecutor = Executors.newSingleThreadExecutor(); + + responseObserver = new StreamObserver() { + @Override + public void onNext(Payload response) { + log.debug("verify service receive message: {}|{} ", response.getMetadata(), response.getBody()); + } + + @Override + public void onError(Throwable t) { + log.error("verify service receive error message: {}", t.getMessage()); + } + + @Override + public void onCompleted() { + log.info("verify service finished receive message and completed"); + } + }; + requestObserver = this.adminServiceStub.invokeBiStream(responseObserver); + } + + public void reportVerifyRequest(ConnectRecord record, ConnectorStage connectorStage) { + reportVerifyExecutor.submit(() -> { + try { + byte[] data = (byte[]) record.getData(); + // use record data + recordUniqueId for md5 + String md5Str = md5(Arrays.toString(data) + record.getExtension("recordUniqueId")); + ReportVerifyRequest reportVerifyRequest = new ReportVerifyRequest(); + reportVerifyRequest.setTaskID(connectorRuntimeConfig.getTaskID()); + reportVerifyRequest.setJobID(connectorRuntimeConfig.getJobID()); + reportVerifyRequest.setRecordID(record.getExtension("recordUniqueId")); + reportVerifyRequest.setRecordSig(md5Str); + reportVerifyRequest.setConnectorName( + IPUtils.getLocalAddress() + "_" + connectorRuntimeConfig.getJobID() + "_" + connectorRuntimeConfig.getRegion()); + reportVerifyRequest.setConnectorStage(connectorStage.name()); + reportVerifyRequest.setPosition(JsonUtils.toJSONString(record.getPosition())); + + Metadata metadata = Metadata.newBuilder().setType(ReportVerifyRequest.class.getSimpleName()).build(); + + Payload request = Payload.newBuilder().setMetadata(metadata) + .setBody( + Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(Objects.requireNonNull(JsonUtils.toJSONBytes(reportVerifyRequest)))) + .build()) + .build(); + requestObserver.onNext(request); + } catch (Exception e) { + log.error("Failed to report verify request", e); + } + }); + } + + private String md5(String input) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(input.getBytes()); + StringBuilder sb = new StringBuilder(); + for (byte b : messageDigest) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + public void stop() { + reportVerifyExecutor.shutdown(); + if (requestObserver != null) { + requestObserver.onCompleted(); + } + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/util/BannerUtil.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/util/BannerUtil.java new file mode 100644 index 0000000000..2569494189 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/util/BannerUtil.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import lombok.extern.slf4j.Slf4j; + +/** + * EventMesh banner util + */ +@Slf4j +public class BannerUtil { + + private static final String LOGO = + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEME EMEMEMEME " + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEMEM " + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME " + System.lineSeparator() + + "EMEMEMEMEMEM EMEMEMEMEM EMEMEMEMEMEMEMEME EMEMEMEMEME" + System.lineSeparator() + + "EMEMEMEME EMEMEMEMEM EMEMEMEMEMEME EMEMEMEME" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEME EMEMEMEM" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEME EMEMEMEMEM EMEMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEM EMEMEMEMEM EMEMEMEMEMEM" + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM " + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME " + System.lineSeparator() + + " MEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME"; + + private static final String LOGONAME = + " ____ _ __ __ _ " + System.lineSeparator() + + " / ____|_ _____ _ __ | |_| \\/ | ___ ___| |__ " + System.lineSeparator() + + " | __|\\ \\ / / _ | '_ \\| __| |\\/| |/ _ |/ __| '_ \\ " + System.lineSeparator() + + " | |___ \\ V / __| | | | |_| | | | __|\\__ \\ | | |" + System.lineSeparator() + + " \\ ____| \\_/ \\___|_| |_|\\__|_| |_|\\___||___/_| |_|"; + + public static void generateBanner() { + String banner = + System.lineSeparator() + + System.lineSeparator() + + LOGO + + System.lineSeparator() + + LOGONAME + + System.lineSeparator(); + if (log.isInfoEnabled()) { + log.info(banner); + } else { + System.out.print(banner); + } + } + +} diff --git a/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/util/RuntimeUtils.java b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/util/RuntimeUtils.java new file mode 100644 index 0000000000..844a9638a3 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/java/org/apache/eventmesh/runtime/util/RuntimeUtils.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.util.Random; + +public class RuntimeUtils { + + public static String getRandomAdminServerAddr(String adminServerAddrList) { + String[] addresses = adminServerAddrList.split(";"); + if (addresses.length == 0) { + throw new IllegalArgumentException("Admin server address list is empty"); + } + Random random = new Random(); + int randomIndex = random.nextInt(addresses.length); + return addresses[randomIndex]; + } + +} diff --git a/eventmesh-runtime-v2/src/main/resources/connector.yaml b/eventmesh-runtime-v2/src/main/resources/connector.yaml new file mode 100644 index 0000000000..3e407fa3e9 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/resources/connector.yaml @@ -0,0 +1,23 @@ +# +# 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. +# + +taskID: 9c18a0d2-7a61-482c-8275-34f8c2786cea +jobID: a01fd5e1-d295-4b89-99bc-0ae23eb85acf +region: region1 +runtimeConfig: # this used for connector runtime config + offsetStoragePluginType: admin + offsetStorageAddr: "127.0.0.1:8081;127.0.0.1:8081" \ No newline at end of file diff --git a/eventmesh-runtime-v2/src/main/resources/function.yaml b/eventmesh-runtime-v2/src/main/resources/function.yaml new file mode 100644 index 0000000000..eae2b063ec --- /dev/null +++ b/eventmesh-runtime-v2/src/main/resources/function.yaml @@ -0,0 +1,21 @@ +# +# 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. +# + +taskID: c6233632-ab9a-4aba-904f-9d22fba6aa74 +jobID: 8190fe5b-1f9b-4815-8983-2467e76edbf0 +region: region1 + diff --git a/eventmesh-runtime-v2/src/main/resources/runtime.yaml b/eventmesh-runtime-v2/src/main/resources/runtime.yaml new file mode 100644 index 0000000000..9ac36f27b0 --- /dev/null +++ b/eventmesh-runtime-v2/src/main/resources/runtime.yaml @@ -0,0 +1,24 @@ +# +# 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. +# + +componentType: CONNECTOR +registryEnabled: false +registryServerAddr: 127.0.0.1:8085 +registryPluginType: nacos +storagePluginType: memory +adminServiceName: eventmesh-admin +adminServiceAddr: "127.0.0.1:8081;127.0.0.1:8081" diff --git a/eventmesh-runtime/bin/start.sh b/eventmesh-runtime/bin/start.sh index 3ad63a71ea..96fac20989 100644 --- a/eventmesh-runtime/bin/start.sh +++ b/eventmesh-runtime/bin/start.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Licensed to Apache Software Foundation (ASF) under one or more contributor # license agreements. See the NOTICE file distributed with @@ -21,24 +21,30 @@ # Java Environment Setting #=========================================================================================== set -e -#Server configuration may be inconsistent, add these configurations to avoid garbled code problems +# Server configuration may be inconsistent, add these configurations to avoid garbled code problems export LANG=en_US.UTF-8 export LC_CTYPE=en_US.UTF-8 export LC_ALL=en_US.UTF-8 -TMP_JAVA_HOME="/nemo/jdk1.8.0_152" +TMP_JAVA_HOME="/customize/your/java/home/here" -#detect operating system. +# Detect operating system. OS=$(uname) -function is_java8 { +function is_java8_or_11 { local _java="$1" [[ -x "$_java" ]] || return 1 - [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' ]] || return 2 + [[ "$("$_java" -version 2>&1)" =~ 'java version "1.8' || "$("$_java" -version 2>&1)" =~ 'openjdk version "1.8' || "$("$_java" -version 2>&1)" =~ 'java version "11' || "$("$_java" -version 2>&1)" =~ 'openjdk version "11' ]] || return 2 return 0 } -#0(not running), 1(is running) +function extract_java_version { + local _java="$1" + local version=$("$_java" -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{if ($1 == 1 && $2 == 8) print "8"; else if ($1 == 11) print "11"; else print "unknown"}') + echo "$version" +} + +# 0(not running), 1(is running) #function is_proxyRunning { # local _pid="$1" # local pid=`ps ax | grep -i 'org.apache.eventmesh.runtime.boot.EventMeshStartup' |grep java | grep -v grep | awk '{print $1}'|grep $_pid` @@ -53,6 +59,13 @@ function get_pid { local ppid="" if [ -f ${EVENTMESH_HOME}/bin/pid.file ]; then ppid=$(cat ${EVENTMESH_HOME}/bin/pid.file) + # If the process does not exist, it indicates that the previous process terminated abnormally. + if [ ! -d /proc/$ppid ]; then + # Remove the residual file. + rm ${EVENTMESH_HOME}/bin/pid.file + echo -e "ERROR\t EventMesh process had already terminated unexpectedly before, please check log output." + ppid="" + fi else if [[ $OS =~ Msys ]]; then # There is a Bug on Msys that may not be able to kill the identified process @@ -61,40 +74,45 @@ function get_pid { # Known problem: grep Java may not be able to accurately identify Java processes ppid=$(/bin/ps -o user,pid,command | grep "java" | grep -i "org.apache.eventmesh.runtime.boot.EventMeshStartup" | grep -Ev "^root" |awk -F ' ' {'print $2'}) else - # It is required to identify the process as accurately as possible on Linux - ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_HOME | grep -i "org.apache.eventmesh.runtime.boot.EventMeshStartup" | grep -Ev "^root" |awk -F ' ' {'print $2'}) + if [ $DOCKER ]; then + # No need to exclude root user in Docker containers. + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_HOME | grep -i "org.apache.eventmesh.runtime.boot.EventMeshStartup" | awk -F ' ' {'print $2'}) + else + # It is required to identify the process as accurately as possible on Linux. + ppid=$(ps -C java -o user,pid,command --cols 99999 | grep -w $EVENTMESH_HOME | grep -i "org.apache.eventmesh.runtime.boot.EventMeshStartup" | grep -Ev "^root" | awk -F ' ' {'print $2'}) + fi fi fi echo "$ppid"; } +#=========================================================================================== +# Locate Java Executable +#=========================================================================================== -if [[ -d "$TMP_JAVA_HOME" ]] && is_java8 "$TMP_JAVA_HOME/bin/java"; then +if [[ -d "$TMP_JAVA_HOME" ]] && is_java8_or_11 "$TMP_JAVA_HOME/bin/java"; then JAVA="$TMP_JAVA_HOME/bin/java" -elif [[ -d "$JAVA_HOME" ]] && is_java8 "$JAVA_HOME/bin/java"; then + JAVA_VERSION=$(extract_java_version "$TMP_JAVA_HOME/bin/java") +elif [[ -d "$JAVA_HOME" ]] && is_java8_or_11 "$JAVA_HOME/bin/java"; then JAVA="$JAVA_HOME/bin/java" -elif is_java8 "/nemo/jdk8/bin/java"; then - JAVA="/nemo/jdk8/bin/java"; -elif is_java8 "/nemo/jdk1.8/bin/java"; then - JAVA="/nemo/jdk1.8/bin/java"; -elif is_java8 "/nemo/jdk/bin/java"; then - JAVA="/nemo/jdk/bin/java"; -elif is_java8 "$(which java)"; then + JAVA_VERSION=$(extract_java_version "$JAVA_HOME/bin/java") +elif is_java8_or_11 "$(which java)"; then JAVA="$(which java)" + JAVA_VERSION=$(extract_java_version "$(which java)") else - echo -e "ERROR\t java(1.8) not found, operation abort." + echo -e "ERROR\t Java 8 or 11 not found, operation abort." exit 9; fi -echo "eventmesh use java location= "$JAVA - -EVENTMESH_HOME=`cd $(dirname $0)/.. && pwd` +echo "EventMesh using Java version: $JAVA_VERSION, path: $JAVA" +EVENTMESH_HOME=$(cd "$(dirname "$0")/.." && pwd) export EVENTMESH_HOME -export EVENTMESH_LOG_HOME=${EVENTMESH_HOME}/logs +EVENTMESH_LOG_HOME="${EVENTMESH_HOME}/logs" +export EVENTMESH_LOG_HOME -echo "EVENTMESH_HOME : ${EVENTMESH_HOME}, EVENTMESH_LOG_HOME : ${EVENTMESH_LOG_HOME}" +echo -e "EVENTMESH_HOME : ${EVENTMESH_HOME}\nEVENTMESH_LOG_HOME : ${EVENTMESH_LOG_HOME}" function make_logs_dir { if [ ! -e "${EVENTMESH_LOG_HOME}" ]; then mkdir -p "${EVENTMESH_LOG_HOME}"; fi @@ -102,7 +120,7 @@ function make_logs_dir { error_exit () { - echo "ERROR: $1 !!" + echo -e "ERROR\t $1 !!" exit 1 } @@ -116,12 +134,23 @@ export JAVA_HOME #elif [ $1 = "dev" ]; then JAVA_OPT="${JAVA_OPT} -server -Xms128M -Xmx256M -Xmn128m -XX:SurvivorRatio=4" #fi +GC_LOG_FILE="${EVENTMESH_LOG_HOME}/eventmesh_gc_%p.log" + #JAVA_OPT="${JAVA_OPT} -server -Xms2048M -Xmx4096M -Xmn2048m -XX:SurvivorRatio=4" JAVA_OPT=`cat ${EVENTMESH_HOME}/conf/server.env | grep APP_START_JVM_OPTION::: | awk -F ':::' {'print $2'}` JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:MaxGCPauseMillis=50" -JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${EVENTMESH_HOME}/logs/eventmesh_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" -JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${EVENTMESH_HOME}/logs -XX:ErrorFile=${EVENTMESH_HOME}/logs/hs_err_%p.log" -JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" +JAVA_OPT="${JAVA_OPT} -verbose:gc" +if [[ "$JAVA_VERSION" == "8" ]]; then + # Set JAVA_OPT for Java 8 + JAVA_OPT="${JAVA_OPT} -Xloggc:${GC_LOG_FILE} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" + JAVA_OPT="${JAVA_OPT} -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" +elif [[ "$JAVA_VERSION" == "11" ]]; then + # Set JAVA_OPT for Java 11 + XLOG_PARAM="time,level,tags:filecount=5,filesize=30m" + JAVA_OPT="${JAVA_OPT} -Xlog:gc*:${GC_LOG_FILE}:${XLOG_PARAM}" + JAVA_OPT="${JAVA_OPT} -Xlog:safepoint:${GC_LOG_FILE}:${XLOG_PARAM} -Xlog:ergo*=debug:${GC_LOG_FILE}:${XLOG_PARAM}" +fi +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${EVENTMESH_LOG_HOME} -XX:ErrorFile=${EVENTMESH_LOG_HOME}/hs_err_%p.log" JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow" JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch" JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=8G" @@ -148,22 +177,24 @@ JAVA_OPT="${JAVA_OPT} -DeventMeshPluginDir=${EVENTMESH_HOME}/plugin" #fi pid=$(get_pid) -if [ -n "$pid" ];then - echo -e "ERROR\t the server is already running (pid=$pid), there is no need to execute start.sh again." - exit 9; +if [[ $pid == "ERROR"* ]]; then + echo -e "${pid}" + exit 9 +fi +if [ -n "$pid" ]; then + echo -e "ERROR\t The server is already running (pid=$pid), there is no need to execute start.sh again." + exit 9 fi make_logs_dir -echo "using jdk[$JAVA]" >> ${EVENTMESH_LOG_HOME}/eventmesh.out - +echo "Using Java version: $JAVA_VERSION, path: $JAVA" >> ${EVENTMESH_LOG_HOME}/eventmesh.out EVENTMESH_MAIN=org.apache.eventmesh.runtime.boot.EventMeshStartup -if [ $DOCKER ] -then +if [ $DOCKER ]; then $JAVA $JAVA_OPT -classpath ${EVENTMESH_HOME}/conf:${EVENTMESH_HOME}/apps/*:${EVENTMESH_HOME}/lib/* $EVENTMESH_MAIN >> ${EVENTMESH_LOG_HOME}/eventmesh.out else $JAVA $JAVA_OPT -classpath ${EVENTMESH_HOME}/conf:${EVENTMESH_HOME}/apps/*:${EVENTMESH_HOME}/lib/* $EVENTMESH_MAIN >> ${EVENTMESH_LOG_HOME}/eventmesh.out 2>&1 & -echo $!>pid.file +echo $!>${EVENTMESH_HOME}/bin/pid.file fi exit 0 diff --git a/eventmesh-runtime/bin/stop.sh b/eventmesh-runtime/bin/stop.sh index e85fbf5ec1..b4f1d00154 100644 --- a/eventmesh-runtime/bin/stop.sh +++ b/eventmesh-runtime/bin/stop.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Licensed to Apache Software Foundation (ASF) under one or more contributor # license agreements. See the NOTICE file distributed with @@ -17,7 +17,7 @@ # specific language governing permissions and limitations # under the License. -#detect operating system. +# Detect operating system OS=$(uname) EVENTMESH_HOME=`cd $(dirname $0)/.. && pwd` @@ -28,6 +28,13 @@ function get_pid { local ppid="" if [ -f ${EVENTMESH_HOME}/bin/pid.file ]; then ppid=$(cat ${EVENTMESH_HOME}/bin/pid.file) + # If the process does not exist, it indicates that the previous process terminated abnormally. + if [ ! -d /proc/$ppid ]; then + # Remove the residual file and return an error status. + rm ${EVENTMESH_HOME}/bin/pid.file + echo -e "ERROR\t EventMesh process had already terminated unexpectedly before, please check log output." + ppid="" + fi else if [[ $OS =~ Msys ]]; then # There is a Bug on Msys that may not be able to kill the identified process @@ -44,20 +51,24 @@ function get_pid { } pid=$(get_pid) +if [[ $pid == "ERROR"* ]]; then + echo -e "${pid}" + exit 9 +fi if [ -z "$pid" ];then - echo -e "No eventmesh running.." - exit 0; + echo -e "ERROR\t No EventMesh server running." + exit 9 fi kill ${pid} -echo "Send shutdown request to eventmesh(${pid}) OK" +echo "Send shutdown request to EventMesh(${pid}) OK" [[ $OS =~ Msys ]] && PS_PARAM=" -W " stop_timeout=60 for no in $(seq 1 $stop_timeout); do if ps $PS_PARAM -p "$pid" 2>&1 > /dev/null; then if [ $no -lt $stop_timeout ]; then - echo "[$no] shutdown server ..." + echo "[$no] server shutting down ..." sleep 1 continue fi diff --git a/eventmesh-runtime/build.gradle b/eventmesh-runtime/build.gradle index 8ee66a6143..0235b46d0e 100644 --- a/eventmesh-runtime/build.gradle +++ b/eventmesh-runtime/build.gradle @@ -15,10 +15,9 @@ * limitations under the License. */ -def grpcVersion = '1.17.1' - dependencies { implementation 'io.cloudevents:cloudevents-core' + implementation 'io.cloudevents:cloudevents-json-jackson' implementation 'io.opentelemetry:opentelemetry-api' implementation 'io.opentelemetry:opentelemetry-sdk' @@ -28,51 +27,58 @@ dependencies { implementation "org.apache.httpcomponents:httpclient" implementation 'io.netty:netty-all' - implementation 'com.github.seancfoley:ipaddress:5.3.3' + implementation "com.alibaba.fastjson2:fastjson2" + + implementation 'com.github.seancfoley:ipaddress' + + implementation "commons-io:commons-io" + + implementation "commons-validator:commons-validator" implementation project(":eventmesh-common") implementation project(":eventmesh-spi") - implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") - implementation project(":eventmesh-connector-plugin:eventmesh-connector-standalone") + implementation project(":eventmesh-function:eventmesh-function-api") + implementation project(":eventmesh-function:eventmesh-function-filter") + implementation project(":eventmesh-function:eventmesh-function-transformer") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-standalone") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-rocketmq") implementation project(":eventmesh-security-plugin:eventmesh-security-api") implementation project(":eventmesh-security-plugin:eventmesh-security-acl") implementation project(":eventmesh-security-plugin:eventmesh-security-auth-http-basic") - implementation project(":eventmesh-registry-plugin:eventmesh-registry-api") - implementation project(":eventmesh-admin:eventmesh-admin-rocketmq") - - - implementation project(":eventmesh-registry-plugin:eventmesh-registry-nacos") - implementation project(":eventmesh-registry-plugin:eventmesh-registry-etcd") - + implementation project(":eventmesh-security-plugin:eventmesh-security-auth-token") + implementation project(":eventmesh-meta:eventmesh-meta-api") + implementation project(":eventmesh-meta:eventmesh-meta-nacos") implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-api") - implementation "io.grpc:grpc-core:${grpcVersion}" - implementation "io.grpc:grpc-protobuf:${grpcVersion}" - implementation "io.grpc:grpc-stub:${grpcVersion}" - implementation "io.grpc:grpc-netty:${grpcVersion}" - implementation "io.grpc:grpc-netty-shaded:${grpcVersion}" + implementation "io.grpc:grpc-core" + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty" + implementation "io.grpc:grpc-netty-shaded" - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' // for debug only, can be removed implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-cloudevents") implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-meshmessage") implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-openmessage") implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-http") + implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-a2a") implementation project(":eventmesh-metrics-plugin:eventmesh-metrics-api") implementation project(":eventmesh-metrics-plugin:eventmesh-metrics-prometheus") implementation project(":eventmesh-trace-plugin:eventmesh-trace-api") implementation project(":eventmesh-trace-plugin:eventmesh-trace-zipkin") - - implementation project(":eventmesh-webhook:eventmesh-webhook-admin") - implementation project(":eventmesh-webhook:eventmesh-webhook-api") - implementation project(":eventmesh-webhook:eventmesh-webhook-receive") - testImplementation "org.mockito:mockito-core" + implementation project(":eventmesh-retry:eventmesh-retry-api") + testImplementation "org.mockito:mockito-inline" - testImplementation "org.powermock:powermock-module-junit4" - testImplementation "org.powermock:powermock-api-mockito2" + testImplementation "org.mockito:mockito-junit-jupiter" + testImplementation "commons-io:commons-io" + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' } diff --git a/eventmesh-runtime/conf/a2a-protocol-config.yaml b/eventmesh-runtime/conf/a2a-protocol-config.yaml new file mode 100644 index 0000000000..4ce81f502d --- /dev/null +++ b/eventmesh-runtime/conf/a2a-protocol-config.yaml @@ -0,0 +1,35 @@ +# 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. + +eventMesh: + protocol: + plugin: + a2a: + # Whether the A2A (Agent-to-Agent) protocol adaptor is enabled + enabled: true + + # Protocol version + version: "2.0" + + # Features configuration + features: + # Enable delegation to existing CloudEvents/HTTP protocols + delegation: true + + # Enable MCP (Model Context Protocol) JSON-RPC 2.0 support + mcp-support: true + + # Enable batch processing support + batch-processing: true diff --git a/eventmesh-runtime/conf/admin-server.jks b/eventmesh-runtime/conf/admin-server.jks new file mode 100644 index 0000000000..92deb897a4 Binary files /dev/null and b/eventmesh-runtime/conf/admin-server.jks differ diff --git a/eventmesh-runtime/conf/eventmesh.properties b/eventmesh-runtime/conf/eventmesh.properties index 5ad8c14fd3..87a24a1369 100644 --- a/eventmesh-runtime/conf/eventmesh.properties +++ b/eventmesh-runtime/conf/eventmesh.properties @@ -14,17 +14,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # -###############################EVNETMESH-runtime ENV################################# +########################## EventMesh Runtime Environment ########################## eventMesh.server.idc=DEFAULT eventMesh.server.env=PRD +eventMesh.server.provide.protocols=HTTP,TCP,GRPC eventMesh.server.cluster=COMMON eventMesh.server.name=EVENTMESH-runtime eventMesh.sysid=0000 +eventMesh.server.tcp.port=10000 eventMesh.server.http.port=10105 eventMesh.server.grpc.port=10205 -########################## eventMesh tcp configuration ############################ -eventMesh.server.tcp.enabled=true -eventMesh.server.tcp.port=10000 +eventMesh.server.admin.http.port=10106 + +########################## EventMesh Network Configuration ########################## eventMesh.server.tcp.readerIdleSeconds=120 eventMesh.server.tcp.writerIdleSeconds=120 eventMesh.server.tcp.allIdleSeconds=120 @@ -48,58 +50,110 @@ eventMesh.server.maxEventBatchSize=10 # thread number about global scheduler eventMesh.server.global.scheduler=5 eventMesh.server.tcp.taskHandleExecutorPoolSize=8 -#retry +# retry eventMesh.server.retry.async.pushRetryTimes=3 eventMesh.server.retry.sync.pushRetryTimes=3 eventMesh.server.retry.async.pushRetryDelayInMills=500 eventMesh.server.retry.sync.pushRetryDelayInMills=500 eventMesh.server.retry.pushRetryQueueSize=10000 -#admin -eventMesh.server.admin.http.port=10106 -#registry -eventMesh.server.registry.registerIntervalInMills=10000 -eventMesh.server.registry.fetchRegistryAddrIntervalInMills=20000 -#auto-ack -#eventMesh.server.defibus.client.comsumeTimeoutInMin=5 +eventMesh.server.retry.plugin.type=default -#sleep interval between closing client of different group in server graceful shutdown +# sleep interval between closing client of different group in server graceful shutdown eventMesh.server.gracefulShutdown.sleepIntervalInMills=1000 eventMesh.server.rebalanceRedirect.sleepIntervalInMills=200 -#ip address blacklist +# TLS +eventMesh.server.useTls.enabled=false +eventMesh.server.ssl.protocol=TLSv1.1 +eventMesh.server.ssl.cer=sChat2.jks +eventMesh.server.ssl.pass=sNetty + +# ip address blacklist eventMesh.server.blacklist.ipv4=0.0.0.0/8,127.0.0.0/8,169.254.0.0/16,255.255.255.255/32 eventMesh.server.blacklist.ipv6=::/128,::1/128,ff00::/8 -#connector plugin -eventMesh.connector.plugin.type=standalone +########################## EventMesh HTTP Admin Configuration ########################## +# thread pool +eventMesh.server.admin.threads.num=2 + +# TLS +eventMesh.server.admin.useTls.enabled=false +eventMesh.server.admin.ssl.protocol=TLSv1.3 +eventMesh.server.admin.ssl.cer=admin-server.jks +eventMesh.server.admin.ssl.pass=eventmesh-admin-server + +# ip address blacklist +eventMesh.server.admin.blacklist.ipv4=0.0.0.0/8,127.0.0.0/8,169.254.0.0/16,255.255.255.255/32 +eventMesh.server.admin.blacklist.ipv6=::/128,::1/128,ff00::/8 -#security plugin +########################## EventMesh Plugin Configuration ########################## +# storage plugin +eventMesh.storage.plugin.type=standalone + +# security plugin eventMesh.server.security.enabled=false eventMesh.security.plugin.type=security +eventMesh.security.validation.type.token=false +eventMesh.security.publickey= + +# metaStorage plugin +eventMesh.metaStorage.plugin.enabled=false +eventMesh.metaStorage.plugin.type=nacos +eventMesh.metaStorage.plugin.server-addr=127.0.0.1:8848 +eventMesh.metaStorage.plugin.username=nacos +eventMesh.metaStorage.plugin.password=nacos + +# metaStorage plugin: raft +# Path to local snapshot storage for raft data +#eventMesh.metaStorage.raft.dataPath=/tmp/eventmesh-meta-raft +# Raft local ip and port +#eventMesh.metaStorage.raft.self=127.0.0.1:9091 +# Members ip and port +#eventMesh.metaStorage.raft.members=192.168.1.2:9091,192.168.1.3:9091 +# Raft leader election timeout second +#eventMesh.metaStorage.raft.electionTimeout=5 +# Raft snapshot interval second +#eventMesh.metaStorage.raft.snapshotInterval=30 +# Raft refresh leader interval second +#eventMesh.metaStorage.raft.refreshLeaderInterval=3 + +# metaStorage plugin: nacos +#eventMesh.metaStorage.nacos.endpoint= +#eventMesh.metaStorage.nacos.accessKey= +#eventMesh.metaStorage.nacos.secretKey= +#eventMesh.metaStorage.nacos.clusterName= +#eventMesh.metaStorage.nacos.namespace= +# The default value is half of CPU's num +#eventMesh.metaStorage.nacos.namingPollingThreadCount=5 + +# metaStorage plugin: zookeeper +#eventMesh.metaStorage.zookeeper.scheme= +#eventMesh.metaStorage.zookeeper.auth= +#eventMesh.metaStorage.zookeeper.connectionTimeoutMs= +#eventMesh.metaStorage.zookeeper.sessionTimeoutMs= + +# Fully qualified name of org.apache.curator.RetryPolicy implementation +#eventMesh.metaStorage.zookeeper.retryPolicy.class= + +# Constructor arguments for different org.apache.curator.RetryPolicy implementations +#eventMesh.metaStorage.zookeeper.retryPolicy.baseSleepTimeMs= +#eventMesh.metaStorage.zookeeper.retryPolicy.maxRetries= +#eventMesh.metaStorage.zookeeper.retryPolicy.maxSleepTimeMs= +#eventMesh.metaStorage.zookeeper.retryPolicy.retryIntervalMs= +#eventMesh.metaStorage.zookeeper.retryPolicy.nTimes= +#eventMesh.metaStorage.zookeeper.retryPolicy.sleepMsBetweenRetries= -#registry plugin -eventMesh.registry.plugin.enabled=false -eventMesh.registry.plugin.type=nacos -eventMesh.registry.plugin.server-addr=127.0.0.1:8848 -eventMesh.registry.plugin.username=nacos -eventMesh.registry.plugin.password=nacos +# The TLS configuration of metaStorage plugin: consul +# keyStoreInstanceType's value can refer to com.ecwid.consul.transport.TLSConfig.KeyStoreInstanceType +#eventMesh.metaStorage.consul.tls.keyStoreInstanceType= +#eventMesh.metaStorage.consul.tls.certificatePath= +#eventMesh.metaStorage.consul.tls.certificatePassword= +#eventMesh.metaStorage.consul.tls.keyStorePath= +#eventMesh.metaStorage.consul.tls.keyStorePassword= # metrics plugin, if you have multiple plugin, you can use ',' to split eventMesh.metrics.plugin=prometheus # trace plugin eventMesh.server.trace.enabled=false -eventMesh.trace.plugin=zipkin - -# webhook -# Start webhook admin service -eventMesh.webHook.admin.start=true -# Webhook event configuration storage mode. Currently, only file and Nacos are supported -eventMesh.webHook.operationMode=file -# The file storage path of the file storage mode. If #{eventmeshhome} is written, it is in the eventmesh root directory -eventMesh.webHook.fileMode.filePath= #{eventMeshHome}/webhook -# Nacos storage mode, and the configuration naming rule is eventmesh webHook. nacosMode. {nacos native configuration key} please see the specific configuration [nacos github api](https://github.com/alibaba/nacos/blob/develop/api/src/main/java/com/alibaba/nacos/api/SystemPropertyKeyConst.java) -## Address of Nacos -eventMesh.webHook.nacosMode.serverAddr=127.0.0.1:8848 -# Webhook eventcloud sending mode. And eventmesh connector. plugin. The type configuration is the same -eventMesh.webHook.producer.connector=standalone +eventMesh.trace.plugin=zipkin \ No newline at end of file diff --git a/eventmesh-runtime/conf/log4j2.xml b/eventmesh-runtime/conf/log4j2.xml index 756abeac33..6341a0e629 100644 --- a/eventmesh-runtime/conf/log4j2.xml +++ b/eventmesh-runtime/conf/log4j2.xml @@ -60,7 +60,7 @@ - + @@ -95,5 +95,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/eventmesh-runtime/conf/server.env b/eventmesh-runtime/conf/server.env index f8c01df100..bad77bb62e 100644 --- a/eventmesh-runtime/conf/server.env +++ b/eventmesh-runtime/conf/server.env @@ -1,18 +1,17 @@ # -# Licensed to 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. Apache Software Foundation (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 +# 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. +# 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. +# APP_START_JVM_OPTION:::-server -Xms128M -Xmx256M -Xmn128m -XX:SurvivorRatio=4 -Duser.language=zh diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2ACardHttpHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2ACardHttpHandler.java new file mode 100644 index 0000000000..1e9f262c84 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2ACardHttpHandler.java @@ -0,0 +1,218 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import org.apache.eventmesh.protocol.a2a.AgentIdentity; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * HTTP handler for A2A Agent Card Registry API. + * Matches EMQX's API pattern: + * - GET /a2a/cards/list - list agent cards + * - GET /a2a/cards/card/{org_id}/{unit_id}/{agent_id} - get specific card + * - POST /a2a/cards/card/{org_id}/{unit_id}/{agent_id} - register card + * - DELETE /a2a/cards/card/{org_id}/{unit_id}/{agent_id} - delete card + */ +@Slf4j +public class A2ACardHttpHandler { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final String PATH_LIST = "/a2a/cards/list"; + private static final String PATH_CARD_PREFIX = "/a2a/cards/card/"; + + private final A2APublishSubscribeService a2aService; + + public A2ACardHttpHandler(A2APublishSubscribeService a2aService) { + this.a2aService = a2aService; + } + + public FullHttpResponse handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String uri = httpRequest.uri(); + QueryStringDecoder decoder = new QueryStringDecoder(uri); + String path = decoder.path(); + HttpMethod method = httpRequest.method(); + + try { + // Handle CORS preflight + if (method == HttpMethod.OPTIONS) { + return corsResponse(); + } + + if (path.equals(PATH_LIST)) { + return handleList(decoder); + } + + if (path.startsWith(PATH_CARD_PREFIX)) { + String[] segments = path.substring(PATH_CARD_PREFIX.length()).split("/"); + if (segments.length != 3) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, + errorBody("Invalid path. Expected /a2a/cards/card/{org_id}/{unit_id}/{agent_id}")); + } + + String orgId = segments[0]; + String unitId = segments[1]; + String agentId = segments[2]; + + if (method == HttpMethod.GET) { + return handleGet(orgId, unitId, agentId); + } else if (method == HttpMethod.POST) { + return handleRegister(orgId, unitId, agentId, httpRequest); + } else if (method == HttpMethod.DELETE) { + return handleDelete(orgId, unitId, agentId); + } + } + + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Not found: " + path)); + } catch (Exception e) { + log.error("A2A card handler error: {}", e.getMessage(), e); + return jsonResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, errorBody(e.getMessage())); + } + } + + private FullHttpResponse handleList(QueryStringDecoder decoder) throws Exception { + String orgId = getQueryParam(decoder, "org_id"); + String unitId = getQueryParam(decoder, "unit_id"); + String agentId = getQueryParam(decoder, "agent_id"); + + List cards = a2aService.listCards(orgId, unitId, agentId); + String body = objectMapper.writeValueAsString(cards); + return jsonResponse(HttpResponseStatus.OK, body); + } + + private FullHttpResponse handleGet(String orgId, String unitId, String agentId) throws Exception { + AgentIdentity identity = AgentIdentity.builder() + .orgId(orgId).unitId(unitId).agentId(agentId).build(); + A2APublishSubscribeService.CardEntry card = a2aService.getCard(identity); + + if (card == null) { + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Card not found")); + } + + String body = objectMapper.writeValueAsString(formatCardOut(card)); + return jsonResponse(HttpResponseStatus.OK, body); + } + + private FullHttpResponse handleRegister(String orgId, String unitId, String agentId, HttpRequest request) throws Exception { + // Read body from request + String requestBody = ""; + if (request instanceof io.netty.handler.codec.http.FullHttpRequest) { + ByteBuf content = ((io.netty.handler.codec.http.FullHttpRequest) request).content(); + requestBody = content.toString(StandardCharsets.UTF_8); + } + + AgentCard card; + try { + card = objectMapper.readValue(requestBody, AgentCard.class); + } catch (Exception e) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, errorBody("Invalid card JSON: " + e.getMessage())); + } + + AgentIdentity identity = AgentIdentity.builder() + .orgId(orgId).unitId(unitId).agentId(agentId).build(); + A2APublishSubscribeService.RegistrationResult result = a2aService.registerCard(identity, card); + + if (result.isSuccess()) { + return jsonResponse(HttpResponseStatus.NO_CONTENT, ""); + } else { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, errorBody(result.getErrorMessage())); + } + } + + private FullHttpResponse handleDelete(String orgId, String unitId, String agentId) throws Exception { + AgentIdentity identity = AgentIdentity.builder() + .orgId(orgId).unitId(unitId).agentId(agentId).build(); + boolean deleted = a2aService.deleteCard(identity); + + if (deleted) { + return jsonResponse(HttpResponseStatus.NO_CONTENT, ""); + } else { + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Card not found")); + } + } + + private Map formatCardOut(A2APublishSubscribeService.CardEntry entry) { + Map out = new LinkedHashMap<>(); + out.put("namespace", entry.getNamespace()); + out.put("id", entry.getId()); + out.put("name", entry.getName()); + out.put("version", entry.getVersion()); + out.put("description", entry.getDescription()); + out.put("status", entry.getStatus()); + return out; + } + + private String getQueryParam(QueryStringDecoder decoder, String key) { + List values = decoder.parameters().get(key); + return (values != null && !values.isEmpty()) ? values.get(0) : null; + } + + private String errorBody(String message) { + try { + return objectMapper.writeValueAsString(Collections.singletonMap("error", message)); + } catch (Exception e) { + return "{\"error\":\"" + message + "\"}"; + } + } + + private FullHttpResponse jsonResponse(HttpResponseStatus status, String body) { + ByteBuf content = Unpooled.copiedBuffer(body, StandardCharsets.UTF_8); + DefaultFullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, status, content); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8"); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); + setCorsHeaders(response); + return response; + } + + private FullHttpResponse corsResponse() { + DefaultFullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + setCorsHeaders(response); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0); + return response; + } + + private void setCorsHeaders(FullHttpResponse response) { + response.headers().set("Access-Control-Allow-Origin", "*"); + response.headers().set("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS"); + response.headers().set("Access-Control-Allow-Headers", "Content-Type, Authorization"); + response.headers().set("Access-Control-Max-Age", "3600"); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayHttpHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayHttpHandler.java new file mode 100644 index 0000000000..8c4722089a --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayHttpHandler.java @@ -0,0 +1,648 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.DefaultHttpContent; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.QueryStringDecoder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * HTTP handler for A2A Gateway API. + * + *

Endpoints: + *

    + *
  • POST /a2a/tasks - submit a new task (sync or async)
  • + *
  • GET /a2a/tasks - list tasks (optional ?state=COMPLETED&limit=100&offset=0)
  • + *
  • GET /a2a/tasks/{taskId} - get task status
  • + *
  • DELETE /a2a/tasks/{taskId} - cancel a task
  • + *
  • GET /a2a/tasks/{taskId}/wait - wait for task result (long-poll)
  • + *
  • GET /a2a/tasks/{taskId}/stream - SSE stream of task status updates
  • + *
  • GET /a2a/agents - list registered agents
  • + *
  • POST /a2a/heartbeat - agent heartbeat
  • + *
  • GET /a2a/health - health check (for liveness/readiness probes)
  • + *
  • OPTIONS * - CORS preflight
  • + *
+ */ +@Slf4j +public class A2AGatewayHttpHandler { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static final String PATH_TASKS = "/a2a/tasks"; + private static final String PATH_AGENTS = "/a2a/agents"; + private static final String PATH_HEARTBEAT = "/a2a/heartbeat"; + private static final String PATH_HEALTH = "/a2a/health"; + + private static final long DEFAULT_WAIT_TIMEOUT_MS = 30_000L; + + private final A2AGatewayService gatewayService; + private final A2APublishSubscribeService a2aService; + + public A2AGatewayHttpHandler(A2AGatewayService gatewayService, + A2APublishSubscribeService a2aService) { + this.gatewayService = gatewayService; + this.a2aService = a2aService; + } + + /** + * Handles an HTTP request. Returns a FullHttpResponse, or null if the response was written + * directly to the channel (e.g. SSE streaming). + */ + public FullHttpResponse handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String uri = httpRequest.uri(); + QueryStringDecoder decoder = new QueryStringDecoder(uri); + String path = decoder.path(); + HttpMethod method = httpRequest.method(); + + try { + // Handle CORS preflight + if (method == HttpMethod.OPTIONS) { + return corsResponse(HttpResponseStatus.OK); + } + + // POST /a2a/tasks + if (PATH_TASKS.equals(path) && method == HttpMethod.POST) { + return handleSubmitTask(httpRequest, decoder); + } + + // GET /a2a/tasks (list tasks with optional pagination) + if (PATH_TASKS.equals(path) && method == HttpMethod.GET) { + return handleListTasks(decoder); + } + + // /a2a/tasks/{taskId} or /a2a/tasks/{taskId}/wait + if (path.startsWith(PATH_TASKS + "/")) { + String suffix = path.substring(PATH_TASKS.length() + 1); + String[] parts = suffix.split("/", 2); + String taskId = parts[0]; + + if (taskId.isEmpty()) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, errorBody("Missing taskId")); + } + + // GET /a2a/tasks/{taskId} + if (method == HttpMethod.GET && parts.length == 1) { + return handleGetTask(taskId); + } + + // DELETE /a2a/tasks/{taskId} + if (method == HttpMethod.DELETE && parts.length == 1) { + return handleCancelTask(taskId); + } + + // GET /a2a/tasks/{taskId}/wait + if (method == HttpMethod.GET && parts.length == 2 && "wait".equals(parts[1])) { + return handleWaitTask(taskId, decoder); + } + + // GET /a2a/tasks/{taskId}/stream (SSE) + if (method == HttpMethod.GET && parts.length == 2 && "stream".equals(parts[1])) { + return handleStreamTask(taskId, ctx); + } + } + + // GET /a2a/health + if (PATH_HEALTH.equals(path) && method == HttpMethod.GET) { + return handleHealth(); + } + + // GET /a2a/agents + if (PATH_AGENTS.equals(path) && method == HttpMethod.GET) { + return handleListAgents(); + } + + // POST /a2a/heartbeat + if (PATH_HEARTBEAT.equals(path) && method == HttpMethod.POST) { + return handleHeartbeat(httpRequest); + } + + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Not found: " + path)); + } catch (Exception e) { + log.error("A2A gateway handler error: {}", e.getMessage(), e); + return jsonResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, errorBody(e.getMessage())); + } + } + + // ========================================================================= + // POST /a2a/tasks + // ========================================================================= + + private FullHttpResponse handleSubmitTask(HttpRequest request, QueryStringDecoder decoder) throws Exception { + String body = readBody(request); + TaskRequest taskRequest; + try { + taskRequest = objectMapper.readValue(body, TaskRequest.class); + } catch (Exception e) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, errorBody("Invalid JSON: " + e.getMessage())); + } + + if (taskRequest.getTargetAgent() == null || taskRequest.getTargetAgent().isEmpty()) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, errorBody("targetAgent is required")); + } + if (taskRequest.getMessage() == null) { + taskRequest.setMessage(""); + } + + String mode = getQueryParam(decoder, "mode"); + String parentTaskId = taskRequest.getParentTaskId(); + + // Generate taskId first so we can include it in the response + String taskId = "task-" + java.util.UUID.randomUUID().toString().substring(0, 8); + + // Submit the task with the explicit taskId + java.util.concurrent.CompletableFuture future = + gatewayService.submitTask(taskId, taskRequest.getTargetAgent(), taskRequest.getMessage(), parentTaskId); + + // For sync mode, wait for result + if ("sync".equalsIgnoreCase(mode) || mode == null) { + try { + A2AGatewayService.TaskResult result = future.get(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + Map response = new LinkedHashMap<>(); + response.put("taskId", taskId); + response.put("state", result.getState().name()); + response.put("data", result.getData()); + if (result.getErrorMessage() != null) { + response.put("error", result.getErrorMessage()); + } + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } catch (java.util.concurrent.TimeoutException e) { + Map response = new LinkedHashMap<>(); + response.put("taskId", taskId); + response.put("state", "TIMEOUT"); + response.put("error", "Task accepted but timed out waiting for response"); + return jsonResponse(HttpResponseStatus.ACCEPTED, objectMapper.writeValueAsString(response)); + } catch (java.util.concurrent.ExecutionException e) { + // Unwrap cause to determine correct status code + Throwable cause = e.getCause() != null ? e.getCause() : e; + if (cause instanceof IllegalArgumentException || cause instanceof IllegalStateException) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, + errorBody(cause.getMessage())); + } + return jsonResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, + errorBody("Task failed: " + cause.getMessage())); + } catch (Exception e) { + return jsonResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, + errorBody("Task failed: " + e.getMessage())); + } + } else { + // Async mode: return task ID immediately + Map response = new LinkedHashMap<>(); + response.put("taskId", taskId); + response.put("status", "accepted"); + response.put("message", "Task submitted. Use GET /a2a/tasks/" + taskId + " to check status."); + return jsonResponse(HttpResponseStatus.ACCEPTED, objectMapper.writeValueAsString(response)); + } + } + + // ========================================================================= + // GET /a2a/tasks (list with optional pagination) + // ========================================================================= + + private FullHttpResponse handleListTasks(QueryStringDecoder decoder) throws Exception { + String stateFilter = getQueryParam(decoder, "state"); + int limit = parseIntQueryParam(decoder, "limit", 100, 1, 1_000); + int offset = parseIntQueryParam(decoder, "offset", 0, 0, Integer.MAX_VALUE); + + List allTasks = gatewayService.getTaskRegistry().listTasks(); + List> filteredTasks = new java.util.ArrayList<>(); + for (TaskRegistry.TaskEntry entry : allTasks) { + if (stateFilter != null && !stateFilter.equalsIgnoreCase(entry.getState().name())) { + continue; + } + Map task = new LinkedHashMap<>(); + task.put("taskId", entry.getTaskId()); + task.put("state", entry.getState().name()); + task.put("targetAgent", entry.getTargetAgent()); + task.put("parentTaskId", entry.getParentTaskId()); + task.put("createdAt", entry.getCreatedAt()); + task.put("updatedAt", entry.getUpdatedAt()); + filteredTasks.add(task); + } + + int total = filteredTasks.size(); + int fromIndex = Math.min(offset, total); + int toIndex = Math.min(fromIndex + limit, total); + List> page = filteredTasks.subList(fromIndex, toIndex); + + Map response = new LinkedHashMap<>(); + response.put("total", total); + response.put("count", page.size()); + response.put("limit", limit); + response.put("offset", offset); + response.put("hasMore", toIndex < total); + response.put("tasks", page); + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } + + // ========================================================================= + // GET /a2a/tasks/{taskId} + // ========================================================================= + + private FullHttpResponse handleGetTask(String taskId) throws Exception { + TaskRegistry.TaskEntry entry = gatewayService.getTaskStatus(taskId); + if (entry == null) { + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Task not found: " + taskId)); + } + Map response = new LinkedHashMap<>(); + response.put("taskId", entry.getTaskId()); + response.put("state", entry.getState().name()); + response.put("targetAgent", entry.getTargetAgent()); + response.put("gatewayId", entry.getGatewayId()); + response.put("parentTaskId", entry.getParentTaskId()); + response.put("createdAt", entry.getCreatedAt()); + response.put("updatedAt", entry.getUpdatedAt()); + if (entry.getResult() != null) { + response.put("result", entry.getResult()); + } + if (entry.getErrorMessage() != null) { + response.put("error", entry.getErrorMessage()); + } + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } + + // ========================================================================= + // DELETE /a2a/tasks/{taskId} + // ========================================================================= + + private FullHttpResponse handleCancelTask(String taskId) throws Exception { + boolean cancelled = gatewayService.cancelTask(taskId); + if (cancelled) { + Map response = new LinkedHashMap<>(); + response.put("taskId", taskId); + response.put("state", "CANCELLED"); + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Task not found or cannot be cancelled: " + taskId)); + } + + // ========================================================================= + // GET /a2a/tasks/{taskId}/wait + // ========================================================================= + + private FullHttpResponse handleWaitTask(String taskId, QueryStringDecoder decoder) throws Exception { + String timeoutStr = getQueryParam(decoder, "timeout"); + long timeout = timeoutStr != null ? Long.parseLong(timeoutStr) : DEFAULT_WAIT_TIMEOUT_MS; + + TaskRegistry.TaskEntry entry = gatewayService.getTaskStatus(taskId); + if (entry == null) { + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Task not found: " + taskId)); + } + + // If already in a terminal state, return immediately + if (isTerminalState(entry.getState())) { + return handleGetTask(taskId); + } + + // Register a status subscriber and wait + java.util.concurrent.CompletableFuture waitFuture = new java.util.concurrent.CompletableFuture<>(); + A2AGatewayService.StatusSubscriber subscriber = (tid, state, data) -> { + if ("completed".equals(state) || "failed".equals(state) || "cancelled".equals(state)) { + waitFuture.complete(gatewayService.getTaskStatus(tid)); + } + }; + gatewayService.registerStatusSubscriber(taskId, subscriber); + + try { + TaskRegistry.TaskEntry result = waitFuture.get(timeout, TimeUnit.MILLISECONDS); + Map response = new LinkedHashMap<>(); + response.put("taskId", result.getTaskId()); + response.put("state", result.getState().name()); + if (result.getResult() != null) { + response.put("result", result.getResult()); + } + if (result.getErrorMessage() != null) { + response.put("error", result.getErrorMessage()); + } + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } catch (java.util.concurrent.TimeoutException e) { + return jsonResponse(HttpResponseStatus.OK, + errorBody("Task still in progress. State: " + entry.getState())); + } catch (Exception e) { + return jsonResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, + errorBody("Wait failed: " + e.getMessage())); + } finally { + gatewayService.unregisterStatusSubscriber(taskId, subscriber); + } + } + + // ========================================================================= + // GET /a2a/tasks/{taskId}/stream (SSE) + // ========================================================================= + + /** + * Streams task status updates via Server-Sent Events. + * Writes directly to the channel and returns null (no FullHttpResponse). + */ + private FullHttpResponse handleStreamTask(String taskId, ChannelHandlerContext ctx) throws Exception { + TaskRegistry.TaskEntry entry = gatewayService.getTaskStatus(taskId); + if (entry == null) { + return jsonResponse(HttpResponseStatus.NOT_FOUND, errorBody("Task not found: " + taskId)); + } + + // Write SSE response headers + HttpResponse headers = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + headers.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/event-stream; charset=utf-8"); + headers.headers().set(HttpHeaderNames.CACHE_CONTROL, "no-cache"); + headers.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + headers.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + headers.headers().set("Access-Control-Allow-Origin", "*"); + ctx.writeAndFlush(headers); + + // Send initial state + sendSseEvent(ctx, taskId, entry.getState().name(), + entry.getResult() != null ? entry.getResult() : entry.getErrorMessage()); + + // If already terminal, close stream + if (isTerminalState(entry.getState())) { + ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); + ctx.close(); + return null; + } + + // Schedule periodic heartbeat to keep connection alive through proxies/load balancers + java.util.concurrent.ScheduledExecutorService heartbeatExecutor = java.util.concurrent.Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "a2a-sse-heartbeat"); + t.setDaemon(true); + return t; + }); + heartbeatExecutor.scheduleAtFixedRate(() -> { + try { + ByteBuf hb = Unpooled.copiedBuffer(": heartbeat\n\n", StandardCharsets.UTF_8); + ctx.writeAndFlush(new DefaultHttpContent(hb)); + } catch (Exception e) { + // Channel may have been closed; ignore + } + }, 15, 15, TimeUnit.SECONDS); + + // Register subscriber for ongoing updates + A2AGatewayService.StatusSubscriber subscriber = (tid, state, data) -> { + sendSseEvent(ctx, tid, state, data); + if ("completed".equals(state) || "failed".equals(state) || "cancelled".equals(state)) { + heartbeatExecutor.shutdownNow(); + ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT) + .addListener(ChannelFutureListener.CLOSE); + } + }; + gatewayService.registerStatusSubscriber(taskId, subscriber); + + // Remove subscriber and stop heartbeat when channel closes + ctx.channel().closeFuture().addListener(future -> { + gatewayService.unregisterStatusSubscriber(taskId, subscriber); + heartbeatExecutor.shutdownNow(); + }); + + return null; // Response already written to channel + } + + private void sendSseEvent(ChannelHandlerContext ctx, String taskId, String state, String data) { + Map event = new LinkedHashMap<>(); + event.put("taskId", taskId); + event.put("state", state); + if (data != null) { + event.put("data", data); + } + String json; + try { + json = objectMapper.writeValueAsString(event); + } catch (Exception e) { + json = "{\"error\":\"" + e.getMessage() + "\"}"; + } + String sse = "data: " + json + "\n\n"; + ByteBuf buf = Unpooled.copiedBuffer(sse, StandardCharsets.UTF_8); + ctx.writeAndFlush(new DefaultHttpContent(buf)); + } + + // ========================================================================= + // GET /a2a/health + // ========================================================================= + + private FullHttpResponse handleHealth() throws Exception { + Map response = new LinkedHashMap<>(); + response.put("status", "UP"); + response.put("gatewayId", gatewayService.getGatewayId()); + response.put("namespace", gatewayService.getNamespace()); + response.put("taskCount", gatewayService.getTaskRegistry().size()); + response.put("agentCount", a2aService.listAllCards().size()); + response.put("timestamp", System.currentTimeMillis()); + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } + + // ========================================================================= + // GET /a2a/agents + // ========================================================================= + + private FullHttpResponse handleListAgents() throws Exception { + return jsonResponse(HttpResponseStatus.OK, + objectMapper.writeValueAsString(a2aService.listAllCards())); + } + + // ========================================================================= + // POST /a2a/heartbeat + // ========================================================================= + + private FullHttpResponse handleHeartbeat(HttpRequest request) throws Exception { + String body = readBody(request); + HeartbeatRequest hb; + try { + hb = objectMapper.readValue(body, HeartbeatRequest.class); + } catch (Exception e) { + return jsonResponse(HttpResponseStatus.BAD_REQUEST, errorBody("Invalid JSON: " + e.getMessage())); + } + + org.apache.eventmesh.protocol.a2a.AgentIdentity identity = + org.apache.eventmesh.protocol.a2a.AgentIdentity.builder() + .orgId(hb.getOrgId()) + .unitId(hb.getUnitId()) + .agentId(hb.getAgentId()) + .build(); + + boolean refreshed = a2aService.heartbeat(identity); + Map response = new LinkedHashMap<>(); + response.put("ok", refreshed); + if (!refreshed) { + response.put("error", "Agent not registered. POST /a2a/cards/card/{org}/{unit}/{agent} first."); + } + return jsonResponse(HttpResponseStatus.OK, objectMapper.writeValueAsString(response)); + } + + // ========================================================================= + // Helpers + // ========================================================================= + + private boolean isTerminalState(TaskRegistry.TaskState state) { + return state == TaskRegistry.TaskState.COMPLETED + || state == TaskRegistry.TaskState.FAILED + || state == TaskRegistry.TaskState.CANCELLED; + } + + private String readBody(HttpRequest request) { + if (request instanceof io.netty.handler.codec.http.FullHttpRequest) { + ByteBuf content = ((io.netty.handler.codec.http.FullHttpRequest) request).content(); + return content.toString(StandardCharsets.UTF_8); + } + return ""; + } + + private String getQueryParam(QueryStringDecoder decoder, String key) { + java.util.List values = decoder.parameters().get(key); + return (values != null && !values.isEmpty()) ? values.get(0) : null; + } + + private int parseIntQueryParam(QueryStringDecoder decoder, String key, + int defaultValue, int minValue, int maxValue) { + String value = getQueryParam(decoder, key); + if (value == null || value.isEmpty()) { + return defaultValue; + } + try { + int parsed = Integer.parseInt(value); + if (parsed < minValue) { + return minValue; + } + if (parsed > maxValue) { + return maxValue; + } + return parsed; + } catch (NumberFormatException e) { + return defaultValue; + } + } + + private String errorBody(String message) { + try { + return objectMapper.writeValueAsString(java.util.Collections.singletonMap("error", message)); + } catch (Exception e) { + return "{\"error\":\"" + message + "\"}"; + } + } + + private FullHttpResponse jsonResponse(HttpResponseStatus status, String body) { + ByteBuf content = Unpooled.copiedBuffer(body, StandardCharsets.UTF_8); + DefaultFullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, status, content); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8"); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); + setCorsHeaders(response); + return response; + } + + private FullHttpResponse corsResponse(HttpResponseStatus status) { + DefaultFullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, status); + setCorsHeaders(response); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0); + return response; + } + + private void setCorsHeaders(HttpResponse response) { + response.headers().set("Access-Control-Allow-Origin", "*"); + response.headers().set("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS"); + response.headers().set("Access-Control-Allow-Headers", "Content-Type, Authorization"); + response.headers().set("Access-Control-Max-Age", "3600"); + } + + // ========================================================================= + // Request / Response DTOs + // ========================================================================= + + public static class TaskRequest { + + private String targetAgent; + private String message; + private String parentTaskId; + + public String getTargetAgent() { + return targetAgent; + } + + public void setTargetAgent(String targetAgent) { + this.targetAgent = targetAgent; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getParentTaskId() { + return parentTaskId; + } + + public void setParentTaskId(String parentTaskId) { + this.parentTaskId = parentTaskId; + } + } + + public static class HeartbeatRequest { + + private String orgId; + private String unitId; + private String agentId; + + public String getOrgId() { + return orgId; + } + + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + public String getUnitId() { + return unitId; + } + + public void setUnitId(String unitId) { + this.unitId = unitId; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayServer.java new file mode 100644 index 0000000000..8db1f400b6 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayServer.java @@ -0,0 +1,338 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import org.apache.eventmesh.protocol.a2a.A2AProtocolConstants; +import org.apache.eventmesh.protocol.a2a.A2ATopicFactory; +import org.apache.eventmesh.protocol.a2a.AgentIdentity; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; +import org.apache.eventmesh.protocol.a2a.model.AgentSkill; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.UUID; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +import lombok.extern.slf4j.Slf4j; + +/** + * Standalone A2A Gateway Server. + * + *

Starts an embedded Netty HTTP server that exposes the A2A Gateway REST API. + * Pre-registers a mock "weather-agent" that auto-responds to task requests. + * + *

Usage: + *

+ *   java org.apache.eventmesh.runtime.a2a.A2AGatewayServer [port]
+ * 
+ * + *

Then run the client demo (A2AGatewayDemo) to submit tasks via HTTP. + */ +@Slf4j +public class A2AGatewayServer { + + private static final String NAMESPACE = "global"; + private static final String GATEWAY_ID = "demo-gateway"; + private static final int DEFAULT_PORT = 10105; + + private final int port; + private EventLoopGroup bossGroup; + private EventLoopGroup workerGroup; + private ChannelFuture serverChannel; + + private InMemoryA2AMessageTransport transport; + private TaskRegistry taskRegistry; + private A2APublishSubscribeService a2aService; + private A2AGatewayService gatewayService; + private A2AGatewayHttpHandler gatewayHandler; + private A2ACardHttpHandler cardHandler; + + public A2AGatewayServer(int port) { + this.port = port; + } + + public void start() throws Exception { + // 1. Initialize components + transport = new InMemoryA2AMessageTransport(); + taskRegistry = new TaskRegistry(); + a2aService = new A2APublishSubscribeService(null); + a2aService.init(); + a2aService.start(); + + gatewayService = new A2AGatewayService(NAMESPACE, GATEWAY_ID, transport, taskRegistry, a2aService); + gatewayService.start(); + + gatewayHandler = new A2AGatewayHttpHandler(gatewayService, a2aService); + cardHandler = new A2ACardHttpHandler(a2aService); + + // 2. Pre-register a mock weather agent + registerMockWeatherAgent(); + + // 3. Start Netty HTTP server + bossGroup = new NioEventLoopGroup(1); + workerGroup = new NioEventLoopGroup(); + + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline() + .addLast(new HttpRequestDecoder()) + .addLast(new HttpObjectAggregator(65536)) + .addLast(new HttpResponseEncoder()) + .addLast(new A2AGatewayRequestHandler(gatewayHandler, cardHandler)); + } + }) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, true); + + serverChannel = bootstrap.bind(port).sync(); + log.info("=== A2A Gateway Server started on port {} ===", port); + log.info("Gateway ID: {}, Namespace: {}", GATEWAY_ID, NAMESPACE); + log.info("Endpoints:"); + log.info(" POST /a2a/tasks - submit task (sync/async)"); + log.info(" GET /a2a/tasks - list tasks (?state=COMPLETED&limit=100&offset=0)"); + log.info(" GET /a2a/tasks/{{taskId}} - get task status"); + log.info(" DELETE /a2a/tasks/{{taskId}} - cancel task"); + log.info(" GET /a2a/tasks/{{taskId}}/wait - wait for result (long-poll)"); + log.info(" GET /a2a/tasks/{{taskId}}/stream - SSE stream of task status updates"); + log.info(" GET /a2a/agents - list registered agents"); + log.info(" POST /a2a/heartbeat - agent heartbeat"); + log.info(" GET /a2a/health - health check"); + log.info(" GET /a2a/cards/list - list agent cards"); + log.info(" POST /a2a/cards/card/{{org}}/{{unit}}/{{agent}} - register card"); + } + + /** + * Registers a mock weather agent that auto-responds to task requests. + */ + private void registerMockWeatherAgent() throws Exception { + AgentCard weatherCard = AgentCard.builder() + .name("weather-agent") + .description("A weather agent that can tell you the weather") + .version("1.0.0") + .supportedInterfaces(Arrays.asList( + org.apache.eventmesh.protocol.a2a.model.AgentInterface.builder() + .url("http://localhost:" + port + "/a2a") + .protocolBinding("JSONRPC") + .protocolVersion("0.3") + .build() + )) + .capabilities(org.apache.eventmesh.protocol.a2a.model.AgentCapabilities.builder() + .streaming(false) + .pushNotifications(false) + .build()) + .skills(Arrays.asList( + AgentSkill.builder() + .id("get-weather") + .name("Get Weather") + .description("Get the current weather for a city") + .tags(Arrays.asList("weather", "test")) + .build() + )) + .defaultInputModes(Arrays.asList("text/plain")) + .defaultOutputModes(Arrays.asList("text/plain")) + .build(); + + AgentIdentity identity = AgentIdentity.builder() + .orgId("default").unitId("default").agentId("weather-agent").build(); + A2APublishSubscribeService.RegistrationResult regResult = + a2aService.registerCard(identity, weatherCard); + if (!regResult.isSuccess()) { + log.warn("Failed to register weather-agent card: {}", regResult.getErrorMessage()); + } + + // Subscribe to agent request topic and auto-respond + String requestTopic = A2ATopicFactory.agentRequestTopic(NAMESPACE, "weather-agent"); + transport.subscribe(requestTopic, (topic, event) -> { + String taskId = event.getId(); + String message = event.getData() != null + ? new String(event.getData().toBytes(), StandardCharsets.UTF_8) : ""; + + log.info("[Weather Agent] Received request: taskId={}, message={}", taskId, message); + + // Simulate processing delay + try { + Thread.sleep(300); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + // Publish response + String gwId = extractGatewayId(event); + String responseTopic = A2ATopicFactory.gatewayResponseTopic(NAMESPACE, gwId, taskId); + String result = "The weather in " + message + " is sunny, 25°C"; + CloudEvent responseEvent = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withType(A2AProtocolConstants.CE_TYPE_PREFIX + "task.response") + .withSource(java.net.URI.create("agent/weather-agent")) + .withDataContentType("application/json") + .withData(result.getBytes(StandardCharsets.UTF_8)) + .withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, A2AProtocolConstants.OP_SEND_MESSAGE) + .build(); + + try { + transport.publish(responseTopic, responseEvent); + log.info("[Weather Agent] Response published: taskId={}", taskId); + } catch (Exception e) { + log.error("[Weather Agent] Failed to publish response", e); + } + }); + + log.info("Mock weather-agent registered and listening for requests."); + } + + private String extractGatewayId(CloudEvent event) { + if (event.getSource() == null) { + return "default-gateway"; + } + String source = event.getSource().toString(); + if (source.startsWith("gateway/")) { + return source.substring("gateway/".length()); + } + return "default-gateway"; + } + + /** + * Returns the actual bound port. Useful when port 0 was specified to let the OS pick a port. + */ + public int getBoundPort() { + if (serverChannel != null) { + return ((io.netty.channel.socket.ServerSocketChannel) serverChannel.channel()).localAddress().getPort(); + } + return port; + } + + public void shutdown() throws Exception { + if (serverChannel != null) { + serverChannel.channel().close().sync(); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (gatewayService != null) { + gatewayService.shutdown(); + } + if (a2aService != null) { + a2aService.shutdown(); + } + log.info("A2A Gateway Server shut down."); + } + + public static void main(String[] args) throws Exception { + int port = args.length > 0 ? Integer.parseInt(args[0]) : DEFAULT_PORT; + + A2AGatewayServer server = new A2AGatewayServer(port); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + server.shutdown(); + } catch (Exception e) { + log.error("Error during shutdown", e); + } + })); + + server.start(); + + // Keep running until interrupted + Thread.currentThread().join(); + } + + // ========================================================================= + // Netty Channel Handler + // ========================================================================= + + private static class A2AGatewayRequestHandler extends io.netty.channel.SimpleChannelInboundHandler { + + private final A2AGatewayHttpHandler gatewayHandler; + private final A2ACardHttpHandler cardHandler; + + A2AGatewayRequestHandler(A2AGatewayHttpHandler gatewayHandler, A2ACardHttpHandler cardHandler) { + this.gatewayHandler = gatewayHandler; + this.cardHandler = cardHandler; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { + String uri = request.uri(); + try { + FullHttpResponse response; + if (uri.startsWith("/a2a/cards")) { + response = cardHandler.handle(request, ctx); + } else if (uri.startsWith("/a2a/")) { + response = gatewayHandler.handle(request, ctx); + } else { + response = jsonError(HttpResponseStatus.NOT_FOUND, "Not found: " + uri); + } + + // null means the handler wrote the response directly (e.g. SSE streaming) + if (response != null) { + ctx.writeAndFlush(response); + } + } catch (Exception e) { + log.error("Error handling request: {} - {}", uri, e.getMessage(), e); + FullHttpResponse errorResponse = jsonError(HttpResponseStatus.INTERNAL_SERVER_ERROR, e.getMessage()); + ctx.writeAndFlush(errorResponse); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + log.error("Channel exception: {}", cause.getMessage(), cause); + ctx.close(); + } + + private FullHttpResponse jsonError(HttpResponseStatus status, String message) { + String body = "{\"error\":\"" + message + "\"}"; + DefaultFullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(body, StandardCharsets.UTF_8)); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8"); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + response.headers().set("Access-Control-Allow-Origin", "*"); + response.headers().set("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS"); + response.headers().set("Access-Control-Allow-Headers", "Content-Type, Authorization"); + return response; + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayService.java new file mode 100644 index 0000000000..ed1d8ffddf --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2AGatewayService.java @@ -0,0 +1,421 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import org.apache.eventmesh.protocol.a2a.A2AMessageTransport; +import org.apache.eventmesh.protocol.a2a.A2AProtocolConstants; +import org.apache.eventmesh.protocol.a2a.A2ATopicFactory; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * A2A Gateway Service: orchestrates task submission, response handling, and SSE streaming. + * + *

This is the core component that ties together: + *

    + *
  • {@link A2AMessageTransport} for pub/sub
  • + *
  • {@link TaskRegistry} for task lifecycle
  • + *
  • {@link A2APublishSubscribeService} for agent discovery
  • + *
  • {@link A2ATopicFactory} for topic routing
  • + *
+ */ +@Slf4j +public class A2AGatewayService { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final String namespace; + private final String gatewayId; + private final A2AMessageTransport transport; + private final TaskRegistry taskRegistry; + private final A2APublishSubscribeService a2aService; + + // Pending tasks waiting for response + private final ConcurrentHashMap> pendingTasks = new ConcurrentHashMap<>(); + // SSE subscribers for status updates + private final ConcurrentHashMap> statusSubscribers = new ConcurrentHashMap<>(); + + private volatile boolean started = false; + private String responseSubscriptionId; + private String statusSubscriptionId; + + // Task timeout: tasks that don't receive a response within this duration are auto-failed + private static final long DEFAULT_TASK_TIMEOUT_MS = 120_000L; // 2 minutes + private final long taskTimeoutMs; + private ScheduledExecutorService taskTimeoutScheduler; + + public A2AGatewayService(String namespace, String gatewayId, + A2AMessageTransport transport, + TaskRegistry taskRegistry, + A2APublishSubscribeService a2aService) { + this(namespace, gatewayId, transport, taskRegistry, a2aService, DEFAULT_TASK_TIMEOUT_MS); + } + + public A2AGatewayService(String namespace, String gatewayId, + A2AMessageTransport transport, + TaskRegistry taskRegistry, + A2APublishSubscribeService a2aService, + long taskTimeoutMs) { + this.namespace = namespace; + this.gatewayId = gatewayId; + this.transport = transport; + this.taskRegistry = taskRegistry; + this.a2aService = a2aService; + this.taskTimeoutMs = taskTimeoutMs; + } + + public String getGatewayId() { + return gatewayId; + } + + public String getNamespace() { + return namespace; + } + + public A2APublishSubscribeService getA2aService() { + return a2aService; + } + + public TaskRegistry getTaskRegistry() { + return taskRegistry; + } + + /** + * Starts the gateway service: subscribes to gateway response/status topics. + */ + public synchronized void start() throws Exception { + if (started) { + return; + } + // Start task registry TTL cleanup + taskRegistry.start(); + + // Start task timeout scheduler + taskTimeoutScheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "a2a-task-timeout"); + t.setDaemon(true); + return t; + }); + + // Subscribe to all responses for this gateway + String responseTopic = A2ATopicFactory.gatewayResponseWildcardTopic(namespace, gatewayId); + responseSubscriptionId = transport.subscribe(responseTopic, this::handleResponse); + + // Subscribe to all status updates for this gateway + String statusTopic = A2ATopicFactory.gatewayStatusWildcardTopic(namespace, gatewayId); + statusSubscriptionId = transport.subscribe(statusTopic, this::handleStatus); + + started = true; + log.info("A2AGatewayService started: gatewayId={}, namespace={}", gatewayId, namespace); + } + + public synchronized void shutdown() throws Exception { + if (!started) { + return; + } + if (responseSubscriptionId != null) { + transport.unsubscribe(responseSubscriptionId); + } + if (statusSubscriptionId != null) { + transport.unsubscribe(statusSubscriptionId); + } + if (taskTimeoutScheduler != null) { + taskTimeoutScheduler.shutdownNow(); + taskTimeoutScheduler = null; + } + pendingTasks.clear(); + statusSubscribers.clear(); + taskRegistry.shutdown(); + started = false; + log.info("A2AGatewayService shutdown."); + } + + // ========================================================================= + // Task Submission + // ========================================================================= + + /** + * Submits an A2A task to a target agent. + * + * @param targetAgent target agent name + * @param message the message content (JSON string) + * @param parentTaskId parent task ID (null for root tasks from external clients) + * @return CompletableFuture that will be completed with the task result + */ + public CompletableFuture submitTask(String targetAgent, String message, String parentTaskId) { + String taskId = generateTaskId(); + return submitTask(taskId, targetAgent, message, parentTaskId); + } + + /** + * Submits an A2A task with a specific task ID. + */ + public CompletableFuture submitTask(String taskId, String targetAgent, + String message, String parentTaskId) { + if (!started) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new IllegalStateException("Gateway not started")); + return future; + } + + // Validate that the target agent is registered + if (!a2aService.isAgentRegistered(targetAgent)) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new IllegalArgumentException( + "Target agent not registered: " + targetAgent)); + return future; + } + + // Create task entry + TaskRegistry.TaskEntry taskEntry = taskRegistry.createTask(taskId, parentTaskId, targetAgent, gatewayId); + + // Build A2A CloudEvent + CloudEvent event = buildTaskRequestEvent(taskId, targetAgent, message, parentTaskId); + + // Register pending future BEFORE publishing to avoid race condition: + // InMemoryTransport delivers synchronously, so if we publish first, + // handleResponse() could run before put() and the future would never complete. + CompletableFuture future = new CompletableFuture<>(); + pendingTasks.put(taskId, future); + + // Schedule timeout: if no response within taskTimeoutMs, auto-fail the task + if (taskTimeoutScheduler != null) { + taskTimeoutScheduler.schedule(() -> { + CompletableFuture pending = pendingTasks.get(taskId); + if (pending != null && !pending.isDone()) { + taskRegistry.markFailed(taskId, "Task timed out after " + taskTimeoutMs + "ms with no response"); + pendingTasks.remove(taskId); + pending.completeExceptionally(new java.util.concurrent.TimeoutException( + "Task " + taskId + " timed out after " + taskTimeoutMs + "ms")); + notifyStatusSubscribers(taskId, "failed", "Task timed out"); + log.warn("Task timed out: taskId={}, targetAgent={}", taskId, targetAgent); + } + }, taskTimeoutMs, TimeUnit.MILLISECONDS); + } + + // Publish to agent request topic + String requestTopic = A2ATopicFactory.agentRequestTopic(namespace, targetAgent); + try { + transport.publish(requestTopic, event); + log.info("Task submitted: taskId={}, targetAgent={}, topic={}", taskId, targetAgent, requestTopic); + } catch (Exception e) { + log.error("Failed to publish task: taskId={}", taskId, e); + taskRegistry.markFailed(taskId, "Publish failed: " + e.getMessage()); + pendingTasks.remove(taskId); + future.completeExceptionally(e); + } + + return future; + } + + /** + * Cancels a task. + */ + public boolean cancelTask(String taskId) { + boolean cancelled = taskRegistry.markCancelled(taskId); + if (cancelled) { + CompletableFuture future = pendingTasks.remove(taskId); + if (future != null) { + future.complete(new TaskResult(TaskRegistry.TaskState.CANCELLED, null, "Task cancelled")); + } + notifyStatusSubscribers(taskId, "cancelled", "Task cancelled"); + return true; + } + return false; + } + + /** + * Gets task status. + */ + public TaskRegistry.TaskEntry getTaskStatus(String taskId) { + return taskRegistry.getTask(taskId); + } + + // ========================================================================= + // SSE Status Subscription + // ========================================================================= + + /** + * Registers a subscriber for status updates on a specific task. + */ + public void registerStatusSubscriber(String taskId, StatusSubscriber subscriber) { + statusSubscribers.computeIfAbsent(taskId, k -> new CopyOnWriteArrayList<>()).add(subscriber); + } + + /** + * Removes a status subscriber. + */ + public void unregisterStatusSubscriber(String taskId, StatusSubscriber subscriber) { + List subs = statusSubscribers.get(taskId); + if (subs != null) { + subs.remove(subscriber); + if (subs.isEmpty()) { + statusSubscribers.remove(taskId); + } + } + } + + // ========================================================================= + // Response / Status Handling + // ========================================================================= + + private void handleResponse(String topic, CloudEvent event) { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse(topic); + if (parsed == null || !parsed.isResponse() || parsed.getTaskId() == null) { + return; + } + String taskId = parsed.getTaskId(); + log.info("Received response for task: {}", taskId); + + TaskRegistry.TaskEntry entry = taskRegistry.getTask(taskId); + if (entry == null) { + log.warn("Response received for unknown task: {}", taskId); + return; + } + + String resultData = extractEventData(event); + taskRegistry.markCompleted(taskId, resultData); + + CompletableFuture future = pendingTasks.remove(taskId); + if (future != null) { + future.complete(new TaskResult(TaskRegistry.TaskState.COMPLETED, resultData, null)); + } + + // Notify SSE subscribers + notifyStatusSubscribers(taskId, "completed", resultData); + } + + private void handleStatus(String topic, CloudEvent event) { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse(topic); + if (parsed == null || !parsed.isStatus() || parsed.getTaskId() == null) { + return; + } + String taskId = parsed.getTaskId(); + String statusData = extractEventData(event); + log.debug("Received status for task: {} -> {}", taskId, statusData); + + // Mark as working if currently submitted + TaskRegistry.TaskEntry entry = taskRegistry.getTask(taskId); + if (entry != null && entry.getState() == TaskRegistry.TaskState.SUBMITTED) { + taskRegistry.markWorking(taskId); + } + + // Notify SSE subscribers + notifyStatusSubscribers(taskId, "working", statusData); + } + + private void notifyStatusSubscribers(String taskId, String state, String data) { + List subs = statusSubscribers.get(taskId); + if (subs != null) { + for (StatusSubscriber sub : subs) { + try { + sub.onStatus(taskId, state, data); + } catch (Exception e) { + log.warn("Status subscriber error for task {}: {}", taskId, e.getMessage()); + } + } + } + } + + // ========================================================================= + // CloudEvent Building + // ========================================================================= + + private CloudEvent buildTaskRequestEvent(String taskId, String targetAgent, + String message, String parentTaskId) { + CloudEventBuilder builder = CloudEventBuilder.v1() + .withId(taskId) + .withType(A2AProtocolConstants.CE_TYPE_PREFIX + "task.request") + .withSource(java.net.URI.create("gateway/" + gatewayId)) + .withDataContentType("application/json") + .withData(message.getBytes(StandardCharsets.UTF_8)) + .withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_METHOD, A2AProtocolConstants.OP_SEND_MESSAGE) + .withExtension(A2AProtocolConstants.CE_EXTENSION_TARGET_AGENT, targetAgent) + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL, "A2A") + .withExtension(A2AProtocolConstants.CE_EXTENSION_PROTOCOL_VERSION, A2AProtocolConstants.PROTOCOL_VERSION); + + if (parentTaskId != null) { + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_COLLABORATION_ID, parentTaskId); + } + + return builder.build(); + } + + private String extractEventData(CloudEvent event) { + if (event.getData() == null) { + return null; + } + return new String(event.getData().toBytes(), StandardCharsets.UTF_8); + } + + private String generateTaskId() { + return "task-" + UUID.randomUUID().toString().substring(0, 8); + } + + // ========================================================================= + // Result Types + // ========================================================================= + + public static class TaskResult { + + private final TaskRegistry.TaskState state; + private final String data; + private final String errorMessage; + + public TaskResult(TaskRegistry.TaskState state, String data, String errorMessage) { + this.state = state; + this.data = data; + this.errorMessage = errorMessage; + } + + public TaskRegistry.TaskState getState() { + return state; + } + + public String getData() { + return data; + } + + public String getErrorMessage() { + return errorMessage; + } + } + + /** + * Callback interface for task status change notifications. + */ + @FunctionalInterface + public interface StatusSubscriber { + void onStatus(String taskId, String state, String data); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2APublishSubscribeService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2APublishSubscribeService.java new file mode 100644 index 0000000000..5171b0e2a9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/A2APublishSubscribeService.java @@ -0,0 +1,451 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import org.apache.eventmesh.protocol.a2a.A2AProtocolConstants; +import org.apache.eventmesh.protocol.a2a.AgentCardValidator; +import org.apache.eventmesh.protocol.a2a.AgentIdentity; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; +import org.apache.eventmesh.runtime.boot.EventMeshServer; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * A2APublishSubscribeService: Manages A2A Agent Card Registry and processes A2A events. + * + *

Features: + * - Agent Card CRUD (register, delete, get, list) + * - Agent status tracking (online/offline) + * - Event processing with status metadata augmentation + * - Hierarchical identity (org_id/unit_id/agent_id) with wildcard queries + */ +@Slf4j +public class A2APublishSubscribeService { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final EventMeshServer eventMeshServer; + private volatile boolean isStarted = false; + + private final ConcurrentHashMap cardRegistry = new ConcurrentHashMap<>(); + private final ConcurrentHashMap agentStatusMap = new ConcurrentHashMap<>(); + + private AgentCardValidator cardValidator; + + // TTL heartbeat configuration + private static final long DEFAULT_CARD_TTL_MS = 60_000L; // 60 seconds + private static final long DEFAULT_CLEANUP_INTERVAL_MS = 15_000L; // 15 seconds + private final long cardTtlMs; + private final long cleanupIntervalMs; + private ScheduledExecutorService cleanupExecutor; + + public A2APublishSubscribeService(EventMeshServer eventMeshServer) { + this(eventMeshServer, DEFAULT_CARD_TTL_MS, DEFAULT_CLEANUP_INTERVAL_MS); + } + + public A2APublishSubscribeService(EventMeshServer eventMeshServer, long cardTtlMs, long cleanupIntervalMs) { + this.eventMeshServer = eventMeshServer; + this.cardTtlMs = cardTtlMs; + this.cleanupIntervalMs = cleanupIntervalMs; + } + + public void init() throws Exception { + this.cardValidator = new AgentCardValidator(true); + log.info("A2APublishSubscribeService initialized with Agent Card Registry (TTL={}ms, cleanup={}ms).", + cardTtlMs, cleanupIntervalMs); + } + + public void start() throws Exception { + isStarted = true; + startCleanupScheduler(); + log.info("A2APublishSubscribeService started."); + } + + public void shutdown() throws Exception { + isStarted = false; + if (cleanupExecutor != null) { + cleanupExecutor.shutdownNow(); + cleanupExecutor = null; + } + cardRegistry.clear(); + agentStatusMap.clear(); + log.info("A2APublishSubscribeService shutdown."); + } + + // ------------------------------------------------------------------------- + // TTL Heartbeat Cleanup + // ------------------------------------------------------------------------- + + private void startCleanupScheduler() { + cleanupExecutor = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "a2a-card-ttl-cleanup"); + t.setDaemon(true); + return t; + }); + cleanupExecutor.scheduleAtFixedRate(this::cleanupExpiredCards, + cleanupIntervalMs, cleanupIntervalMs, TimeUnit.MILLISECONDS); + } + + /** + * Removes AgentCards that have not been refreshed within the TTL window. + */ + void cleanupExpiredCards() { + if (!isStarted) { + return; + } + long now = System.currentTimeMillis(); + int removed = 0; + Iterator> it = cardRegistry.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + RegisteredCard rc = entry.getValue(); + if (now - rc.lastHeartbeat > cardTtlMs) { + it.remove(); + agentStatusMap.remove(entry.getKey().clientId()); + removed++; + log.info("Agent card expired and removed: {} (lastHeartbeat={}ms ago)", + entry.getKey().clientId(), now - rc.lastHeartbeat); + } + } + if (removed > 0) { + log.info("TTL cleanup removed {} expired agent card(s).", removed); + } + } + + /** + * Refreshes the heartbeat timestamp for an agent card (agent calls this periodically). + */ + public boolean heartbeat(AgentIdentity identity) { + if (!isStarted) { + throw new IllegalStateException("A2APublishSubscribeService is not started"); + } + RegisteredCard rc = cardRegistry.get(identity); + if (rc == null) { + return false; + } + rc.lastHeartbeat = System.currentTimeMillis(); + agentStatusMap.put(identity.clientId(), AgentStatus.ONLINE); + return true; + } + + // ========================================================================= + // Agent Card Registry Operations + // ========================================================================= + + /** + * Registers an Agent Card. Validates the card and identity before storing. + * + * @param identity the agent identity (org_id/unit_id/agent_id) + * @param card the agent card + * @return RegistrationResult with success/failure + */ + public RegistrationResult registerCard(AgentIdentity identity, AgentCard card) { + if (!isStarted) { + throw new IllegalStateException("A2APublishSubscribeService is not started"); + } + + // Validate identity + if (!identity.isValid()) { + String msg = String.format("Invalid agent identity: orgId=%s, unitId=%s, agentId=%s", + identity.getOrgId(), identity.getUnitId(), identity.getAgentId()); + log.warn(msg); + return RegistrationResult.failure(msg); + } + + // Validate card + try { + String cardJson = objectMapper.writeValueAsString(card); + AgentCardValidator.ValidationResult result = cardValidator.validate(cardJson); + if (!result.isValid()) { + log.warn("Agent card schema validation failed for {}: {}", identity.clientId(), result.getErrorMessage()); + return RegistrationResult.failure(result.getErrorMessage()); + } + } catch (Exception e) { + log.warn("Failed to serialize/validate agent card for {}: {}", identity.clientId(), e.getMessage()); + return RegistrationResult.failure("Card validation error: " + e.getMessage()); + } + + RegisteredCard existing = cardRegistry.put(identity, new RegisteredCard(card, System.currentTimeMillis())); + if (existing != null) { + log.info("Updated agent card for {}", identity.clientId()); + } else { + log.info("Registered new agent card for {}", identity.clientId()); + } + + // Set agent online + agentStatusMap.put(identity.clientId(), AgentStatus.ONLINE); + + return RegistrationResult.success(); + } + + /** + * Deletes an Agent Card from the registry. + */ + public boolean deleteCard(AgentIdentity identity) { + if (!isStarted) { + throw new IllegalStateException("A2APublishSubscribeService is not started"); + } + RegisteredCard removed = cardRegistry.remove(identity); + if (removed != null) { + agentStatusMap.remove(identity.clientId()); + log.info("Deleted agent card for {}", identity.clientId()); + return true; + } + return false; + } + + /** + * Gets a specific Agent Card. + */ + public CardEntry getCard(AgentIdentity identity) { + if (!isStarted) { + throw new IllegalStateException("A2APublishSubscribeService is not started"); + } + RegisteredCard rc = cardRegistry.get(identity); + if (rc == null) { + return null; + } + return new CardEntry(identity, rc.card, lookupAgentStatus(identity)); + } + + /** + * Lists Agent Cards matching the given filters. Use null or "+" for wildcard matching. + */ + public List listCards(String orgId, String unitId, String agentId) { + if (!isStarted) { + throw new IllegalStateException("A2APublishSubscribeService is not started"); + } + List results = new ArrayList<>(); + for (Map.Entry entry : cardRegistry.entrySet()) { + AgentIdentity id = entry.getKey(); + if (id.matchesFilter(orgId, unitId, agentId)) { + results.add(new CardEntry(id, entry.getValue().card, lookupAgentStatus(id))); + } + } + return results; + } + + /** + * Lists all registered Agent Cards. + */ + public List listAllCards() { + return listCards(null, null, null); + } + + /** + * Checks whether an agent with the given name is registered. + * + * @param agentName the agent name (or agentId segment) to look up + * @return true if a registered card's name matches + */ + public boolean isAgentRegistered(String agentName) { + if (!isStarted || agentName == null) { + return false; + } + for (RegisteredCard rc : cardRegistry.values()) { + if (agentName.equals(rc.card.getName())) { + return true; + } + } + return false; + } + + // ========================================================================= + // Agent Status + // ========================================================================= + + /** + * Looks up the status of an agent (online/offline). + */ + public String lookupAgentStatus(AgentIdentity identity) { + AgentStatus status = agentStatusMap.get(identity.clientId()); + return status != null ? status.value : A2AProtocolConstants.STATUS_OFFLINE; + } + + /** + * Sets the status of an agent. + */ + public void setAgentStatus(AgentIdentity identity, String status) { + if (A2AProtocolConstants.STATUS_ONLINE.equals(status)) { + agentStatusMap.put(identity.clientId(), AgentStatus.ONLINE); + } else { + agentStatusMap.put(identity.clientId(), AgentStatus.OFFLINE); + } + } + + // ========================================================================= + // Event Processing + // ========================================================================= + + /** + * Processes an A2A CloudEvent. Augments events with agent status metadata. + * + * @param event The CloudEvent to process. + * @return The processed (potentially modified) CloudEvent. + */ + public CloudEvent process(CloudEvent event) { + if (!isStarted) { + throw new IllegalStateException("A2APublishSubscribeService is not started"); + } + + log.debug("Processing A2A event: {}", event.getId()); + + // Check if this is an A2A discovery topic event + String subject = event.getSubject(); + if (subject != null && subject.startsWith(A2AProtocolConstants.TOPIC_NAMESPACE + "/")) { + AgentIdentity identity = AgentIdentity.fromDiscoveryTopic(subject); + if (identity != null) { + return augmentWithStatusMetadata(event, identity); + } + } + + return event; + } + + /** + * Augments a CloudEvent with agent status metadata (a2astatus, a2astatussource extensions). + * Matches EMQX's on_message_delivered hook behavior. + */ + private CloudEvent augmentWithStatusMetadata(CloudEvent event, AgentIdentity identity) { + String status = lookupAgentStatus(identity); + CloudEventBuilder builder = CloudEventBuilder.from(event); + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_STATUS, status); + builder.withExtension(A2AProtocolConstants.CE_EXTENSION_A2A_STATUS_SOURCE, "eventmesh"); + return builder.build(); + } + + // ========================================================================= + // Inner Types + // ========================================================================= + + private enum AgentStatus { + ONLINE(A2AProtocolConstants.STATUS_ONLINE), + OFFLINE(A2AProtocolConstants.STATUS_OFFLINE); + + final String value; + + AgentStatus(String value) { + this.value = value; + } + } + + private static class RegisteredCard { + + final AgentCard card; + final long registeredAt; + volatile long lastHeartbeat; + + RegisteredCard(AgentCard card, long registeredAt) { + this.card = card; + this.registeredAt = registeredAt; + this.lastHeartbeat = registeredAt; + } + } + + /** + * Represents a registered agent card entry with identity, card data, and status. + */ + public static class CardEntry { + + private final AgentIdentity identity; + private final AgentCard card; + private final String status; + + public CardEntry(AgentIdentity identity, AgentCard card, String status) { + this.identity = identity; + this.card = card; + this.status = status; + } + + public AgentIdentity getIdentity() { + return identity; + } + + public AgentCard getCard() { + return card; + } + + public String getStatus() { + return status; + } + + public String getNamespace() { + return identity.getNamespace(); + } + + public String getId() { + return identity.clientId(); + } + + public String getName() { + return card.getName(); + } + + public String getVersion() { + return card.getVersion(); + } + + public String getDescription() { + return card.getDescription(); + } + } + + /** + * Result of a card registration attempt. + */ + public static class RegistrationResult { + + private final boolean success; + private final String errorMessage; + + private RegistrationResult(boolean success, String errorMessage) { + this.success = success; + this.errorMessage = errorMessage; + } + + public static RegistrationResult success() { + return new RegistrationResult(true, null); + } + + public static RegistrationResult failure(String errorMessage) { + return new RegistrationResult(false, errorMessage); + } + + public boolean isSuccess() { + return success; + } + + public String getErrorMessage() { + return errorMessage; + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/InMemoryA2AMessageTransport.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/InMemoryA2AMessageTransport.java new file mode 100644 index 0000000000..d7f2f2ed4d --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/InMemoryA2AMessageTransport.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import org.apache.eventmesh.protocol.a2a.A2AMessageTransport; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; + +/** + * Simple in-memory implementation of {@link A2AMessageTransport} for testing and PoC. + * Messages are delivered directly to subscribers in the same JVM. + */ +public class InMemoryA2AMessageTransport implements A2AMessageTransport { + + private static final Logger log = LoggerFactory.getLogger(InMemoryA2AMessageTransport.class); + + private final ConcurrentHashMap subscriptions = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> topicToSubscriptions = new ConcurrentHashMap<>(); + + @Override + public void publish(String topic, CloudEvent event) throws Exception { + log.debug("InMemory publish to topic: {}", topic); + int delivered = 0; + for (ConcurrentHashMap.Entry> entry : topicToSubscriptions.entrySet()) { + String pattern = entry.getKey(); + if (matchesWildcard(pattern, topic)) { + for (Subscription sub : entry.getValue()) { + sub.callback.onMessage(topic, event); + delivered++; + } + } + } + if (delivered == 0) { + log.debug("No subscribers matched topic: {}", topic); + } + } + + @Override + public String subscribe(String topicPattern, MessageCallback callback) throws Exception { + String subId = UUID.randomUUID().toString(); + Subscription sub = new Subscription(subId, topicPattern, callback); + subscriptions.put(subId, sub); + topicToSubscriptions.computeIfAbsent(topicPattern, k -> new CopyOnWriteArrayList<>()).add(sub); + log.info("InMemory subscribe: pattern={}, subId={}", topicPattern, subId); + return subId; + } + + @Override + public void unsubscribe(String subscriptionId) throws Exception { + Subscription sub = subscriptions.remove(subscriptionId); + if (sub != null) { + List subs = topicToSubscriptions.get(sub.topicPattern); + if (subs != null) { + subs.remove(sub); + if (subs.isEmpty()) { + topicToSubscriptions.remove(sub.topicPattern); + } + } + log.info("InMemory unsubscribe: subId={}", subscriptionId); + } + } + + /** + * Simple wildcard matching supporting "+" (single-level). + */ + private boolean matchesWildcard(String pattern, String topic) { + if (pattern.equals(topic)) { + return true; + } + String[] patternParts = pattern.split("/"); + String[] topicParts = topic.split("/"); + if (patternParts.length != topicParts.length) { + return false; + } + for (int i = 0; i < patternParts.length; i++) { + if (!"+".equals(patternParts[i]) && !patternParts[i].equals(topicParts[i])) { + return false; + } + } + return true; + } + + private static class Subscription { + + final String id; + final String topicPattern; + final MessageCallback callback; + + Subscription(String id, String topicPattern, MessageCallback callback) { + this.id = id; + this.topicPattern = topicPattern; + this.callback = callback; + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/TaskRegistry.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/TaskRegistry.java new file mode 100644 index 0000000000..549296447a --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/a2a/TaskRegistry.java @@ -0,0 +1,348 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +/** + * In-memory registry for A2A task lifecycle management. + * + *

Maintains task state transitions and parent-child task relationships. + * + *

State machine: + *

+ *   SUBMITTED -> WORKING -> COMPLETED
+ *                       \-> FAILED
+ *                       \-> CANCELLED
+ * 
+ */ +@Slf4j +public class TaskRegistry { + + public enum TaskState { + SUBMITTED, + WORKING, + COMPLETED, + FAILED, + CANCELLED + } + + public static class TaskEntry { + + private final String taskId; + private final String parentTaskId; + private final String targetAgent; + private final String gatewayId; + private final long createdAt; + private volatile long updatedAt; + private volatile TaskState state; + private volatile String result; + private volatile String errorMessage; + + public TaskEntry(String taskId, String parentTaskId, String targetAgent, String gatewayId) { + this.taskId = taskId; + this.parentTaskId = parentTaskId; + this.targetAgent = targetAgent; + this.gatewayId = gatewayId; + this.createdAt = System.currentTimeMillis(); + this.updatedAt = this.createdAt; + this.state = TaskState.SUBMITTED; + } + + public String getTaskId() { + return taskId; + } + + public String getParentTaskId() { + return parentTaskId; + } + + public String getTargetAgent() { + return targetAgent; + } + + public String getGatewayId() { + return gatewayId; + } + + public long getCreatedAt() { + return createdAt; + } + + public long getUpdatedAt() { + return updatedAt; + } + + public TaskState getState() { + return state; + } + + public String getResult() { + return result; + } + + public String getErrorMessage() { + return errorMessage; + } + } + + private final ConcurrentHashMap tasks = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> parentToChildren = new ConcurrentHashMap<>(); + + // TTL cleanup configuration + private static final long DEFAULT_TASK_TTL_MS = 300_000L; // 5 minutes + private static final long DEFAULT_TASK_CLEANUP_INTERVAL_MS = 60_000L; // 60 seconds + private final long taskTtlMs; + private final long cleanupIntervalMs; + private ScheduledExecutorService cleanupExecutor; + private volatile boolean started = false; + + public TaskRegistry() { + this(DEFAULT_TASK_TTL_MS, DEFAULT_TASK_CLEANUP_INTERVAL_MS); + } + + public TaskRegistry(long taskTtlMs, long cleanupIntervalMs) { + this.taskTtlMs = taskTtlMs; + this.cleanupIntervalMs = cleanupIntervalMs; + } + + /** + * Starts the TTL cleanup scheduler. Terminal-state tasks older than TTL are automatically removed. + */ + public void start() { + if (started) { + return; + } + started = true; + cleanupExecutor = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "a2a-task-ttl-cleanup"); + t.setDaemon(true); + return t; + }); + cleanupExecutor.scheduleAtFixedRate(this::cleanupExpiredTasks, + cleanupIntervalMs, cleanupIntervalMs, TimeUnit.MILLISECONDS); + log.info("TaskRegistry started (TTL={}ms, cleanup={}ms)", taskTtlMs, cleanupIntervalMs); + } + + /** + * Shuts down the TTL cleanup scheduler. + */ + public void shutdown() { + if (!started) { + return; + } + started = false; + if (cleanupExecutor != null) { + cleanupExecutor.shutdownNow(); + cleanupExecutor = null; + } + log.info("TaskRegistry shut down."); + } + + /** + * Removes terminal-state tasks whose updatedAt timestamp is older than TTL. + */ + void cleanupExpiredTasks() { + if (!started) { + return; + } + long now = System.currentTimeMillis(); + int removed = 0; + Iterator> it = tasks.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + TaskEntry te = entry.getValue(); + if (isTerminalState(te.getState()) && (now - te.getUpdatedAt()) > taskTtlMs) { + it.remove(); + if (te.getParentTaskId() != null) { + List siblings = parentToChildren.get(te.getParentTaskId()); + if (siblings != null) { + siblings.remove(te.getTaskId()); + } + } + removed++; + } + } + if (removed > 0) { + log.info("TTL cleanup removed {} expired task(s).", removed); + } + } + + private boolean isTerminalState(TaskState state) { + return state == TaskState.COMPLETED || state == TaskState.FAILED || state == TaskState.CANCELLED; + } + + /** + * Creates a new task entry. + * + * @param taskId unique task ID + * @param parentTaskId parent task ID (null for root tasks) + * @param targetAgent target agent name + * @param gatewayId gateway ID (null for agent-to-agent tasks) + * @return the created task entry + */ + public TaskEntry createTask(String taskId, String parentTaskId, String targetAgent, String gatewayId) { + TaskEntry entry = new TaskEntry(taskId, parentTaskId, targetAgent, gatewayId); + tasks.put(taskId, entry); + if (parentTaskId != null) { + parentToChildren.computeIfAbsent(parentTaskId, k -> new CopyOnWriteArrayList<>()).add(taskId); + } + log.info("Task created: taskId={}, parentTaskId={}, targetAgent={}", taskId, parentTaskId, targetAgent); + return entry; + } + + /** + * Transitions a task to WORKING state. + */ + public boolean markWorking(String taskId) { + TaskEntry entry = tasks.get(taskId); + if (entry == null) { + return false; + } + synchronized (entry) { + if (entry.state != TaskState.SUBMITTED) { + log.warn("Cannot mark task {} as WORKING from state {}", taskId, entry.state); + return false; + } + entry.state = TaskState.WORKING; + entry.updatedAt = System.currentTimeMillis(); + } + log.info("Task working: taskId={}", taskId); + return true; + } + + /** + * Transitions a task to COMPLETED state with result. + */ + public boolean markCompleted(String taskId, String result) { + TaskEntry entry = tasks.get(taskId); + if (entry == null) { + return false; + } + synchronized (entry) { + if (entry.state == TaskState.COMPLETED || entry.state == TaskState.CANCELLED) { + return false; + } + entry.state = TaskState.COMPLETED; + entry.result = result; + entry.updatedAt = System.currentTimeMillis(); + } + log.info("Task completed: taskId={}", taskId); + return true; + } + + /** + * Transitions a task to FAILED state with error message. + */ + public boolean markFailed(String taskId, String errorMessage) { + TaskEntry entry = tasks.get(taskId); + if (entry == null) { + return false; + } + synchronized (entry) { + if (entry.state == TaskState.COMPLETED || entry.state == TaskState.CANCELLED) { + return false; + } + entry.state = TaskState.FAILED; + entry.errorMessage = errorMessage; + entry.updatedAt = System.currentTimeMillis(); + } + log.info("Task failed: taskId={}, error={}", taskId, errorMessage); + return true; + } + + /** + * Transitions a task to CANCELLED state. + */ + public boolean markCancelled(String taskId) { + TaskEntry entry = tasks.get(taskId); + if (entry == null) { + return false; + } + synchronized (entry) { + if (entry.state == TaskState.COMPLETED || entry.state == TaskState.CANCELLED) { + return false; + } + entry.state = TaskState.CANCELLED; + entry.updatedAt = System.currentTimeMillis(); + } + log.info("Task cancelled: taskId={}", taskId); + return true; + } + + /** + * Gets a task entry by ID. + */ + public TaskEntry getTask(String taskId) { + return tasks.get(taskId); + } + + /** + * Lists all tasks. + */ + public List listTasks() { + return new ArrayList<>(tasks.values()); + } + + /** + * Lists child tasks of a parent task. + */ + public List getChildTasks(String parentTaskId) { + List children = parentToChildren.get(parentTaskId); + return children != null ? new ArrayList<>(children) : new ArrayList<>(); + } + + /** + * Removes a task from the registry. + */ + public TaskEntry removeTask(String taskId) { + TaskEntry removed = tasks.remove(taskId); + if (removed != null && removed.parentTaskId != null) { + List siblings = parentToChildren.get(removed.parentTaskId); + if (siblings != null) { + siblings.remove(taskId); + } + } + return removed; + } + + /** + * Returns the current size of the registry. + */ + public int size() { + return tasks.size(); + } + + /** + * Clears all tasks. + */ + public void clear() { + tasks.clear(); + parentToChildren.clear(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/acl/Acl.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/acl/Acl.java index c37f3ed94b..94061e5027 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/acl/Acl.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/acl/Acl.java @@ -17,128 +17,223 @@ package org.apache.eventmesh.runtime.acl; -import org.apache.eventmesh.api.acl.AclPropertyKeys; +import org.apache.eventmesh.api.acl.AclProperties; import org.apache.eventmesh.api.acl.AclService; import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; import org.apache.eventmesh.common.protocol.tcp.UserAgent; import org.apache.eventmesh.spi.EventMeshExtensionFactory; import org.apache.commons.lang3.StringUtils; -import java.util.Properties; -import java.util.ServiceLoader; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class Acl { - private static final Logger logger = LoggerFactory.getLogger(Acl.class); - private static AclService aclService; - public void init(String aclPluginType) throws AclException { - aclService = EventMeshExtensionFactory.getExtension(AclService.class, aclPluginType); - if (aclService == null) { - logger.error("can't load the aclService plugin, please check."); + private static final Map ACL_CACHE = new HashMap<>(16); + + private AclService aclService; + + private final AtomicBoolean inited = new AtomicBoolean(false); + + private final AtomicBoolean started = new AtomicBoolean(false); + + private final AtomicBoolean shutdown = new AtomicBoolean(false); + + private Acl() { + + } + + public static Acl getInstance(String aclPluginType) { + return ACL_CACHE.computeIfAbsent(aclPluginType, Acl::aclBuilder); + } + + private static Acl aclBuilder(String aclPluginType) { + AclService aclServiceExt = EventMeshExtensionFactory.getExtension(AclService.class, aclPluginType); + if (aclServiceExt == null) { + log.error("can't load the aclService plugin, please check."); throw new RuntimeException("doesn't load the aclService plugin, please check."); } + Acl acl = new Acl(); + + acl.aclService = aclServiceExt; + + return acl; + } + + public void init() throws AclException { + if (!inited.compareAndSet(false, true)) { + return; + } aclService.init(); } public void start() throws AclException { + if (!started.compareAndSet(false, true)) { + return; + } aclService.start(); } public void shutdown() throws AclException { + inited.compareAndSet(true, false); + started.compareAndSet(true, false); + if (!shutdown.compareAndSet(false, true)) { + return; + } aclService.shutdown(); } - public static void doAclCheckInTcpConnect(String remoteAddr, UserAgent userAgent, int requestCode) throws AclException { + public void doAclCheckInTcpConnect(String remoteAddr, UserAgent userAgent, int requestCode) throws AclException { aclService.doAclCheckInConnect(buildTcpAclProperties(remoteAddr, userAgent, null, requestCode)); } - public static void doAclCheckInTcpHeartbeat(String remoteAddr, UserAgent userAgent, int requestCode) throws AclException { - aclService.doAclCheckInHeartbeat(buildTcpAclProperties(remoteAddr, userAgent, null, requestCode)); + public void doAclCheckInTcpConnect(String remoteAddr, String token, String subsystem, Object obj) throws AclException { + aclService.doAclCheckInConnect(buildTcpAclProperties(remoteAddr, token, subsystem, obj)); } - public static void doAclCheckInTcpSend(String remoteAddr, UserAgent userAgent, String topic, int requestCode) throws AclException { - aclService.doAclCheckInSend(buildTcpAclProperties(remoteAddr, userAgent, topic, requestCode)); - } - - public static void doAclCheckInTcpReceive(String remoteAddr, UserAgent userAgent, String topic, int requestCode) throws AclException { - aclService.doAclCheckInReceive(buildTcpAclProperties(remoteAddr, userAgent, topic, requestCode)); + public void doAclCheckInTcpHeartbeat(String remoteAddr, UserAgent userAgent, int requestCode) throws AclException { + aclService.doAclCheckInHeartbeat(buildTcpAclProperties(remoteAddr, userAgent, null, requestCode)); } - private static Properties buildTcpAclProperties(String remoteAddr, UserAgent userAgent, String topic, int requestCode) { - Properties aclProperties = new Properties(); - aclProperties.put(AclPropertyKeys.CLIENT_IP, remoteAddr); - aclProperties.put(AclPropertyKeys.USER, userAgent.getUsername()); - aclProperties.put(AclPropertyKeys.PASSWORD, userAgent.getPassword()); - aclProperties.put(AclPropertyKeys.SUBSYSTEM, userAgent.getSubsystem()); - aclProperties.put(AclPropertyKeys.REQUEST_CODE, requestCode); - if (StringUtils.isNotBlank(topic)) { - aclProperties.put(AclPropertyKeys.TOPIC, topic); - } - return aclProperties; + public void doAclCheckInTcpSend(String remoteAddr, UserAgent userAgent, String topic, int requestCode) throws AclException { + aclService.doAclCheckInSend(buildTcpAclProperties(remoteAddr, userAgent, topic, requestCode)); } - public static void doAclCheckInHttpSend(String remoteAddr, String user, String pass, String subsystem, String topic, - int requestCode) throws AclException { + public void doAclCheckInHttpSend(String remoteAddr, String user, String pass, String subsystem, String topic, int requestCode) + throws AclException { aclService.doAclCheckInSend(buildHttpAclProperties(remoteAddr, user, pass, subsystem, topic, requestCode)); } - public static void doAclCheckInHttpSend(String remoteAddr, String user, String pass, String subsystem, String topic, - String requestURI) throws AclException { + public void doAclCheckInHttpSend(String remoteAddr, String user, String pass, String subsystem, String topic, + String requestURI) throws AclException { aclService.doAclCheckInSend(buildHttpAclProperties(remoteAddr, user, pass, subsystem, topic, requestURI)); } - public static void doAclCheckInHttpReceive(String remoteAddr, String user, String pass, String subsystem, String topic, - int requestCode) throws AclException { + public void doAclCheckInHttpSend(String remoteAddr, String token, String subsystem, String topic, String requestURI, Object obj) + throws AclException { + aclService.doAclCheckInSend(buildHttpAclProperties(remoteAddr, token, subsystem, topic, requestURI, obj)); + } + + public void doAclCheckInHttpReceive(String remoteAddr, String user, String pass, String subsystem, String topic, + int requestCode) throws AclException { aclService.doAclCheckInReceive(buildHttpAclProperties(remoteAddr, user, pass, subsystem, topic, requestCode)); } - public static void doAclCheckInHttpReceive(String remoteAddr, String user, String pass, String subsystem, String topic, - String requestURI) throws AclException { + public void doAclCheckInHttpReceive(String remoteAddr, String user, String pass, String subsystem, String topic, + String requestURI) throws AclException { aclService.doAclCheckInReceive(buildHttpAclProperties(remoteAddr, user, pass, subsystem, topic, requestURI)); } - public static void doAclCheckInHttpHeartbeat(String remoteAddr, String user, String pass, String subsystem, String topic, - int requestCode) throws AclException { + public void doAclCheckInTcpReceive(String remoteAddr, String token, String subsystem, String topic, + String requestURI, Object obj) throws AclException { + aclService.doAclCheckInReceive(buildTcpAclProperties(remoteAddr, token, subsystem, topic, requestURI, obj)); + } + + public void doAclCheckInTcpReceive(String remoteAddr, UserAgent userAgent, String topic, int requestCode) throws Exception { + aclService.doAclCheckInReceive(buildTcpAclProperties(remoteAddr, userAgent, topic, requestCode)); + } + + public void doAclCheckInHttpHeartbeat(String remoteAddr, String user, String pass, String subsystem, String topic, + int requestCode) throws AclException { aclService.doAclCheckInHeartbeat(buildHttpAclProperties(remoteAddr, user, pass, subsystem, topic, requestCode)); } - private static Properties buildHttpAclProperties(String remoteAddr, String user, String pass, String subsystem, - String topic, int requestCode) { - Properties aclProperties = new Properties(); - aclProperties.put(AclPropertyKeys.CLIENT_IP, remoteAddr); - aclProperties.put(AclPropertyKeys.USER, user); - aclProperties.put(AclPropertyKeys.PASSWORD, pass); - aclProperties.put(AclPropertyKeys.SUBSYSTEM, subsystem); - aclProperties.put(AclPropertyKeys.REQUEST_CODE, requestCode); + private AclProperties buildHttpAclProperties(String remoteAddr, String user, String pass, String subsystem, String topic, int requestCode) { + AclProperties aclProperties = new AclProperties(); + aclProperties.setClientIp(remoteAddr); + aclProperties.setUser(user); + aclProperties.setPwd(pass); + aclProperties.setSubsystem(subsystem); + aclProperties.setRequestCode(requestCode); if (StringUtils.isNotBlank(topic)) { - aclProperties.put(AclPropertyKeys.TOPIC, topic); + aclProperties.setTopic(topic); } return aclProperties; } - private static Properties buildHttpAclProperties(String remoteAddr, String user, String pass, String subsystem, - String topic, String requestURI) { - Properties aclProperties = new Properties(); - aclProperties.put(AclPropertyKeys.CLIENT_IP, remoteAddr); - aclProperties.put(AclPropertyKeys.USER, user); - aclProperties.put(AclPropertyKeys.PASSWORD, pass); - aclProperties.put(AclPropertyKeys.SUBSYSTEM, subsystem); - aclProperties.put(AclPropertyKeys.REQUEST_URI, requestURI); + private AclProperties buildHttpAclProperties(String remoteAddr, String user, String pass, String subsystem, String topic, String requestURI) { + AclProperties aclProperties = new AclProperties(); + aclProperties.setClientIp(remoteAddr); + aclProperties.setUser(user); + aclProperties.setPwd(pass); + aclProperties.setSubsystem(subsystem); + aclProperties.setRequestURI(requestURI); if (StringUtils.isNotBlank(topic)) { - aclProperties.put(AclPropertyKeys.TOPIC, topic); + aclProperties.setTopic(topic); } return aclProperties; } - private AclService getSpiAclService() { - ServiceLoader serviceLoader = ServiceLoader.load(AclService.class); - if (serviceLoader.iterator().hasNext()) { - return serviceLoader.iterator().next(); + private AclProperties buildHttpAclProperties(String remoteAddr, String token, String subsystem, String topic, String requestURI, Object obj) { + AclProperties aclProperties = new AclProperties(); + aclProperties.setClientIp(remoteAddr); + aclProperties.setSubsystem(subsystem); + aclProperties.setRequestURI(requestURI); + if (StringUtils.isNotBlank(token)) { + aclProperties.setToken(token); + } + if (StringUtils.isNotBlank(topic)) { + aclProperties.setTopic(topic); } - return null; + + if (obj instanceof EventMeshServicePubTopicInfo) { + aclProperties.setExtendedField("group", ((EventMeshServicePubTopicInfo) obj).getService()); + aclProperties.setExtendedField("topics", ((EventMeshServicePubTopicInfo) obj).getTopics()); + } + return aclProperties; } + + private static AclProperties buildTcpAclProperties(String remoteAddr, UserAgent userAgent, String topic, int requestCode) { + AclProperties aclProperties = new AclProperties(); + aclProperties.setClientIp(remoteAddr); + aclProperties.setUser(userAgent.getUsername()); + aclProperties.setPwd(userAgent.getPassword()); + aclProperties.setSubsystem(userAgent.getSubsystem()); + aclProperties.setRequestCode(requestCode); + aclProperties.setVersion(userAgent.getVersion()); + if (StringUtils.isNotBlank(topic)) { + aclProperties.setTopic(topic); + } + + return aclProperties; + } + + private AclProperties buildTcpAclProperties(String remoteAddr, String token, String subsystem, String topic, String requestURI, Object obj) { + AclProperties aclProperties = new AclProperties(); + aclProperties.setClientIp(remoteAddr); + aclProperties.setSubsystem(subsystem); + aclProperties.setRequestURI(requestURI); + if (StringUtils.isNotBlank(token)) { + aclProperties.setTopic(token); + } + if (StringUtils.isNotBlank(topic)) { + aclProperties.setTopic(topic); + } + if (obj instanceof EventMeshAppSubTopicInfo) { + aclProperties.setExtendedField("group", ((EventMeshAppSubTopicInfo) obj).getApp()); + aclProperties.setExtendedField("topics", ((EventMeshAppSubTopicInfo) obj).getTopics()); + } + return aclProperties; + } + + private AclProperties buildTcpAclProperties(String remoteAddr, String token, String subsystem, Object obj) { + AclProperties aclProperties = new AclProperties(); + aclProperties.setClientIp(remoteAddr); + aclProperties.setSubsystem(subsystem); + if (StringUtils.isNotBlank(token)) { + aclProperties.setTopic(token); + } + if (obj instanceof EventMeshAppSubTopicInfo) { + aclProperties.setExtendedField("group", ((EventMeshAppSubTopicInfo) obj).getApp()); + } + return aclProperties; + } + } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/controller/ClientManageController.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/controller/ClientManageController.java deleted file mode 100644 index 5084a9de12..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/controller/ClientManageController.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.controller; - -import org.apache.eventmesh.admin.rocketmq.controller.AdminController; -import org.apache.eventmesh.runtime.admin.handler.DeleteWebHookConfigHandler; -import org.apache.eventmesh.runtime.admin.handler.InsertWebHookConfigHandler; -import org.apache.eventmesh.runtime.admin.handler.QueryRecommendEventMeshHandler; -import org.apache.eventmesh.runtime.admin.handler.QueryWebHookConfigByIdHandler; -import org.apache.eventmesh.runtime.admin.handler.QueryWebHookConfigByManufacturerHandler; -import org.apache.eventmesh.runtime.admin.handler.RedirectClientByIpPortHandler; -import org.apache.eventmesh.runtime.admin.handler.RedirectClientByPathHandler; -import org.apache.eventmesh.runtime.admin.handler.RedirectClientBySubSystemHandler; -import org.apache.eventmesh.runtime.admin.handler.RejectAllClientHandler; -import org.apache.eventmesh.runtime.admin.handler.RejectClientByIpPortHandler; -import org.apache.eventmesh.runtime.admin.handler.RejectClientBySubSystemHandler; -import org.apache.eventmesh.runtime.admin.handler.ShowClientBySystemHandler; -import org.apache.eventmesh.runtime.admin.handler.ShowClientHandler; -import org.apache.eventmesh.runtime.admin.handler.ShowListenClientByTopicHandler; -import org.apache.eventmesh.runtime.admin.handler.UpdateWebHookConfigHandler; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.webhook.admin.AdminWebHookConfigOperationManage; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Objects; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpServer; - -import lombok.Setter; - -@SuppressWarnings("restriction") -public class ClientManageController { - - private static final Logger logger = LoggerFactory.getLogger(ClientManageController.class); - - private EventMeshTCPServer eventMeshTCPServer; - - private AdminController adminController; - - @Setter - private AdminWebHookConfigOperationManage adminWebHookConfigOperationManage; - - public ClientManageController(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - - public void start() throws IOException { - int port = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerAdminPort; - HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); - server.createContext("/clientManage/showClient", new ShowClientHandler(eventMeshTCPServer)); - server.createContext("/clientManage/showClientBySystem", new ShowClientBySystemHandler(eventMeshTCPServer)); - server.createContext("/clientManage/rejectAllClient", new RejectAllClientHandler(eventMeshTCPServer)); - server.createContext("/clientManage/rejectClientByIpPort", new RejectClientByIpPortHandler(eventMeshTCPServer)); - server.createContext("/clientManage/rejectClientBySubSystem", new RejectClientBySubSystemHandler(eventMeshTCPServer)); - server.createContext("/clientManage/redirectClientBySubSystem", new RedirectClientBySubSystemHandler(eventMeshTCPServer)); - server.createContext("/clientManage/redirectClientByPath", new RedirectClientByPathHandler(eventMeshTCPServer)); - server.createContext("/clientManage/redirectClientByIpPort", new RedirectClientByIpPortHandler(eventMeshTCPServer)); - server.createContext("/clientManage/showListenClientByTopic", new ShowListenClientByTopicHandler(eventMeshTCPServer)); - server.createContext("/eventMesh/recommend", new QueryRecommendEventMeshHandler(eventMeshTCPServer)); - - if (Objects.nonNull(adminWebHookConfigOperationManage.getWebHookConfigOperation())) { - WebHookConfigOperation webHookConfigOperation = adminWebHookConfigOperationManage.getWebHookConfigOperation(); - server.createContext("/webhook/insertWebHookConfig", new InsertWebHookConfigHandler(webHookConfigOperation)); - server.createContext("/webhook/updateWebHookConfig", new UpdateWebHookConfigHandler(webHookConfigOperation)); - server.createContext("/webhook/deleteWebHookConfig", new DeleteWebHookConfigHandler(webHookConfigOperation)); - server.createContext("/webhook/queryWebHookConfigById", new QueryWebHookConfigByIdHandler(webHookConfigOperation)); - server.createContext("/webhook/queryWebHookConfigByManufacturer", new QueryWebHookConfigByManufacturerHandler(webHookConfigOperation)); - } - - adminController = new AdminController(); - adminController.run(server); - - server.start(); - logger.info("ClientManageController start success, port:{}", port); - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/AbstractHttpHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/AbstractHttpHandler.java new file mode 100644 index 0000000000..516960e7b6 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/AbstractHttpHandler.java @@ -0,0 +1,169 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler; + +import org.apache.eventmesh.common.enums.HttpMethod; +import org.apache.eventmesh.runtime.admin.response.Result; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.util.HttpResponseUtils; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONWriter; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public abstract class AbstractHttpHandler implements HttpHandler { + + protected void writeText(ChannelHandlerContext ctx, String text) { + HttpHeaders responseHeaders = HttpResponseUtils.buildDefaultHttpHeaders(HttpHeaderValues.TEXT_HTML); + write(ctx, HttpResponseUtils.buildHttpResponse(text, ctx, responseHeaders, HttpResponseStatus.OK)); + } + + /** + * Return given JSON String with given {@link HttpResponseStatus}. + */ + protected void writeJson(ChannelHandlerContext ctx, String json, HttpResponseStatus status) { + HttpHeaders responseHeaders = HttpResponseUtils.buildDefaultHttpHeaders(HttpHeaderValues.APPLICATION_JSON); + write(ctx, HttpResponseUtils.buildHttpResponse(json, ctx, responseHeaders, status)); + } + + /** + * Return given JSON String with status {@link HttpResponseStatus#OK}. + */ + protected void writeJson(ChannelHandlerContext ctx, String json) { + writeJson(ctx, json, HttpResponseStatus.OK); + } + + /** + * Serialize given data into the JSON String of {@link Result} and return with status {@link HttpResponseStatus#OK}. + */ + protected void writeSuccess(ChannelHandlerContext ctx, Object data) { + Result result = Result.success(data); + String json = JSON.toJSONString(result, JSONWriter.Feature.WriteNulls); + writeJson(ctx, json); + } + + /** + * Wrap given message to {@link Result} and return with status {@link HttpResponseStatus#BAD_REQUEST}. + */ + protected void writeBadRequest(ChannelHandlerContext ctx, String message) { + Result result = new Result<>(message); + String json = JSON.toJSONString(result, JSONWriter.Feature.WriteNulls); + writeJson(ctx, json, HttpResponseStatus.BAD_REQUEST); + } + + protected void writeUnauthorized(ChannelHandlerContext ctx, String message) { + Result result = new Result<>(message); + String json = JSON.toJSONString(result, JSONWriter.Feature.WriteNulls); + writeJson(ctx, json, HttpResponseStatus.UNAUTHORIZED); + } + + protected void writeInternalServerError(ChannelHandlerContext ctx, String message) { + Result result = new Result<>(message); + String json = JSON.toJSONString(result, JSONWriter.Feature.WriteNulls); + writeJson(ctx, json, HttpResponseStatus.INTERNAL_SERVER_ERROR); + } + + /** + * Use {@link HttpResponseUtils#buildHttpResponse} to build {@link HttpResponse} param. + */ + protected void write(ChannelHandlerContext ctx, HttpResponse response) { + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + }); + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + try { + switch (HttpMethod.valueOf(httpRequest.method().name())) { + case OPTIONS: + preflight(ctx); + break; + case GET: + get(httpRequest, ctx); + break; + case POST: + post(httpRequest, ctx); + break; + case PUT: + put(httpRequest, ctx); + break; + case DELETE: + delete(httpRequest, ctx); + break; + default: // do nothing + } + } catch (RuntimeException e) { + StackTraceElement element = e.getStackTrace()[0]; + String className = element.getClassName(); + String handlerName = className.substring(className.lastIndexOf(".") + 1); + if (e instanceof IllegalArgumentException) { + log.warn("Admin endpoint {}:{} - {}", handlerName, element.getLineNumber(), e.getMessage()); + writeBadRequest(ctx, e.getMessage()); + } else { + log.error("Admin endpoint {}:{} - {}", handlerName, element.getLineNumber(), e.getMessage(), e); + writeInternalServerError(ctx, e.getMessage()); + } + } + } + + protected void preflight(ChannelHandlerContext ctx) { + HttpHeaders responseHeaders = new DefaultHttpHeaders(); + responseHeaders.add(EventMeshConstants.HANDLER_ORIGIN, "*"); + responseHeaders.add(EventMeshConstants.HANDLER_METHODS, "*"); + responseHeaders.add(EventMeshConstants.HANDLER_HEADERS, "*"); + responseHeaders.add(EventMeshConstants.HANDLER_AGE, EventMeshConstants.MAX_AGE); + write(ctx, HttpResponseUtils.buildHttpResponse("", ctx, responseHeaders, HttpResponseStatus.OK)); + } + + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Override this method in subclass + } + + /** + * Add new resource. + */ + protected void post(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Override this method in subclass + } + + /** + * Update resource, should be idempotent. + */ + protected void put(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Override this method in subclass + } + + protected void delete(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Override this method in subclass + } +} + diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/AdminHandlerManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/AdminHandlerManager.java new file mode 100644 index 0000000000..672479f1dc --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/AdminHandlerManager.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler; + +import org.apache.eventmesh.runtime.admin.handler.v1.ConfigurationHandlerV1; +import org.apache.eventmesh.runtime.admin.handler.v1.EventHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.GrpcClientHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.HTTPClientHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.MetaHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.QueryRecommendEventMeshHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.RedirectClientByIpPortHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.RedirectClientByPathHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.RedirectClientBySubSystemHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.RejectAllClientHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.RejectClientByIpPortHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.RejectClientBySubSystemHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.ShowClientBySystemHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.ShowClientHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.ShowListenClientByTopicHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.TCPClientHandler; +import org.apache.eventmesh.runtime.admin.handler.v1.TopicHandler; +import org.apache.eventmesh.runtime.admin.handler.v2.ConfigurationHandler; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.boot.EventMeshServer; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + + +public class AdminHandlerManager { + + private EventMeshServer eventMeshServer; + + private EventMeshTCPServer eventMeshTCPServer; + + private EventMeshHTTPServer eventMeshHTTPServer; + + private EventMeshGrpcServer eventMeshGrpcServer; + + private MetaStorage eventMeshMetaStorage; + + private final Map httpHandlerMap = new ConcurrentHashMap<>(); + + public AdminHandlerManager(EventMeshServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + this.eventMeshTCPServer = eventMeshServer.getEventMeshTCPServer(); + this.eventMeshGrpcServer = eventMeshServer.getEventMeshGrpcServer(); + this.eventMeshHTTPServer = eventMeshServer.getEventMeshHTTPServer(); + this.eventMeshMetaStorage = eventMeshServer.getMetaStorage(); + } + + public void registerHttpHandler() { + // v1 endpoints + initHandler(new ShowClientHandler(eventMeshTCPServer)); + initHandler(new ShowClientBySystemHandler(eventMeshTCPServer)); + initHandler(new RejectAllClientHandler(eventMeshTCPServer)); + initHandler(new RejectClientByIpPortHandler(eventMeshTCPServer)); + initHandler(new RejectClientBySubSystemHandler(eventMeshTCPServer)); + initHandler(new RedirectClientBySubSystemHandler(eventMeshTCPServer)); + initHandler(new RedirectClientByPathHandler(eventMeshTCPServer)); + initHandler(new RedirectClientByIpPortHandler(eventMeshTCPServer)); + initHandler(new ShowListenClientByTopicHandler(eventMeshTCPServer)); + initHandler(new QueryRecommendEventMeshHandler(eventMeshTCPServer)); + initHandler(new TCPClientHandler(eventMeshTCPServer)); + initHandler(new HTTPClientHandler(eventMeshHTTPServer)); + initHandler(new GrpcClientHandler(eventMeshGrpcServer)); + initHandler(new ConfigurationHandlerV1( + eventMeshTCPServer.getEventMeshTCPConfiguration(), + eventMeshHTTPServer.getEventMeshHttpConfiguration(), + eventMeshGrpcServer.getEventMeshGrpcConfiguration())); + initHandler(new TopicHandler(eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshStoragePluginType())); + initHandler(new EventHandler(eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshStoragePluginType())); + initHandler(new MetaHandler(eventMeshMetaStorage)); + + // v2 endpoints + initHandler(new ConfigurationHandler( + eventMeshServer.getConfiguration(), + eventMeshTCPServer.getEventMeshTCPConfiguration(), + eventMeshHTTPServer.getEventMeshHttpConfiguration(), + eventMeshGrpcServer.getEventMeshGrpcConfiguration())); + } + + private void initHandler(HttpHandler httpHandler) { + EventMeshHttpHandler eventMeshHttpHandler = httpHandler.getClass().getAnnotation(EventMeshHttpHandler.class); + httpHandlerMap.putIfAbsent(eventMeshHttpHandler.path(), httpHandler); + } + + public Optional getHttpHandler(String path) { + return Optional.ofNullable(httpHandlerMap.get(path)); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/DeleteWebHookConfigHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/DeleteWebHookConfigHandler.java deleted file mode 100644 index bad9da5353..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/DeleteWebHookConfigHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.admin.rocketmq.util.JsonUtils; -import org.apache.eventmesh.admin.rocketmq.util.NetUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - -import java.io.IOException; -import java.io.OutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -@SuppressWarnings("restriction") -public class DeleteWebHookConfigHandler implements HttpHandler { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private WebHookConfigOperation operation; - - public DeleteWebHookConfigHandler(WebHookConfigOperation operation) { - this.operation = operation; - } - - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - httpExchange.sendResponseHeaders(200, 0); - - // get requestBody and resolve to WebHookConfig - String requestBody = NetUtils.parsePostBody(httpExchange); - WebHookConfig webHookConfig = JsonUtils.toObject(requestBody, WebHookConfig.class); - - try (OutputStream out = httpExchange.getResponseBody()) { - - Integer code = operation.deleteWebHookConfig(webHookConfig); // operating result - String result = 1 == code ? "deleteWebHookConfig Succeed!" : "deleteWebHookConfig Failed!"; - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("get WebHookConfigOperation implementation Failed.", e); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/HttpHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/HttpHandler.java new file mode 100644 index 0000000000..bfce52b12d --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/HttpHandler.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +/** + * Admin HttpHandler + */ +public interface HttpHandler { + + void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception; +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/InsertWebHookConfigHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/InsertWebHookConfigHandler.java deleted file mode 100644 index 1434b16a8b..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/InsertWebHookConfigHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.admin.rocketmq.util.JsonUtils; -import org.apache.eventmesh.admin.rocketmq.util.NetUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - - -import java.io.IOException; -import java.io.OutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -@SuppressWarnings("restriction") -public class InsertWebHookConfigHandler implements HttpHandler { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private WebHookConfigOperation operation; - - public InsertWebHookConfigHandler(WebHookConfigOperation operation) { - this.operation = operation; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - httpExchange.sendResponseHeaders(200, 0); - - // get requestBody and resolve to WebHookConfig - String requestBody = NetUtils.parsePostBody(httpExchange); - WebHookConfig webHookConfig = JsonUtils.toObject(requestBody, WebHookConfig.class); - - try (OutputStream out = httpExchange.getResponseBody()) { - Integer code = operation.insertWebHookConfig(webHookConfig); // operating result - String result = 1 == code ? "insertWebHookConfig Succeed!" : "insertWebHookConfig Failed!"; - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("get WebHookConfigOperation implementation Failed.", e); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandler.java deleted file mode 100644 index 51ebf9e68c..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandler.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendStrategy; -import org.apache.eventmesh.runtime.util.NetUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -/** - * query recommend eventmesh - */ -public class QueryRecommendEventMeshHandler implements HttpHandler { - - private Logger logger = LoggerFactory.getLogger(QueryRecommendEventMeshHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public QueryRecommendEventMeshHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - if (!eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerRegistryEnable) { - throw new Exception("registry enable config is false, not support"); - } - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String group = queryStringInfo.get(EventMeshConstants.MANAGE_GROUP); - String purpose = queryStringInfo.get(EventMeshConstants.MANAGE_PURPOSE); - if (StringUtils.isBlank(group) || StringUtils.isBlank(purpose)) { - httpExchange.sendResponseHeaders(200, 0); - result = "params illegal!"; - out.write(result.getBytes()); - return; - } - - EventMeshRecommendStrategy eventMeshRecommendStrategy = new EventMeshRecommendImpl(eventMeshTCPServer); - String recommendEventMeshResult = eventMeshRecommendStrategy.calculateRecommendEventMesh(group, purpose); - result = (recommendEventMeshResult == null) ? "null" : recommendEventMeshResult; - logger.info("recommend eventmesh:{},group:{},purpose:{}", result, group, purpose); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("QueryRecommendEventMeshHandler fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryWebHookConfigByIdHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryWebHookConfigByIdHandler.java deleted file mode 100644 index 6e1345cd1c..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryWebHookConfigByIdHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.admin.rocketmq.util.JsonUtils; -import org.apache.eventmesh.admin.rocketmq.util.NetUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - -import java.io.IOException; -import java.io.OutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -@SuppressWarnings("restriction") -public class QueryWebHookConfigByIdHandler implements HttpHandler { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private WebHookConfigOperation operation; - - public QueryWebHookConfigByIdHandler(WebHookConfigOperation operation) { - this.operation = operation; - } - - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - httpExchange.sendResponseHeaders(200, 0); - httpExchange.getResponseHeaders().add("Content-Type", "application/json"); - - // get requestBody and resolve to WebHookConfig - String requestBody = NetUtils.parsePostBody(httpExchange); - WebHookConfig webHookConfig = JsonUtils.toObject(requestBody, WebHookConfig.class); - - try (OutputStream out = httpExchange.getResponseBody()) { - WebHookConfig result = operation.queryWebHookConfigById(webHookConfig); // operating result - out.write(JsonUtils.toJson(result).getBytes()); - } catch (Exception e) { - logger.error("get WebHookConfigOperation implementation Failed.", e); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryWebHookConfigByManufacturerHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryWebHookConfigByManufacturerHandler.java deleted file mode 100644 index 81f5d808c5..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/QueryWebHookConfigByManufacturerHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.admin.rocketmq.util.JsonUtils; -import org.apache.eventmesh.admin.rocketmq.util.NetUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -@SuppressWarnings("restriction") -public class QueryWebHookConfigByManufacturerHandler implements HttpHandler { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private WebHookConfigOperation operation; - - public QueryWebHookConfigByManufacturerHandler(WebHookConfigOperation operation) { - this.operation = operation; - } - - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - httpExchange.sendResponseHeaders(200, 0); - httpExchange.getResponseHeaders().add("Content-Type", "application/json"); - - // get requestBody and resolve to WebHookConfig - String requestBody = NetUtils.parsePostBody(httpExchange); - JsonNode node = JsonUtils.getJsonNode(requestBody); - WebHookConfig webHookConfig = JsonUtils.toObject(node.get("webHookConfig").toString(), WebHookConfig.class); - Integer pageNum = Integer.parseInt(node.get("pageNum").toString()); - Integer pageSize = Integer.parseInt(node.get("pageSize").toString()); - - try (OutputStream out = httpExchange.getResponseBody()) { - List result = operation.queryWebHookConfigByManufacturer(webHookConfig, pageNum, pageSize); // operating result - out.write(JsonUtils.toJson(result).getBytes()); - } catch (Exception e) { - logger.error("get WebHookConfigOperation implementation Failed.", e); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByIpPortHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByIpPortHandler.java deleted file mode 100644 index 2039c227f2..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByIpPortHandler.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -public class RedirectClientByIpPortHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(RedirectClientByIpPortHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public RedirectClientByIpPortHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String ip = queryStringInfo.get(EventMeshConstants.MANAGE_IP); - String port = queryStringInfo.get(EventMeshConstants.MANAGE_PORT); - String destEventMeshIp = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_IP); - String destEventMeshPort = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_PORT); - - if (StringUtils.isBlank(ip) || !StringUtils.isNumeric(port) - || StringUtils.isBlank(destEventMeshIp) || StringUtils.isBlank(destEventMeshPort) - || !StringUtils.isNumeric(destEventMeshPort)) { - httpExchange.sendResponseHeaders(200, 0); - result = "params illegal!"; - out.write(result.getBytes()); - return; - } - logger.info("redirectClientByIpPort in admin,ip:{},port:{},destIp:{},destPort:{}====================", ip, - port, destEventMeshIp, destEventMeshPort); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - String redirectResult = ""; - try { - if (!sessionMap.isEmpty()) { - for (Session session : sessionMap.values()) { - if (session.getClient().getHost().equals(ip) && String.valueOf( - session.getClient().getPort()).equals(port)) { - redirectResult += "|"; - redirectResult += EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer, - destEventMeshIp, Integer.parseInt(destEventMeshPort), - session, clientSessionGroupMapping); - } - } - } - } catch (Exception e) { - logger.error("clientManage|redirectClientByIpPort|fail|ip={}|port={}|destEventMeshIp" - + - "={}|destEventMeshPort={},errMsg={}", ip, port, destEventMeshIp, destEventMeshPort, e); - result = String.format("redirectClientByIpPort fail! sessionMap size {%d}, {clientIp=%s clientPort=%s " - + - "destEventMeshIp=%s destEventMeshPort=%s}, result {%s}, errorMsg : %s", - sessionMap.size(), ip, port, destEventMeshIp, destEventMeshPort, redirectResult, e - .getMessage()); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - return; - } - result = String.format("redirectClientByIpPort success! sessionMap size {%d}, {ip=%s port=%s " - + - "destEventMeshIp=%s destEventMeshPort=%s}, result {%s} ", - sessionMap.size(), ip, port, destEventMeshIp, destEventMeshPort, redirectResult); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("redirectClientByIpPort fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandler.java deleted file mode 100644 index b5f83ac890..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandler.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -/** - * redirect subsystem for path - */ -public class RedirectClientByPathHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(RedirectClientByPathHandler.class); - - private EventMeshTCPServer eventMeshTCPServer; - - public RedirectClientByPathHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String path = queryStringInfo.get(EventMeshConstants.MANAGE_PATH); - String destEventMeshIp = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_IP); - String destEventMeshPort = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_PORT); - - if (StringUtils.isBlank(path) || StringUtils.isBlank(destEventMeshIp) - || StringUtils.isBlank(destEventMeshPort) - || !StringUtils.isNumeric(destEventMeshPort)) { - httpExchange.sendResponseHeaders(200, 0); - result = "params illegal!"; - out.write(result.getBytes()); - return; - } - logger.info("redirectClientByPath in admin,path:{},destIp:{},destPort:{}====================", path, - destEventMeshIp, destEventMeshPort); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - String redirectResult = ""; - try { - if (!sessionMap.isEmpty()) { - for (Session session : sessionMap.values()) { - if (session.getClient().getPath().contains(path)) { - redirectResult += "|"; - redirectResult += EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer, - destEventMeshIp, Integer.parseInt(destEventMeshPort), - session, clientSessionGroupMapping); - } - } - } - } catch (Exception e) { - logger.error("clientManage|redirectClientByPath|fail|path={}|destEventMeshIp" - + - "={}|destEventMeshPort={},errMsg={}", path, destEventMeshIp, destEventMeshPort, e); - result = String.format("redirectClientByPath fail! sessionMap size {%d}, {path=%s " - + - "destEventMeshIp=%s destEventMeshPort=%s}, result {%s}, errorMsg : %s", - sessionMap.size(), path, destEventMeshIp, destEventMeshPort, redirectResult, e - .getMessage()); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - return; - } - result = String.format("redirectClientByPath success! sessionMap size {%d}, {path=%s " - + - "destEventMeshIp=%s destEventMeshPort=%s}, result {%s} ", - sessionMap.size(), path, destEventMeshIp, destEventMeshPort, redirectResult); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("redirectClientByPath fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientBySubSystemHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientBySubSystemHandler.java deleted file mode 100644 index 6fae83c30f..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientBySubSystemHandler.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -/** - * redirect subsystem for subsys and dcn - */ -public class RedirectClientBySubSystemHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(RedirectClientBySubSystemHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public RedirectClientBySubSystemHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String subSystem = queryStringInfo.get(EventMeshConstants.MANAGE_SUBSYSTEM); - String destEventMeshIp = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_IP); - String destEventMeshPort = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_PORT); - - if (!StringUtils.isNumeric(subSystem) - || StringUtils.isBlank(destEventMeshIp) || StringUtils.isBlank(destEventMeshPort) - || !StringUtils.isNumeric(destEventMeshPort)) { - httpExchange.sendResponseHeaders(200, 0); - result = "params illegal!"; - out.write(result.getBytes()); - return; - } - logger.info("redirectClientBySubSystem in admin,subsys:{},destIp:{},destPort:{}====================", - subSystem, destEventMeshIp, destEventMeshPort); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - String redirectResult = ""; - try { - if (!sessionMap.isEmpty()) { - for (Session session : sessionMap.values()) { - if (session.getClient().getSubsystem().equals(subSystem)) { - redirectResult += "|"; - redirectResult += EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer, - destEventMeshIp, Integer.parseInt(destEventMeshPort), - session, clientSessionGroupMapping); - } - } - } - } catch (Exception e) { - logger.error("clientManage|redirectClientBySubSystem|fail|subSystem={}|destEventMeshIp" - + - "={}|destEventMeshPort={},errMsg={}", subSystem, destEventMeshIp, destEventMeshPort, e); - result = String.format("redirectClientBySubSystem fail! sessionMap size {%d}, {subSystem=%s " - + - "destEventMeshIp=%s destEventMeshPort=%s}, result {%s}, errorMsg : %s", - sessionMap.size(), subSystem, destEventMeshIp, destEventMeshPort, redirectResult, e - .getMessage()); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - return; - } - result = String.format("redirectClientBySubSystem success! sessionMap size {%d}, {subSystem=%s " - + - "destEventMeshIp=%s destEventMeshPort=%s}, result {%s} ", - sessionMap.size(), subSystem, destEventMeshIp, destEventMeshPort, redirectResult); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("redirectClientBySubSystem fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectAllClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectAllClientHandler.java deleted file mode 100644 index ca445a3b44..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectAllClientHandler.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -public class RejectAllClientHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(RejectAllClientHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public RejectAllClientHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - /** - * remove all clients accessed by eventMesh - * - * @param httpExchange - * @throws IOException - */ - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - final List successRemoteAddrs = new ArrayList<>(); - try { - logger.info("rejectAllClient in admin===================="); - if (!sessionMap.isEmpty()) { - for (Map.Entry entry : sessionMap.entrySet()) { - InetSocketAddress addr = EventMeshTcp2Client.serverGoodby2Client( - eventMeshTCPServer, entry.getValue(), clientSessionGroupMapping); - if (addr != null) { - successRemoteAddrs.add(addr); - } - } - } - } catch (Exception e) { - logger.error("clientManage|rejectAllClient|fail", e); - result = String.format("rejectAllClient fail! sessionMap size {%d}, had reject {%s}, errorMsg : %s", - sessionMap.size(), NetUtils.addressToString(successRemoteAddrs), e.getMessage()); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - return; - } - result = String.format("rejectAllClient success! sessionMap size {%d}, had reject {%s}", sessionMap.size(), - NetUtils.addressToString(successRemoteAddrs)); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("rejectAllClient fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectClientByIpPortHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectClientByIpPortHandler.java deleted file mode 100644 index 00533f59d5..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectClientByIpPortHandler.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -public class RejectClientByIpPortHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(RejectClientByIpPortHandler.class); - - private EventMeshTCPServer eventMeshTCPServer; - - public RejectClientByIpPortHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String ip = queryStringInfo.get(EventMeshConstants.MANAGE_IP); - String port = queryStringInfo.get(EventMeshConstants.MANAGE_PORT); - - if (StringUtils.isBlank(ip) || StringUtils.isBlank(port)) { - httpExchange.sendResponseHeaders(200, 0); - result = "params illegal!"; - out.write(result.getBytes()); - return; - } - logger.info("rejectClientByIpPort in admin,ip:{},port:{}====================", ip, port); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - final List successRemoteAddrs = new ArrayList(); - try { - if (!sessionMap.isEmpty()) { - for (Map.Entry entry : sessionMap.entrySet()) { - if (entry.getKey().getHostString().equals(ip) && String.valueOf(entry.getKey().getPort()).equals(port)) { - InetSocketAddress addr = EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer, - entry.getValue(), clientSessionGroupMapping); - if (addr != null) { - successRemoteAddrs.add(addr); - } - } - } - } - } catch (Exception e) { - logger.error("clientManage|rejectClientByIpPort|fail|ip={}|port={},errMsg={}", ip, port, e); - result = String.format("rejectClientByIpPort fail! {ip=%s port=%s}, had reject {%s}, errorMsg : %s", ip, - port, NetUtils.addressToString(successRemoteAddrs), e.getMessage()); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - return; - } - - result = String.format("rejectClientByIpPort success! {ip=%s port=%s}, had reject {%s}", ip, port, - NetUtils.addressToString(successRemoteAddrs)); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("rejectClientByIpPort fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectClientBySubSystemHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectClientBySubSystemHandler.java deleted file mode 100644 index 90cca19104..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/RejectClientBySubSystemHandler.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -public class RejectClientBySubSystemHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(RejectClientBySubSystemHandler.class); - - private EventMeshTCPServer eventMeshTCPServer; - - public RejectClientBySubSystemHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - private String printClients(List clients) { - if (clients.isEmpty()) { - return "no session had been closed"; - } - StringBuilder sb = new StringBuilder(); - for (InetSocketAddress addr : clients) { - sb.append(addr).append("|"); - } - return sb.toString(); - } - - /** - * remove c client by dcn and susysId - * - * @param httpExchange - * @throws IOException - */ - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String subSystem = queryStringInfo.get(EventMeshConstants.MANAGE_SUBSYSTEM); - - if (StringUtils.isBlank(subSystem)) { - httpExchange.sendResponseHeaders(200, 0); - result = "params illegal!"; - out.write(result.getBytes()); - return; - } - - logger.info("rejectClientBySubSystem in admin,subsys:{}====================", subSystem); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - final List successRemoteAddrs = new ArrayList(); - try { - if (!sessionMap.isEmpty()) { - for (Session session : sessionMap.values()) { - if (session.getClient().getSubsystem().equals(subSystem)) { - InetSocketAddress addr = EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer, session, clientSessionGroupMapping); - if (addr != null) { - successRemoteAddrs.add(addr); - } - } - } - } - } catch (Exception e) { - logger.error("clientManage|rejectClientBySubSystem|fail|subSystemId={},errMsg={}", subSystem, e); - result = String.format("rejectClientBySubSystem fail! sessionMap size {%d}, had reject {%d} , {" - + - "subSystemId=%s}, errorMsg : %s", sessionMap.size(), printClients(successRemoteAddrs), subSystem, e.getMessage()); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - return; - } - result = String.format("rejectClientBySubSystem success! sessionMap size {%d}, had reject {%s} , {" - + - "subSystemId=%s}", sessionMap.size(), printClients(successRemoteAddrs), subSystem); - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("rejectClientBySubSystem fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowClientBySystemHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowClientBySystemHandler.java deleted file mode 100644 index 29d4cd58bd..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowClientBySystemHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -public class ShowClientBySystemHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(ShowClientBySystemHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public ShowClientBySystemHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - /** - * print clientInfo by subsys - * - * @param httpExchange - * @throws IOException - */ - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String subSystem = queryStringInfo.get(EventMeshConstants.MANAGE_SUBSYSTEM); - - String newLine = System.getProperty("line.separator"); - logger.info("showClientBySubsys,subsys:{}=================", subSystem); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); - if (!sessionMap.isEmpty()) { - for (Session session : sessionMap.values()) { - if (session.getClient().getSubsystem().equals(subSystem)) { - UserAgent userAgent = session.getClient(); - result += String.format("pid=%s | ip=%s | port=%s | path=%s | purpose=%s", userAgent.getPid(), userAgent - .getHost(), userAgent.getPort(), userAgent.getPath(), userAgent.getPurpose()) + newLine; - } - } - } - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("ShowClientBySystemAndHandler fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - } - - -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowClientHandler.java deleted file mode 100644 index 9c28f53166..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowClientHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -/** - * This handler used to print the total client info - */ -public class ShowClientHandler implements HttpHandler { - - private static final Logger logger = LoggerFactory.getLogger(ShowClientHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public ShowClientHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String newLine = System.getProperty("line.separator"); - logger.info("showAllClient================="); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - - HashMap statMap = new HashMap(); - - Map sessionMap = clientSessionGroupMapping.getSessionMap(); - if (!sessionMap.isEmpty()) { - for (Session session : sessionMap.values()) { - String key = session.getClient().getSubsystem(); - if (!statMap.containsKey(key)) { - statMap.put(key, new AtomicInteger(1)); - } else { - statMap.get(key).incrementAndGet(); - } - } - - for (Map.Entry entry : statMap.entrySet()) { - result += String.format("System=%s | ClientNum=%d", entry.getKey(), entry.getValue().intValue()) - + - newLine; - } - } - - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("ShowClientHandler fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowListenClientByTopicHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowListenClientByTopicHandler.java deleted file mode 100644 index a7b11bea83..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/ShowListenClientByTopicHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientGroupWrapper; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -/** - * query client subscription by topic - */ -public class ShowListenClientByTopicHandler implements HttpHandler { - - private Logger logger = LoggerFactory.getLogger(ShowListenClientByTopicHandler.class); - - private final EventMeshTCPServer eventMeshTCPServer; - - public ShowListenClientByTopicHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String result = ""; - OutputStream out = httpExchange.getResponseBody(); - try { - String queryString = httpExchange.getRequestURI().getQuery(); - Map queryStringInfo = NetUtils.formData2Dic(queryString); - String topic = queryStringInfo.get(EventMeshConstants.MANAGE_TOPIC); - - String newLine = System.getProperty("line.separator"); - logger.info("showListeningClientByTopic,topic:{}=================", topic); - ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); - ConcurrentHashMap clientGroupMap = clientSessionGroupMapping.getClientGroupMap(); - if (!clientGroupMap.isEmpty()) { - for (ClientGroupWrapper cgw : clientGroupMap.values()) { - Set listenSessionSet = cgw.getTopic2sessionInGroupMapping().get(topic); - if (listenSessionSet != null && listenSessionSet.size() > 0) { - result += String.format("group:%s", cgw.getGroup()) + newLine; - for (Session session : listenSessionSet) { - UserAgent userAgent = session.getClient(); - result += String.format("pid=%s | ip=%s | port=%s | path=%s | version=%s", userAgent.getPid(), userAgent - .getHost(), userAgent.getPort(), userAgent.getPath(), userAgent.getVersion()) + newLine; - } - } - } - } - httpExchange.sendResponseHeaders(200, 0); - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("ShowListenClientByTopicHandler fail...", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - logger.warn("out close failed...", e); - } - } - } - - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/UpdateWebHookConfigHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/UpdateWebHookConfigHandler.java deleted file mode 100644 index c9f77e2c95..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/UpdateWebHookConfigHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.admin.rocketmq.util.JsonUtils; -import org.apache.eventmesh.admin.rocketmq.util.NetUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - -import java.io.IOException; -import java.io.OutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -@SuppressWarnings("restriction") -public class UpdateWebHookConfigHandler implements HttpHandler { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - - private WebHookConfigOperation operation; - - public UpdateWebHookConfigHandler(WebHookConfigOperation operation) { - this.operation = operation; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - httpExchange.sendResponseHeaders(200, 0); - - // get requestBody and resolve to WebHookConfig - String requestBody = NetUtils.parsePostBody(httpExchange); - WebHookConfig webHookConfig = JsonUtils.toObject(requestBody, WebHookConfig.class); - - try (OutputStream out = httpExchange.getResponseBody()) { - Integer code = operation.updateWebHookConfig(webHookConfig); // operating result - String result = 1 == code ? "updateWebHookConfig Succeed!" : "updateWebHookConfig Failed!"; - out.write(result.getBytes()); - } catch (Exception e) { - logger.error("get WebHookConfigOperation implementation Failed.", e); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ConfigurationHandlerV1.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ConfigurationHandlerV1.java new file mode 100644 index 0000000000..5c2670f306 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ConfigurationHandlerV1.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.response.v1.GetConfigurationResponse; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /configuration} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /}. + *

+ * This handler is responsible for retrieving the current configuration information of the EventMesh node, including service name, service + * environment, and listening ports for various protocols. + *

+ * TODO The path of endpoints under v1 package shall be changed to {@code /v1/configuration} with Next.js EventMesh Dashboard. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/configuration") +public class ConfigurationHandlerV1 extends AbstractHttpHandler { + + private final EventMeshTCPConfiguration eventMeshTCPConfiguration; + private final EventMeshHTTPConfiguration eventMeshHTTPConfiguration; + private final EventMeshGrpcConfiguration eventMeshGrpcConfiguration; + + /** + * Constructs a new instance with the provided configurations. + * + * @param eventMeshTCPConfiguration the TCP configuration for EventMesh + * @param eventMeshHTTPConfiguration the HTTP configuration for EventMesh + * @param eventMeshGrpcConfiguration the gRPC configuration for EventMesh + */ + public ConfigurationHandlerV1( + EventMeshTCPConfiguration eventMeshTCPConfiguration, + EventMeshHTTPConfiguration eventMeshHTTPConfiguration, + EventMeshGrpcConfiguration eventMeshGrpcConfiguration) { + super(); + this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; + this.eventMeshHTTPConfiguration = eventMeshHTTPConfiguration; + this.eventMeshGrpcConfiguration = eventMeshGrpcConfiguration; + } + + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + GetConfigurationResponse getConfigurationResponse = new GetConfigurationResponse( + eventMeshTCPConfiguration.getSysID(), + eventMeshTCPConfiguration.getMetaStorageAddr(), + eventMeshTCPConfiguration.getEventMeshEnv(), + eventMeshTCPConfiguration.getEventMeshIDC(), + eventMeshTCPConfiguration.getEventMeshCluster(), + eventMeshTCPConfiguration.getEventMeshServerIp(), + eventMeshTCPConfiguration.getEventMeshName(), + eventMeshTCPConfiguration.isEventMeshServerSecurityEnable(), + eventMeshTCPConfiguration.isEventMeshServerMetaStorageEnable(), + // TCP Configuration + eventMeshTCPConfiguration.getEventMeshTcpServerPort(), + // HTTP Configuration + eventMeshHTTPConfiguration.getHttpServerPort(), + eventMeshHTTPConfiguration.isEventMeshServerUseTls(), + // gRPC Configuration + eventMeshGrpcConfiguration.getGrpcServerPort(), + eventMeshGrpcConfiguration.isEventMeshServerUseTls()); + String result = JsonUtils.toJSONString(getConfigurationResponse); + writeJson(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/EventHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/EventHandler.java new file mode 100644 index 0000000000..4e1fe4a03a --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/EventHandler.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.plugin.MQAdminWrapper; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.jackson.JsonFormat; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /event} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /event}. + *

+ * It is responsible for managing operations on events, including retrieving the event list and creating events. + *

+ * The GET method supports querying events by {@code topicName}, and uses {@code offset} and {@code length} parameters for pagination. + *

+ * An instance of {@link MQAdminWrapper} is used to interact with the messaging system. + * + * @see AbstractHttpHandler + * @see MQAdminWrapper + */ + +@Slf4j +@EventMeshHttpHandler(path = "/event") +public class EventHandler extends AbstractHttpHandler { + + private final MQAdminWrapper admin; + + /** + * Constructs a new instance with the specified connector plugin type. + * + * @param connectorPluginType The name of event storage connector plugin. + */ + public EventHandler( + String connectorPluginType) { + super(); + admin = new MQAdminWrapper(connectorPluginType); + try { + admin.init(null); + } catch (Exception ignored) { + log.info("failed to initialize MQAdminWrapper"); + } + } + + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + HttpHeaders responseHeaders = new DefaultHttpHeaders(); + responseHeaders.add(EventMeshConstants.HANDLER_ORIGIN, "*"); + String queryString = URI.create(httpRequest.uri()).getQuery(); + if (queryString == null || queryString.isEmpty()) { + writeUnauthorized(ctx, ""); + return; + } + Map queryMap = HttpRequestUtil.queryStringToMap(queryString); + String topicName = queryMap.get("topicName"); + int offset = Integer.parseInt(queryMap.get("offset")); + int length = Integer.parseInt(queryMap.get("length")); + List eventList = admin.getEvent(topicName, offset, length); + + List eventJsonList = new ArrayList<>(); + for (CloudEvent event : eventList) { + byte[] serializedEvent = Objects.requireNonNull(EventFormatProvider + .getInstance() + .resolveFormat(JsonFormat.CONTENT_TYPE)) + .serialize(event); + eventJsonList.add(new String(serializedEvent, StandardCharsets.UTF_8)); + } + String result = JsonUtils.toJSONString(eventJsonList); + writeJson(ctx, result); + } + + @Override + protected void post(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + HttpHeaders responseHeaders = new DefaultHttpHeaders(); + responseHeaders.add(EventMeshConstants.HANDLER_ORIGIN, "*"); + String request = JsonUtils.toJSONString(HttpRequestUtil.parseHttpRequestBody(httpRequest)); + byte[] rawRequest = request.getBytes(StandardCharsets.UTF_8); + CloudEvent event = Objects.requireNonNull(EventFormatProvider + .getInstance() + .resolveFormat(JsonFormat.CONTENT_TYPE)).deserialize(rawRequest); + admin.publish(event); + writeText(ctx, ""); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/GrpcClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/GrpcClientHandler.java new file mode 100644 index 0000000000..af48aea960 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/GrpcClientHandler.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.request.DeleteGrpcClientRequest; +import org.apache.eventmesh.runtime.admin.response.v1.GetClientResponse; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.ConsumerManager; +import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupClient; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /client/grpc} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /grpc}. + *

+ * It is responsible for managing operations on gRPC clients, including retrieving the information list of connected gRPC clients and deleting gRPC + * clients by disconnecting their connections based on the provided host and port. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/client/grpc") +public class GrpcClientHandler extends AbstractHttpHandler { + + private final EventMeshGrpcServer eventMeshGrpcServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshGrpcServer the gRPC server instance of EventMesh + */ + public GrpcClientHandler( + EventMeshGrpcServer eventMeshGrpcServer) { + super(); + this.eventMeshGrpcServer = eventMeshGrpcServer; + } + + @Override + protected void delete(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + Map body = HttpRequestUtil.parseHttpRequestBody(httpRequest); + Objects.requireNonNull(body, "body can not be null"); + DeleteGrpcClientRequest deleteGrpcClientRequest = JsonUtils.mapToObject(body, DeleteGrpcClientRequest.class); + String url = Objects.requireNonNull(deleteGrpcClientRequest).getUrl(); + ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); + Map> clientTable = consumerManager.getClientTable(); + // Find the client that matches the url to be deleted + for (List clientList : clientTable.values()) { + for (ConsumerGroupClient client : clientList) { + if (Objects.equals(client.getUrl(), url)) { + // Call the deregisterClient method to close the gRPC client stream and remove it + consumerManager.deregisterClient(client); + } + } + } + writeText(ctx, ""); + } + + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Get the list of gRPC clients + List getClientResponseList = new ArrayList<>(); + + ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); + Map> clientTable = consumerManager.getClientTable(); + for (List clientList : clientTable.values()) { + // Convert each Client object to GetClientResponse and add to getClientResponseList + for (ConsumerGroupClient client : clientList) { + GetClientResponse getClientResponse = new GetClientResponse( + Optional.ofNullable(client.env).orElse(""), + Optional.ofNullable(client.sys).orElse(""), + Optional.ofNullable(client.url).orElse(""), + "0", + Optional.ofNullable(client.hostname).orElse(""), + 0, + Optional.ofNullable(client.apiVersion).orElse(""), + Optional.ofNullable(client.idc).orElse(""), + Optional.ofNullable(client.consumerGroup).orElse(""), + "", + "gRPC"); + getClientResponseList.add(getClientResponse); + } + } + + // Sort the getClientResponseList by host and port + getClientResponseList.sort((lhs, rhs) -> { + if (lhs.getHost().equals(rhs.getHost())) { + return lhs.getHost().compareTo(rhs.getHost()); + } + return Integer.compare(rhs.getPort(), lhs.getPort()); + }); + // Convert getClientResponseList to JSON and send the response + String result = JsonUtils.toJSONString(getClientResponseList); + writeJson(ctx, result); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/HTTPClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/HTTPClientHandler.java new file mode 100644 index 0000000000..2a72241949 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/HTTPClientHandler.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.request.DeleteHTTPClientRequest; +import org.apache.eventmesh.runtime.admin.response.v1.GetClientResponse; +import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /client/http} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /http}. + *

+ * It is responsible for managing operations on HTTP clients, including retrieving the information list of connected HTTP clients and deleting HTTP + * clients by disconnecting their connections based on the provided host and port. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/client/http") +public class HTTPClientHandler extends AbstractHttpHandler { + + private final EventMeshHTTPServer eventMeshHTTPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshHTTPServer the HTTP server instance of EventMesh + */ + public HTTPClientHandler( + EventMeshHTTPServer eventMeshHTTPServer) { + super(); + this.eventMeshHTTPServer = eventMeshHTTPServer; + } + + protected void delete(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + Map body = HttpRequestUtil.parseHttpRequestBody(httpRequest); + if (!Objects.isNull(body)) { + DeleteHTTPClientRequest deleteHTTPClientRequest = JsonUtils.mapToObject(body, DeleteHTTPClientRequest.class); + String url = Objects.requireNonNull(deleteHTTPClientRequest).getUrl(); + + for (List clientList : eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping().values()) { + // Find the client that matches the url to be deleted + clientList.removeIf(client -> Objects.equals(client.getUrl(), url)); + } + // Set the response headers and send a 200 status code empty response + writeText(ctx, ""); + } + + } + + /** + * Handles the GET request for {@code /client/http}. + *

+ * This method retrieves the list of connected HTTP clients and returns it as a JSON response. + * + * @throws Exception if an I/O error occurs while handling the request + */ + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Get the list of HTTP clients + List getClientResponseList = new ArrayList<>(); + + for (List clientList : eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping().values()) { + // Convert each Client object to GetClientResponse and add to getClientResponseList + for (Client client : clientList) { + GetClientResponse getClientResponse = new GetClientResponse( + Optional.ofNullable(client.getEnv()).orElse(""), + Optional.ofNullable(client.getSys()).orElse(""), + Optional.ofNullable(client.getUrl()).orElse(""), + "0", + Optional.ofNullable(client.getHostname()).orElse(""), + 0, + Optional.ofNullable(client.getApiVersion()).orElse(""), + Optional.ofNullable(client.getIdc()).orElse(""), + Optional.ofNullable(client.getConsumerGroup()).orElse(""), + "", + EventMeshConstants.PROTOCOL_HTTP.toUpperCase() + + ); + getClientResponseList.add(getClientResponse); + } + } + + // Sort the getClientResponseList by host and port + getClientResponseList.sort((lhs, rhs) -> { + if (lhs.getHost().equals(rhs.getHost())) { + return lhs.getHost().compareTo(rhs.getHost()); + } + return Integer.compare(rhs.getPort(), lhs.getPort()); + }); + + // Convert getClientResponseList to JSON and send the response + String result = JsonUtils.toJSONString(getClientResponseList); + writeJson(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/MetaHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/MetaHandler.java new file mode 100644 index 0000000000..7e10906630 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/MetaHandler.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.response.v1.GetRegistryResponse; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /registry} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /registry}. + *

+ * This handler is responsible for retrieving a list of EventMesh clusters from the {@link MetaStorage} object, encapsulate them into a list of {@link + * GetRegistryResponse} objects, and sort them by {@code EventMeshClusterName}. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/meta") +public class MetaHandler extends AbstractHttpHandler { + + private final MetaStorage eventMeshMetaStorage; + + /** + * @param eventMeshMetaStorage The {@link MetaStorage} instance used for retrieving EventMesh cluster information. + */ + public MetaHandler(MetaStorage eventMeshMetaStorage) { + super(); + this.eventMeshMetaStorage = eventMeshMetaStorage; + } + + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws IOException { + try { + List getRegistryResponseList = new ArrayList<>(); + List eventMeshDataInfos = eventMeshMetaStorage.findAllEventMeshInfo(); + for (EventMeshDataInfo eventMeshDataInfo : eventMeshDataInfos) { + GetRegistryResponse getRegistryResponse = new GetRegistryResponse( + eventMeshDataInfo.getEventMeshClusterName(), + eventMeshDataInfo.getEventMeshName(), + eventMeshDataInfo.getEndpoint(), + eventMeshDataInfo.getLastUpdateTimestamp(), + eventMeshDataInfo.getMetadata().toString()); + getRegistryResponseList.add(getRegistryResponse); + } + getRegistryResponseList.sort(Comparator.comparing(GetRegistryResponse::getEventMeshClusterName)); + String result = JsonUtils.toJSONString(getRegistryResponseList); + writeJson(ctx, result); + } catch (NullPointerException e) { + // registry not initialized, return empty list + String result = JsonUtils.toJSONString(new ArrayList<>()); + writeJson(ctx, result); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/QueryRecommendEventMeshHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/QueryRecommendEventMeshHandler.java new file mode 100644 index 0000000000..f9aabc84b1 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/QueryRecommendEventMeshHandler.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendStrategy; + +import org.apache.commons.lang3.StringUtils; + +import java.net.URI; +import java.util.Map; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /eventMesh/recommend} endpoint, which is used to calculate and return the recommended EventMesh + * server node to the client based on the provided {@code group} and {@code purpose} parameters. + *

+ * Parameters: + *

    + *
  • client group: {@code group} | Example: {@code EventmeshTestGroup}
  • + *
  • client purpose: {@code purpose} | Example: {@code sub}
  • + *
+ * It uses an {@link EventMeshRecommendStrategy} which is implemented by {@link EventMeshRecommendImpl} + * to calculate the recommended EventMesh server node. + * + * @see AbstractHttpHandler + */ +@Slf4j +@EventMeshHttpHandler(path = "/eventMesh/recommend") +public class QueryRecommendEventMeshHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public QueryRecommendEventMeshHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String result = ""; + if (!eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerMetaStorageEnable()) { + throw new Exception("registry enable config is false, not support"); + } + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameters from the query string + String group = queryStringInfo.get(EventMeshConstants.MANAGE_GROUP); + String purpose = queryStringInfo.get(EventMeshConstants.MANAGE_PURPOSE); + // Check the validity of the parameters + if (StringUtils.isBlank(group) || StringUtils.isBlank(purpose)) { + result = "params illegal!"; + writeText(ctx, result); + return; + } + + EventMeshRecommendStrategy eventMeshRecommendStrategy = new EventMeshRecommendImpl(eventMeshTCPServer); + // Calculate the recommended EventMesh node according to the given group and purpose + String recommendEventMeshResult = eventMeshRecommendStrategy.calculateRecommendEventMesh(group, purpose); + result = (recommendEventMeshResult == null) ? "null" : recommendEventMeshResult; + log.info("recommend eventmesh:{},group:{},purpose:{}", result, group, purpose); + writeText(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientByIpPortHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientByIpPortHandler.java new file mode 100644 index 0000000000..33922456f1 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientByIpPortHandler.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.lang3.StringUtils; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/redirectClientByIpPort} endpoint, which is used to redirect matching clients to a + * target EventMesh server node based on the provided IP address and port. + *

+ * The request must specify the client's and target EventMesh node's IP and port. + *

+ * Parameters: + *

    + *
  • client's IP: {@code ip}
  • + *
  • client's port: {@code port}
  • + *
  • target EventMesh node's IP: {@code desteventmeshIp}
  • + *
  • target EventMesh node's port: {@code desteventmeshport}
  • + *
+ * It uses the {@link EventMeshTcp2Client#redirectClient2NewEventMesh} method to redirect the matching client. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/redirectClientByIpPort") +public class RedirectClientByIpPortHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public RedirectClientByIpPortHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String result = ""; + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameters from the query string + String ip = queryStringInfo.get(EventMeshConstants.MANAGE_IP); + String port = queryStringInfo.get(EventMeshConstants.MANAGE_PORT); + String destEventMeshIp = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_IP); + String destEventMeshPort = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_PORT); + + // Check the validity of the parameters + if (StringUtils.isBlank(ip) || !StringUtils.isNumeric(port) + || StringUtils.isBlank(destEventMeshIp) || StringUtils.isBlank(destEventMeshPort) + || !StringUtils.isNumeric(destEventMeshPort)) { + result = "params illegal!"; + writeText(ctx, result); + return; + } + log.info("redirectClientByIpPort in admin,ip:{},port:{},destIp:{},destPort:{}====================", ip, + port, destEventMeshIp, destEventMeshPort); + // Retrieve the mapping between Sessions and their corresponding client address + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + StringBuilder redirectResult = new StringBuilder(); + try { + if (!sessionMap.isEmpty()) { + // Iterate through the sessionMap to find matching sessions where the client's IP and port match the given ones + for (Session session : sessionMap.values()) { + // For each matching session found, redirect the client + // to the new EventMesh node specified by given EventMesh IP and port. + if (session.getClient().getHost().equals(ip) && String.valueOf( + session.getClient().getPort()).equals(port)) { + redirectResult.append("|"); + redirectResult.append(EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer.getTcpThreadPoolGroup(), + destEventMeshIp, Integer.parseInt(destEventMeshPort), + session, clientSessionGroupMapping)); + } + } + } + } catch (Exception e) { + log.error("clientManage|redirectClientByIpPort|fail|ip={}|port={}|destEventMeshIp" + + "={}|destEventMeshPort={}", ip, port, destEventMeshIp, destEventMeshPort, e); + result = String.format("redirectClientByIpPort fail! sessionMap size {%d}, {clientIp=%s clientPort=%s " + + "destEventMeshIp=%s destEventMeshPort=%s}, result {%s}, errorMsg : %s", + sessionMap.size(), ip, port, destEventMeshIp, destEventMeshPort, redirectResult, e.getMessage()); + writeText(ctx, result); + return; + } + // Serialize the result of redirection into output stream + result = String.format("redirectClientByIpPort success! sessionMap size {%d}, {ip=%s port=%s " + + "destEventMeshIp=%s destEventMeshPort=%s}, result {%s} ", + sessionMap.size(), ip, port, destEventMeshIp, destEventMeshPort, redirectResult); + writeText(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientByPathHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientByPathHandler.java new file mode 100644 index 0000000000..54b089ce54 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientByPathHandler.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.lang3.StringUtils; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/redirectClientByPath} endpoint, which is used to redirect matching clients to a target + * EventMesh server node based on the provided client UserAgent path. + *

+ * The request must specify the client's path and target EventMesh node's IP and port. + *

+ * Parameters: + *

    + *
  • client's path: {@code path} | Example: {@code /data/app/umg_proxy}
  • + *
  • target EventMesh node's IP: {@code desteventmeshIp}
  • + *
  • target EventMesh node's port: {@code desteventmeshport}
  • + *
+ * It uses the {@link EventMeshTcp2Client#redirectClient2NewEventMesh} method to redirect the matching client. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/redirectClientByPath") +public class RedirectClientByPathHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public RedirectClientByPathHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String result = ""; + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameters from the query string + String path = queryStringInfo.get(EventMeshConstants.MANAGE_PATH); + String destEventMeshIp = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_IP); + String destEventMeshPort = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_PORT); + + // Check the validity of the parameters + if (StringUtils.isBlank(path) || StringUtils.isBlank(destEventMeshIp) + || StringUtils.isBlank(destEventMeshPort) || !StringUtils.isNumeric(destEventMeshPort)) { + result = "params illegal!"; + writeText(ctx, result); + return; + } + log.info("redirectClientByPath in admin,path:{},destIp:{},destPort:{}====================", path, + destEventMeshIp, destEventMeshPort); + // Retrieve the mapping between Sessions and their corresponding client address + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + StringBuilder redirectResult = new StringBuilder(); + try { + if (!sessionMap.isEmpty()) { + // Iterate through the sessionMap to find matching sessions where the client's path matches the given param + for (Session session : sessionMap.values()) { + // For each matching session found, redirect the client + // to the new EventMesh node specified by given EventMesh IP and port. + if (session.getClient().getPath().contains(path)) { + redirectResult.append("|"); + redirectResult.append(EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer.getTcpThreadPoolGroup(), + destEventMeshIp, Integer.parseInt(destEventMeshPort), + session, clientSessionGroupMapping)); + } + } + } + } catch (Exception e) { + log.error("clientManage|redirectClientByPath|fail|path={}|destEventMeshIp" + + "={}|destEventMeshPort={}", path, destEventMeshIp, destEventMeshPort, e); + result = String.format("redirectClientByPath fail! sessionMap size {%d}, {path=%s " + + "destEventMeshIp=%s destEventMeshPort=%s}, result {%s}, errorMsg : %s", + sessionMap.size(), path, destEventMeshIp, destEventMeshPort, redirectResult, e.getMessage()); + writeText(ctx, result); + return; + } + result = String.format("redirectClientByPath success! sessionMap size {%d}, {path=%s " + + "destEventMeshIp=%s destEventMeshPort=%s}, result {%s} ", + sessionMap.size(), path, destEventMeshIp, destEventMeshPort, redirectResult); + writeText(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientBySubSystemHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientBySubSystemHandler.java new file mode 100644 index 0000000000..0aff5fe8b7 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RedirectClientBySubSystemHandler.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.lang3.StringUtils; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/redirectClientBySubSystem} endpoint, which is used to redirect matching clients to a + * target EventMesh server node based on the provided client subsystem id in a Data Communication Network (DCN). + *

+ * The request must specify the client's subsystem id and target EventMesh node's IP and port. + *

+ * Parameters: + *

    + *
  • client's subsystem id: {@code subsystem} | Example: {@code 5023}
  • + *
  • target EventMesh node's IP: {@code desteventmeshIp}
  • + *
  • target EventMesh node's port: {@code desteventmeshport}
  • + *
+ * It uses the {@link EventMeshTcp2Client#redirectClient2NewEventMesh} method to redirect the matching client. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/redirectClientBySubSystem") +public class RedirectClientBySubSystemHandler extends AbstractHttpHandler { + + private final transient EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public RedirectClientBySubSystemHandler(final EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + final Map queryStringInfo = NetUtils.formData2Dic(URI.create(httpRequest.uri()).getQuery()); + // Extract parameters from the query string + final String subSystem = queryStringInfo.get(EventMeshConstants.MANAGE_SUBSYSTEM); + final String destEventMeshIp = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_IP); + final String destEventMeshPort = queryStringInfo.get(EventMeshConstants.MANAGE_DEST_PORT); + + // Check the validity of the parameters + if (!StringUtils.isNumeric(subSystem) + || StringUtils.isBlank(destEventMeshIp) || StringUtils.isBlank(destEventMeshPort) + || !StringUtils.isNumeric(destEventMeshPort)) { + writeText(ctx, "params illegal!"); + return; + } + log.info("redirectClientBySubSystem in admin,subsys:{},destIp:{},destPort:{}====================", + subSystem, destEventMeshIp, destEventMeshPort); + + // Retrieve the mapping between Sessions and their corresponding client address + final ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + final ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final StringBuilder redirectResult = new StringBuilder(); + try { + if (!sessionMap.isEmpty()) { + // Iterate through the sessionMap to find matching sessions where the client's subsystem id matches the given param + for (final Session session : sessionMap.values()) { + // For each matching session found, redirect the client + // to the new EventMesh node specified by given EventMesh IP and port. + if (session.getClient().getSubsystem().equals(subSystem)) { + redirectResult.append('|') + .append(EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer.getTcpThreadPoolGroup(), + destEventMeshIp, Integer.parseInt(destEventMeshPort), + session, clientSessionGroupMapping)); + } + } + } + } catch (Exception e) { + log.error("clientManage|redirectClientBySubSystem|fail|subSystem={}|destEventMeshIp" + + "={}|destEventMeshPort={}", subSystem, destEventMeshIp, destEventMeshPort, e); + + writeText(ctx, String.format("redirectClientBySubSystem fail! sessionMap size {%d}, {subSystem=%s " + + "destEventMeshIp=%s destEventMeshPort=%s}, result {%s}, errorMsg : %s", + sessionMap.size(), subSystem, destEventMeshIp, destEventMeshPort, redirectResult, e.getMessage())); + return; + } + writeText(ctx, String.format("redirectClientBySubSystem success! sessionMap size {%d}, {subSystem=%s " + + "destEventMeshIp=%s destEventMeshPort=%s}, result {%s} ", + sessionMap.size(), subSystem, destEventMeshIp, destEventMeshPort, redirectResult)); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectAllClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectAllClientHandler.java new file mode 100644 index 0000000000..bc139b3938 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectAllClientHandler.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/rejectAllClient} endpoint, which is used to reject ALL client connections belonging to + * the current EventMesh server node. + *

+ * CAUTION: USE WITH CARE + *

+ * It uses the {@link EventMeshTcp2Client#serverGoodby2Client} method to close the matching client connection. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/rejectAllClient") +public class RejectAllClientHandler extends AbstractHttpHandler { + + private final transient EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public RejectAllClientHandler(final EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Retrieve the mapping between Sessions and their corresponding client address + final ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + final ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final List successRemoteAddrs = new ArrayList<>(); + try { + log.info("rejectAllClient in admin===================="); + if (!sessionMap.isEmpty()) { + // Iterate through the sessionMap and close each client connection + for (final Map.Entry entry : sessionMap.entrySet()) { + final InetSocketAddress addr = EventMeshTcp2Client.serverGoodby2Client( + eventMeshTCPServer.getTcpThreadPoolGroup(), entry.getValue(), clientSessionGroupMapping); + // Add the remote client address to a list of successfully rejected addresses + if (addr != null) { + successRemoteAddrs.add(addr); + } + } + } + } catch (Exception e) { + log.error("clientManage rejectAllClient fail", e); + writeText(ctx, String.format("rejectAllClient fail! sessionMap size {%d}, had reject {%s}, errorMsg : %s", + sessionMap.size(), NetUtils.addressToString(successRemoteAddrs), e.getMessage())); + return; + } + writeText(ctx, String.format("rejectAllClient success! sessionMap size {%d}, had reject {%s}", + sessionMap.size(), NetUtils.addressToString(successRemoteAddrs))); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectClientByIpPortHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectClientByIpPortHandler.java new file mode 100644 index 0000000000..6d6165785e --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectClientByIpPortHandler.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.lang3.StringUtils; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/rejectClientByIpPort} endpoint, which is used to reject a client connection that + * matches the provided IP address and port. + *

+ * The request must specify the client's and target EventMesh node's IP and port. + *

+ * Parameters: + *

    + *
  • client's IP: {@code ip}
  • + *
  • client's port: {@code port}
  • + *
  • target EventMesh node's IP: {@code desteventmeshIp}
  • + *
  • target EventMesh node's port: {@code desteventmeshport}
  • + *
+ * It uses the {@link EventMeshTcp2Client#serverGoodby2Client} method to close the matching client connection. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/rejectClientByIpPort") +public class RejectClientByIpPortHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public RejectClientByIpPortHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String result = ""; + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameters from the query string + String ip = queryStringInfo.get(EventMeshConstants.MANAGE_IP); + String port = queryStringInfo.get(EventMeshConstants.MANAGE_PORT); + + // Check the validity of the parameters + if (StringUtils.isBlank(ip) || StringUtils.isBlank(port)) { + result = "params illegal!"; + writeText(ctx, result); + return; + } + log.info("rejectClientByIpPort in admin,ip:{},port:{}====================", ip, port); + // Retrieve the mapping between Sessions and their corresponding client address + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final List successRemoteAddrs = new ArrayList<>(); + try { + if (!sessionMap.isEmpty()) { + // Iterate through the sessionMap to find matching sessions where the remote client address matches the given IP and port + for (Map.Entry entry : sessionMap.entrySet()) { + // Reject client connection for each matching session found + if (entry.getKey().getHostString().equals(ip) && String.valueOf(entry.getKey().getPort()).equals(port)) { + InetSocketAddress addr = EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer.getTcpThreadPoolGroup(), + entry.getValue(), clientSessionGroupMapping); + // Add the remote client address to a list of successfully rejected addresses + if (addr != null) { + successRemoteAddrs.add(addr); + } + } + } + } + } catch (Exception e) { + log.error("clientManage|rejectClientByIpPort|fail|ip={}|port={}", ip, port, e); + result = String.format("rejectClientByIpPort fail! {ip=%s port=%s}, had reject {%s}, errorMsg : %s", ip, + port, NetUtils.addressToString(successRemoteAddrs), e.getMessage()); + writeText(ctx, result); + return; + } + result = String.format("rejectClientByIpPort success! {ip=%s port=%s}, had reject {%s}", ip, port, + NetUtils.addressToString(successRemoteAddrs)); + writeText(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectClientBySubSystemHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectClientBySubSystemHandler.java new file mode 100644 index 0000000000..ac8a8814e6 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/RejectClientBySubSystemHandler.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.lang3.StringUtils; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/rejectClientBySubSystem} endpoint, which is used to reject a client connection that + * matches the provided client subsystem id in a Data Communication Network (DCN). + *

+ * The request must specify the client's subsystem id. + *

+ * Parameters: + *

    + *
  • client's subsystem id: {@code subsystem} | Example: {@code 5023}
  • + *
+ * It uses the {@link EventMeshTcp2Client#serverGoodby2Client} method to close the matching client connection. + * + * @see AbstractHttpHandler + */ + +@EventMeshHttpHandler(path = "/clientManage/rejectClientBySubSystem") +@Slf4j +public class RejectClientBySubSystemHandler extends AbstractHttpHandler { + + private final transient EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public RejectClientBySubSystemHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + private String printClients(Collection clients) { + if (clients == null || clients.isEmpty()) { + return "no session had been closed"; + } + StringBuilder sb = new StringBuilder(); + for (InetSocketAddress addr : clients) { + sb.append(addr).append("|"); + } + return sb.toString(); + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + String result; + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameter from the query string + String subSystem = queryStringInfo.get(EventMeshConstants.MANAGE_SUBSYSTEM); + + // Check the validity of the parameters + if (StringUtils.isBlank(subSystem)) { + result = "params illegal!"; + writeText(ctx, result); + return; + } + + log.info("rejectClientBySubSystem in admin,subsys:{}====================", subSystem); + // Retrieve the mapping between Sessions and their corresponding client address + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + final List successRemoteAddrs = new ArrayList<>(); + try { + if (!sessionMap.isEmpty()) { + // Iterate through the sessionMap to find matching sessions where the client's subsystem id matches the given param + for (Session session : sessionMap.values()) { + // Reject client connection for each matching session found + if (session.getClient().getSubsystem().equals(subSystem)) { + InetSocketAddress addr = EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer.getTcpThreadPoolGroup(), session, + clientSessionGroupMapping); + // Add the remote client address to a list of successfully rejected addresses + if (addr != null) { + successRemoteAddrs.add(addr); + } + } + } + } + } catch (Exception e) { + log.error("clientManage|rejectClientBySubSystem|fail|subSystemId={}", subSystem, e); + result = String.format("rejectClientBySubSystem fail! sessionMap size {%d}, had reject {%s} , {" + + + "subSystemId=%s}, errorMsg : %s", sessionMap.size(), printClients(successRemoteAddrs), + subSystem, e.getMessage()); + writeText(ctx, result); + return; + } + // Serialize the successfully rejected client addresses into output stream + result = String.format("rejectClientBySubSystem success! sessionMap size {%d}, had reject {%s} , {" + + + "subSystemId=%s}", sessionMap.size(), printClients(successRemoteAddrs), subSystem); + writeText(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowClientBySystemHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowClientBySystemHandler.java new file mode 100644 index 0000000000..491789ceb3 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowClientBySystemHandler.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/showClientBySystem} endpoint, which is used to display connected clients information + * under a specific subsystem by subsystem id. + *

+ * Parameters: + *

    + *
  • client's subsystem id: {@code subsystem} | Example: {@code 5023}
  • + *
+ * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/showClientBySystem") +public class ShowClientBySystemHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public ShowClientBySystemHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + StringBuilder result = new StringBuilder(); + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameter from the query string + String subSystem = queryStringInfo.get(EventMeshConstants.MANAGE_SUBSYSTEM); + + String newLine = System.getProperty("line.separator"); + log.info("showClientBySubsys,subsys:{}", subSystem); + // Retrieve the mapping between Sessions and their corresponding client address + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + if (sessionMap != null && !sessionMap.isEmpty()) { + // Iterate through the sessionMap to find matching sessions where the client's subsystem id matches the given param + for (Session session : sessionMap.values()) { + // For each matching session found, append the client's information to the result + if (session.getClient().getSubsystem().equals(subSystem)) { + UserAgent userAgent = session.getClient(); + result.append(String.format("pid=%s | ip=%s | port=%s | path=%s | purpose=%s", + userAgent.getPid(), userAgent.getHost(), userAgent.getPort(), userAgent.getPath(), userAgent.getPurpose())) + .append(newLine); + } + } + } + writeText(ctx, result.toString()); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowClientHandler.java new file mode 100644 index 0000000000..fc288ba7e6 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowClientHandler.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/showClient} endpoint. + *

+ * It is used to query information about all clients connected to the current EventMesh server node and to provide statistics on the number of clients + * in each subsystem. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/showClient") +public class ShowClientHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public ShowClientHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + StringBuilder result = new StringBuilder(); + String newLine = System.getProperty("line.separator"); + log.info("showAllClient================="); + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + + // Store the subsystem and the corresponding client count. + HashMap statMap = new HashMap<>(); + + Map sessionMap = clientSessionGroupMapping.getSessionMap(); + if (!sessionMap.isEmpty()) { + // Iterate through each Session to count the clients in each subsystem. + for (Session session : sessionMap.values()) { + String key = session.getClient().getSubsystem(); + if (!statMap.containsKey(key)) { + statMap.put(key, new AtomicInteger(1)); + } else { + statMap.get(key).incrementAndGet(); + } + } + // Generate the result with the number of clients for each subsystem. + for (Map.Entry entry : statMap.entrySet()) { + result.append(String.format("System=%s | ClientNum=%d", entry.getKey(), entry.getValue().intValue())).append(newLine); + } + } + writeText(ctx, result.toString()); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowListenClientByTopicHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowListenClientByTopicHandler.java new file mode 100644 index 0000000000..266ffbc06d --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/ShowListenClientByTopicHandler.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.NetUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientGroupWrapper; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the HTTP requests of {@code /clientManage/showListenClientByTopic} endpoint, which is used to display clients information + * subscribed to a specific topic. + *

+ * Parameters: + *

    + *
  • Message Topic: {@code topic}
  • + *
+ * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/clientManage/showListenClientByTopic") +public class ShowListenClientByTopicHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public ShowListenClientByTopicHandler(EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void handle(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + StringBuilder result = new StringBuilder(); + String queryString = URI.create(httpRequest.uri()).getQuery(); + Map queryStringInfo = NetUtils.formData2Dic(queryString); + // Extract parameter from the query string + String topic = queryStringInfo.get(EventMeshConstants.MANAGE_TOPIC); + + String newLine = System.getProperty("line.separator"); + log.info("showListeningClientByTopic,topic:{}=================", topic); + // Retrieve the mappings of client subsystem to client group + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap clientGroupMap = clientSessionGroupMapping.getClientGroupMap(); + if (!clientGroupMap.isEmpty()) { + // Iterate through the client group to get matching sessions in the group by given topic + for (ClientGroupWrapper cgw : clientGroupMap.values()) { + Map listenSessions = cgw.getTopic2sessionInGroupMapping().get(topic); + if (listenSessions != null && !listenSessions.isEmpty()) { + result.append(String.format("group:%s", cgw.getGroup())).append(newLine); + // Iterate through the sessions to get each client information + for (Session session : listenSessions.values()) { + UserAgent userAgent = session.getClient(); + result.append(String.format("pid=%s | ip=%s | port=%s | path=%s | version=%s", userAgent.getPid(), userAgent + .getHost(), userAgent.getPort(), userAgent.getPath(), userAgent.getVersion())) + .append(newLine); + } + } + } + } + writeText(ctx, result.toString()); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/TCPClientHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/TCPClientHandler.java new file mode 100644 index 0000000000..429ce426ed --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/TCPClientHandler.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.request.DeleteTCPClientRequest; +import org.apache.eventmesh.runtime.admin.response.v1.GetClientResponse; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /client/tcp} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /tcp}. + *

+ * It is responsible for managing operations on TCP clients, including retrieving the information list of connected TCP clients and deleting TCP + * clients by disconnecting their connections based on the provided host and port. + * + * @see AbstractHttpHandler + */ + +@Slf4j +@EventMeshHttpHandler(path = "/client/tcp") +public class TCPClientHandler extends AbstractHttpHandler { + + private final EventMeshTCPServer eventMeshTCPServer; + + /** + * Constructs a new instance with the provided server instance. + * + * @param eventMeshTCPServer the TCP server instance of EventMesh + */ + public TCPClientHandler( + EventMeshTCPServer eventMeshTCPServer) { + super(); + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + protected void delete(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Parse the request body string into a DeleteTCPClientRequest object + Map body = HttpRequestUtil.parseHttpRequestBody(httpRequest); + Objects.requireNonNull(body, "body can not be null"); + DeleteTCPClientRequest deleteTCPClientRequest = JsonUtils.mapToObject(body, DeleteTCPClientRequest.class); + String host = Objects.requireNonNull(deleteTCPClientRequest).getHost(); + int port = deleteTCPClientRequest.getPort(); + + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + ConcurrentHashMap sessionMap = clientSessionGroupMapping.getSessionMap(); + if (!sessionMap.isEmpty()) { + for (Map.Entry entry : sessionMap.entrySet()) { + // Find the Session object that matches the host and port to be deleted + if (entry.getKey().getHostString().equals(host) && entry.getKey().getPort() == port) { + // Call the serverGoodby2Client method in EventMeshTcp2Client to disconnect the client's connection + EventMeshTcp2Client.serverGoodby2Client( + eventMeshTCPServer.getTcpThreadPoolGroup(), + entry.getValue(), + clientSessionGroupMapping); + } + } + } + + // Set the response headers and send a 200 status code empty response + writeText(ctx, ""); + } + + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + // Get the list of connected TCP clients + ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping(); + Map sessionMap = clientSessionGroupMapping.getSessionMap(); + List getClientResponseList = new ArrayList<>(); + // Convert each Session object to GetClientResponse and add to getClientResponseList + for (Session session : sessionMap.values()) { + UserAgent userAgent = session.getClient(); + GetClientResponse getClientResponse = new GetClientResponse( + Optional.ofNullable(userAgent.getEnv()).orElse(""), + Optional.ofNullable(userAgent.getSubsystem()).orElse(""), + Optional.ofNullable(userAgent.getPath()).orElse(""), + String.valueOf(userAgent.getPid()), + Optional.ofNullable(userAgent.getHost()).orElse(""), + userAgent.getPort(), + Optional.ofNullable(userAgent.getVersion()).orElse(""), + Optional.ofNullable(userAgent.getIdc()).orElse(""), + Optional.ofNullable(userAgent.getGroup()).orElse(""), + Optional.ofNullable(userAgent.getPurpose()).orElse(""), + "TCP"); + getClientResponseList.add(getClientResponse); + } + + // Sort the getClientResponseList by host and port + getClientResponseList.sort((lhs, rhs) -> { + if (lhs.getHost().equals(rhs.getHost())) { + return lhs.getHost().compareTo(rhs.getHost()); + } + return Integer.compare(rhs.getPort(), lhs.getPort()); + }); + + // Convert getClientResponseList to JSON and send the response + String result = JsonUtils.toJSONString(getClientResponseList); + writeJson(ctx, result); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/TopicHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/TopicHandler.java new file mode 100644 index 0000000000..b536150354 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v1/TopicHandler.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v1; + +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.request.CreateTopicRequest; +import org.apache.eventmesh.runtime.admin.request.DeleteTopicRequest; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.plugin.MQAdminWrapper; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * This class handles the {@code /topic} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /topic}, including the "Create Topic" + * and "Remove" buttons. + *

+ * It provides functionality for managing topics, including retrieving the list of topics (GET), creating a new topic (POST), and deleting an existing + * topic (DELETE). + *

+ * An instance of {@link MQAdminWrapper} is used to interact with the messaging system. + * + * @see AbstractHttpHandler + * @see MQAdminWrapper + */ + +@Slf4j +@EventMeshHttpHandler(path = "/topic") +public class TopicHandler extends AbstractHttpHandler { + + private final MQAdminWrapper admin; + + /** + * Constructs a new instance with the specified connector plugin type. + * + * @param connectorPluginType The name of event storage connector plugin. + */ + public TopicHandler( + String connectorPluginType) { + super(); + admin = new MQAdminWrapper(connectorPluginType); + try { + admin.init(null); + } catch (Exception ignored) { + log.info("failed to initialize MQAdminWrapper"); + } + } + + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + List topicList = admin.getTopic(); + String result = JsonUtils.toJSONString(topicList); + writeJson(ctx, result); + } + + @Override + protected void post(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + Map body = HttpRequestUtil.parseHttpRequestBody(httpRequest); + Objects.requireNonNull(body, "body can not be null"); + HttpHeaders responseHeaders = new DefaultHttpHeaders(); + responseHeaders.add(EventMeshConstants.CONTENT_TYPE, EventMeshConstants.APPLICATION_JSON); + responseHeaders.add(EventMeshConstants.HANDLER_ORIGIN, "*"); + CreateTopicRequest createTopicRequest = JsonUtils.mapToObject(body, CreateTopicRequest.class); + String topicName = Objects.requireNonNull(createTopicRequest).getName(); + admin.createTopic(topicName); + writeText(ctx, ""); + } + + @Override + protected void delete(HttpRequest httpRequest, ChannelHandlerContext ctx) throws Exception { + Map body = HttpRequestUtil.parseHttpRequestBody(httpRequest); + Objects.requireNonNull(body, "body can not be null"); + HttpHeaders responseHeaders = new DefaultHttpHeaders(); + responseHeaders.add(EventMeshConstants.CONTENT_TYPE, EventMeshConstants.APPLICATION_JSON); + responseHeaders.add(EventMeshConstants.HANDLER_ORIGIN, "*"); + DeleteTopicRequest deleteTopicRequest = JsonUtils.mapToObject(body, DeleteTopicRequest.class); + String topicName = Objects.requireNonNull(deleteTopicRequest).getName(); + admin.deleteTopic(topicName); + writeText(ctx, ""); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v2/ConfigurationHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v2/ConfigurationHandler.java new file mode 100644 index 0000000000..234e0e79cb --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/handler/v2/ConfigurationHandler.java @@ -0,0 +1,234 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler.v2; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.runtime.admin.handler.AbstractHttpHandler; +import org.apache.eventmesh.runtime.admin.response.Result; +import org.apache.eventmesh.runtime.admin.response.v2.GetConfigurationResponse; +import org.apache.eventmesh.runtime.common.EventMeshHttpHandler; +import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; +import org.apache.eventmesh.runtime.constants.EventMeshVersion; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.filter.Filter; +import com.alibaba.fastjson2.filter.NameFilter; +import com.alibaba.fastjson2.filter.PropertyFilter; +import com.alibaba.fastjson2.filter.ValueFilter; + +import lombok.extern.slf4j.Slf4j; + +import inet.ipaddr.IPAddress; + +/** + * This class handles the {@code /v2/configuration} endpoint, corresponding to the {@code eventmesh-dashboard} path {@code /}. + *

+ * This handler is responsible for retrieving the current configuration information of the EventMesh node, including service name, service + * environment, and listening ports for various protocols. + */ + +@Slf4j +@EventMeshHttpHandler(path = "/v2/configuration") +public class ConfigurationHandler extends AbstractHttpHandler { + + private final CommonConfiguration commonConfiguration; + private final EventMeshTCPConfiguration eventMeshTCPConfiguration; + private final EventMeshHTTPConfiguration eventMeshHTTPConfiguration; + private final EventMeshGrpcConfiguration eventMeshGrpcConfiguration; + + /** + * Constructs a new instance with the provided configurations. + * + * @param eventMeshTCPConfiguration the TCP configuration for EventMesh + * @param eventMeshHTTPConfiguration the HTTP configuration for EventMesh + * @param eventMeshGrpcConfiguration the gRPC configuration for EventMesh + */ + public ConfigurationHandler( + CommonConfiguration commonConfiguration, + EventMeshTCPConfiguration eventMeshTCPConfiguration, + EventMeshHTTPConfiguration eventMeshHTTPConfiguration, + EventMeshGrpcConfiguration eventMeshGrpcConfiguration) { + super(); + this.commonConfiguration = commonConfiguration; + this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; + this.eventMeshHTTPConfiguration = eventMeshHTTPConfiguration; + this.eventMeshGrpcConfiguration = eventMeshGrpcConfiguration; + } + + /** + * Parameters: + *

    + *
  • + * {@code format}: String; Optional, DefaultValue: {@code properties}, SelectableValue: {@code bean}. + *

    When {@code properties}, the field names are returned in Properties format; + *

    When {@code bean}, the field names themselves are used as json keys. + *

  • + *
  • + * {@code configs}: String; Optional, DefaultValue: {@code exclusive}, SelectableValue: {@code all}. + *

    When {@code exclusive}, protocol-specific configurations will only contain protocol-exclusive fields + * and won't contain any {@link CommonConfiguration} fields; + *

    When {@code all}, protocol-specific configurations will contain all fields, including those in {@link CommonConfiguration}. + *

  • + *
+ */ + @Override + protected void get(HttpRequest httpRequest, ChannelHandlerContext ctx) { + String format = HttpRequestUtil.getQueryParam(httpRequest, "format", "properties"); + String configs = HttpRequestUtil.getQueryParam(httpRequest, "configs", "exclusive"); + + List filters = new ArrayList<>(); + switch (configs) { + case "exclusive": + filters.add(new SuperClassFieldFilter()); + break; + case "all": break; + default: + throw new IllegalArgumentException("Invalid param 'configs': " + configs); + } + switch (format) { + case "properties": + filters.add(new ConfigFieldFilter()); + break; + case "bean": break; + default: + throw new IllegalArgumentException("Invalid param 'format': " + format); + } + filters.add(new IPAddressToStringFilter()); + + GetConfigurationResponse getConfigurationResponse = new GetConfigurationResponse( + commonConfiguration, + eventMeshTCPConfiguration, + eventMeshHTTPConfiguration, + eventMeshGrpcConfiguration, + EventMeshVersion.getCurrentVersionDesc() + ); + String json = JSON.toJSONString(Result.success(getConfigurationResponse), filters.toArray(new Filter[0])); + writeJson(ctx, json); + } + + /** + * For each member of configuration classes, + * the value of the {@link ConfigField} annotation for each field is obtained through reflection, + * and then concatenated with the configuration prefix in the {@link Config} annotation to serve as the JSON key for this field. + *

+ * When the {@code name} is a member that only exists in the superclass, it will be searched for in the {@link CommonConfiguration} class. + *

+ * If a field does not have a {@link ConfigField} annotation or the value of the {@link ConfigField} annotation is empty, + * this field will be added to the JSON with the field name as the key, rather than in properties format. + */ + static class ConfigFieldFilter implements NameFilter { + @Override + public String process(Object object, String name, Object value) { + try { + Field field = findFieldInClassHierarchy(object.getClass(), name); + if (field != null && field.isAnnotationPresent(ConfigField.class)) { + ConfigField configField = field.getAnnotation(ConfigField.class); + String fieldAnnotationValue = configField.field(); + if (!fieldAnnotationValue.isEmpty()) { + Config config = object.getClass().getAnnotation(Config.class); + String prefix = config.prefix(); + return prefix + "." + fieldAnnotationValue; + } + } + } catch (NoSuchFieldException e) { + log.error("Failed to get field {} from object {}", name, object, e); + } + return name; + } + + private Field findFieldInClassHierarchy(Class clazz, String fieldName) throws NoSuchFieldException { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + Class superclass = clazz.getSuperclass(); + if (superclass == null) { + throw e; + } else { + return findFieldInClassHierarchy(superclass, fieldName); + } + } + } + } + + /** + * For each member of {@link EventMeshTCPConfiguration}, {@link EventMeshHTTPConfiguration}, and {@link EventMeshGrpcConfiguration}, + * if the {@code name} is a member that exists in {@link CommonConfiguration} class, it will be skipped. + */ + static class SuperClassFieldFilter implements PropertyFilter { + @Override + public boolean apply(Object object, String name, Object value) { + try { + Field field = findFieldInClassNonHierarchy(object.getClass(), name); + return field != null; + } catch (NoSuchFieldException e) { + log.error("Failed to get field {} from object {}", name, object, e); + } + return true; + } + + /** + * If a field of a subclass exists in the superclass, return null, causing FastJSON to skip this field. + */ + private Field findFieldInClassNonHierarchy(Class clazz, String fieldName) throws NoSuchFieldException { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + Class superclass = clazz.getSuperclass(); + if (superclass == null) { + throw e; + } else { + return null; + } + } + } + } + + /** + * {@link IPAddress} can't be serialized directly by FastJSON, + * so this filter converts {@link IPAddress} objects to their string representation. + */ + static class IPAddressToStringFilter implements ValueFilter { + @Override + public Object apply(Object object, String name, Object value) { + if (name.equals("eventMeshIpv4BlackList") || name.equals("eventMeshIpv6BlackList")) { + if (value instanceof List) { + List ipList = new ArrayList<>(); + for (Object o : (List) value) { + if (o instanceof IPAddress) { + ipList.add(((IPAddress) o).toNormalizedString()); + } + } + return ipList; + } + } + return value; + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/CreateTopicRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/CreateTopicRequest.java new file mode 100644 index 0000000000..28f121a796 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/CreateTopicRequest.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.request; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class CreateTopicRequest { + + private String name; + + @JsonCreator + public CreateTopicRequest(@JsonProperty("name") String name) { + super(); + this.name = name; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteGrpcClientRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteGrpcClientRequest.java new file mode 100644 index 0000000000..e8eb265584 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteGrpcClientRequest.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.request; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class DeleteGrpcClientRequest { + + private String url; + + @JsonCreator + public DeleteGrpcClientRequest(@JsonProperty("url") String url) { + super(); + this.url = url; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteHTTPClientRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteHTTPClientRequest.java new file mode 100644 index 0000000000..1561bb3911 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteHTTPClientRequest.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.request; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class DeleteHTTPClientRequest { + + private String url; + + @JsonCreator + public DeleteHTTPClientRequest(@JsonProperty("url") String url) { + super(); + this.url = url; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteTCPClientRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteTCPClientRequest.java new file mode 100644 index 0000000000..07ff93551c --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteTCPClientRequest.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.request; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class DeleteTCPClientRequest { + + private String host; + + private int port; + + @JsonCreator + public DeleteTCPClientRequest( + @JsonProperty("host") String host, + @JsonProperty("port") int port) { + + super(); + this.host = host; + this.port = port; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteTopicRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteTopicRequest.java new file mode 100644 index 0000000000..aa6d29339c --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/request/DeleteTopicRequest.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.request; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class DeleteTopicRequest { + + private String name; + + @JsonCreator + public DeleteTopicRequest(@JsonProperty("name") String name) { + super(); + this.name = name; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/Result.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/Result.java new file mode 100644 index 0000000000..f8ba718e94 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/Result.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * A RESTful response DTO. + */ + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Result { + + private T data; + + private String message; + + public Result(String message) { + this.message = message; + } + + /** + * The request is valid and the result is wrapped in {@link Result}. + */ + public static Result success() { + return new Result<>("Success"); + } + + public static Result success(T data) { + return new Result<>(data, "Success"); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetClientResponse.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetClientResponse.java new file mode 100644 index 0000000000..42c21a0d5f --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetClientResponse.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.response.v1; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class GetClientResponse { + + private String env; + private String subsystem; + private String url; + private String pid; + private String host; + private int port; + private String version; + private String idc; + private String group; + private String purpose; + private String protocol; + + @JsonCreator + public GetClientResponse( + @JsonProperty("env") String env, + @JsonProperty("subsystem") String subsystem, + @JsonProperty("url") String url, + @JsonProperty("pid") String pid, + @JsonProperty("host") String host, + @JsonProperty("port") int port, + @JsonProperty("version") String version, + @JsonProperty("idc") String idc, + @JsonProperty("group") String group, + @JsonProperty("purpose") String purpose, + @JsonProperty("protocol") String protocol) { + + super(); + this.env = env; + this.subsystem = subsystem; + this.url = url; + this.pid = pid; + this.host = host; + this.port = port; + this.idc = idc; + this.group = group; + this.purpose = purpose; + this.version = version; + this.protocol = protocol; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetConfigurationResponse.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetConfigurationResponse.java new file mode 100644 index 0000000000..bdcbb5da67 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetConfigurationResponse.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.response.v1; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class GetConfigurationResponse { + + private String eventMeshEnv; + private String eventMeshIDC; + private String eventMeshCluster; + private String eventMeshServerIp; + private boolean eventMeshServerSecurityEnable; + private boolean eventMeshServerRegistryEnable; + private String eventMeshName; + private String sysID; + private String namesrvAddr; + + private int eventMeshTcpServerPort; + + private int eventMeshHttpServerPort; + private boolean eventMeshHttpServerUseTls; + + private int eventMeshGrpcServerPort; + private boolean eventMeshGrpcServerUseTls; + + @JsonCreator + public GetConfigurationResponse( + // Common Configuration + @JsonProperty("sysID") String sysID, + @JsonProperty("namesrvAddr") String namesrvAddr, + @JsonProperty("eventMeshEnv") String eventMeshEnv, + @JsonProperty("eventMeshIDC") String eventMeshIDC, + @JsonProperty("eventMeshCluster") String eventMeshCluster, + @JsonProperty("eventMeshServerIp") String eventMeshServerIp, + @JsonProperty("eventMeshName") String eventMeshName, + @JsonProperty("eventMeshServerSecurityEnable") boolean eventMeshServerSecurityEnable, + @JsonProperty("eventMeshServerRegistryEnable") boolean eventMeshServerRegistryEnable, + + // TCP Configuration + @JsonProperty("eventMeshTcpServerPort") int eventMeshTcpServerPort, + + // HTTP Configuration + @JsonProperty("eventMeshHttpServerPort") int eventMeshHttpServerPort, + @JsonProperty("eventMeshHttpServerUseTls") boolean eventMeshHttpServerUseTls, + + // gRPC Configuration + @JsonProperty("eventMeshGrpcServerPort") int eventMeshGrpcServerPort, + @JsonProperty("eventMeshGrpcServerUseTls") boolean eventMeshGrpcServerUseTls) { + + super(); + this.sysID = sysID; + this.namesrvAddr = namesrvAddr; + this.eventMeshEnv = eventMeshEnv; + this.eventMeshIDC = eventMeshIDC; + this.eventMeshCluster = eventMeshCluster; + this.eventMeshServerIp = eventMeshServerIp; + this.eventMeshName = eventMeshName; + this.eventMeshServerSecurityEnable = eventMeshServerSecurityEnable; + this.eventMeshServerRegistryEnable = eventMeshServerRegistryEnable; + + this.eventMeshTcpServerPort = eventMeshTcpServerPort; + + this.eventMeshHttpServerPort = eventMeshHttpServerPort; + this.eventMeshHttpServerUseTls = eventMeshHttpServerUseTls; + + this.eventMeshGrpcServerPort = eventMeshGrpcServerPort; + this.eventMeshGrpcServerUseTls = eventMeshGrpcServerUseTls; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetMetricsResponse.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetMetricsResponse.java new file mode 100644 index 0000000000..16f1e232f3 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetMetricsResponse.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.response.v1; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class GetMetricsResponse { + + // HTTP Metrics + private double maxHTTPTPS; + private double avgHTTPTPS; + private long maxHTTPCost; + private double avgHTTPCost; + private double avgHTTPBodyDecodeCost; + private long httpDiscard; + private double maxBatchSendMsgTPS; + private double avgBatchSendMsgTPS; + private long sendBatchMsgNumSum; + private long sendBatchMsgFailNumSum; + private double sendBatchMsgFailRate; + private long sendBatchMsgDiscardNumSum; + private double maxSendMsgTPS; + private double avgSendMsgTPS; + private long sendMsgNumSum; + private long sendMsgFailNumSum; + private double sendMsgFailRate; + private long replyMsgNumSum; + private long replyMsgFailNumSum; + private double maxPushMsgTPS; + private double avgPushMsgTPS; + private long pushHTTPMsgNumSum; + private long pushHTTPMsgFailNumSum; + private double pushHTTPMsgFailRate; + private double maxHTTPPushLatency; + private double avgHTTPPushLatency; + private long batchMsgQueueSize; + private long sendMsgQueueSize; + private long pushMsgQueueSize; + private long retryHTTPQueueSize; + private double avgBatchSendMsgCost; + private double avgSendMsgCost; + private double avgReplyMsgCost; + + // TCP Metrics + private int retryTCPQueueSize; + private double client2eventMeshTCPTPS; + private double eventMesh2mqTCPTPS; + private double mq2eventMeshTCPTPS; + private double eventMesh2clientTCPTPS; + private double allTCPTPS; + private long allTCPConnections; + private long subTopicTCPNum; + + + @JsonCreator + public GetMetricsResponse( + // HTTP Metrics + @JsonProperty("maxHTTPTPS") double maxHTTPTPS, + @JsonProperty("avgHTTPTPS") double avgHTTPTPS, + @JsonProperty("maxHTTPCost") long maxHTTPCost, + @JsonProperty("avgHTTPCost") double avgHTTPCost, + @JsonProperty("avgHTTPBodyDecodeCost") double avgHTTPBodyDecodeCost, + @JsonProperty("httpDiscard") long httpDiscard, + @JsonProperty("maxBatchSendMsgTPS") double maxBatchSendMsgTPS, + @JsonProperty("avgBatchSendMsgTPS") double avgBatchSendMsgTPS, + @JsonProperty("sendBatchMsgNumSum") long sendBatchMsgNumSum, + @JsonProperty("sendBatchMsgFailNumSum") long sendBatchMsgFailNumSum, + @JsonProperty("sendBatchMsgFailRate") double sendBatchMsgFailRate, + @JsonProperty("sendBatchMsgDiscardNumSum") long sendBatchMsgDiscardNumSum, + @JsonProperty("maxSendMsgTPS") double maxSendMsgTPS, + @JsonProperty("avgSendMsgTPS") double avgSendMsgTPS, + @JsonProperty("sendMsgNumSum") long sendMsgNumSum, + @JsonProperty("sendMsgFailNumSum") long sendMsgFailNumSum, + @JsonProperty("sendMsgFailRate") double sendMsgFailRate, + @JsonProperty("replyMsgNumSum") long replyMsgNumSum, + @JsonProperty("replyMsgFailNumSum") long replyMsgFailNumSum, + @JsonProperty("maxPushMsgTPS") double maxPushMsgTPS, + @JsonProperty("avgPushMsgTPS") double avgPushMsgTPS, + @JsonProperty("pushHTTPMsgNumSum") long pushHTTPMsgNumSum, + @JsonProperty("pushHTTPMsgFailNumSum") long pushHTTPMsgFailNumSum, + @JsonProperty("pushHTTPMsgFailRate") double pushHTTPMsgFailRate, + @JsonProperty("maxHTTPPushLatency") double maxHTTPPushLatency, + @JsonProperty("avgHTTPPushLatency") double avgHTTPPushLatency, + @JsonProperty("batchMsgQueueSize") long batchMsgQueueSize, + @JsonProperty("sendMsgQueueSize") long sendMsgQueueSize, + @JsonProperty("pushMsgQueueSize") long pushMsgQueueSize, + @JsonProperty("retryHTTPQueueSize") long retryHTTPQueueSize, + @JsonProperty("avgBatchSendMsgCost") double avgBatchSendMsgCost, + @JsonProperty("avgSendMsgCost") double avgSendMsgCost, + @JsonProperty("avgReplyMsgCost") double avgReplyMsgCost, + // TCP Metrics + @JsonProperty("retryTCPQueueSize") int retryTCPQueueSize, + @JsonProperty("client2eventMeshTCPTPS") double client2eventMeshTCPTPS, + @JsonProperty("eventMesh2mqTCPTPS") double eventMesh2mqTCPTPS, + @JsonProperty("mq2eventMeshTCPTPS") double mq2eventMeshTCPTPS, + @JsonProperty("eventMesh2clientTCPTPS") double eventMesh2clientTCPTPS, + @JsonProperty("allTCPTPS") double allTCPTPS, + @JsonProperty("allTCPConnections") long allTCPConnections, + @JsonProperty("subTopicTCPNum") long subTopicTCPNum) { + + super(); + this.maxHTTPTPS = maxHTTPTPS; + this.avgHTTPTPS = avgHTTPTPS; + this.maxHTTPCost = maxHTTPCost; + this.avgHTTPCost = avgHTTPCost; + this.avgHTTPBodyDecodeCost = avgHTTPBodyDecodeCost; + this.httpDiscard = httpDiscard; + this.maxBatchSendMsgTPS = maxBatchSendMsgTPS; + this.avgBatchSendMsgTPS = avgBatchSendMsgTPS; + this.sendBatchMsgNumSum = sendBatchMsgNumSum; + this.sendBatchMsgFailNumSum = sendBatchMsgFailNumSum; + this.sendBatchMsgFailRate = sendBatchMsgFailRate; + this.sendBatchMsgDiscardNumSum = sendBatchMsgDiscardNumSum; + this.maxSendMsgTPS = maxSendMsgTPS; + this.avgSendMsgTPS = avgSendMsgTPS; + this.sendMsgNumSum = sendMsgNumSum; + this.sendMsgFailNumSum = sendMsgFailNumSum; + this.sendMsgFailRate = sendMsgFailRate; + this.replyMsgNumSum = replyMsgNumSum; + this.replyMsgFailNumSum = replyMsgFailNumSum; + this.maxPushMsgTPS = maxPushMsgTPS; + this.avgPushMsgTPS = avgPushMsgTPS; + this.pushHTTPMsgNumSum = pushHTTPMsgNumSum; + this.pushHTTPMsgFailNumSum = pushHTTPMsgFailNumSum; + this.pushHTTPMsgFailRate = pushHTTPMsgFailRate; + this.maxHTTPPushLatency = maxHTTPPushLatency; + this.avgHTTPPushLatency = avgHTTPPushLatency; + this.batchMsgQueueSize = batchMsgQueueSize; + this.sendMsgQueueSize = sendMsgQueueSize; + this.pushMsgQueueSize = pushMsgQueueSize; + this.retryHTTPQueueSize = retryHTTPQueueSize; + this.avgBatchSendMsgCost = avgBatchSendMsgCost; + this.avgSendMsgCost = avgSendMsgCost; + this.avgReplyMsgCost = avgReplyMsgCost; + this.retryTCPQueueSize = retryTCPQueueSize; + this.client2eventMeshTCPTPS = client2eventMeshTCPTPS; + this.eventMesh2mqTCPTPS = eventMesh2mqTCPTPS; + this.mq2eventMeshTCPTPS = mq2eventMeshTCPTPS; + this.eventMesh2clientTCPTPS = eventMesh2clientTCPTPS; + this.allTCPTPS = allTCPTPS; + this.allTCPConnections = allTCPConnections; + this.subTopicTCPNum = subTopicTCPNum; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetRegistryResponse.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetRegistryResponse.java new file mode 100644 index 0000000000..698b6458d0 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v1/GetRegistryResponse.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.response.v1; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class GetRegistryResponse { + + private String eventMeshClusterName; + private String eventMeshName; + private String endpoint; + private long lastUpdateTimestamp; + private String metadata; + + @JsonCreator + public GetRegistryResponse( + @JsonProperty("eventMeshClusterName") String eventMeshClusterName, + @JsonProperty("eventMeshName") String eventMeshName, + @JsonProperty("endpoint") String endpoint, + @JsonProperty("lastUpdateTimestamp") long lastUpdateTimestamp, + @JsonProperty("metadata") String metadata) { + super(); + this.eventMeshClusterName = eventMeshClusterName; + this.eventMeshName = eventMeshName; + this.endpoint = endpoint; + this.lastUpdateTimestamp = lastUpdateTimestamp; + this.metadata = metadata; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v2/GetConfigurationResponse.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v2/GetConfigurationResponse.java new file mode 100644 index 0000000000..5ae9eeb2d3 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/admin/response/v2/GetConfigurationResponse.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.response.v2; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GetConfigurationResponse { + + private CommonConfiguration commonConfiguration; + private EventMeshTCPConfiguration eventMeshTCPConfiguration; + private EventMeshHTTPConfiguration eventMeshHTTPConfiguration; + private EventMeshGrpcConfiguration eventMeshGrpcConfiguration; + private String eventMeshVersion; +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractHTTPServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractHTTPServer.java index 165e673eb7..6c0cb4742c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractHTTPServer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractHTTPServer.java @@ -18,37 +18,34 @@ package org.apache.eventmesh.runtime.boot; import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.CommonConfiguration; import org.apache.eventmesh.common.protocol.http.HttpCommand; -import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; import org.apache.eventmesh.common.protocol.http.body.Body; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.common.protocol.http.header.Header; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.runtime.common.Pair; +import org.apache.eventmesh.common.utils.AssertUtils; import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.processor.HandlerService; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.EventProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.apache.eventmesh.runtime.metrics.http.HTTPMetricsServer; -import org.apache.eventmesh.runtime.trace.TraceUtils; +import org.apache.eventmesh.runtime.metrics.http.EventMeshHttpMetricsManager; +import org.apache.eventmesh.runtime.util.HttpRequestUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.TraceUtils; +import org.apache.eventmesh.runtime.util.Utils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.entity.ContentType; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; @@ -57,22 +54,19 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; +import io.netty.channel.epoll.EpollServerSocketChannel; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; @@ -84,150 +78,138 @@ import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; -import io.netty.handler.codec.http.QueryStringDecoder; -import io.netty.handler.codec.http.multipart.Attribute; import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import io.netty.handler.codec.http.multipart.DiskAttribute; -import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; -import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.ssl.SslHandler; import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; import io.netty.util.ReferenceCountUtil; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; -import com.fasterxml.jackson.core.type.TypeReference; -import com.google.common.base.Preconditions; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +/** + * HTTP serves as the runtime module server for the protocol + */ +@Slf4j public abstract class AbstractHTTPServer extends AbstractRemotingServer { - public Logger httpServerLogger = LoggerFactory.getLogger(this.getClass()); - - public Logger httpLogger = LoggerFactory.getLogger("http"); + private final transient EventMeshHTTPConfiguration eventMeshHttpConfiguration; - protected HandlerService handlerService; + @Getter + @Setter + private EventMeshHttpMetricsManager eventMeshHttpMetricsManager; - public HTTPMetricsServer metrics; + private static final DefaultHttpDataFactory DEFAULT_HTTP_DATA_FACTORY = new DefaultHttpDataFactory(false); - public DefaultHttpDataFactory defaultHttpDataFactory = new DefaultHttpDataFactory(false); + static { + DiskAttribute.deleteOnExitTemporaryFile = false; + } - private AtomicBoolean started = new AtomicBoolean(false); + protected final transient AtomicBoolean started = new AtomicBoolean(false); - private boolean useTLS; + @Getter + private final transient boolean useTLS; - public Boolean useTrace = false; //Determine whether trace is enabled + @Getter + @Setter + private Boolean useTrace = false; // Determine whether trace is enabled - private EventMeshHTTPConfiguration eventMeshHttpConfiguration; + private static final int MAX_CONNECTIONS = 20_000; - public ThreadPoolExecutor asyncContextCompleteHandler = - ThreadPoolFactory.createThreadPoolExecutor(10, 10, "EventMesh-http-asyncContext-"); + /** + * key: request code + */ + protected final transient Map httpRequestProcessorTable = + new ConcurrentHashMap<>(64); - static { - DiskAttribute.deleteOnExitTemporaryFile = false; - } + private HttpConnectionHandler httpConnectionHandler; + private HttpDispatcher httpDispatcher; - protected final Map> - processorTable = new HashMap<>(64); + @Setter + @Getter + private HandlerService handlerService; + private final transient ThreadPoolExecutor asyncContextCompleteHandler = + ThreadPoolFactory.createThreadPoolExecutor(10, 10, "EventMesh-http-asyncContext"); - protected final Map> - eventProcessorTable = new HashMap<>(64); + @Getter + private final HTTPThreadPoolGroup httpThreadPoolGroup; - public AbstractHTTPServer(int port, boolean useTLS, EventMeshHTTPConfiguration eventMeshHttpConfiguration) { - this.port = port; + public AbstractHTTPServer(final int port, final boolean useTLS, + final EventMeshHTTPConfiguration eventMeshHttpConfiguration) { + super(); + this.setPort(port); this.useTLS = useTLS; this.eventMeshHttpConfiguration = eventMeshHttpConfiguration; + this.httpThreadPoolGroup = new HTTPThreadPoolGroup(eventMeshHttpConfiguration); } - public void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status); - HttpHeaders responseHeaders = response.headers(); - responseHeaders.add( - HttpHeaderNames.CONTENT_TYPE, String.format("text/plain; charset=%s", EventMeshConstants.DEFAULT_CHARSET) - ); - responseHeaders.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); - responseHeaders.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + protected void initSharableHandlers() { + httpConnectionHandler = new HttpConnectionHandler(); + httpDispatcher = new HttpDispatcher(); + } - ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + public void init() throws Exception { + super.init("eventMesh-http"); + initProducerManager(); + httpThreadPoolGroup.initThreadPool(); } - public void sendResponse(ChannelHandlerContext ctx, DefaultFullHttpResponse response) { - ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { - if (!f.isSuccess()) { - httpLogger.warn("send response to [{}] fail, will close this channel", - RemotingHelper.parseChannelRemoteAddr(f.channel())); - f.channel().close(); - } - }); + @Override + public CommonConfiguration getConfiguration() { + return eventMeshHttpConfiguration; } @Override public void start() throws Exception { - super.start(); - Runnable r = () -> { - ServerBootstrap b = new ServerBootstrap(); - SSLContext sslContext = useTLS ? SSLContextFactory.getSslContext() : null; - b.group(this.bossGroup, this.workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new HttpsServerInitializer(sslContext)) - .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE); + + initSharableHandlers(); + + final Thread thread = new Thread(() -> { + final ServerBootstrap bootstrap = new ServerBootstrap(); try { - httpServerLogger.info("HTTPServer[port={}] started......", this.port); - ChannelFuture future = b.bind(this.port).sync(); - future.channel().closeFuture().sync(); + bootstrap.group(this.getBossGroup(), this.getIoGroup()) + .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) + .childHandler(new HttpsServerInitializer(useTLS ? SSLContextFactory.getSslContext(eventMeshHttpConfiguration) : null)) + .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE); + + log.info("HTTPServer[port={}] started.", this.getPort()); + + bootstrap.bind(this.getPort()) + .channel() + .closeFuture() + .sync(); } catch (Exception e) { - httpServerLogger.error("HTTPServer start Err!", e); + log.error("HTTPServer start error!", e); try { shutdown(); - } catch (Exception e1) { - httpServerLogger.error("HTTPServer shutdown Err!", e); + } catch (Exception ex) { + log.error("HTTPServer shutdown error!", ex); } + System.exit(-1); } - }; - - Thread t = new Thread(r, "EventMesh-http-server"); - t.start(); + }, "EventMesh-http-server"); + thread.setDaemon(true); + thread.start(); started.compareAndSet(false, true); } - @Override - public void init(String threadPrefix) throws Exception { - super.init(threadPrefix); - } - @Override public void shutdown() throws Exception { super.shutdown(); + httpThreadPoolGroup.shutdownThreadPool(); started.compareAndSet(true, false); } - public void registerProcessor(Integer requestCode, HttpRequestProcessor processor, ThreadPoolExecutor executor) { - Preconditions.checkState(ObjectUtils.allNotNull(requestCode), "requestCode can't be null"); - Preconditions.checkState(ObjectUtils.allNotNull(processor), "processor can't be null"); - Preconditions.checkState(ObjectUtils.allNotNull(executor), "executor can't be null"); - Pair pair = new Pair<>(processor, executor); - this.processorTable.put(requestCode.toString(), pair); - } - - public void registerProcessor(String requestURI, EventProcessor processor, ThreadPoolExecutor executor) { - Preconditions.checkState(ObjectUtils.allNotNull(requestURI), "requestURI can't be null"); - Preconditions.checkState(ObjectUtils.allNotNull(processor), "processor can't be null"); - Preconditions.checkState(ObjectUtils.allNotNull(executor), "executor can't be null"); - Pair pair = new Pair<>(processor, executor); - this.eventProcessorTable.put(requestURI, pair); - } - - private Map parseHttpHeader(HttpRequest fullReq) { - Map headerParam = new HashMap<>(); - for (String key : fullReq.headers().names()) { - if (StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_TYPE.toString(), key) - || StringUtils.equalsIgnoreCase(HttpHeaderNames.ACCEPT_ENCODING.toString(), key) - || StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_LENGTH.toString(), key)) { - continue; - } - headerParam.put(key, fullReq.headers().get(key)); - } - return headerParam; + /** + * Registers the processors required by the runtime module + */ + public void registerProcessor(final Integer requestCode, final HttpRequestProcessor processor) { + AssertUtils.notNull(requestCode, "requestCode can't be null"); + AssertUtils.notNull(processor, "processor can't be null"); + this.httpRequestProcessorTable.putIfAbsent(requestCode.toString(), processor); } /** @@ -236,41 +218,47 @@ private Map parseHttpHeader(HttpRequest fullReq) { * @param httpRequest * @return if request is validated return null else return error status */ - private HttpResponseStatus validateHttpRequest(HttpRequest httpRequest) { + private HttpResponseStatus validateHttpRequest(final HttpRequest httpRequest) { if (!started.get()) { return HttpResponseStatus.SERVICE_UNAVAILABLE; } + if (!httpRequest.decoderResult().isSuccess()) { return HttpResponseStatus.BAD_REQUEST; } + if (!HttpMethod.GET.equals(httpRequest.method()) && !HttpMethod.POST.equals(httpRequest.method())) { return HttpResponseStatus.METHOD_NOT_ALLOWED; } - final String protocolVersion = httpRequest.headers().get(ProtocolKey.VERSION); - if (!ProtocolVersion.contains(protocolVersion)) { + + if (!ProtocolVersion.contains(httpRequest.headers().get(ProtocolKey.VERSION))) { return HttpResponseStatus.BAD_REQUEST; } + return null; } - /** - * Inject ip and protocol version, if the protocol version is empty, set default to {@link ProtocolVersion#V1}. - * - * @param ctx - * @param httpRequest - */ - private void preProcessHttpRequestHeader(ChannelHandlerContext ctx, HttpRequest httpRequest) { - long startTime = System.currentTimeMillis(); - HttpHeaders requestHeaders = httpRequest.headers(); - requestHeaders.set(ProtocolKey.ClientInstanceKey.IP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel())); - - String protocolVersion = httpRequest.headers().get(ProtocolKey.VERSION); - if (StringUtils.isBlank(protocolVersion)) { - requestHeaders.set(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); - } - requestHeaders.set(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, startTime); - requestHeaders.set(EventMeshConstants.REQ_SEND_EVENTMESH_IP, eventMeshHttpConfiguration.eventMeshServerIp); + public void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status) { + final FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status); + final HttpHeaders responseHeaders = response.headers(); + responseHeaders.add( + HttpHeaderNames.CONTENT_TYPE, String.format("text/plain; charset=%s", EventMeshConstants.DEFAULT_CHARSET)); + responseHeaders.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + responseHeaders.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + }); + } + + public void sendResponse(final ChannelHandlerContext ctx, final DefaultFullHttpResponse response) { + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { + if (!f.isSuccess()) { + log.warn("send response to [{}] fail, will close this channel", RemotingHelper.parseChannelRemoteAddr(f.channel())); + f.channel().close(); + } + }); + }); } /** @@ -279,34 +267,28 @@ private void preProcessHttpRequestHeader(ChannelHandlerContext ctx, HttpRequest * @param httpRequest * @return */ - private Map parseHttpRequestBody(HttpRequest httpRequest) throws IOException { - final long bodyDecodeStart = System.currentTimeMillis(); - Map httpRequestBody = new HashMap<>(); - - if (HttpMethod.GET.equals(httpRequest.method())) { - QueryStringDecoder getDecoder = new QueryStringDecoder(httpRequest.uri()); - getDecoder.parameters().forEach((key, value) -> httpRequestBody.put(key, value.get(0))); - } else if (HttpMethod.POST.equals(httpRequest.method())) { - HttpPostRequestDecoder decoder = - new HttpPostRequestDecoder(defaultHttpDataFactory, httpRequest); - for (InterfaceHttpData parm : decoder.getBodyHttpDatas()) { - if (parm.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) { - Attribute data = (Attribute) parm; - httpRequestBody.put(data.getName(), data.getValue()); - } - } - decoder.destroy(); - } - metrics.getSummaryMetrics().recordDecodeTimeCost(System.currentTimeMillis() - bodyDecodeStart); - return httpRequestBody; + private Map parseHttpRequestBody(final HttpRequest httpRequest) throws IOException { + return HttpRequestUtil.parseHttpRequestBody(httpRequest, () -> System.currentTimeMillis(), + (startTime) -> eventMeshHttpMetricsManager.getHttpMetrics().recordDecodeTimeCost(System.currentTimeMillis() - startTime)); } - class HTTPHandler extends ChannelInboundHandlerAdapter { + @Sharable + private class HttpDispatcher extends ChannelInboundHandlerAdapter { + /** + * Is called for each message of type {@link HttpRequest}. + * + * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelInboundHandlerAdapter} belongs to + * @param msg the message to handle + */ @Override - public void channelRead(ChannelHandlerContext ctx, Object message) { + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (!(msg instanceof HttpRequest)) { + return; + } + + HttpRequest httpRequest = (HttpRequest) msg; - HttpRequest httpRequest = (HttpRequest) message; if (Objects.nonNull(handlerService) && handlerService.isProcessorWrapper(httpRequest)) { handlerService.handler(ctx, httpRequest, asyncContextCompleteHandler); return; @@ -315,338 +297,214 @@ public void channelRead(ChannelHandlerContext ctx, Object message) { try { Span span = null; + injectHttpRequestHeader(ctx, httpRequest); - - preProcessHttpRequestHeader(ctx, httpRequest); - - final Map headerMap = parseHttpHeader(httpRequest); - - + final Map headerMap = Utils.parseHttpHeader(httpRequest); final HttpResponseStatus errorStatus = validateHttpRequest(httpRequest); if (errorStatus != null) { sendError(ctx, errorStatus); - - span = TraceUtils.prepareServerSpan(headerMap, EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); + span = TraceUtils.prepareServerSpan(headerMap, + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); TraceUtils.finishSpanWithException(span, headerMap, errorStatus.reasonPhrase(), null); return; } - metrics.getSummaryMetrics().recordHTTPRequest(); - - boolean useRequestURI = false; - for (String processURI : eventProcessorTable.keySet()) { - if (httpRequest.uri().startsWith(processURI)) { - useRequestURI = true; - break; - } + eventMeshHttpMetricsManager.getHttpMetrics().recordHTTPRequest(); + + // process http + final HttpCommand requestCommand = new HttpCommand(); + final Map bodyMap = parseHttpRequestBody(httpRequest); + + final String requestCode = HttpMethod.POST.equals(httpRequest.method()) + ? httpRequest.headers().get(ProtocolKey.REQUEST_CODE) + : MapUtils.getString(bodyMap, StringUtils.lowerCase(ProtocolKey.REQUEST_CODE), ""); + + requestCommand.setHttpMethod(httpRequest.method().name()); + requestCommand.setHttpVersion(httpRequest.protocolVersion() == null ? "" + : httpRequest.protocolVersion().protocolName()); + requestCommand.setRequestCode(requestCode); + + HttpCommand responseCommand = null; + + if (StringUtils.isBlank(requestCode) + || !httpRequestProcessorTable.containsKey(requestCode) + || !RequestCode.contains(Integer.valueOf(requestCode))) { + responseCommand = + requestCommand.createHttpCommandResponse(EventMeshRetCode.EVENTMESH_REQUESTCODE_INVALID); + sendResponse(ctx, responseCommand.httpResponse(HttpResponseStatus.BAD_REQUEST)); + + span = TraceUtils.prepareServerSpan(headerMap, + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); + TraceUtils.finishSpanWithException(span, headerMap, + EventMeshRetCode.EVENTMESH_REQUESTCODE_INVALID.getErrMsg(), null); + return; } - if (useRequestURI) { - if (useTrace) { - span.setAttribute(SemanticAttributes.HTTP_METHOD, httpRequest.method().name()); - span.setAttribute(SemanticAttributes.HTTP_FLAVOR, httpRequest.protocolVersion().protocolName()); - span.setAttribute(SemanticAttributes.HTTP_URL, httpRequest.uri()); - } - HttpEventWrapper httpEventWrapper = parseHttpRequest(httpRequest); - - AsyncContext asyncContext = - new AsyncContext<>(httpEventWrapper, null, asyncContextCompleteHandler); - processHttpRequest(ctx, asyncContext); - - } else { - final HttpCommand requestCommand = new HttpCommand(); - - final Map bodyMap = parseHttpRequestBody(httpRequest); - - String requestCode = - (httpRequest.method() == HttpMethod.POST) - ? httpRequest.headers().get(ProtocolKey.REQUEST_CODE) - : MapUtils.getString(bodyMap, StringUtils.lowerCase(ProtocolKey.REQUEST_CODE), ""); - - requestCommand.setHttpMethod(httpRequest.method().name()); - requestCommand.setHttpVersion(httpRequest.protocolVersion().protocolName()); - requestCommand.setRequestCode(requestCode); - HttpCommand responseCommand = null; - - if (StringUtils.isBlank(requestCode) - || !processorTable.containsKey(requestCode) - || !RequestCode.contains(Integer.valueOf(requestCode))) { - responseCommand = - requestCommand.createHttpCommandResponse(EventMeshRetCode.EVENTMESH_REQUESTCODE_INVALID); - sendResponse(ctx, responseCommand.httpResponse()); - - span = TraceUtils.prepareServerSpan(headerMap, EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(span, headerMap, EventMeshRetCode.EVENTMESH_REQUESTCODE_INVALID.getErrMsg(), null); - return; - } - - try { - requestCommand.setHeader(Header.buildHeader(requestCode, headerMap)); - requestCommand.setBody(Body.buildBody(requestCode, bodyMap)); - } catch (Exception e) { - responseCommand = requestCommand.createHttpCommandResponse(EventMeshRetCode.EVENTMESH_RUNTIME_ERR); - sendResponse(ctx, responseCommand.httpResponse()); - - span = TraceUtils.prepareServerSpan(headerMap, EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(span, headerMap, EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg(), e); - return; - } - - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", requestCommand); - } + try { + requestCommand.setHeader(Header.buildHeader(requestCode, headerMap)); + requestCommand.setBody(Body.buildBody(requestCode, bodyMap)); + } catch (Exception e) { + responseCommand = requestCommand.createHttpCommandResponse(EventMeshRetCode.EVENTMESH_RUNTIME_ERR); + sendResponse(ctx, responseCommand.httpResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR)); - AsyncContext asyncContext = - new AsyncContext<>(requestCommand, responseCommand, asyncContextCompleteHandler); - processEventMeshRequest(ctx, asyncContext); + span = TraceUtils.prepareServerSpan(headerMap, + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); + TraceUtils.finishSpanWithException(span, headerMap, + EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg(), e); + return; } + log.debug("{}", requestCommand); + + final AsyncContext asyncContext = + new AsyncContext<>(requestCommand, responseCommand, asyncContextCompleteHandler); + processHttpCommandRequest(ctx, asyncContext); } catch (Exception ex) { - httpServerLogger.error("AbrstractHTTPServer.HTTPHandler.channelRead err", ex); + log.error("AbstractHTTPServer.HTTPHandler.channelRead error", ex); + sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR); } finally { - ReferenceCountUtil.release(message); + ReferenceCountUtil.release(httpRequest); } } - public void processHttpRequest(final ChannelHandlerContext ctx, - final AsyncContext asyncContext) { - final HttpEventWrapper requestWrapper = asyncContext.getRequest(); - String requestURI = requestWrapper.getRequestURI(); - String processorKey = "/"; - for (String eventProcessorKey : eventProcessorTable.keySet()) { - if (requestURI.startsWith(eventProcessorKey)) { - processorKey = eventProcessorKey; - break; - } + /** + * Inject ip and protocol version, if the protocol version is empty, set default to {@link ProtocolVersion#V1}. + * + * @param ctx + * @param httpRequest + */ + private void injectHttpRequestHeader(final ChannelHandlerContext ctx, final HttpRequest httpRequest) { + final long startTime = System.currentTimeMillis(); + final HttpHeaders requestHeaders = httpRequest.headers(); + + requestHeaders.set(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, startTime); + if (StringUtils.isBlank(requestHeaders.get(ProtocolKey.VERSION))) { + requestHeaders.set(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); } - final Pair choosed = eventProcessorTable.get(processorKey); - try { - choosed.getObject2().submit(() -> { - try { - EventProcessor processor = choosed.getObject1(); - if (processor.rejectRequest()) { - - HttpEventWrapper responseWrapper = - requestWrapper.createHttpResponse(EventMeshRetCode.EVENTMESH_REJECT_BY_PROCESSOR_ERROR); - - asyncContext.onComplete(responseWrapper); - if (asyncContext.isComplete()) { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", asyncContext.getResponse()); - } - sendResponse(ctx, asyncContext.getResponse().httpResponse()); - } - return; - } - - processor.processRequest(ctx, asyncContext); - if (!asyncContext.isComplete()) { - return; - } - metrics.getSummaryMetrics() - .recordHTTPReqResTimeCost(System.currentTimeMillis() - requestWrapper.getReqTime()); + requestHeaders.set(ProtocolKey.ClientInstanceKey.IP.getKey(), + RemotingHelper.parseChannelRemoteAddr(ctx.channel())); + requestHeaders.set(EventMeshConstants.REQ_SEND_EVENTMESH_IP, eventMeshHttpConfiguration.getEventMeshServerIp()); + } - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", asyncContext.getResponse()); + private void processHttpCommandRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) { + final HttpCommand request = asyncContext.getRequest(); + final HttpRequestProcessor choosed = httpRequestProcessorTable.get(request.getRequestCode()); + Runnable runnable = () -> { + try { + final HttpRequestProcessor processor = choosed; + if (processor.rejectRequest()) { + final HttpCommand responseCommand = + request.createHttpCommandResponse(EventMeshRetCode.EVENTMESH_REJECT_BY_PROCESSOR_ERROR); + asyncContext.onComplete(responseCommand); + + if (asyncContext.isComplete()) { + sendResponse(ctx, responseCommand.httpResponse()); + log.debug("{}", asyncContext.getResponse()); + final Map traceMap = asyncContext.getRequest().getHeader().toMap(); + TraceUtils.finishSpanWithException(TraceUtils.prepareServerSpan(traceMap, + + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, + false), + traceMap, + EventMeshRetCode.EVENTMESH_REJECT_BY_PROCESSOR_ERROR.getErrMsg(), null); } - sendResponse(ctx, asyncContext.getResponse().httpResponse()); - } catch (Exception e) { - httpServerLogger.error("process error", e); + return; } - }); - } catch (RejectedExecutionException re) { - HttpEventWrapper responseWrapper = requestWrapper.createHttpResponse(EventMeshRetCode.OVERLOAD); - asyncContext.onComplete(responseWrapper); - metrics.getSummaryMetrics().recordHTTPDiscard(); - metrics.getSummaryMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - requestWrapper.getReqTime()); - try { + + processor.processRequest(ctx, asyncContext); + if (!asyncContext.isComplete()) { + return; + } + + log.debug("{}", asyncContext.getResponse()); + eventMeshHttpMetricsManager.getHttpMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - request.getReqTime()); sendResponse(ctx, asyncContext.getResponse().httpResponse()); + } catch (Exception e) { - // ignore + log.error("process error", e); } - } + }; - } - - public void processEventMeshRequest(final ChannelHandlerContext ctx, - final AsyncContext asyncContext) { - final HttpCommand request = asyncContext.getRequest(); - final Pair choosed = processorTable.get(request.getRequestCode()); try { - choosed.getObject2().submit(() -> { - try { - HttpRequestProcessor processor = choosed.getObject1(); - if (processor.rejectRequest()) { - HttpCommand responseCommand = - request.createHttpCommandResponse(EventMeshRetCode.EVENTMESH_REJECT_BY_PROCESSOR_ERROR); - asyncContext.onComplete(responseCommand); - if (asyncContext.isComplete()) { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", asyncContext.getResponse()); - } - sendResponse(ctx, responseCommand.httpResponse()); - - Map traceMap = asyncContext.getRequest().getHeader().toMap(); - Span span = TraceUtils.prepareServerSpan(traceMap, EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, - false); - TraceUtils.finishSpanWithException(span, traceMap, - EventMeshRetCode.EVENTMESH_REJECT_BY_PROCESSOR_ERROR.getErrMsg(), null); - } - return; - } - - processor.processRequest(ctx, asyncContext); - if (!asyncContext.isComplete()) { - return; - } - - metrics.getSummaryMetrics() - .recordHTTPReqResTimeCost(System.currentTimeMillis() - request.getReqTime()); - - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", asyncContext.getResponse()); - } - - sendResponse(ctx, asyncContext.getResponse().httpResponse()); + if (Objects.nonNull(choosed.executor())) { + choosed.executor().execute(() -> { + runnable.run(); + }); + } else { + runnable.run(); + } - } catch (Exception e) { - httpServerLogger.error("process error", e); - } - }); } catch (RejectedExecutionException re) { - HttpCommand responseCommand = request.createHttpCommandResponse(EventMeshRetCode.OVERLOAD); - asyncContext.onComplete(responseCommand); - metrics.getSummaryMetrics().recordHTTPDiscard(); - metrics.getSummaryMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - request.getReqTime()); + asyncContext.onComplete(request.createHttpCommandResponse(EventMeshRetCode.OVERLOAD)); + eventMeshHttpMetricsManager.getHttpMetrics().recordHTTPDiscard(); + eventMeshHttpMetricsManager.getHttpMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - request.getReqTime()); try { sendResponse(ctx, asyncContext.getResponse().httpResponse()); - Map traceMap = asyncContext.getRequest().getHeader().toMap(); - Span span = TraceUtils.prepareServerSpan(traceMap, EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(span, traceMap, EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg(), re); + final Map traceMap = asyncContext.getRequest().getHeader().toMap(); + + TraceUtils.finishSpanWithException( + TraceUtils.prepareServerSpan(traceMap, + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, + false), + traceMap, + EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg(), + re); } catch (Exception e) { - httpServerLogger.error("processEventMeshRequest fail", re); + log.error("processEventMeshRequest fail", re); } } } @Override - public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + public void channelReadComplete(final ChannelHandlerContext ctx) throws Exception { super.channelReadComplete(ctx); ctx.flush(); } @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - if (null != cause) { - logger.error("", cause); + public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) { + if (cause != null) { + log.error("", cause); } - if (null != ctx) { - ctx.close(); - } - } - - Map extractFromRequest(HttpRequest httpRequest) { - return null; - } - } - - private HttpEventWrapper parseHttpRequest(HttpRequest httpRequest) throws IOException { - HttpEventWrapper httpEventWrapper = new HttpEventWrapper(); - httpEventWrapper.setHttpMethod(httpRequest.method().name()); - httpEventWrapper.setHttpVersion(httpRequest.protocolVersion().protocolName()); - httpEventWrapper.setRequestURI(httpRequest.uri()); - - //parse http header - for (String key : httpRequest.headers().names()) { - httpEventWrapper.getHeaderMap().put(key, httpRequest.headers().get(key)); - } - final long bodyDecodeStart = System.currentTimeMillis(); - //parse http body - FullHttpRequest fullHttpRequest = (FullHttpRequest) httpRequest; - final Map bodyMap = new HashMap<>(); - if (HttpMethod.GET == fullHttpRequest.method()) { - QueryStringDecoder getDecoder = new QueryStringDecoder(fullHttpRequest.uri()); - getDecoder.parameters().forEach((key, value) -> bodyMap.put(key, value.get(0))); - } else if (HttpMethod.POST == fullHttpRequest.method()) { - - if (StringUtils.contains(httpRequest.headers().get("Content-Type"), ContentType.APPLICATION_JSON.getMimeType())) { - int length = fullHttpRequest.content().readableBytes(); - if (length > 0) { - byte[] body = new byte[length]; - fullHttpRequest.content().readBytes(body); - JsonUtils.deserialize(new String(body), new TypeReference>() { - }).forEach(bodyMap::put); - } - } else { - HttpPostRequestDecoder decoder = - new HttpPostRequestDecoder(defaultHttpDataFactory, httpRequest); - for (InterfaceHttpData parm : decoder.getBodyHttpDatas()) { - if (parm.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) { - Attribute data = (Attribute) parm; - bodyMap.put(data.getName(), data.getValue()); - } - } - decoder.destroy(); + if (ctx != null) { + ctx.close(); } - - } else { - throw new RuntimeException("UnSupported Method " + fullHttpRequest.method()); } - - byte[] requestBody = JsonUtils.serialize(bodyMap).getBytes(StandardCharsets.UTF_8); - httpEventWrapper.setBody(requestBody); - - metrics.getSummaryMetrics().recordDecodeTimeCost(System.currentTimeMillis() - bodyDecodeStart); - - return httpEventWrapper; } - class HttpConnectionHandler extends ChannelDuplexHandler { - public final AtomicInteger connections = new AtomicInteger(0); - - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - super.channelRegistered(ctx); - } + @Sharable + protected class HttpConnectionHandler extends ChannelDuplexHandler { - @Override - public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - super.channelUnregistered(ctx); - } + public final transient AtomicInteger connections = new AtomicInteger(0); @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - int c = connections.incrementAndGet(); - if (c > 20000) { - httpServerLogger - .warn("client|http|channelActive|remoteAddress={}|msg={}", remoteAddress, - "too many client(20000) connect this eventMesh server"); + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + if (connections.incrementAndGet() > MAX_CONNECTIONS) { + log.warn("client|http|channelActive|remoteAddress={}|msg=too many client({}) connect this eventMesh server", + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), MAX_CONNECTIONS); ctx.close(); return; } - super.channelActive(ctx); } @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { + public void channelInactive(final ChannelHandlerContext ctx) throws Exception { connections.decrementAndGet(); super.channelInactive(ctx); } @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { + public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt) { if (evt instanceof IdleStateEvent) { - IdleStateEvent event = (IdleStateEvent) evt; + final IdleStateEvent event = (IdleStateEvent) evt; if (event.state().equals(IdleState.ALL_IDLE)) { final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - httpServerLogger.info("client|http|userEventTriggered|remoteAddress={}|msg={}", - remoteAddress, evt.getClass().getName()); + log.info("client|http|userEventTriggered|remoteAddress={}|msg={}", remoteAddress, evt.getClass().getName()); ctx.close(); } } @@ -655,31 +513,30 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { } } - class HttpsServerInitializer extends ChannelInitializer { + private class HttpsServerInitializer extends ChannelInitializer { - private final SSLContext sslContext; + private final transient SSLContext sslContext; - public HttpsServerInitializer(SSLContext sslContext) { + public HttpsServerInitializer(final SSLContext sslContext) { this.sslContext = sslContext; } @Override - protected void initChannel(SocketChannel channel) { - ChannelPipeline pipeline = channel.pipeline(); - + protected void initChannel(final SocketChannel channel) { + final ChannelPipeline pipeline = channel.pipeline(); if (sslContext != null && useTLS) { - SSLEngine sslEngine = sslContext.createSSLEngine(); + final SSLEngine sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); - pipeline.addFirst("ssl", new SslHandler(sslEngine)); + pipeline.addFirst(getWorkerGroup(), "ssl", new SslHandler(sslEngine)); } - pipeline.addLast(new HttpRequestDecoder(), - new HttpResponseEncoder(), - new HttpConnectionHandler(), + pipeline.addLast(getWorkerGroup(), + new HttpRequestDecoder(), + new HttpResponseEncoder(), + httpConnectionHandler, new HttpObjectAggregator(Integer.MAX_VALUE), - new HTTPHandler()); + httpDispatcher); } } - } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractRemotingServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractRemotingServer.java index 311ae2e086..e310042622 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractRemotingServer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractRemotingServer.java @@ -17,96 +17,107 @@ package org.apache.eventmesh.runtime.boot; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.utils.SystemUtils; import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.TimeUnit; +import io.netty.channel.DefaultEventLoopGroup; import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.concurrent.EventExecutorGroup; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * The most basic server + */ +@Slf4j +@Getter +public abstract class AbstractRemotingServer implements RemotingServer { -public abstract class AbstractRemotingServer { + private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors(); + private static final int DEFAULT_SLEEP_SECONDS = 30; - public Logger logger = LoggerFactory.getLogger(this.getClass()); + @Setter + private EventLoopGroup bossGroup; - public EventLoopGroup bossGroup; + @Setter + private EventLoopGroup ioGroup; - public EventLoopGroup ioGroup; + @Setter + private EventExecutorGroup workerGroup; - public EventLoopGroup workerGroup; + protected ProducerManager producerManager; - public int port; + @Setter + private int port; - private EventLoopGroup initBossGroup(String threadPrefix) { - bossGroup = new NioEventLoopGroup(1, new ThreadFactory() { - AtomicInteger count = new AtomicInteger(0); + protected void buildBossGroup(final String threadPrefix) { + if (useEpoll()) { + bossGroup = new EpollEventLoopGroup(1, new EventMeshThreadFactory(threadPrefix + "NettyEpoll-Boss", true)); + } else { + bossGroup = new NioEventLoopGroup(1, new EventMeshThreadFactory(threadPrefix + "NettyNio-Boss", true)); + } - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, threadPrefix + "-boss-" + count.incrementAndGet()); - t.setDaemon(true); - return t; - } - }); + } - return bossGroup; + private void buildIOGroup(final String threadPrefix) { + if (useEpoll()) { + ioGroup = new EpollEventLoopGroup(MAX_THREADS, new EventMeshThreadFactory(threadPrefix + "-NettyEpoll-IO")); + } else { + ioGroup = new NioEventLoopGroup(MAX_THREADS, new EventMeshThreadFactory(threadPrefix + "-NettyNio-IO")); + } } - private EventLoopGroup initIOGroup(String threadPrefix) { - ioGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { - AtomicInteger count = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, threadPrefix + "-io-" + count.incrementAndGet()); - return t; - } - }); - return ioGroup; + private void buildWorkerGroup(final String threadPrefix) { + workerGroup = new DefaultEventLoopGroup(MAX_THREADS, new EventMeshThreadFactory(threadPrefix + "-worker")); } - private EventLoopGroup initWorkerGroup(String threadPrefix) { - workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { - AtomicInteger count = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, threadPrefix + "-worker-" + count.incrementAndGet()); - return t; - } - }); - return workerGroup; + protected void initProducerManager() throws Exception { + producerManager = new ProducerManager(this); + producerManager.init(); } - public void init(String threadPrefix) throws Exception { - initBossGroup(threadPrefix); - initIOGroup(threadPrefix); - initWorkerGroup(threadPrefix); + public void init(final String threadPrefix) throws Exception { + buildBossGroup(threadPrefix); + buildIOGroup(threadPrefix); + buildWorkerGroup(threadPrefix); + } + + public void start() throws Exception { + producerManager.start(); } public void shutdown() throws Exception { if (bossGroup != null) { bossGroup.shutdownGracefully(); - logger.info("shutdown bossGroup"); + log.info("shutdown bossGroup"); + } + if (producerManager != null) { + producerManager.shutdown(); } - ThreadUtils.randomSleep(30); + ThreadUtils.randomPause(TimeUnit.SECONDS.toMillis(DEFAULT_SLEEP_SECONDS)); if (ioGroup != null) { ioGroup.shutdownGracefully(); - logger.info("shutdown ioGroup"); + log.info("shutdown ioGroup"); } - if (workerGroup != null) { workerGroup.shutdownGracefully(); - logger.info("shutdown workerGroup"); + + log.info("shutdown workerGroup"); } } - public void start() throws Exception { - + protected boolean useEpoll() { + return SystemUtils.isLinuxPlatform() && Epoll.isAvailable(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractTCPServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractTCPServer.java new file mode 100644 index 0000000000..eb9793be6b --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/AbstractTCPServer.java @@ -0,0 +1,490 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.Pair; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.protocol.tcp.codec.Codec; +import org.apache.eventmesh.common.utils.AssertUtils; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.TcpProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.SessionState; +import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMetricsManager; +import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.TraceUtils; +import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.AdaptiveRecvByteBufAllocator; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.handler.traffic.ChannelTrafficShapingHandler; +import io.netty.handler.traffic.GlobalTrafficShapingHandler; +import io.opentelemetry.api.trace.Span; + +import lombok.extern.slf4j.Slf4j; + +/** + * TCP serves as the runtime module server for the protocol + */ +@Slf4j +public class AbstractTCPServer extends AbstractRemotingServer { + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); + + private final EventMeshTCPConfiguration eventMeshTCPConfiguration; + private ClientSessionGroupMapping clientSessionGroupMapping; + + protected EventMeshTcpMetricsManager eventMeshTcpMetricsManager; + + private transient GlobalTrafficShapingHandler globalTrafficShapingHandler; + private TcpConnectionHandler tcpConnectionHandler; + private TcpDispatcher tcpDispatcher; + + private final Map> tcpRequestProcessorTable = + new ConcurrentHashMap<>(64); + + private final transient AtomicBoolean started = new AtomicBoolean(false); + + private final TCPThreadPoolGroup tcpThreadPoolGroup; + + public AbstractTCPServer(EventMeshTCPConfiguration eventMeshTCPConfiguration) { + this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; + this.tcpThreadPoolGroup = new TCPThreadPoolGroup(eventMeshTCPConfiguration); + } + + private void initSharableHandlers() { + tcpConnectionHandler = new TcpConnectionHandler(); + tcpDispatcher = new TcpDispatcher(); + } + + public void init() throws Exception { + super.init("eventMesh-tcp"); + initProducerManager(); + tcpThreadPoolGroup.initThreadPool(); + } + + @Override + public CommonConfiguration getConfiguration() { + return eventMeshTCPConfiguration; + } + + @Override + public void start() throws Exception { + initSharableHandlers(); + + Thread thread = new Thread(() -> { + final ServerBootstrap bootstrap = new ServerBootstrap(); + + bootstrap.group(this.getBossGroup(), this.getIoGroup()) + .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) + .option(ChannelOption.SO_BACKLOG, 128) + .option(ChannelOption.SO_REUSEADDR, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) + .childOption(ChannelOption.SO_KEEPALIVE, false) + .childOption(ChannelOption.SO_LINGER, 0) + .childOption(ChannelOption.SO_TIMEOUT, 600_000) + .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.SO_SNDBUF, 65_535 * 4) + .childOption(ChannelOption.SO_RCVBUF, 65_535 * 4) + .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(2_048, 4_096, 65_536)) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childHandler(new TcpServerInitializer()); + + try { + int port = eventMeshTCPConfiguration.getEventMeshTcpServerPort(); + ChannelFuture f = bootstrap.bind(port).sync(); + log.info("EventMeshTCPServer[port={}] started.....", port); + f.channel().closeFuture().sync(); + } catch (Exception e) { + log.error("EventMeshTCPServer RemotingServer Start Err!", e); + try { + shutdown(); + } catch (Exception ex) { + log.error("EventMeshTCPServer RemotingServer shutdown Err!", ex); + } + System.exit(-1); + } + }, "eventMesh-tcp-server"); + thread.start(); + + started.compareAndSet(false, true); + + } + + @Override + public void shutdown() throws Exception { + super.shutdown(); + tcpThreadPoolGroup.shutdownThreadPool(); + globalTrafficShapingHandler.release(); + started.compareAndSet(true, false); + } + + /** + * Registers the processors required by the runtime module + */ + public void registerProcessor(final Command command, final TcpProcessor processor, + final ThreadPoolExecutor executor) { + AssertUtils.notNull(command, "command can't be null"); + AssertUtils.notNull(processor, "processor can't be null"); + AssertUtils.notNull(executor, "executor can't be null"); + this.tcpRequestProcessorTable.put(command, new Pair<>(processor, executor)); + } + + private class TcpServerInitializer extends ChannelInitializer { + + @Override + protected void initChannel(SocketChannel ch) { + globalTrafficShapingHandler = newGTSHandler(tcpThreadPoolGroup.getScheduler(), eventMeshTCPConfiguration.getCtc().getReadLimit()); + ch.pipeline() + .addLast(getWorkerGroup(), new Codec.Encoder()) + .addLast(getWorkerGroup(), new Codec.Decoder()) + .addLast(getWorkerGroup(), "global-traffic-shaping", globalTrafficShapingHandler) + .addLast(getWorkerGroup(), "channel-traffic-shaping", newCTSHandler(eventMeshTCPConfiguration.getCtc().getReadLimit())) + .addLast(getWorkerGroup(), tcpConnectionHandler) + .addLast(getWorkerGroup(), + new IdleStateHandler( + eventMeshTCPConfiguration.getEventMeshTcpIdleReadSeconds(), + eventMeshTCPConfiguration.getEventMeshTcpIdleWriteSeconds(), + eventMeshTCPConfiguration.getEventMeshTcpIdleAllSeconds()), + new TcpDispatcher()); + } + + private GlobalTrafficShapingHandler newGTSHandler(final ScheduledExecutorService executor, final long readLimit) { + GlobalTrafficShapingHandler handler = new GlobalTrafficShapingHandler(executor, 0, readLimit) { + + @Override + protected long calculateSize(final Object msg) { + return 1; + } + }; + handler.setMaxTimeWait(1_000); + return handler; + } + + private ChannelTrafficShapingHandler newCTSHandler(final long readLimit) { + ChannelTrafficShapingHandler handler = new ChannelTrafficShapingHandler(0, readLimit) { + + @Override + protected long calculateSize(final Object msg) { + return 1; + } + }; + handler.setMaxTimeWait(3_000); + return handler; + } + + } + + @Sharable + private class TcpDispatcher extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Package pkg) throws Exception { + long startTime = System.currentTimeMillis(); + validateMsg(pkg); + + eventMeshTcpMetricsManager.client2eventMeshMsgNumIncrement(IPUtils.parseChannelRemoteAddr(ctx.channel())); + + Command cmd = pkg.getHeader().getCmd(); + try { + if (isNeedTrace(cmd)) { + pkg.getHeader().getProperties() + .put(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, startTime); + pkg.getHeader().getProperties().put(EventMeshConstants.REQ_SEND_EVENTMESH_IP, + eventMeshTCPConfiguration.getEventMeshServerIp()); + Session session = clientSessionGroupMapping.getSession(ctx); + + pkg.getHeader().getProperties().put(EventMeshConstants.REQ_SYS, session.getClient().getSubsystem()); + pkg.getHeader().getProperties().put(EventMeshConstants.REQ_IP, session.getClient().getHost()); + pkg.getHeader().getProperties().put(EventMeshConstants.REQ_IDC, session.getClient().getIdc()); + pkg.getHeader().getProperties().put(EventMeshConstants.REQ_GROUP, session.getClient().getGroup()); + } + + if (Command.HELLO_REQUEST == cmd || Command.RECOMMEND_REQUEST == cmd) { + MESSAGE_LOGGER.info("pkg|c2eventMesh|cmd={}|pkg={}", cmd, pkg); + processTcpCommandRequest(pkg, ctx, startTime, cmd); + return; + } + + if (clientSessionGroupMapping.getSession(ctx) == null) { + MESSAGE_LOGGER.info("pkg|c2eventMesh|cmd={}|pkg={}, no session is found", cmd, pkg); + throw new Exception("no session is found"); + } + + logMessageFlow(ctx, pkg, cmd); + + if (clientSessionGroupMapping.getSession(ctx) + .getSessionState() == SessionState.CLOSED) { + throw new Exception( + "this eventMesh tcp session will be closed, may be reboot or version change!"); + } + + processTcpCommandRequest(pkg, ctx, startTime, cmd); + } catch (Exception e) { + log.error("exception occurred while pkg|cmd={}|pkg={}", cmd, pkg, e); + + if (isNeedTrace(cmd)) { + Span span = TraceUtils.prepareServerSpan(pkg.getHeader().getProperties(), + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, startTime, + TimeUnit.MILLISECONDS, false); + TraceUtils.finishSpanWithException(span, pkg.getHeader().getProperties(), + "exception occurred while dispatch pkg", e); + } + + writeToClient(cmd, pkg, ctx, e); + } + } + + private void processTcpCommandRequest(final Package pkg, final ChannelHandlerContext ctx, + final long startTime, final Command cmd) { + + Pair pair = tcpRequestProcessorTable.get(cmd); + pair.getRight().submit(() -> { + TcpProcessor processor = pair.getLeft(); + + processor.process(pkg, ctx, startTime); + + }); + } + + private boolean isNeedTrace(Command cmd) { + return eventMeshTCPConfiguration.isEventMeshServerTraceEnable() + && (Command.REQUEST_TO_SERVER == cmd + || Command.ASYNC_MESSAGE_TO_SERVER == cmd + || Command.BROADCAST_MESSAGE_TO_SERVER == cmd); + } + + private void writeToClient(Command cmd, Package pkg, ChannelHandlerContext ctx, Exception e) { + try { + Package res = new Package(); + res.setHeader(new Header(getReplyCommand(cmd), OPStatus.FAIL.getCode(), e.toString(), + pkg.getHeader().getSeq())); + ctx.channel().eventLoop().execute(() -> ctx.writeAndFlush(res)); + } catch (Exception ex) { + log.warn("writeToClient failed", ex); + } + } + + private Command getReplyCommand(Command cmd) { + switch (cmd) { + case HELLO_REQUEST: + return Command.HELLO_RESPONSE; + case RECOMMEND_REQUEST: + return Command.RECOMMEND_RESPONSE; + case HEARTBEAT_REQUEST: + return Command.HEARTBEAT_RESPONSE; + case SUBSCRIBE_REQUEST: + return Command.SUBSCRIBE_RESPONSE; + case UNSUBSCRIBE_REQUEST: + return Command.UNSUBSCRIBE_RESPONSE; + case LISTEN_REQUEST: + return Command.LISTEN_RESPONSE; + case CLIENT_GOODBYE_REQUEST: + return Command.CLIENT_GOODBYE_RESPONSE; + case REQUEST_TO_SERVER: + return Command.RESPONSE_TO_CLIENT; + case ASYNC_MESSAGE_TO_SERVER: + return Command.ASYNC_MESSAGE_TO_SERVER_ACK; + case BROADCAST_MESSAGE_TO_SERVER: + return Command.BROADCAST_MESSAGE_TO_SERVER_ACK; + default: + return cmd; + } + } + + private void logMessageFlow(ChannelHandlerContext ctx, Package pkg, Command cmd) { + if (!MESSAGE_LOGGER.isInfoEnabled()) { + return; + } + + if (pkg.getBody() instanceof EventMeshMessage) { + MESSAGE_LOGGER.info("pkg|c2eventMesh|cmd={}|Msg={}|user={}", cmd, + EventMeshUtil.printMqMessage((EventMeshMessage) pkg.getBody()), + clientSessionGroupMapping.getSession(ctx).getClient()); + } else { + MESSAGE_LOGGER.info("pkg|c2eventMesh|cmd={}|pkg={}|user={}", cmd, pkg, + clientSessionGroupMapping.getSession(ctx).getClient()); + } + } + + private void validateMsg(Package pkg) throws Exception { + if (pkg == null) { + throw new Exception("the incoming message is empty."); + } + if (pkg.getHeader() == null) { + log.error("the incoming message does not have a header|pkg={}", pkg); + throw new Exception("the incoming message does not have a header."); + } + if (pkg.getHeader().getCmd() == null) { + log.error("the incoming message does not have a command type|pkg={}", pkg); + throw new Exception("the incoming message does not have a command type."); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + Session session = clientSessionGroupMapping.getSession(ctx); + UserAgent client = session == null ? null : session.getClient(); + log.error("exceptionCaught, push goodbye to client|user={}, errMsg={}", client, cause.fillInStackTrace()); + String errMsg; + if (cause.toString().contains("value not one of declared Enum instance names")) { + errMsg = "Unknown Command type"; + } else { + errMsg = cause.toString(); + } + + if (session != null) { + EventMeshTcp2Client.goodBye2Client(tcpThreadPoolGroup, session, errMsg, OPStatus.FAIL.getCode(), + clientSessionGroupMapping); + } else { + EventMeshTcp2Client.goodBye2Client(ctx, errMsg, clientSessionGroupMapping, eventMeshTcpMetricsManager); + } + } + + } + + @Sharable + public class TcpConnectionHandler extends ChannelDuplexHandler { + + private final AtomicInteger connections = new AtomicInteger(0); + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("client|tcp|channelRegistered|remoteAddress={}|msg={}", remoteAddress, ""); + super.channelRegistered(ctx); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("client|tcp|channelUnregistered|remoteAddress={}|msg={}", remoteAddress, ""); + super.channelUnregistered(ctx); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("client|tcp|channelActive|remoteAddress={}|msg={}", remoteAddress, ""); + + if (connections.incrementAndGet() > eventMeshTCPConfiguration.getEventMeshTcpClientMaxNum()) { + log.warn("client|tcp|channelActive|remoteAddress={}|msg={}", remoteAddress, "too many client connect this eventMesh server"); + ctx.close(); + return; + } + + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + connections.decrementAndGet(); + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("client|tcp|channelInactive|remoteAddress={}|msg={}", remoteAddress, ""); + clientSessionGroupMapping.closeSession(ctx); + super.channelInactive(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state().equals(IdleState.ALL_IDLE)) { + final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("client|tcp|userEventTriggered|remoteAddress={}|msg={}", remoteAddress, evt.getClass().getName()); + clientSessionGroupMapping.closeSession(ctx); + } + } + + ctx.fireUserEventTriggered(evt); + } + + public int getConnectionCount() { + return this.connections.get(); + } + } + + public TcpConnectionHandler getTcpConnectionHandler() { + return tcpConnectionHandler; + } + + public EventMeshTcpMetricsManager getEventMeshTcpMetricsManager() { + return eventMeshTcpMetricsManager; + } + + public void setEventMeshTcpMetricsManager(EventMeshTcpMetricsManager eventMeshTcpMetricsManager) { + this.eventMeshTcpMetricsManager = eventMeshTcpMetricsManager; + } + + public TcpDispatcher getTcpDispatcher() { + return tcpDispatcher; + } + + public void setTcpDispatcher(TcpDispatcher tcpDispatcher) { + this.tcpDispatcher = tcpDispatcher; + } + + public TCPThreadPoolGroup getTcpThreadPoolGroup() { + return tcpThreadPoolGroup; + } + + public ClientSessionGroupMapping getClientSessionGroupMapping() { + return clientSessionGroupMapping; + } + + public void setClientSessionGroupMapping(ClientSessionGroupMapping clientSessionGroupMapping) { + this.clientSessionGroupMapping = clientSessionGroupMapping; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshAdminBootstrap.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshAdminBootstrap.java new file mode 100644 index 0000000000..b170afd3ab --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshAdminBootstrap.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import static org.apache.eventmesh.common.Constants.ADMIN; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.runtime.configuration.EventMeshAdminConfiguration; + +import lombok.Getter; + +public class EventMeshAdminBootstrap implements EventMeshBootstrap { + + @Getter + private EventMeshAdminServer eventMeshAdminServer; + + private final EventMeshAdminConfiguration eventMeshAdminConfiguration; + + private final EventMeshServer eventMeshServer; + + public EventMeshAdminBootstrap(EventMeshServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + + ConfigService configService = ConfigService.getInstance(); + this.eventMeshAdminConfiguration = configService.buildConfigInstance(EventMeshAdminConfiguration.class); + + ConfigurationContextUtil.putIfAbsent(ADMIN, eventMeshAdminConfiguration); + } + + @Override + public void init() throws Exception { + if (eventMeshServer != null) { + eventMeshAdminServer = new EventMeshAdminServer(eventMeshServer, eventMeshAdminConfiguration); + eventMeshAdminServer.init(); + } + } + + @Override + public void start() throws Exception { + if (eventMeshAdminServer != null) { + eventMeshAdminServer.start(); + } + } + + @Override + public void shutdown() throws Exception { + if (eventMeshAdminServer != null) { + eventMeshAdminServer.shutdown(); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshAdminServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshAdminServer.java new file mode 100644 index 0000000000..e7f2748cca --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshAdminServer.java @@ -0,0 +1,186 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.runtime.admin.handler.AdminHandlerManager; +import org.apache.eventmesh.runtime.admin.handler.HttpHandler; +import org.apache.eventmesh.runtime.configuration.EventMeshAdminConfiguration; +import org.apache.eventmesh.runtime.core.protocol.http.processor.AdminMetricsProcessor; +import org.apache.eventmesh.runtime.util.HttpResponseUtils; + +import java.net.URI; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.ssl.SslHandler; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshAdminServer extends AbstractHTTPServer { + + private final EventMeshAdminConfiguration eventMeshAdminConfiguration; + + private HttpConnectionHandler httpConnectionHandler = new HttpConnectionHandler(); + + private AdminHandlerManager adminHandlerManager; + + @Getter + private ThreadPoolExecutor adminMetricsExecutor; + + public EventMeshAdminServer(final EventMeshServer eventMeshServer, final EventMeshAdminConfiguration eventMeshAdminConfiguration) { + super(eventMeshAdminConfiguration.getEventMeshServerAdminPort(), + eventMeshAdminConfiguration.isEventMeshServerUseTls(), + eventMeshAdminConfiguration); + this.eventMeshAdminConfiguration = eventMeshAdminConfiguration; + adminHandlerManager = new AdminHandlerManager(eventMeshServer); + } + + @Override + public void init() throws Exception { + super.init("eventMesh-admin"); + initThreadPool(); + adminHandlerManager.registerHttpHandler(); + registerAdminRequestProcessor(); + } + + @Override + public void start() throws Exception { + final Thread thread = new Thread(() -> { + final ServerBootstrap bootstrap = new ServerBootstrap(); + try { + bootstrap.group(this.getBossGroup(), this.getIoGroup()) + .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) + .childHandler(new AdminServerInitializer( + this.isUseTLS() ? SSLContextFactory.getSslContext(eventMeshAdminConfiguration) : null, this.isUseTLS())) + .childOption(ChannelOption.AUTO_CLOSE, Boolean.TRUE); + + log.info("AdminHttpServer[port={}] started.", this.getPort()); + + bootstrap.bind(this.getPort()) + .channel() + .closeFuture() + .sync(); + } catch (Exception e) { + log.error("AdminHttpServer start error!", e); + try { + shutdown(); + } catch (Exception ex) { + log.error("AdminHttpServer shutdown error!", ex); + } + System.exit(-1); + } + }, "EventMesh-admin-server"); + thread.setDaemon(true); + thread.start(); + started.compareAndSet(false, true); + } + + private void initThreadPool() { + adminMetricsExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshAdminConfiguration.getEventMeshServerAdminThreadNum(), + eventMeshAdminConfiguration.getEventMeshServerAdminThreadNum(), + new LinkedBlockingQueue<>(50), "eventMesh-admin-metrics", true); + } + + private void registerAdminRequestProcessor() { + final AdminMetricsProcessor adminMetricsProcessor = new AdminMetricsProcessor(this); + registerProcessor(RequestCode.ADMIN_METRICS.getRequestCode(), adminMetricsProcessor); + } + + private class AdminServerInitializer extends ChannelInitializer { + + private final transient SSLContext sslContext; + private final transient boolean useTLS; + + public AdminServerInitializer(final SSLContext sslContext, final boolean useTLS) { + this.sslContext = sslContext; + this.useTLS = useTLS; + } + + @Override + protected void initChannel(final SocketChannel channel) { + final ChannelPipeline pipeline = channel.pipeline(); + + if (sslContext != null && useTLS) { + final SSLEngine sslEngine = sslContext.createSSLEngine(); + sslEngine.setUseClientMode(false); + pipeline.addFirst(getWorkerGroup(), "ssl", new SslHandler(sslEngine)); + } + + pipeline.addLast(getWorkerGroup(), + new HttpRequestDecoder(), + new HttpResponseEncoder(), + httpConnectionHandler, + new HttpObjectAggregator(Integer.MAX_VALUE), + new SimpleChannelInboundHandler() { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) { + parseHttpRequest(ctx, msg); + } + }); + } + + private void parseHttpRequest(ChannelHandlerContext ctx, HttpRequest httpRequest) { + String uriStr = httpRequest.uri(); + URI uri = URI.create(uriStr); + Optional httpHandlerOpt = adminHandlerManager.getHttpHandler(uri.getPath()); + if (httpHandlerOpt.isPresent()) { + try { + httpHandlerOpt.get().handle(httpRequest, ctx); + } catch (Exception e) { + log.error("admin server channelRead error", e); + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(HttpResponseUtils.buildHttpResponse(Objects.requireNonNull(e.getMessage()), ctx, + HttpHeaderValues.APPLICATION_JSON, HttpResponseStatus.INTERNAL_SERVER_ERROR)).addListener(ChannelFutureListener.CLOSE); + }); + } + } else { + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(HttpResponseUtils.createNotFound()).addListener(ChannelFutureListener.CLOSE); + } + ); + } + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshBootstrap.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshBootstrap.java new file mode 100644 index 0000000000..8f0e340582 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshBootstrap.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +/** + * concrete server bootstrap + */ +public interface EventMeshBootstrap { + + void init() throws Exception; + + void start() throws Exception; + + void shutdown() throws Exception; +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcBootstrap.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcBootstrap.java new file mode 100644 index 0000000000..b6e493c1bc --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcBootstrap.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import static org.apache.eventmesh.common.Constants.GRPC; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; + +import lombok.Getter; + +public class EventMeshGrpcBootstrap implements EventMeshBootstrap { + + private final EventMeshGrpcConfiguration eventMeshGrpcConfiguration; + + @Getter + private EventMeshGrpcServer eventMeshGrpcServer; + + private final EventMeshServer eventMeshServer; + + public EventMeshGrpcBootstrap(final EventMeshServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + ConfigService configService = ConfigService.getInstance(); + this.eventMeshGrpcConfiguration = configService.buildConfigInstance(EventMeshGrpcConfiguration.class); + + ConfigurationContextUtil.putIfAbsent(GRPC, eventMeshGrpcConfiguration); + } + + @Override + public void init() throws Exception { + // server init + if (eventMeshGrpcConfiguration != null) { + eventMeshGrpcServer = new EventMeshGrpcServer(this.eventMeshServer, this.eventMeshGrpcConfiguration); + eventMeshGrpcServer.init(); + } + } + + @Override + public void start() throws Exception { + // server start + if (eventMeshGrpcConfiguration != null) { + eventMeshGrpcServer.start(); + } + } + + @Override + public void shutdown() throws Exception { + if (eventMeshGrpcConfiguration != null) { + eventMeshGrpcServer.shutdown(); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcServer.java index 467257aca4..17165012d8 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcServer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshGrpcServer.java @@ -17,50 +17,58 @@ package org.apache.eventmesh.runtime.boot; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; +import static org.apache.eventmesh.common.Constants.GRPC; + +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.CommonConfiguration; import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.metrics.api.MetricsPluginFactory; +import org.apache.eventmesh.metrics.api.MetricsRegistry; +import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.ConsumerManager; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.ProducerManager; import org.apache.eventmesh.runtime.core.protocol.grpc.retry.GrpcRetryer; import org.apache.eventmesh.runtime.core.protocol.grpc.service.ConsumerService; import org.apache.eventmesh.runtime.core.protocol.grpc.service.HeartbeatService; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.ProducerService; -import org.apache.eventmesh.runtime.registry.Registry; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.PublisherService; +import org.apache.eventmesh.runtime.meta.MetaStorage; +import org.apache.eventmesh.runtime.metrics.grpc.EventMeshGrpcMetricsManager; import org.apache.commons.lang3.RandomUtils; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; +import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.assertj.core.util.Lists; import io.grpc.Server; import io.grpc.ServerBuilder; import com.google.common.util.concurrent.RateLimiter; -public class EventMeshGrpcServer { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class EventMeshGrpcServer extends AbstractRemotingServer { private final EventMeshGrpcConfiguration eventMeshGrpcConfiguration; - private Server server; + private static final int MIN_LIMIT = 5; + + private static final int MAX_LIMIT = 10; - private ProducerManager producerManager; + private Server server; private ConsumerManager consumerManager; @@ -78,60 +86,73 @@ public class EventMeshGrpcServer { private RateLimiter msgRateLimiter; - private Registry registry; + private final MetaStorage metaStorage; + + private final Acl acl; + + private final EventMeshServer eventMeshServer; - public EventMeshGrpcServer(EventMeshGrpcConfiguration eventMeshGrpcConfiguration, Registry registry) { + private EventMeshGrpcMetricsManager eventMeshGrpcMetricsManager; + + public EventMeshGrpcServer(final EventMeshServer eventMeshServer, final EventMeshGrpcConfiguration eventMeshGrpcConfiguration) { + this.eventMeshServer = eventMeshServer; this.eventMeshGrpcConfiguration = eventMeshGrpcConfiguration; - this.registry = registry; + this.metaStorage = eventMeshServer.getMetaStorage(); + this.acl = eventMeshServer.getAcl(); } public void init() throws Exception { - logger.info("==================EventMeshGRPCServer Initializing=================="); + log.info("==================EventMeshGRPCServer Initializing=================="); initThreadPool(); initHttpClientPool(); - msgRateLimiter = RateLimiter.create(eventMeshGrpcConfiguration.eventMeshMsgReqNumPerSecond); - - producerManager = new ProducerManager(this); - producerManager.init(); + msgRateLimiter = RateLimiter.create(eventMeshGrpcConfiguration.getEventMeshMsgReqNumPerSecond()); + initProducerManager(); consumerManager = new ConsumerManager(this); consumerManager.init(); grpcRetryer = new GrpcRetryer(this); - grpcRetryer.init(); - int serverPort = eventMeshGrpcConfiguration.grpcServerPort; + int serverPort = eventMeshGrpcConfiguration.getGrpcServerPort(); server = ServerBuilder.forPort(serverPort) - .addService(new ProducerService(this, sendMsgExecutor)) - .addService(new ConsumerService(this, clientMgmtExecutor, replyMsgExecutor)) - .addService(new HeartbeatService(this, clientMgmtExecutor)) + .addService(new ConsumerService(this, sendMsgExecutor, replyMsgExecutor)) + .addService(new HeartbeatService(this, sendMsgExecutor)) + .addService(new PublisherService(this, sendMsgExecutor)) .build(); - logger.info("GRPCServer[port={}] started", serverPort); - logger.info("-----------------EventMeshGRPCServer initialized"); + initMetricsMonitor(); + + log.info("GRPCServer[port={}] started", serverPort); + log.info("-----------------EventMeshGRPCServer initialized"); + } + + @Override + public CommonConfiguration getConfiguration() { + return eventMeshGrpcConfiguration; } public void start() throws Exception { - logger.info("---------------EventMeshGRPCServer starting-------------------"); + log.info("---------------EventMeshGRPCServer starting-------------------"); producerManager.start(); consumerManager.start(); grpcRetryer.start(); server.start(); - if (eventMeshGrpcConfiguration.eventMeshServerRegistryEnable) { + if (eventMeshGrpcConfiguration.isEventMeshServerMetaStorageEnable()) { this.register(); } - logger.info("---------------EventMeshGRPCServer running-------------------"); + eventMeshGrpcMetricsManager.start(); + log.info("---------------EventMeshGRPCServer running-------------------"); } public void shutdown() throws Exception { - logger.info("---------------EventMeshGRPCServer stopping-------------------"); + log.info("---------------EventMeshGRPCServer stopping-------------------"); producerManager.shutdown(); consumerManager.shutdown(); @@ -142,26 +163,28 @@ public void shutdown() throws Exception { server.shutdown(); - if (eventMeshGrpcConfiguration.eventMeshServerRegistryEnable) { + if (eventMeshGrpcConfiguration.isEventMeshServerMetaStorageEnable()) { this.unRegister(); } - logger.info("---------------EventMeshGRPCServer stopped-------------------"); + eventMeshGrpcMetricsManager.shutdown(); + log.info("---------------EventMeshGRPCServer stopped-------------------"); } public boolean register() { boolean registerResult = false; try { String endPoints = IPUtils.getLocalAddress() - + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshGrpcConfiguration.grpcServerPort; + + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshGrpcConfiguration.getGrpcServerPort(); EventMeshRegisterInfo eventMeshRegisterInfo = new EventMeshRegisterInfo(); - eventMeshRegisterInfo.setEventMeshClusterName(eventMeshGrpcConfiguration.eventMeshCluster); - eventMeshRegisterInfo.setEventMeshName(eventMeshGrpcConfiguration.eventMeshName + "-" + ConfigurationContextUtil.GRPC); + eventMeshRegisterInfo.setEventMeshClusterName(eventMeshGrpcConfiguration.getEventMeshCluster()); + eventMeshRegisterInfo.setEventMeshName(eventMeshGrpcConfiguration.getEventMeshName() + "-" + + GRPC); eventMeshRegisterInfo.setEndPoint(endPoints); - eventMeshRegisterInfo.setProtocolType(ConfigurationContextUtil.GRPC); - registerResult = registry.register(eventMeshRegisterInfo); + eventMeshRegisterInfo.setProtocolType(GRPC); + registerResult = metaStorage.register(eventMeshRegisterInfo); } catch (Exception e) { - logger.warn("eventMesh register to registry failed", e); + log.warn("eventMesh register to registry failed", e); } return registerResult; @@ -169,13 +192,13 @@ public boolean register() { private void unRegister() throws Exception { String endPoints = IPUtils.getLocalAddress() - + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshGrpcConfiguration.grpcServerPort; + + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshGrpcConfiguration.getGrpcServerPort(); EventMeshUnRegisterInfo eventMeshUnRegisterInfo = new EventMeshUnRegisterInfo(); - eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshGrpcConfiguration.eventMeshCluster); - eventMeshUnRegisterInfo.setEventMeshName(eventMeshGrpcConfiguration.eventMeshName); + eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshGrpcConfiguration.getEventMeshCluster()); + eventMeshUnRegisterInfo.setEventMeshName(eventMeshGrpcConfiguration.getEventMeshName()); eventMeshUnRegisterInfo.setEndPoint(endPoints); - eventMeshUnRegisterInfo.setProtocolType(ConfigurationContextUtil.GRPC); - boolean registerResult = registry.unRegister(eventMeshUnRegisterInfo); + eventMeshUnRegisterInfo.setProtocolType(GRPC); + boolean registerResult = metaStorage.unRegister(eventMeshUnRegisterInfo); if (!registerResult) { throw new EventMeshException("eventMesh fail to unRegister"); } @@ -185,10 +208,6 @@ public EventMeshGrpcConfiguration getEventMeshGrpcConfiguration() { return this.eventMeshGrpcConfiguration; } - public ProducerManager getProducerManager() { - return producerManager; - } - public ConsumerManager getConsumerManager() { return consumerManager; } @@ -218,44 +237,59 @@ public CloseableHttpClient getHttpClient() { return httpClientPool.get(RandomUtils.nextInt(size, 2 * size) % size); } + public EventMeshGrpcMetricsManager getEventMeshGrpcMetricsManager() { + return eventMeshGrpcMetricsManager; + } + private void initThreadPool() { BlockingQueue sendMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshGrpcConfiguration.eventMeshServerSendMsgBlockQueueSize); + new LinkedBlockingQueue(eventMeshGrpcConfiguration.getEventMeshServerSendMsgBlockQueueSize()); - sendMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(eventMeshGrpcConfiguration.eventMeshServerSendMsgThreadNum, - eventMeshGrpcConfiguration.eventMeshServerSendMsgThreadNum, sendMsgThreadPoolQueue, - "eventMesh-grpc-sendMsg-%d", true); + sendMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshGrpcConfiguration.getEventMeshServerSendMsgThreadNum(), + eventMeshGrpcConfiguration.getEventMeshServerSendMsgThreadNum(), sendMsgThreadPoolQueue, + "eventMesh-grpc-sendMsg", true); BlockingQueue subscribeMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshGrpcConfiguration.eventMeshServerSubscribeMsgBlockQueueSize); + new LinkedBlockingQueue(eventMeshGrpcConfiguration.getEventMeshServerSubscribeMsgBlockQueueSize()); - clientMgmtExecutor = ThreadPoolFactory.createThreadPoolExecutor(eventMeshGrpcConfiguration.eventMeshServerSubscribeMsgThreadNum, - eventMeshGrpcConfiguration.eventMeshServerSubscribeMsgThreadNum, subscribeMsgThreadPoolQueue, - "eventMesh-grpc-clientMgmt-%d", true); + clientMgmtExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshGrpcConfiguration.getEventMeshServerSubscribeMsgThreadNum(), + eventMeshGrpcConfiguration.getEventMeshServerSubscribeMsgThreadNum(), subscribeMsgThreadPoolQueue, + "eventMesh-grpc-clientMgmt", true); BlockingQueue pushMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshGrpcConfiguration.eventMeshServerPushMsgBlockQueueSize); + new LinkedBlockingQueue(eventMeshGrpcConfiguration.getEventMeshServerPushMsgBlockQueueSize()); - pushMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(eventMeshGrpcConfiguration.eventMeshServerPushMsgThreadNum, - eventMeshGrpcConfiguration.eventMeshServerPushMsgThreadNum, pushMsgThreadPoolQueue, - "eventMesh-grpc-pushMsg-%d", true); + pushMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshGrpcConfiguration.getEventMeshServerPushMsgThreadNum(), + eventMeshGrpcConfiguration.getEventMeshServerPushMsgThreadNum(), pushMsgThreadPoolQueue, + "eventMesh-grpc-pushMsg", true); - BlockingQueue replyMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshGrpcConfiguration.eventMeshServerSendMsgBlockQueueSize); - - replyMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor(eventMeshGrpcConfiguration.eventMeshServerReplyMsgThreadNum, - eventMeshGrpcConfiguration.eventMeshServerReplyMsgThreadNum, sendMsgThreadPoolQueue, - "eventMesh-grpc-replyMsg-%d", true); + replyMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshGrpcConfiguration.getEventMeshServerReplyMsgThreadNum(), + eventMeshGrpcConfiguration.getEventMeshServerReplyMsgThreadNum(), sendMsgThreadPoolQueue, + "eventMesh-grpc-replyMsg", true); } private void initHttpClientPool() { - httpClientPool = new LinkedList<>(); - for (int i = 0; i < 8; i++) { + httpClientPool = new ArrayList<>(); + int clientPool = RandomUtils.nextInt(MIN_LIMIT, MAX_LIMIT); + for (int i = 0; i < clientPool; i++) { CloseableHttpClient client = HttpClients.createDefault(); httpClientPool.add(client); } } + + + private void initMetricsMonitor() throws Exception { + final List metricsRegistries = Lists.newArrayList(); + Optional.ofNullable(eventMeshGrpcConfiguration.getEventMeshMetricsPluginType()).ifPresent( + metricsPlugins -> metricsPlugins.forEach(pluginType -> metricsRegistries.add(MetricsPluginFactory.getMetricsRegistry(pluginType)))); + eventMeshGrpcMetricsManager = new EventMeshGrpcMetricsManager(this, metricsRegistries); + } + private void shutdownThreadPools() { sendMsgExecutor.shutdown(); clientMgmtExecutor.shutdown(); @@ -275,4 +309,12 @@ private void shutdownHttpClientPool() { itr.remove(); } } -} \ No newline at end of file + + public MetaStorage getMetaStorage() { + return metaStorage; + } + + public Acl getAcl() { + return acl; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHTTPServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHTTPServer.java index f7280efac1..1528e71f28 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHTTPServer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHTTPServer.java @@ -17,27 +17,29 @@ package org.apache.eventmesh.runtime.boot; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.ThreadPoolFactory; +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; import org.apache.eventmesh.common.exception.EventMeshException; import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.metrics.api.MetricsPluginFactory; import org.apache.eventmesh.metrics.api.MetricsRegistry; -import org.apache.eventmesh.runtime.common.ServiceState; +import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; +import org.apache.eventmesh.runtime.core.consumer.SubscriptionManager; import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerManager; -import org.apache.eventmesh.runtime.core.protocol.http.processor.AdminMetricsProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.BatchSendMessageProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.BatchSendMessageV2Processor; +import org.apache.eventmesh.runtime.core.protocol.http.processor.CreateTopicProcessor; +import org.apache.eventmesh.runtime.core.protocol.http.processor.DeleteTopicProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.HandlerService; import org.apache.eventmesh.runtime.core.protocol.http.processor.HeartBeatProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.LocalSubscribeEventProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.LocalUnSubscribeEventProcessor; +import org.apache.eventmesh.runtime.core.protocol.http.processor.QuerySubscriptionProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.RemoteSubscribeEventProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.RemoteUnSubscribeEventProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.ReplyMessageProcessor; @@ -47,204 +49,77 @@ import org.apache.eventmesh.runtime.core.protocol.http.processor.SendSyncMessageProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.SubscribeProcessor; import org.apache.eventmesh.runtime.core.protocol.http.processor.UnSubscribeProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.processor.WebHookProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; -import org.apache.eventmesh.runtime.core.protocol.http.producer.ProducerManager; import org.apache.eventmesh.runtime.core.protocol.http.push.HTTPClientPool; import org.apache.eventmesh.runtime.core.protocol.http.retry.HttpRetryer; -import org.apache.eventmesh.runtime.metrics.http.HTTPMetricsServer; -import org.apache.eventmesh.runtime.registry.Registry; -import org.apache.eventmesh.webhook.receive.WebHookController; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.meta.MetaStorage; +import org.apache.eventmesh.runtime.metrics.http.EventMeshHttpMetricsManager; import org.apache.commons.lang3.StringUtils; import java.util.List; import java.util.Optional; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; import org.assertj.core.util.Lists; import com.google.common.eventbus.EventBus; import com.google.common.util.concurrent.RateLimiter; -public class EventMeshHTTPServer extends AbstractHTTPServer { - - private EventMeshServer eventMeshServer; - - public ServiceState serviceState; - - private EventMeshHTTPConfiguration eventMeshHttpConfiguration; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; - private Registry registry; - public final ConcurrentHashMap localConsumerGroupMapping = - new ConcurrentHashMap<>(); - - public final ConcurrentHashMap> localClientInfoMapping = - new ConcurrentHashMap<>(); - - public EventMeshHTTPServer(EventMeshServer eventMeshServer, - EventMeshHTTPConfiguration eventMeshHttpConfiguration) { - super(eventMeshHttpConfiguration.httpServerPort, eventMeshHttpConfiguration.eventMeshServerUseTls, eventMeshHttpConfiguration); - this.eventMeshServer = eventMeshServer; - this.eventMeshHttpConfiguration = eventMeshHttpConfiguration; - this.registry = eventMeshServer.getRegistry(); - } +/** + * Add multiple managers to the underlying server + */ +@Slf4j +@Getter +public class EventMeshHTTPServer extends AbstractHTTPServer { - public EventMeshServer getEventMeshServer() { - return eventMeshServer; - } + private final EventMeshServer eventMeshServer; + private final EventMeshHTTPConfiguration eventMeshHttpConfiguration; - public EventBus eventBus = new EventBus(); + private final MetaStorage metaStorage; + private final Acl acl; + private final EventBus eventBus = new EventBus(); + private final transient HTTPClientPool httpClientPool = new HTTPClientPool(10); private ConsumerManager consumerManager; - private ProducerManager producerManager; - + private SubscriptionManager subscriptionManager; + private FilterEngine filterEngine; + private TransformerEngine transformerEngine; private HttpRetryer httpRetryer; + private transient RateLimiter msgRateLimiter; + private transient RateLimiter batchRateLimiter; - public ThreadPoolExecutor batchMsgExecutor; - - public ThreadPoolExecutor sendMsgExecutor; - - public ThreadPoolExecutor remoteMsgExecutor; - - public ThreadPoolExecutor replyMsgExecutor; - - public ThreadPoolExecutor pushMsgExecutor; - - public ThreadPoolExecutor clientManageExecutor; - - public ThreadPoolExecutor adminExecutor; - - public ThreadPoolExecutor webhookExecutor; - - private RateLimiter msgRateLimiter; - - private RateLimiter batchRateLimiter; - - public HTTPClientPool httpClientPool = new HTTPClientPool(10); - - public void shutdownThreadPool() throws Exception { - batchMsgExecutor.shutdown(); - adminExecutor.shutdown(); - clientManageExecutor.shutdown(); - sendMsgExecutor.shutdown(); - remoteMsgExecutor.shutdown(); - pushMsgExecutor.shutdown(); - replyMsgExecutor.shutdown(); - } - - public void initThreadPool() throws Exception { - - BlockingQueue batchMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshHttpConfiguration.eventMeshServerBatchBlockQSize); - batchMsgExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerBatchMsgThreadNum, - eventMeshHttpConfiguration.eventMeshServerBatchMsgThreadNum, batchMsgThreadPoolQueue, - "eventMesh-batchMsg-", true); - - BlockingQueue sendMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshHttpConfiguration.eventMeshServerSendMsgBlockQSize); - sendMsgExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerSendMsgThreadNum, - eventMeshHttpConfiguration.eventMeshServerSendMsgThreadNum, sendMsgThreadPoolQueue, - "eventMesh-sendMsg-", true); - - BlockingQueue remoteMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshHttpConfiguration.eventMeshServerRemoteMsgBlockQSize); - remoteMsgExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerRemoteMsgThreadNum, - eventMeshHttpConfiguration.eventMeshServerRemoteMsgThreadNum, remoteMsgThreadPoolQueue, - "eventMesh-remoteMsg-", true); - - BlockingQueue pushMsgThreadPoolQueue = - new LinkedBlockingQueue(eventMeshHttpConfiguration.eventMeshServerPushMsgBlockQSize); - pushMsgExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerPushMsgThreadNum, - eventMeshHttpConfiguration.eventMeshServerPushMsgThreadNum, pushMsgThreadPoolQueue, - "eventMesh-pushMsg-", true); - - BlockingQueue clientManageThreadPoolQueue = - new LinkedBlockingQueue(eventMeshHttpConfiguration.eventMeshServerClientManageBlockQSize); - clientManageExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerClientManageThreadNum, - eventMeshHttpConfiguration.eventMeshServerClientManageThreadNum, clientManageThreadPoolQueue, - "eventMesh-clientManage-", true); - - BlockingQueue adminThreadPoolQueue = new LinkedBlockingQueue(50); - adminExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerAdminThreadNum, - eventMeshHttpConfiguration.eventMeshServerAdminThreadNum, adminThreadPoolQueue, "eventMesh-admin-", - true); - - BlockingQueue replyMessageThreadPoolQueue = new LinkedBlockingQueue(100); - replyMsgExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerReplyMsgThreadNum, - eventMeshHttpConfiguration.eventMeshServerReplyMsgThreadNum, replyMessageThreadPoolQueue, - "eventMesh-replyMsg-", true); - } - - public ThreadPoolExecutor getBatchMsgExecutor() { - return batchMsgExecutor; - } - - public ThreadPoolExecutor getSendMsgExecutor() { - return sendMsgExecutor; - } - - public ThreadPoolExecutor getReplyMsgExecutor() { - return replyMsgExecutor; - } - - public ThreadPoolExecutor getPushMsgExecutor() { - return pushMsgExecutor; - } - - public ThreadPoolExecutor getClientManageExecutor() { - return clientManageExecutor; - } - - public ThreadPoolExecutor getAdminExecutor() { - return adminExecutor; - } - - public RateLimiter getMsgRateLimiter() { - return msgRateLimiter; - } - - public RateLimiter getBatchRateLimiter() { - return batchRateLimiter; - } - - public Registry getRegistry() { - return registry; + public EventMeshHTTPServer(final EventMeshServer eventMeshServer, final EventMeshHTTPConfiguration eventMeshHttpConfiguration) { + super(eventMeshHttpConfiguration.getHttpServerPort(), + eventMeshHttpConfiguration.isEventMeshServerUseTls(), + eventMeshHttpConfiguration); + this.eventMeshServer = eventMeshServer; + this.eventMeshHttpConfiguration = eventMeshHttpConfiguration; + this.metaStorage = eventMeshServer.getMetaStorage(); + this.acl = eventMeshServer.getAcl(); } public void init() throws Exception { - logger.info("==================EventMeshHTTPServer Initialing=================="); - super.init("eventMesh-http"); - - initThreadPool(); + log.info("==================EventMeshHTTPServer Initialing=================="); + super.init(); - msgRateLimiter = RateLimiter.create(eventMeshHttpConfiguration.eventMeshHttpMsgReqNumPerSecond); - batchRateLimiter = RateLimiter.create(eventMeshHttpConfiguration.eventMeshBatchMsgRequestNumPerSecond); + msgRateLimiter = RateLimiter.create(eventMeshHttpConfiguration.getEventMeshHttpMsgReqNumPerSecond()); + batchRateLimiter = RateLimiter.create(eventMeshHttpConfiguration.getEventMeshBatchMsgRequestNumPerSecond()); // The MetricsRegistry is singleton, so we can use factory method to get. final List metricsRegistries = Lists.newArrayList(); - Optional.ofNullable(eventMeshHttpConfiguration.eventMeshMetricsPluginType) - .ifPresent( - metricsPlugins -> metricsPlugins.forEach( - pluginType -> metricsRegistries.add(MetricsPluginFactory.getMetricsRegistry(pluginType)))); + Optional.ofNullable(eventMeshHttpConfiguration.getEventMeshMetricsPluginType()).ifPresent( + metricsPlugins -> metricsPlugins.forEach( + pluginType -> metricsRegistries.add(MetricsPluginFactory.getMetricsRegistry(pluginType)))); httpRetryer = new HttpRetryer(this); - httpRetryer.init(); - metrics = new HTTPMetricsServer(this, metricsRegistries); - metrics.init(); + super.setEventMeshHttpMetricsManager(new EventMeshHttpMetricsManager(this, metricsRegistries)); + subscriptionManager = new SubscriptionManager(eventMeshHttpConfiguration.isEventMeshServerMetaStorageEnable(), metaStorage); consumerManager = new ConsumerManager(this); consumerManager.init(); @@ -252,34 +127,42 @@ public void init() throws Exception { producerManager = new ProducerManager(this); producerManager.init(); - this.handlerService = new HandlerService(); - this.handlerService.setMetrics(metrics); + filterEngine = new FilterEngine(metaStorage, producerManager, consumerManager); + transformerEngine = new TransformerEngine(metaStorage, producerManager, consumerManager); - //get the trace-plugin - if (StringUtils.isNotEmpty(eventMeshHttpConfiguration.eventMeshTracePluginType) && eventMeshHttpConfiguration.eventMeshServerTraceEnable) { + super.setHandlerService(new HandlerService()); + super.getHandlerService().setMetrics(this.getEventMeshHttpMetricsManager()); - super.useTrace = eventMeshHttpConfiguration.eventMeshServerTraceEnable; + // get the trace-plugin + if (StringUtils.isNotEmpty(eventMeshHttpConfiguration.getEventMeshTracePluginType()) + && eventMeshHttpConfiguration.isEventMeshServerTraceEnable()) { + super.setUseTrace(eventMeshHttpConfiguration.isEventMeshServerTraceEnable()); } - - this.handlerService.setHttpTrace(new HTTPTrace(eventMeshHttpConfiguration.eventMeshServerTraceEnable)); + super.getHandlerService().setHttpTrace(new HTTPTrace(eventMeshHttpConfiguration.isEventMeshServerTraceEnable())); registerHTTPRequestProcessor(); - this.initWebhook(); - logger.info("--------------------------EventMeshHTTPServer inited"); + + log.info("==================EventMeshHTTPServer initialized=================="); } @Override public void start() throws Exception { super.start(); - metrics.start(); + this.getEventMeshHttpMetricsManager().start(); + consumerManager.start(); producerManager.start(); httpRetryer.start(); - if (eventMeshHttpConfiguration.eventMeshServerRegistryEnable) { + // filterEngine depend on metaStorage + if (metaStorage.getStarted().get()) { + filterEngine.start(); + } + + if (eventMeshHttpConfiguration.isEventMeshServerMetaStorageEnable()) { this.register(); } - logger.info("--------------------------EventMeshHTTPServer started"); + log.info("==================EventMeshHTTPServer started=================="); } @Override @@ -287,11 +170,13 @@ public void shutdown() throws Exception { super.shutdown(); - metrics.shutdown(); + this.getEventMeshHttpMetricsManager().shutdown(); - consumerManager.shutdown(); + filterEngine.shutdown(); - shutdownThreadPool(); + transformerEngine.shutdown(); + + consumerManager.shutdown(); httpClientPool.shutdown(); @@ -299,132 +184,101 @@ public void shutdown() throws Exception { httpRetryer.shutdown(); - if (eventMeshHttpConfiguration.eventMeshServerRegistryEnable) { + if (eventMeshHttpConfiguration.isEventMeshServerMetaStorageEnable()) { this.unRegister(); } - logger.info("--------------------------EventMeshHTTPServer shutdown"); + log.info("==================EventMeshHTTPServer shutdown=================="); } + /** + * Related to the registry module + */ public boolean register() { boolean registerResult = false; try { - String endPoints = IPUtils.getLocalAddress() - + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshHttpConfiguration.httpServerPort; - EventMeshRegisterInfo eventMeshRegisterInfo = new EventMeshRegisterInfo(); - eventMeshRegisterInfo.setEventMeshClusterName(eventMeshHttpConfiguration.eventMeshCluster); - eventMeshRegisterInfo.setEventMeshName(eventMeshHttpConfiguration.eventMeshName + "-" + ConfigurationContextUtil.HTTP); + final String endPoints = IPUtils.getLocalAddress() + + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshHttpConfiguration.getHttpServerPort(); + final EventMeshRegisterInfo eventMeshRegisterInfo = new EventMeshRegisterInfo(); + eventMeshRegisterInfo.setEventMeshClusterName(eventMeshHttpConfiguration.getEventMeshCluster()); + eventMeshRegisterInfo.setEventMeshName(eventMeshHttpConfiguration.getEventMeshName() + + "-" + HTTP); eventMeshRegisterInfo.setEndPoint(endPoints); - eventMeshRegisterInfo.setProtocolType(ConfigurationContextUtil.HTTP); - registerResult = registry.register(eventMeshRegisterInfo); + eventMeshRegisterInfo.setProtocolType(HTTP); + registerResult = metaStorage.register(eventMeshRegisterInfo); } catch (Exception e) { - logger.warn("eventMesh register to registry failed", e); + log.error("eventMesh register to registry failed", e); } return registerResult; } - private void unRegister() throws Exception { - String endPoints = IPUtils.getLocalAddress() - + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshHttpConfiguration.httpServerPort; - EventMeshUnRegisterInfo eventMeshUnRegisterInfo = new EventMeshUnRegisterInfo(); - eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshHttpConfiguration.eventMeshCluster); - eventMeshUnRegisterInfo.setEventMeshName(eventMeshHttpConfiguration.eventMeshName); + /** + * Related to the registry module + */ + private void unRegister() { + final String endPoints = IPUtils.getLocalAddress() + + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshHttpConfiguration.getHttpServerPort(); + final EventMeshUnRegisterInfo eventMeshUnRegisterInfo = new EventMeshUnRegisterInfo(); + eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshHttpConfiguration.getEventMeshCluster()); + eventMeshUnRegisterInfo.setEventMeshName(eventMeshHttpConfiguration.getEventMeshName()); eventMeshUnRegisterInfo.setEndPoint(endPoints); - eventMeshUnRegisterInfo.setProtocolType(ConfigurationContextUtil.HTTP); - boolean registerResult = registry.unRegister(eventMeshUnRegisterInfo); + eventMeshUnRegisterInfo.setProtocolType(HTTP); + final boolean registerResult = metaStorage.unRegister(eventMeshUnRegisterInfo); if (!registerResult) { throw new EventMeshException("eventMesh fail to unRegister"); } } - public void registerHTTPRequestProcessor() { - BatchSendMessageProcessor batchSendMessageProcessor = new BatchSendMessageProcessor(this); - registerProcessor(RequestCode.MSG_BATCH_SEND.getRequestCode(), batchSendMessageProcessor, batchMsgExecutor); - - BatchSendMessageV2Processor batchSendMessageV2Processor = new BatchSendMessageV2Processor(this); - registerProcessor(RequestCode.MSG_BATCH_SEND_V2.getRequestCode(), batchSendMessageV2Processor, - batchMsgExecutor); - - SendSyncMessageProcessor sendSyncMessageProcessor = new SendSyncMessageProcessor(this); - registerProcessor(RequestCode.MSG_SEND_SYNC.getRequestCode(), sendSyncMessageProcessor, sendMsgExecutor); - - SendAsyncMessageProcessor sendAsyncMessageProcessor = new SendAsyncMessageProcessor(this); - registerProcessor(RequestCode.MSG_SEND_ASYNC.getRequestCode(), sendAsyncMessageProcessor, sendMsgExecutor); - - SendAsyncEventProcessor sendAsyncEventProcessor = new SendAsyncEventProcessor(this); - handlerService.register(sendAsyncEventProcessor, sendMsgExecutor); - - SendAsyncRemoteEventProcessor sendAsyncRemoteEventProcessor = new SendAsyncRemoteEventProcessor(this); - handlerService.register(sendAsyncRemoteEventProcessor, remoteMsgExecutor); - - AdminMetricsProcessor adminMetricsProcessor = new AdminMetricsProcessor(this); - registerProcessor(RequestCode.ADMIN_METRICS.getRequestCode(), adminMetricsProcessor, adminExecutor); - - HeartBeatProcessor heartProcessor = new HeartBeatProcessor(this); - registerProcessor(RequestCode.HEARTBEAT.getRequestCode(), heartProcessor, clientManageExecutor); - - SubscribeProcessor subscribeProcessor = new SubscribeProcessor(this); - registerProcessor(RequestCode.SUBSCRIBE.getRequestCode(), subscribeProcessor, clientManageExecutor); + private void registerHTTPRequestProcessor() throws Exception { + final BatchSendMessageProcessor batchSendMessageProcessor = new BatchSendMessageProcessor(this); + registerProcessor(RequestCode.MSG_BATCH_SEND.getRequestCode(), batchSendMessageProcessor); - LocalSubscribeEventProcessor localSubscribeEventProcessor = new LocalSubscribeEventProcessor(this); - handlerService.register(localSubscribeEventProcessor, clientManageExecutor); + final BatchSendMessageV2Processor batchSendMessageV2Processor = new BatchSendMessageV2Processor(this); + registerProcessor(RequestCode.MSG_BATCH_SEND_V2.getRequestCode(), batchSendMessageV2Processor); - RemoteSubscribeEventProcessor remoteSubscribeEventProcessor = new RemoteSubscribeEventProcessor(this); - handlerService.register(remoteSubscribeEventProcessor, clientManageExecutor); + final SendSyncMessageProcessor sendSyncMessageProcessor = new SendSyncMessageProcessor(this); + registerProcessor(RequestCode.MSG_SEND_SYNC.getRequestCode(), sendSyncMessageProcessor); - UnSubscribeProcessor unSubscribeProcessor = new UnSubscribeProcessor(this); - registerProcessor(RequestCode.UNSUBSCRIBE.getRequestCode(), unSubscribeProcessor, clientManageExecutor); + final SendAsyncMessageProcessor sendAsyncMessageProcessor = new SendAsyncMessageProcessor(this); + registerProcessor(RequestCode.MSG_SEND_ASYNC.getRequestCode(), sendAsyncMessageProcessor); - LocalUnSubscribeEventProcessor localUnSubscribeEventProcessor = new LocalUnSubscribeEventProcessor(this); - handlerService.register(localUnSubscribeEventProcessor, clientManageExecutor); + final SendAsyncEventProcessor sendAsyncEventProcessor = new SendAsyncEventProcessor(this); + this.getHandlerService().register(sendAsyncEventProcessor); - RemoteUnSubscribeEventProcessor remoteUnSubscribeEventProcessor = new RemoteUnSubscribeEventProcessor(this); - handlerService.register(remoteUnSubscribeEventProcessor, clientManageExecutor); + final SendAsyncRemoteEventProcessor sendAsyncRemoteEventProcessor = new SendAsyncRemoteEventProcessor(this); + this.getHandlerService().register(sendAsyncRemoteEventProcessor); - ReplyMessageProcessor replyMessageProcessor = new ReplyMessageProcessor(this); - registerProcessor(RequestCode.REPLY_MESSAGE.getRequestCode(), replyMessageProcessor, replyMsgExecutor); + final HeartBeatProcessor heartProcessor = new HeartBeatProcessor(this); + registerProcessor(RequestCode.HEARTBEAT.getRequestCode(), heartProcessor); + final SubscribeProcessor subscribeProcessor = new SubscribeProcessor(this); + registerProcessor(RequestCode.SUBSCRIBE.getRequestCode(), subscribeProcessor); - } + final LocalSubscribeEventProcessor localSubscribeEventProcessor = new LocalSubscribeEventProcessor(this); + this.getHandlerService().register(localSubscribeEventProcessor); - private void initWebhook() throws Exception { + final RemoteSubscribeEventProcessor remoteSubscribeEventProcessor = new RemoteSubscribeEventProcessor(this); + this.getHandlerService().register(remoteSubscribeEventProcessor); + final UnSubscribeProcessor unSubscribeProcessor = new UnSubscribeProcessor(this); + registerProcessor(RequestCode.UNSUBSCRIBE.getRequestCode(), unSubscribeProcessor); - BlockingQueue webhookThreadPoolQueue = new LinkedBlockingQueue(100); - webhookExecutor = - ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpConfiguration.eventMeshServerWebhookThreadNum, - eventMeshHttpConfiguration.eventMeshServerWebhookThreadNum, webhookThreadPoolQueue, - "eventMesh-webhook-", true); - WebHookProcessor webHookProcessor = new WebHookProcessor(); + final LocalUnSubscribeEventProcessor localUnSubscribeEventProcessor = new LocalUnSubscribeEventProcessor(this); + this.getHandlerService().register(localUnSubscribeEventProcessor); - WebHookController webHookController = new WebHookController(); - webHookController.setConfigurationWrapper(eventMeshHttpConfiguration.getConfigurationWrapper()); - webHookController.init(); - webHookProcessor.setWebHookController(webHookController); - this.handlerService.register(webHookProcessor, webhookExecutor); - } + final RemoteUnSubscribeEventProcessor remoteUnSubscribeEventProcessor = new RemoteUnSubscribeEventProcessor(this); + this.getHandlerService().register(remoteUnSubscribeEventProcessor); - public ConsumerManager getConsumerManager() { - return consumerManager; - } + final ReplyMessageProcessor replyMessageProcessor = new ReplyMessageProcessor(this); + registerProcessor(RequestCode.REPLY_MESSAGE.getRequestCode(), replyMessageProcessor); - public ProducerManager getProducerManager() { - return producerManager; - } + final CreateTopicProcessor createTopicProcessor = new CreateTopicProcessor(this); + this.getHandlerService().register(createTopicProcessor); - public ServiceState getServiceState() { - return serviceState; - } - - public EventMeshHTTPConfiguration getEventMeshHttpConfiguration() { - return eventMeshHttpConfiguration; - } - - public EventBus getEventBus() { - return eventBus; - } + final DeleteTopicProcessor deleteTopicProcessor = new DeleteTopicProcessor(this); + this.getHandlerService().register(deleteTopicProcessor); - public HttpRetryer getHttpRetryer() { - return httpRetryer; + final QuerySubscriptionProcessor querySubscriptionProcessor = new QuerySubscriptionProcessor(this); + this.getHandlerService().register(querySubscriptionProcessor); } -} +} \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHttpBootstrap.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHttpBootstrap.java new file mode 100644 index 0000000000..df3b227e42 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshHttpBootstrap.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import static org.apache.eventmesh.common.Constants.HTTP; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; + +import lombok.Getter; + +public class EventMeshHttpBootstrap implements EventMeshBootstrap { + + @Getter + public EventMeshHTTPServer eventMeshHttpServer; + + private final EventMeshHTTPConfiguration eventMeshHttpConfiguration; + + private final EventMeshServer eventMeshServer; + + public EventMeshHttpBootstrap(final EventMeshServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + + ConfigService configService = ConfigService.getInstance(); + this.eventMeshHttpConfiguration = configService.buildConfigInstance(EventMeshHTTPConfiguration.class); + + ConfigurationContextUtil.putIfAbsent(HTTP, eventMeshHttpConfiguration); + } + + @Override + public void init() throws Exception { + // server init + if (eventMeshHttpConfiguration != null) { + eventMeshHttpServer = new EventMeshHTTPServer(eventMeshServer, eventMeshHttpConfiguration); + eventMeshHttpServer.init(); + } + } + + @Override + public void start() throws Exception { + // server start + if (eventMeshHttpServer != null) { + eventMeshHttpServer.start(); + } + } + + @Override + public void shutdown() throws Exception { + // server shutdown + if (eventMeshHttpServer != null) { + eventMeshHttpServer.shutdown(); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshServer.java index e6569432bd..d61580b9c8 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshServer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshServer.java @@ -17,218 +17,235 @@ package org.apache.eventmesh.runtime.boot; +import static org.apache.eventmesh.common.Constants.GRPC; +import static org.apache.eventmesh.common.Constants.HTTP; +import static org.apache.eventmesh.common.Constants.TCP; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.AssertUtils; import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.metrics.api.MetricsPluginFactory; +import org.apache.eventmesh.metrics.api.MetricsRegistry; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.common.ServiceState; -import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; -import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; -import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; -import org.apache.eventmesh.runtime.connector.ConnectorResource; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.registry.Registry; +import org.apache.eventmesh.runtime.core.protocol.http.producer.ProducerTopicManager; +import org.apache.eventmesh.runtime.meta.MetaStorage; +import org.apache.eventmesh.runtime.metrics.EventMeshMetricsManager; +import org.apache.eventmesh.runtime.metrics.MetricsManager; +import org.apache.eventmesh.runtime.storage.StorageResource; import org.apache.eventmesh.runtime.trace.Trace; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.collections4.CollectionUtils; -public class EventMeshServer { +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; - public Logger logger = LoggerFactory.getLogger(this.getClass()); +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; - public EventMeshHTTPServer eventMeshHTTPServer; +@Slf4j +public class EventMeshServer { - private EventMeshTCPServer eventMeshTCPServer; + @Getter + private final Acl acl; - private EventMeshGrpcServer eventMeshGrpcServer; + @Getter + @Setter + private MetaStorage metaStorage; - private EventMeshGrpcConfiguration eventMeshGrpcConfiguration; + @Getter + private static Trace trace; - private EventMeshHTTPConfiguration eventMeshHttpConfiguration; + private final StorageResource storageResource; - private EventMeshTCPConfiguration eventMeshTcpConfiguration; + @Getter + private ServiceState serviceState; - private Acl acl; + @Getter + private ProducerTopicManager producerTopicManager; - private Registry registry; + @Getter + private final CommonConfiguration configuration; - private static Trace trace; + // private transient ClientManageController clientManageController; - private ConnectorResource connectorResource; + private static final List BOOTSTRAP_LIST = new CopyOnWriteArrayList<>(); - private ServiceState serviceState; + private static final String SERVER_STATE_MSG = "server state:{}"; - public EventMeshServer(EventMeshHTTPConfiguration eventMeshHttpConfiguration, - EventMeshTCPConfiguration eventMeshTcpConfiguration, - EventMeshGrpcConfiguration eventMeshGrpcConfiguration) { - this.eventMeshHttpConfiguration = eventMeshHttpConfiguration; - this.eventMeshTcpConfiguration = eventMeshTcpConfiguration; - this.eventMeshGrpcConfiguration = eventMeshGrpcConfiguration; - this.acl = new Acl(); - this.registry = new Registry(); - this.trace = new Trace(eventMeshHttpConfiguration.eventMeshServerTraceEnable); - this.connectorResource = new ConnectorResource(); - - ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.TCP, eventMeshTcpConfiguration); - ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.GRPC, eventMeshGrpcConfiguration); - ConfigurationContextUtil.putIfAbsent(ConfigurationContextUtil.HTTP, eventMeshHttpConfiguration); - } + private static final ConfigService configService = ConfigService.getInstance(); - public void init() throws Exception { - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerSecurityEnable) { - acl.init(eventMeshHttpConfiguration.eventMeshSecurityPluginType); - } + @Getter + private EventMeshTCPServer eventMeshTCPServer = null; - // registry init - if (eventMeshTcpConfiguration != null - && eventMeshTcpConfiguration.eventMeshTcpServerEnabled - && eventMeshTcpConfiguration.eventMeshServerRegistryEnable) { - registry.init(eventMeshTcpConfiguration.eventMeshRegistryPluginType); - } + @Getter + private EventMeshHTTPServer eventMeshHTTPServer = null; - if (eventMeshGrpcConfiguration != null && eventMeshGrpcConfiguration.eventMeshServerRegistryEnable) { - registry.init(eventMeshGrpcConfiguration.eventMeshRegistryPluginType); - } + @Getter + private EventMeshGrpcServer eventMeshGrpcServer = null; - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerRegistryEnable) { - registry.init(eventMeshHttpConfiguration.eventMeshRegistryPluginType); - } + @Getter + private EventMeshAdminServer eventMeshAdminServer = null; - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerTraceEnable) { - trace.init(eventMeshHttpConfiguration.eventMeshTracePluginType); - } + private EventMeshMetricsManager eventMeshMetricsManager; - connectorResource.init(eventMeshHttpConfiguration.eventMeshConnectorPluginType); + public EventMeshServer() { - // server init - if (eventMeshGrpcConfiguration != null) { - eventMeshGrpcServer = new EventMeshGrpcServer(eventMeshGrpcConfiguration, registry); - eventMeshGrpcServer.init(); - } + // Initialize configuration + this.configuration = configService.buildConfigInstance(CommonConfiguration.class); + AssertUtils.notNull(this.configuration, "configuration is null"); - if (eventMeshHttpConfiguration != null) { - eventMeshHTTPServer = new EventMeshHTTPServer(this, eventMeshHttpConfiguration); - eventMeshHTTPServer.init(); - } + // Initialize acl, registry, trace and storageResource + this.acl = Acl.getInstance(this.configuration.getEventMeshSecurityPluginType()); + this.metaStorage = MetaStorage.getInstance(this.configuration.getEventMeshMetaStoragePluginType()); + trace = Trace.getInstance(this.configuration.getEventMeshTracePluginType(), this.configuration.isEventMeshServerTraceEnable()); + this.storageResource = StorageResource.getInstance(this.configuration.getEventMeshStoragePluginType()); - if (eventMeshTcpConfiguration != null) { - eventMeshTCPServer = new EventMeshTCPServer(this, eventMeshTcpConfiguration, registry); - if (eventMeshTcpConfiguration.eventMeshTcpServerEnabled) { - eventMeshTCPServer.init(); + // Initialize BOOTSTRAP_LIST based on protocols provided in configuration + final List provideServerProtocols = configuration.getEventMeshProvideServerProtocols(); + for (String provideServerProtocol : provideServerProtocols) { + switch (provideServerProtocol.toUpperCase()) { + case HTTP: + BOOTSTRAP_LIST.add(new EventMeshHttpBootstrap(this)); + break; + case TCP: + BOOTSTRAP_LIST.add(new EventMeshTcpBootstrap(this)); + break; + case GRPC: + BOOTSTRAP_LIST.add(new EventMeshGrpcBootstrap(this)); + break; + default: // nothing to do } } - String eventStore = System - .getProperty(EventMeshConstants.EVENT_STORE_PROPERTIES, System.getenv(EventMeshConstants.EVENT_STORE_ENV)); - logger.info("eventStore : {}", eventStore); + // If no protocols are provided, initialize BOOTSTRAP_LIST with default protocols + if (BOOTSTRAP_LIST.isEmpty()) { + BOOTSTRAP_LIST.add(new EventMeshTcpBootstrap(this)); + } - serviceState = ServiceState.INITED; - logger.info("server state:{}", serviceState); - } + // HTTP Admin Server always enabled + BOOTSTRAP_LIST.add(new EventMeshAdminBootstrap(this)); - public void start() throws Exception { - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerSecurityEnable) { - acl.start(); - } - // registry start - if (eventMeshTcpConfiguration != null - && eventMeshTcpConfiguration.eventMeshTcpServerEnabled - && eventMeshTcpConfiguration.eventMeshServerRegistryEnable) { - registry.start(); - } - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerRegistryEnable) { - registry.start(); - } - if (eventMeshGrpcConfiguration != null && eventMeshGrpcConfiguration.eventMeshServerRegistryEnable) { - registry.start(); + List metricsPluginTypes = configuration.getEventMeshMetricsPluginType(); + if (CollectionUtils.isNotEmpty(metricsPluginTypes)) { + List metricsRegistries = metricsPluginTypes.stream().map(metric -> MetricsPluginFactory.getMetricsRegistry(metric)) + .collect(Collectors.toList()); + eventMeshMetricsManager = new EventMeshMetricsManager(metricsRegistries); } + } - // server start - if (eventMeshGrpcConfiguration != null) { - eventMeshGrpcServer.start(); + public void init() throws Exception { + storageResource.init(); + if (configuration.isEventMeshServerSecurityEnable()) { + acl.init(); } - if (eventMeshHttpConfiguration != null) { - eventMeshHTTPServer.start(); + if (configuration.isEventMeshServerMetaStorageEnable()) { + metaStorage.init(); } - if (eventMeshTcpConfiguration != null && eventMeshTcpConfiguration.eventMeshTcpServerEnabled) { - eventMeshTCPServer.start(); + if (configuration.isEventMeshServerTraceEnable()) { + trace.init(); } - serviceState = ServiceState.RUNNING; - logger.info("server state:{}", serviceState); - } - - public void shutdown() throws Exception { - serviceState = ServiceState.STOPING; - logger.info("server state:{}", serviceState); - if (eventMeshHttpConfiguration != null) { - eventMeshHTTPServer.shutdown(); + // server init + for (final EventMeshBootstrap eventMeshBootstrap : BOOTSTRAP_LIST) { + eventMeshBootstrap.init(); + if (eventMeshBootstrap instanceof EventMeshTcpBootstrap) { + eventMeshTCPServer = ((EventMeshTcpBootstrap) eventMeshBootstrap).getEventMeshTcpServer(); + } + if (eventMeshBootstrap instanceof EventMeshHttpBootstrap) { + eventMeshHTTPServer = ((EventMeshHttpBootstrap) eventMeshBootstrap).getEventMeshHttpServer(); + } + if (eventMeshBootstrap instanceof EventMeshGrpcBootstrap) { + eventMeshGrpcServer = ((EventMeshGrpcBootstrap) eventMeshBootstrap).getEventMeshGrpcServer(); + } + if (eventMeshBootstrap instanceof EventMeshAdminBootstrap) { + eventMeshAdminServer = ((EventMeshAdminBootstrap) eventMeshBootstrap).getEventMeshAdminServer(); + } } - if (eventMeshTcpConfiguration != null - && eventMeshTcpConfiguration.eventMeshTcpServerEnabled) { - eventMeshTCPServer.shutdown(); + if (Objects.nonNull(eventMeshTCPServer)) { + MetricsManager metricsManager = eventMeshTCPServer.getEventMeshTcpMetricsManager(); + addMetricsManagerAndMetrics(metricsManager); } - if (eventMeshGrpcConfiguration != null) { - eventMeshGrpcServer.shutdown(); + if (Objects.nonNull(eventMeshGrpcServer)) { + MetricsManager metricsManager = eventMeshGrpcServer.getEventMeshGrpcMetricsManager(); + addMetricsManagerAndMetrics(metricsManager); } - if (eventMeshHttpConfiguration != null - && eventMeshHttpConfiguration.eventMeshServerRegistryEnable) { - registry.shutdown(); + if (Objects.nonNull(eventMeshHTTPServer)) { + MetricsManager metricsManager = eventMeshHTTPServer.getEventMeshHttpMetricsManager(); + addMetricsManagerAndMetrics(metricsManager); } - if (eventMeshTcpConfiguration != null - && eventMeshTcpConfiguration.eventMeshTcpServerEnabled - && eventMeshTcpConfiguration.eventMeshServerRegistryEnable) { - registry.shutdown(); + if (Objects.nonNull(eventMeshMetricsManager)) { + eventMeshMetricsManager.init(); } - if (eventMeshGrpcConfiguration != null - && eventMeshGrpcConfiguration.eventMeshServerRegistryEnable) { - registry.shutdown(); - } + producerTopicManager = new ProducerTopicManager(this); + producerTopicManager.init(); - connectorResource.release(); + serviceState = ServiceState.INITED; + log.info(SERVER_STATE_MSG, serviceState); + } - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerSecurityEnable) { - acl.shutdown(); + private void addMetricsManagerAndMetrics(MetricsManager metricsManager) { + if (Objects.nonNull(metricsManager)) { + this.eventMeshMetricsManager.addMetricManager(metricsManager); + this.eventMeshMetricsManager.addMetrics(metricsManager.getMetrics()); } + } - if (eventMeshHttpConfiguration != null && eventMeshHttpConfiguration.eventMeshServerTraceEnable) { - trace.shutdown(); + public void start() throws Exception { + if (Objects.nonNull(configuration)) { + if (configuration.isEventMeshServerSecurityEnable()) { + acl.start(); + } + // registry start + if (configuration.isEventMeshServerMetaStorageEnable()) { + metaStorage.start(); + } + } + // server start + for (final EventMeshBootstrap eventMeshBootstrap : BOOTSTRAP_LIST) { + eventMeshBootstrap.start(); } - ConfigurationContextUtil.clear(); - serviceState = ServiceState.STOPED; - logger.info("server state:{}", serviceState); - } + producerTopicManager.start(); - public EventMeshGrpcServer getEventMeshGrpcServer() { - return eventMeshGrpcServer; + serviceState = ServiceState.RUNNING; + log.info(SERVER_STATE_MSG, serviceState); } - public EventMeshHTTPServer getEventMeshHTTPServer() { - return eventMeshHTTPServer; - } + public void shutdown() throws Exception { + serviceState = ServiceState.STOPPING; + log.info(SERVER_STATE_MSG, serviceState); - public EventMeshTCPServer getEventMeshTCPServer() { - return eventMeshTCPServer; - } + for (final EventMeshBootstrap eventMeshBootstrap : BOOTSTRAP_LIST) { + eventMeshBootstrap.shutdown(); + } - public static Trace getTrace() { - return trace; - } + if (configuration != null && configuration.isEventMeshServerMetaStorageEnable()) { + metaStorage.shutdown(); + } - public ServiceState getServiceState() { - return serviceState; - } + storageResource.release(); - public Registry getRegistry() { - return registry; - } + if (configuration != null && configuration.isEventMeshServerSecurityEnable()) { + acl.shutdown(); + } + + if (configuration != null && configuration.isEventMeshServerTraceEnable()) { + trace.shutdown(); + } + producerTopicManager.shutdown(); + ConfigurationContextUtil.clear(); - public void setRegistry(Registry registry) { - this.registry = registry; + serviceState = ServiceState.STOPPED; + log.info(SERVER_STATE_MSG, serviceState); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshStartup.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshStartup.java index 5150be94c3..5c6ae90aae 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshStartup.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshStartup.java @@ -17,50 +17,43 @@ package org.apache.eventmesh.runtime.boot; -import org.apache.eventmesh.common.config.ConfigurationWrapper; -import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; -import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; -import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; +import org.apache.eventmesh.common.config.ConfigService; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.util.BannerUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.File; -public class EventMeshStartup { +import lombok.extern.slf4j.Slf4j; - public static Logger logger = LoggerFactory.getLogger(EventMeshStartup.class); +@Slf4j +public class EventMeshStartup { public static void main(String[] args) throws Exception { try { - ConfigurationWrapper configurationWrapper = - new ConfigurationWrapper(EventMeshConstants.EVENTMESH_CONF_HOME, - EventMeshConstants.EVENTMESH_CONF_FILE, false); - EventMeshHTTPConfiguration eventMeshHttpConfiguration = new EventMeshHTTPConfiguration(configurationWrapper); - eventMeshHttpConfiguration.init(); - EventMeshTCPConfiguration eventMeshTcpConfiguration = new EventMeshTCPConfiguration(configurationWrapper); - eventMeshTcpConfiguration.init(); - EventMeshGrpcConfiguration eventMeshGrpcConfiguration = new EventMeshGrpcConfiguration(configurationWrapper); - eventMeshGrpcConfiguration.init(); - EventMeshServer server = new EventMeshServer(eventMeshHttpConfiguration, eventMeshTcpConfiguration, eventMeshGrpcConfiguration); + ConfigService.getInstance() + .setConfigPath(EventMeshConstants.EVENTMESH_CONF_HOME + File.separator) + .setRootConfig(EventMeshConstants.EVENTMESH_CONF_FILE); + + EventMeshServer server = new EventMeshServer(); + BannerUtil.generateBanner(); server.init(); server.start(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { - logger.info("eventMesh shutting down hook begin..."); + log.info("eventMesh shutting down hook begin."); long start = System.currentTimeMillis(); server.shutdown(); long end = System.currentTimeMillis(); - logger.info("eventMesh shutdown cost {}ms", end - start); + + log.info("eventMesh shutdown cost {}ms", end - start); } catch (Exception e) { - logger.error("exception when shutdown...", e); + log.error("exception when shutdown.", e); } })); } catch (Throwable e) { - logger.error("EventMesh start fail.", e); - e.printStackTrace(); + log.error("EventMesh start fail.", e); System.exit(-1); } } } - diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTCPServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTCPServer.java index 68e58ec6b4..3bede2a442 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTCPServer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTCPServer.java @@ -17,379 +17,218 @@ package org.apache.eventmesh.runtime.boot; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.common.ThreadPoolFactory; +import static org.apache.eventmesh.common.Constants.TCP; + +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.tcp.codec.Codec; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.common.protocol.tcp.Command; import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.metrics.api.MetricsPluginFactory; import org.apache.eventmesh.metrics.api.MetricsRegistry; -import org.apache.eventmesh.runtime.admin.controller.ClientManageController; +import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpConnectionHandler; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpExceptionHandler; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpMessageDispatcher; import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.GoodbyeProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.HeartBeatProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.HelloProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.ListenProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.MessageAckProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.MessageTransferProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.RecommendProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.SubscribeProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.processor.UnSubscribeProcessor; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance.EventMeshRebalanceImpl; import org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance.EventMeshRebalanceService; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance.EventmeshRebalanceImpl; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.EventMeshTcpRetryer; -import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMonitor; -import org.apache.eventmesh.runtime.registry.Registry; -import org.apache.eventmesh.runtime.util.EventMeshThreadFactoryImpl; -import org.apache.eventmesh.webhook.admin.AdminWebHookConfigOperationManage; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.TcpRetryer; +import org.apache.eventmesh.runtime.meta.MetaStorage; +import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMetricsManager; import java.util.List; import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import org.assertj.core.util.Lists; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.channel.AdaptiveRecvByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.timeout.IdleStateHandler; -import io.netty.handler.traffic.ChannelTrafficShapingHandler; -import io.netty.handler.traffic.GlobalTrafficShapingHandler; - import com.google.common.util.concurrent.RateLimiter; -public class EventMeshTCPServer extends AbstractRemotingServer { - - private ClientSessionGroupMapping clientSessionGroupMapping; - - private EventMeshTcpRetryer eventMeshTcpRetryer; - - private EventMeshTcpMonitor eventMeshTcpMonitor; - - private ClientManageController clientManageController; - - private EventMeshServer eventMeshServer; - - private EventMeshTCPConfiguration eventMeshTCPConfiguration; - - private GlobalTrafficShapingHandler globalTrafficShapingHandler; - - private ScheduledExecutorService scheduler; - - private ExecutorService taskHandleExecutorService; - - private ExecutorService broadcastMsgDownstreamExecutorService; - - private Registry registry; - - private EventMeshRebalanceService eventMeshRebalanceService; - - public void setClientSessionGroupMapping(ClientSessionGroupMapping clientSessionGroupMapping) { - this.clientSessionGroupMapping = clientSessionGroupMapping; - } - - public ClientManageController getClientManageController() { - return clientManageController; - } - - public void setClientManageController(ClientManageController clientManageController) { - this.clientManageController = clientManageController; - } - - public ScheduledExecutorService getScheduler() { - return scheduler; - } - - public void setScheduler(ScheduledExecutorService scheduler) { - this.scheduler = scheduler; - } - - public ExecutorService getTaskHandleExecutorService() { - return taskHandleExecutorService; - } +import lombok.extern.slf4j.Slf4j; - public ExecutorService getBroadcastMsgDownstreamExecutorService() { - return broadcastMsgDownstreamExecutorService; - } +/** + * Add multiple managers to the underlying server + */ +@Slf4j +public class EventMeshTCPServer extends AbstractTCPServer { - public void setTaskHandleExecutorService(ExecutorService taskHandleExecutorService) { - this.taskHandleExecutorService = taskHandleExecutorService; - } + private final EventMeshServer eventMeshServer; + private final EventMeshTCPConfiguration eventMeshTCPConfiguration; - public RateLimiter getRateLimiter() { - return rateLimiter; - } + private final MetaStorage metaStorage; + private final Acl acl; - public void setRateLimiter(RateLimiter rateLimiter) { - this.rateLimiter = rateLimiter; - } + private ClientSessionGroupMapping clientSessionGroupMapping; - private ScheduledFuture tcpRegisterTask; + private TcpRetryer tcpRetryer; private RateLimiter rateLimiter; + private EventMeshRebalanceService eventMeshRebalanceService; - public EventMeshTCPServer(EventMeshServer eventMeshServer, - EventMeshTCPConfiguration eventMeshTCPConfiguration, Registry registry) { - super(); + public EventMeshTCPServer(final EventMeshServer eventMeshServer, final EventMeshTCPConfiguration eventMeshTCPConfiguration) { + super(eventMeshTCPConfiguration); this.eventMeshServer = eventMeshServer; this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; - this.registry = registry; - } - - private void startServer() { - Runnable r = () -> { - ServerBootstrap bootstrap = new ServerBootstrap(); - ChannelInitializer channelInitializer = new ChannelInitializer() { - @Override - public void initChannel(Channel ch) throws Exception { - ch.pipeline() - .addLast(new Codec.Encoder()) - .addLast(new Codec.Decoder()) - .addLast("global-traffic-shaping", globalTrafficShapingHandler) - .addLast("channel-traffic-shaping", newCTSHandler()) - .addLast(new EventMeshTcpConnectionHandler(EventMeshTCPServer.this)) - .addLast( - workerGroup, - new IdleStateHandler( - eventMeshTCPConfiguration.eventMeshTcpIdleReadSeconds, - eventMeshTCPConfiguration.eventMeshTcpIdleWriteSeconds, - eventMeshTCPConfiguration.eventMeshTcpIdleAllSeconds), - new EventMeshTcpMessageDispatcher(EventMeshTCPServer.this), - new EventMeshTcpExceptionHandler(EventMeshTCPServer.this) - ); - } - }; - - bootstrap.group(bossGroup, ioGroup) - .channel(NioServerSocketChannel.class) - .option(ChannelOption.SO_BACKLOG, 128) - .option(ChannelOption.SO_REUSEADDR, true) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) - .childOption(ChannelOption.SO_KEEPALIVE, false) - .childOption(ChannelOption.SO_LINGER, 0) - .childOption(ChannelOption.SO_TIMEOUT, 600000) - .childOption(ChannelOption.TCP_NODELAY, true) - .childOption(ChannelOption.SO_SNDBUF, 65535 * 4) - .childOption(ChannelOption.SO_RCVBUF, 65535 * 4) - .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(2048, 4096, 65536)) - .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) - .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) - .childHandler(channelInitializer); - - try { - int port = eventMeshTCPConfiguration.eventMeshTcpServerPort; - ChannelFuture f = bootstrap.bind(port).sync(); - logger.info("EventMeshTCPServer[port={}] started.....", port); - f.channel().closeFuture().sync(); - } catch (Exception e) { - logger.error("EventMeshTCPServer RemotingServer Start Err!", e); - try { - shutdown(); - } catch (Exception e1) { - logger.error("EventMeshTCPServer RemotingServer shutdown Err!", e); - } - } - }; - - Thread t = new Thread(r, "eventMesh-tcp-server"); - t.start(); + this.metaStorage = eventMeshServer.getMetaStorage(); + this.acl = eventMeshServer.getAcl(); } public void init() throws Exception { - logger.info("==================EventMeshTCPServer Initialing=================="); - initThreadPool(); + log.info("==================EventMeshTCPServer Initialing=================="); + super.init(); - rateLimiter = RateLimiter.create(eventMeshTCPConfiguration.eventMeshTcpMsgReqnumPerSecond); + rateLimiter = RateLimiter.create(eventMeshTCPConfiguration.getEventMeshTcpMsgReqnumPerSecond()); - globalTrafficShapingHandler = newGTSHandler(); + // The MetricsRegistry is singleton, so we can use factory method to get. + final List metricsRegistries = Lists.newArrayList(); + Optional.ofNullable(eventMeshTCPConfiguration.getEventMeshMetricsPluginType()).ifPresent( + metricsPlugins -> metricsPlugins.forEach( + pluginType -> metricsRegistries.add(MetricsPluginFactory.getMetricsRegistry(pluginType)))); - - AdminWebHookConfigOperationManage adminWebHookConfigOperationManage = new AdminWebHookConfigOperationManage(); - adminWebHookConfigOperationManage.setConfigurationWrapper(eventMeshTCPConfiguration.getConfigurationWrapper()); - adminWebHookConfigOperationManage.init(); - - clientManageController = new ClientManageController(this); - clientManageController.setAdminWebHookConfigOperationManage(adminWebHookConfigOperationManage); + tcpRetryer = new TcpRetryer(this); clientSessionGroupMapping = new ClientSessionGroupMapping(this); clientSessionGroupMapping.init(); + super.setClientSessionGroupMapping(clientSessionGroupMapping); - eventMeshTcpRetryer = new EventMeshTcpRetryer(this); - eventMeshTcpRetryer.init(); + super.setEventMeshTcpMetricsManager(new EventMeshTcpMetricsManager(this, metricsRegistries)); - // The MetricsRegistry is singleton, so we can use factory method to get. - final List metricsRegistries = Lists.newArrayList(); - Optional.ofNullable(eventMeshTCPConfiguration.eventMeshMetricsPluginType) - .ifPresent( - metricsPlugins -> metricsPlugins.forEach( - pluginType -> metricsRegistries.add(MetricsPluginFactory.getMetricsRegistry(pluginType)))); - eventMeshTcpMonitor = new EventMeshTcpMonitor(this, metricsRegistries); - eventMeshTcpMonitor.init(); - - if (eventMeshTCPConfiguration.eventMeshServerRegistryEnable) { - eventMeshRebalanceService = new EventMeshRebalanceService(this, - new EventmeshRebalanceImpl(this)); + if (eventMeshTCPConfiguration.isEventMeshServerMetaStorageEnable()) { + eventMeshRebalanceService = new EventMeshRebalanceService(this, new EventMeshRebalanceImpl(this)); eventMeshRebalanceService.init(); } - logger.info("--------------------------EventMeshTCPServer Inited"); + + registerTCPRequestProcessor(); + + log.info("--------------------------EventMeshTCPServer Inited"); } @Override public void start() throws Exception { - startServer(); + super.start(); + super.getEventMeshTcpMetricsManager().start(); clientSessionGroupMapping.start(); + tcpRetryer.start(); - eventMeshTcpRetryer.start(); - - eventMeshTcpMonitor.start(); - - clientManageController.start(); - - if (eventMeshTCPConfiguration.eventMeshServerRegistryEnable) { + if (eventMeshTCPConfiguration.isEventMeshServerMetaStorageEnable()) { this.register(); eventMeshRebalanceService.start(); } - logger.info("--------------------------EventMeshTCPServer Started"); + log.info("--------------------------EventMeshTCPServer Started"); } @Override public void shutdown() throws Exception { - if (bossGroup != null) { - bossGroup.shutdownGracefully(); - logger.info("shutdown bossGroup, no client is allowed to connect access server"); - } - - if (eventMeshTCPConfiguration.eventMeshServerRegistryEnable) { - eventMeshRebalanceService.shutdown(); + super.shutdown(); - this.unRegister(); - } + super.getEventMeshTcpMetricsManager().shutdown(); clientSessionGroupMapping.shutdown(); - try { - Thread.sleep(40 * 1000); - } catch (InterruptedException e) { - logger.error("interruptedException occurred while sleeping", e); - } + ThreadUtils.sleep(40, TimeUnit.SECONDS); - globalTrafficShapingHandler.release(); + tcpRetryer.shutdown(); - if (ioGroup != null) { - ioGroup.shutdownGracefully(); - logger.info("shutdown ioGroup"); - } - if (workerGroup != null) { - workerGroup.shutdownGracefully(); - logger.info("shutdown workerGroup"); + if (eventMeshTCPConfiguration.isEventMeshServerMetaStorageEnable()) { + eventMeshRebalanceService.shutdown(); + this.unRegister(); } - eventMeshTcpRetryer.shutdown(); - - eventMeshTcpMonitor.shutdown(); - - shutdownThreadPool(); - logger.info("--------------------------EventMeshTCPServer Shutdown"); + log.info("--------------------------EventMeshTCPServer Shutdown"); } + /** + * Related to the registry module + * + * @return boolean + */ public boolean register() { boolean registerResult = false; try { String endPoints = IPUtils.getLocalAddress() - + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshTCPConfiguration.eventMeshTcpServerPort; + + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshTCPConfiguration.getEventMeshTcpServerPort(); EventMeshRegisterInfo eventMeshRegisterInfo = new EventMeshRegisterInfo(); - eventMeshRegisterInfo.setEventMeshClusterName(eventMeshTCPConfiguration.eventMeshCluster); - eventMeshRegisterInfo.setEventMeshName(eventMeshTCPConfiguration.eventMeshName + "-" + ConfigurationContextUtil.TCP); + eventMeshRegisterInfo.setEventMeshClusterName(eventMeshTCPConfiguration.getEventMeshCluster()); + eventMeshRegisterInfo.setEventMeshName(eventMeshTCPConfiguration.getEventMeshName() + "-" + TCP); eventMeshRegisterInfo.setEndPoint(endPoints); eventMeshRegisterInfo.setEventMeshInstanceNumMap(clientSessionGroupMapping.prepareProxyClientDistributionData()); - eventMeshRegisterInfo.setProtocolType(ConfigurationContextUtil.TCP); - registerResult = registry.register(eventMeshRegisterInfo); + eventMeshRegisterInfo.setProtocolType(TCP); + registerResult = metaStorage.register(eventMeshRegisterInfo); } catch (Exception e) { - logger.warn("eventMesh register to registry failed", e); + log.error("eventMesh register to registry failed", e); } return registerResult; } - private void unRegister() throws Exception { - String endPoints = IPUtils.getLocalAddress() - + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshTCPConfiguration.eventMeshTcpServerPort; + /** + * Related to the registry module + */ + private void unRegister() { + String endPoints = IPUtils.getLocalAddress() + EventMeshConstants.IP_PORT_SEPARATOR + eventMeshTCPConfiguration.getEventMeshTcpServerPort(); EventMeshUnRegisterInfo eventMeshUnRegisterInfo = new EventMeshUnRegisterInfo(); - eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshTCPConfiguration.eventMeshCluster); - eventMeshUnRegisterInfo.setEventMeshName(eventMeshTCPConfiguration.eventMeshName); + eventMeshUnRegisterInfo.setEventMeshClusterName(eventMeshTCPConfiguration.getEventMeshCluster()); + eventMeshUnRegisterInfo.setEventMeshName(eventMeshTCPConfiguration.getEventMeshName()); eventMeshUnRegisterInfo.setEndPoint(endPoints); - eventMeshUnRegisterInfo.setProtocolType(ConfigurationContextUtil.TCP); - boolean registerResult = registry.unRegister(eventMeshUnRegisterInfo); + eventMeshUnRegisterInfo.setProtocolType(TCP); + boolean registerResult = metaStorage.unRegister(eventMeshUnRegisterInfo); if (!registerResult) { throw new EventMeshException("eventMesh fail to unRegister"); } } - private void initThreadPool() throws Exception { - super.init("eventMesh-tcp"); + private void registerTCPRequestProcessor() { + ThreadPoolExecutor taskHandleExecutorService = super.getTcpThreadPoolGroup().getTaskHandleExecutorService(); - scheduler = ThreadPoolFactory.createScheduledExecutor(eventMeshTCPConfiguration.eventMeshTcpGlobalScheduler, - new EventMeshThreadFactoryImpl("eventMesh-tcp-scheduler", true)); + HelloProcessor helloProcessor = new HelloProcessor(this); + registerProcessor(Command.HELLO_REQUEST, helloProcessor, taskHandleExecutorService); - taskHandleExecutorService = ThreadPoolFactory.createThreadPoolExecutor( - eventMeshTCPConfiguration.eventMeshTcpTaskHandleExecutorPoolSize, - eventMeshTCPConfiguration.eventMeshTcpTaskHandleExecutorPoolSize, - new LinkedBlockingQueue<>(10000), - new EventMeshThreadFactoryImpl("eventMesh-tcp-task-handle", true)); + RecommendProcessor recommendProcessor = new RecommendProcessor(this); + registerProcessor(Command.RECOMMEND_REQUEST, recommendProcessor, taskHandleExecutorService); - broadcastMsgDownstreamExecutorService = ThreadPoolFactory.createThreadPoolExecutor( - eventMeshTCPConfiguration.eventMeshTcpMsgDownStreamExecutorPoolSize, - eventMeshTCPConfiguration.eventMeshTcpMsgDownStreamExecutorPoolSize, - new LinkedBlockingQueue<>(10000), - new EventMeshThreadFactoryImpl("eventMesh-tcp-msg-downstream", true)); - } + HeartBeatProcessor heartBeatProcessor = new HeartBeatProcessor(this); + registerProcessor(Command.HEARTBEAT_REQUEST, heartBeatProcessor, taskHandleExecutorService); - private void shutdownThreadPool() { - scheduler.shutdown(); - taskHandleExecutorService.shutdown(); - } + GoodbyeProcessor goodbyeProcessor = new GoodbyeProcessor(this); + registerProcessor(Command.CLIENT_GOODBYE_REQUEST, goodbyeProcessor, taskHandleExecutorService); + registerProcessor(Command.SERVER_GOODBYE_RESPONSE, goodbyeProcessor, taskHandleExecutorService); - private GlobalTrafficShapingHandler newGTSHandler() { - GlobalTrafficShapingHandler handler = new GlobalTrafficShapingHandler(scheduler, 0, - eventMeshTCPConfiguration.getGtc().getReadLimit()) { - @Override - protected long calculateSize(Object msg) { - return 1; - } - }; - handler.setMaxTimeWait(1000); - return handler; - } + SubscribeProcessor subscribeProcessor = new SubscribeProcessor(this); + registerProcessor(Command.SUBSCRIBE_REQUEST, subscribeProcessor, taskHandleExecutorService); - private ChannelTrafficShapingHandler newCTSHandler() { - ChannelTrafficShapingHandler handler = new ChannelTrafficShapingHandler(0, - eventMeshTCPConfiguration.getCtc().getReadLimit()) { - @Override - protected long calculateSize(Object msg) { - return 1; - } - }; - handler.setMaxTimeWait(3000); - return handler; - } + UnSubscribeProcessor unSubscribeProcessor = new UnSubscribeProcessor(this); + registerProcessor(Command.UNSUBSCRIBE_REQUEST, unSubscribeProcessor, taskHandleExecutorService); - public ClientSessionGroupMapping getClientSessionGroupMapping() { - return clientSessionGroupMapping; - } + ListenProcessor listenProcessor = new ListenProcessor(this); + registerProcessor(Command.LISTEN_REQUEST, listenProcessor, taskHandleExecutorService); - public EventMeshTcpRetryer getEventMeshTcpRetryer() { - return eventMeshTcpRetryer; - } + ThreadPoolExecutor sendExecutorService = super.getTcpThreadPoolGroup().getSendExecutorService(); + MessageTransferProcessor messageTransferProcessor = new MessageTransferProcessor(this); + registerProcessor(Command.REQUEST_TO_SERVER, messageTransferProcessor, sendExecutorService); + registerProcessor(Command.ASYNC_MESSAGE_TO_SERVER, messageTransferProcessor, sendExecutorService); + registerProcessor(Command.BROADCAST_MESSAGE_TO_SERVER, messageTransferProcessor, sendExecutorService); - public EventMeshTcpMonitor getEventMeshTcpMonitor() { - return eventMeshTcpMonitor; + ThreadPoolExecutor replyExecutorService = super.getTcpThreadPoolGroup().getReplyExecutorService(); + registerProcessor(Command.RESPONSE_TO_SERVER, messageTransferProcessor, replyExecutorService); + + ThreadPoolExecutor ackExecutorService = super.getTcpThreadPoolGroup().getAckExecutorService(); + MessageAckProcessor messageAckProcessor = new MessageAckProcessor(this); + registerProcessor(Command.RESPONSE_TO_CLIENT_ACK, messageAckProcessor, ackExecutorService); + registerProcessor(Command.ASYNC_MESSAGE_TO_CLIENT_ACK, messageAckProcessor, ackExecutorService); + registerProcessor(Command.BROADCAST_MESSAGE_TO_CLIENT_ACK, messageAckProcessor, ackExecutorService); + registerProcessor(Command.REQUEST_TO_CLIENT_ACK, messageAckProcessor, ackExecutorService); } public EventMeshServer getEventMeshServer() { @@ -400,11 +239,37 @@ public EventMeshTCPConfiguration getEventMeshTCPConfiguration() { return eventMeshTCPConfiguration; } - public Registry getRegistry() { - return registry; + public MetaStorage getMetaStorage() { + return metaStorage; } public EventMeshRebalanceService getEventMeshRebalanceService() { return eventMeshRebalanceService; } + + public Acl getAcl() { + return acl; + } + + public ClientSessionGroupMapping getClientSessionGroupMapping() { + return clientSessionGroupMapping; + } + + public void setClientSessionGroupMapping(ClientSessionGroupMapping clientSessionGroupMapping) { + this.clientSessionGroupMapping = clientSessionGroupMapping; + } + + public RateLimiter getRateLimiter() { + return rateLimiter; + } + + public void setRateLimiter(RateLimiter rateLimiter) { + this.rateLimiter = rateLimiter; + } + + public TcpRetryer getTcpRetryer() { + return tcpRetryer; + } + + } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTcpBootstrap.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTcpBootstrap.java new file mode 100644 index 0000000000..e098b203c4 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/EventMeshTcpBootstrap.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import static org.apache.eventmesh.common.Constants.TCP; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; + +import lombok.Getter; + +public class EventMeshTcpBootstrap implements EventMeshBootstrap { + + @Getter + private EventMeshTCPServer eventMeshTcpServer; + + private final EventMeshTCPConfiguration eventMeshTcpConfiguration; + + private final EventMeshServer eventMeshServer; + + public EventMeshTcpBootstrap(EventMeshServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + + ConfigService configService = ConfigService.getInstance(); + this.eventMeshTcpConfiguration = configService.buildConfigInstance(EventMeshTCPConfiguration.class); + + ConfigurationContextUtil.putIfAbsent(TCP, eventMeshTcpConfiguration); + } + + @Override + public void init() throws Exception { + // server init + if (eventMeshTcpConfiguration != null) { + eventMeshTcpServer = new EventMeshTCPServer(eventMeshServer, eventMeshTcpConfiguration); + eventMeshTcpServer.init(); + } + } + + @Override + public void start() throws Exception { + // server start + if (eventMeshTcpConfiguration != null) { + eventMeshTcpServer.start(); + } + } + + @Override + public void shutdown() throws Exception { + if (eventMeshTcpConfiguration != null) { + eventMeshTcpServer.shutdown(); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/FilterEngine.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/FilterEngine.java new file mode 100644 index 0000000000..14677dc690 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/FilterEngine.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.function.filter.pattern.Pattern; +import org.apache.eventmesh.function.filter.patternbuild.PatternBuilder; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerGroupManager; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import com.fasterxml.jackson.databind.JsonNode; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FilterEngine { + + /** + * key:group-topic + **/ + private final Map filterPatternMap = new HashMap<>(); + + private final String filterPrefix = "filter-"; + + private final MetaStorage metaStorage; + + private MetaServiceListener metaServiceListener; + + private final ProducerManager producerManager; + + private final ConsumerManager consumerManager; + + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + + public FilterEngine(MetaStorage metaStorage, ProducerManager producerManager, ConsumerManager consumerManager) { + this.metaStorage = metaStorage; + this.producerManager = producerManager; + this.consumerManager = consumerManager; + } + + public void start() { + Map filterMetaData = metaStorage.getMetaData(filterPrefix, true); + for (Entry filterDataEntry : filterMetaData.entrySet()) { + // filter-group + String key = filterDataEntry.getKey(); + // topic-filterRule list + String value = filterDataEntry.getValue(); + updateFilterPatternMap(key, value); + } + metaServiceListener = this::updateFilterPatternMap; + + // addListeners for producerManager & consumerManager + scheduledExecutorService.scheduleAtFixedRate(() -> { + ConcurrentHashMap producerMap = producerManager.getProducerTable(); + for (String producerGroup : producerMap.keySet()) { + for (String filterKey : filterPatternMap.keySet()) { + if (!StringUtils.contains(filterKey, producerGroup)) { + addFilterListener(producerGroup); + log.info("addFilterListener for producer group: " + producerGroup); + } + } + } + ConcurrentHashMap consumerMap = consumerManager.getClientTable(); + for (String consumerGroup : consumerMap.keySet()) { + for (String filterKey : filterPatternMap.keySet()) { + if (!StringUtils.contains(filterKey, consumerGroup)) { + addFilterListener(consumerGroup); + log.info("addFilterListener for consumer group: " + consumerGroup); + } + } + } + }, 10_000, 5_000, TimeUnit.MILLISECONDS); + } + + private void updateFilterPatternMap(String key, String value) { + String group = StringUtils.substringAfter(key, filterPrefix); + + JsonNode filterJsonNodeArray = JsonUtils.getJsonNode(value); + if (filterJsonNodeArray != null) { + for (JsonNode filterJsonNode : filterJsonNodeArray) { + String topic = filterJsonNode.get("topic").asText(); + String filterCondition = filterJsonNode.get("condition").toString(); + Pattern filterPattern = PatternBuilder.build(filterCondition); + filterPatternMap.put(group + "-" + topic, filterPattern); + } + } + addFilterListener(group); + } + + public void addFilterListener(String group) { + String filterKey = filterPrefix + group; + try { + metaStorage.getMetaDataWithListener(metaServiceListener, filterKey); + } catch (Exception e) { + throw new RuntimeException("addFilterListener exception", e); + } + } + + public void shutdown() { + scheduledExecutorService.shutdown(); + } + + public Pattern getFilterPattern(String key) { + return filterPatternMap.get(key); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPThreadPoolGroup.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPThreadPoolGroup.java new file mode 100644 index 0000000000..4eb1e2d749 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPThreadPoolGroup.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; + +import lombok.Getter; + +public class HTTPThreadPoolGroup implements ThreadPoolGroup { + + private final EventMeshHTTPConfiguration eventMeshHttpConfiguration; + + @Getter + private ThreadPoolExecutor batchMsgExecutor; + @Getter + private ThreadPoolExecutor sendMsgExecutor; + @Getter + private ThreadPoolExecutor remoteMsgExecutor; + @Getter + private ThreadPoolExecutor replyMsgExecutor; + @Getter + private ThreadPoolExecutor pushMsgExecutor; + @Getter + private ThreadPoolExecutor clientManageExecutor; + + public HTTPThreadPoolGroup(EventMeshHTTPConfiguration eventMeshHttpConfiguration) { + this.eventMeshHttpConfiguration = eventMeshHttpConfiguration; + } + + @Override + public void initThreadPool() { + + batchMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshHttpConfiguration.getEventMeshServerBatchMsgThreadNum(), + eventMeshHttpConfiguration.getEventMeshServerBatchMsgThreadNum(), + new LinkedBlockingQueue<>(eventMeshHttpConfiguration.getEventMeshServerBatchBlockQSize()), + "eventMesh-batchMsg", true); + + sendMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshHttpConfiguration.getEventMeshServerSendMsgThreadNum(), + eventMeshHttpConfiguration.getEventMeshServerSendMsgThreadNum(), + new LinkedBlockingQueue<>(eventMeshHttpConfiguration.getEventMeshServerSendMsgBlockQSize()), + "eventMesh-sendMsg", true); + + remoteMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshHttpConfiguration.getEventMeshServerRemoteMsgThreadNum(), + eventMeshHttpConfiguration.getEventMeshServerRemoteMsgThreadNum(), + new LinkedBlockingQueue<>(eventMeshHttpConfiguration.getEventMeshServerRemoteMsgBlockQSize()), + "eventMesh-remoteMsg", true); + + pushMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshHttpConfiguration.getEventMeshServerPushMsgThreadNum(), + eventMeshHttpConfiguration.getEventMeshServerPushMsgThreadNum(), + new LinkedBlockingQueue<>(eventMeshHttpConfiguration.getEventMeshServerPushMsgBlockQSize()), + "eventMesh-pushMsg", true); + + clientManageExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshHttpConfiguration.getEventMeshServerClientManageThreadNum(), + eventMeshHttpConfiguration.getEventMeshServerClientManageThreadNum(), + new LinkedBlockingQueue<>(eventMeshHttpConfiguration.getEventMeshServerClientManageBlockQSize()), + "eventMesh-clientManage", true); + + replyMsgExecutor = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshHttpConfiguration.getEventMeshServerReplyMsgThreadNum(), + eventMeshHttpConfiguration.getEventMeshServerReplyMsgThreadNum(), + new LinkedBlockingQueue<>(100), "eventMesh-replyMsg", true); + } + + @Override + public void shutdownThreadPool() { + if (batchMsgExecutor != null) { + batchMsgExecutor.shutdown(); + } + if (clientManageExecutor != null) { + clientManageExecutor.shutdown(); + } + if (sendMsgExecutor != null) { + sendMsgExecutor.shutdown(); + } + if (remoteMsgExecutor != null) { + remoteMsgExecutor.shutdown(); + } + if (pushMsgExecutor != null) { + pushMsgExecutor.shutdown(); + } + if (replyMsgExecutor != null) { + replyMsgExecutor.shutdown(); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPTrace.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPTrace.java index 9e80180b8f..f712aaea2b 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPTrace.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/HTTPTrace.java @@ -17,19 +17,17 @@ package org.apache.eventmesh.runtime.boot; -import org.apache.eventmesh.runtime.trace.TraceUtils; +import org.apache.eventmesh.runtime.util.TraceUtils; +import org.apache.eventmesh.runtime.util.Utils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; import java.util.Map; +import java.util.Objects; import javax.annotation.Nullable; import io.cloudevents.CloudEvent; import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpRequest; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; @@ -39,7 +37,7 @@ public class HTTPTrace { - public boolean useTrace; + public final boolean useTrace; public HTTPTrace(boolean useTrace) { this.useTrace = useTrace; @@ -47,34 +45,21 @@ public HTTPTrace(boolean useTrace) { public TraceOperation getTraceOperation(HttpRequest httpRequest, Channel channel, boolean traceEnabled) { - final Map headerMap = parseHttpHeader(httpRequest); + final Map headerMap = Utils.parseHttpHeader(httpRequest); Span span = TraceUtils.prepareServerSpan(headerMap, EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); return new TraceOperation(span, null, traceEnabled); } - private Map parseHttpHeader(HttpRequest fullReq) { - Map headerParam = new HashMap<>(); - for (String key : fullReq.headers().names()) { - if (StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_TYPE.toString(), key) - || StringUtils.equalsIgnoreCase(HttpHeaderNames.ACCEPT_ENCODING.toString(), key) - || StringUtils.equalsIgnoreCase(HttpHeaderNames.CONTENT_LENGTH.toString(), key)) { - continue; - } - headerParam.put(key, fullReq.headers().get(key)); - } - return headerParam; - } - @AllArgsConstructor @Getter public class TraceOperation { - private Span span; + private final Span span; private TraceOperation childTraceOperation; - private boolean traceEnabled; + private final boolean traceEnabled; public void endTrace(CloudEvent ce) { if (!HTTPTrace.this.useTrace) { @@ -96,7 +81,7 @@ public void exceptionTrace(@Nullable Throwable ex, Map map) { childTraceOperation.exceptionTrace(ex, map); } try (Scope ignored = span.makeCurrent()) { - TraceUtils.finishSpanWithException(span, map, ex.getMessage(), ex); + TraceUtils.finishSpanWithException(span, map, Objects.requireNonNull(ex).getMessage(), ex); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/RemotingServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/RemotingServer.java new file mode 100644 index 0000000000..764075cc64 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/RemotingServer.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.config.CommonConfiguration; + +/** + * Remoting server interface. + */ +public interface RemotingServer { + + void init() throws Exception; + + CommonConfiguration getConfiguration(); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/SSLContextFactory.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/SSLContextFactory.java index 0d7fff5d04..a0736b430a 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/SSLContextFactory.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/SSLContextFactory.java @@ -1,74 +1,70 @@ /* - * Licensed to 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. Apache Software Foundation (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 + * 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. + * 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. */ package org.apache.eventmesh.runtime.boot; +import org.apache.eventmesh.runtime.configuration.EventMeshAdminConfiguration; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.commons.lang3.StringUtils; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.security.KeyManagementException; import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class SSLContextFactory { - private static Logger httpLogger = LoggerFactory.getLogger("http"); - - private static String protocol = "TLSv1.1"; - - private static String fileName; - - private static String pass; + /** + * {@link EventMeshAdminConfiguration} will be parsed into {@link EventMeshHTTPConfiguration}. + */ + public static SSLContext getSslContext(final EventMeshHTTPConfiguration eventMeshHttpConfiguration) + throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { - public static SSLContext getSslContext() { + String protocol = eventMeshHttpConfiguration.getEventMeshServerSSLProtocol(); + String fileName = eventMeshHttpConfiguration.getEventMeshServerSSLCer(); + String password = eventMeshHttpConfiguration.getEventMeshServerSSLPass(); SSLContext sslContext; - try { - protocol = System.getProperty("ssl.server.protocol", "TLSv1.1"); - fileName = System.getProperty("ssl.server.cer", "sChat2.jks"); + try (InputStream inputStream = Files.newInputStream(Paths.get(EventMeshConstants.EVENTMESH_CONF_HOME + File.separator + fileName), + StandardOpenOption.READ)) { - char[] filePass = null; - pass = System.getProperty("ssl.server.pass", "sNetty"); - if (StringUtils.isNotBlank(pass)) { - filePass = pass.toCharArray(); - } - sslContext = SSLContext.getInstance(protocol); - KeyStore keyStore = KeyStore.getInstance("JKS"); - keyStore.load(Files.newInputStream(Paths.get(EventMeshConstants.EVENTMESH_CONF_HOME - + File.separator - + fileName), StandardOpenOption.READ), filePass); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + char[] filePass = StringUtils.isNotBlank(password) ? password.toCharArray() : new char[0]; + final KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(inputStream, filePass); + final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, filePass); + + sslContext = SSLContext.getInstance(protocol); sslContext.init(kmf.getKeyManagers(), null, null); - } catch (Exception e) { - httpLogger.warn("sslContext init failed", e); - sslContext = null; } + return sslContext; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/TCPThreadPoolGroup.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/TCPThreadPoolGroup.java new file mode 100644 index 0000000000..5f71a57f55 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/TCPThreadPoolGroup.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + +public class TCPThreadPoolGroup implements ThreadPoolGroup { + + private final EventMeshTCPConfiguration eventMeshTCPConfiguration; + private ScheduledExecutorService scheduler; + private ThreadPoolExecutor taskHandleExecutorService; + private ThreadPoolExecutor sendExecutorService; + private ThreadPoolExecutor ackExecutorService; + private ThreadPoolExecutor replyExecutorService; + private ThreadPoolExecutor broadcastMsgDownstreamExecutorService; + + public TCPThreadPoolGroup(EventMeshTCPConfiguration eventMeshTCPConfiguration) { + this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; + } + + @Override + public void initThreadPool() { + + scheduler = ThreadPoolFactory.createScheduledExecutor(eventMeshTCPConfiguration.getEventMeshTcpGlobalScheduler(), + new EventMeshThreadFactory("eventMesh-tcp-scheduler", true)); + + taskHandleExecutorService = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshTCPConfiguration.getEventMeshTcpTaskHandleExecutorPoolSize(), + eventMeshTCPConfiguration.getEventMeshTcpTaskHandleExecutorPoolSize(), + new LinkedBlockingQueue<>(eventMeshTCPConfiguration.getEventMeshTcpTaskHandleExecutorQueueSize()), + new EventMeshThreadFactory("eventMesh-tcp-task-handle", true)); + + sendExecutorService = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshTCPConfiguration.getEventMeshTcpMsgSendExecutorPoolSize(), + eventMeshTCPConfiguration.getEventMeshTcpMsgSendExecutorPoolSize(), + new LinkedBlockingQueue<>(eventMeshTCPConfiguration.getEventMeshTcpMsgSendExecutorQueueSize()), + new EventMeshThreadFactory("eventMesh-tcp-msg-send", true)); + + replyExecutorService = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshTCPConfiguration.getEventMeshTcpMsgReplyExecutorPoolSize(), + eventMeshTCPConfiguration.getEventMeshTcpMsgReplyExecutorPoolSize(), + new LinkedBlockingQueue<>(eventMeshTCPConfiguration.getEventMeshTcpMsgReplyExecutorQueueSize()), + new EventMeshThreadFactory("eventMesh-tcp-msg-reply", true)); + + ackExecutorService = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshTCPConfiguration.getEventMeshTcpMsgAckExecutorPoolSize(), + eventMeshTCPConfiguration.getEventMeshTcpMsgAckExecutorPoolSize(), + new LinkedBlockingQueue<>(eventMeshTCPConfiguration.getEventMeshTcpMsgAckExecutorQueueSize()), + new EventMeshThreadFactory("eventMesh-tcp-msg-ack", true)); + + broadcastMsgDownstreamExecutorService = ThreadPoolFactory.createThreadPoolExecutor( + eventMeshTCPConfiguration.getEventMeshTcpMsgDownStreamExecutorPoolSize(), + eventMeshTCPConfiguration.getEventMeshTcpMsgDownStreamExecutorPoolSize(), + new LinkedBlockingQueue<>(10_000), + new EventMeshThreadFactory("eventMesh-tcp-msg-downstream", true)); + } + + @Override + public void shutdownThreadPool() { + scheduler.shutdown(); + taskHandleExecutorService.shutdown(); + sendExecutorService.shutdown();; + replyExecutorService.shutdown(); + ackExecutorService.shutdown(); + broadcastMsgDownstreamExecutorService.shutdown(); + } + + public ScheduledExecutorService getScheduler() { + return scheduler; + } + + public ThreadPoolExecutor getTaskHandleExecutorService() { + return taskHandleExecutorService; + } + + public ThreadPoolExecutor getBroadcastMsgDownstreamExecutorService() { + return broadcastMsgDownstreamExecutorService; + } + + public ThreadPoolExecutor getSendExecutorService() { + return sendExecutorService; + } + + public ThreadPoolExecutor getAckExecutorService() { + return ackExecutorService; + } + + public ThreadPoolExecutor getReplyExecutorService() { + return replyExecutorService; + } +} \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/ThreadPoolGroup.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/ThreadPoolGroup.java new file mode 100644 index 0000000000..412094e6e9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/ThreadPoolGroup.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +/** + * The implementation class for this interface is used to assemble the thread pool required by the server + * + */ +public interface ThreadPoolGroup { + + void initThreadPool(); + + void shutdownThreadPool(); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/TransformerEngine.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/TransformerEngine.java new file mode 100644 index 0000000000..1d2f8ca30c --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/boot/TransformerEngine.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.function.transformer.Transformer; +import org.apache.eventmesh.function.transformer.TransformerBuilder; +import org.apache.eventmesh.function.transformer.TransformerParam; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerGroupManager; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import com.fasterxml.jackson.databind.JsonNode; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TransformerEngine { + + /** + * key:group-topic + **/ + private final Map transformerMap = new HashMap<>(); + + private final String transformerPrefix = "transformer-"; + + private final MetaStorage metaStorage; + + private MetaServiceListener metaServiceListener; + + private final ProducerManager producerManager; + + private final ConsumerManager consumerManager; + + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + + public TransformerEngine(MetaStorage metaStorage, ProducerManager producerManager, ConsumerManager consumerManager) { + this.metaStorage = metaStorage; + this.producerManager = producerManager; + this.consumerManager = consumerManager; + } + + public void start() { + Map transformerMetaData = metaStorage.getMetaData(transformerPrefix, true); + for (Entry transformerDataEntry : transformerMetaData.entrySet()) { + // transformer-group + String key = transformerDataEntry.getKey(); + // topic-transformerParam list + String value = transformerDataEntry.getValue(); + updateTransformerMap(key, value); + } + metaServiceListener = this::updateTransformerMap; + + // addListeners for producerManager & consumerManager + scheduledExecutorService.scheduleAtFixedRate(() -> { + ConcurrentHashMap producerMap = producerManager.getProducerTable(); + for (String producerGroup : producerMap.keySet()) { + for (String transformerKey : transformerMap.keySet()) { + if (!StringUtils.contains(transformerKey, producerGroup)) { + addTransformerListener(producerGroup); + log.info("addTransformerListener for producer group: " + producerGroup); + } + } + } + ConcurrentHashMap consumerMap = consumerManager.getClientTable(); + for (String consumerGroup : consumerMap.keySet()) { + for (String transformerKey : transformerMap.keySet()) { + if (!StringUtils.contains(transformerKey, consumerGroup)) { + addTransformerListener(consumerGroup); + log.info("addTransformerListener for consumer group: " + consumerGroup); + } + } + } + }, 10_000, 5_000, TimeUnit.MILLISECONDS); + } + + private void updateTransformerMap(String key, String value) { + String group = StringUtils.substringAfter(key, transformerPrefix); + + JsonNode transformerJsonNodeArray = JsonUtils.getJsonNode(value); + + if (transformerJsonNodeArray != null) { + for (JsonNode transformerJsonNode : transformerJsonNodeArray) { + String topic = transformerJsonNode.get("topic").asText(); + String transformerParam = transformerJsonNode.get("transformerParam").toString(); + TransformerParam tfp = JsonUtils.parseObject(transformerParam, TransformerParam.class); + Transformer transformer = TransformerBuilder.buildTransformer(tfp); + transformerMap.put(group + "-" + topic, transformer); + } + } + addTransformerListener(group); + } + + public void addTransformerListener(String group) { + String transformerKey = transformerPrefix + group; + try { + metaStorage.getMetaDataWithListener(metaServiceListener, transformerKey); + } catch (Exception e) { + throw new RuntimeException("addTransformerListener exception", e); + } + } + + public void shutdown() { + scheduledExecutorService.shutdown(); + } + + public Transformer getTransformer(String key) { + return transformerMap.get(key); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshHttpHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshHttpHandler.java new file mode 100644 index 0000000000..dd30f65e6a --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshHttpHandler.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.common; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface EventMeshHttpHandler { + + /** + * request path + * + * @return path + */ + String path(); + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshTrace.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshTrace.java index 348f74120e..e356d855a4 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshTrace.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/EventMeshTrace.java @@ -1,20 +1,18 @@ /* - * 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 + * 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 + * 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. + * 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. */ package org.apache.eventmesh.runtime.common; @@ -29,6 +27,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface EventMeshTrace { + /** * If true, enable the trace */ diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/Pair.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/Pair.java deleted file mode 100644 index 5e2a428ef6..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/Pair.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.common; - -public class Pair { - private T1 object1; - private T2 object2; - - public Pair(T1 object1, T2 object2) { - this.object1 = object1; - this.object2 = object2; - } - - public T1 getObject1() { - return object1; - } - - public void setObject1(T1 object1) { - this.object1 = object1; - } - - public T2 getObject2() { - return object2; - } - - public void setObject2(T2 object2) { - this.object2 = object2; - } -} - diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/ServiceState.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/ServiceState.java index 6848b2c2bc..841450d5b6 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/ServiceState.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/common/ServiceState.java @@ -23,7 +23,7 @@ public enum ServiceState { RUNNING, - STOPING, + STOPPING, - STOPED; + STOPPED; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshAdminConfiguration.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshAdminConfiguration.java new file mode 100644 index 0000000000..dff80eaaa2 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshAdminConfiguration.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.configuration; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import java.util.Collections; +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import inet.ipaddr.IPAddress; + +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Config(prefix = "eventMesh.server") +public class EventMeshAdminConfiguration extends EventMeshHTTPConfiguration { + + @ConfigField(field = "admin.http.port") + private int eventMeshServerAdminPort = 10106; + + @ConfigField(field = "admin.threads.num") + private int eventMeshServerAdminThreadNum = 2; + + @ConfigField(field = "admin.useTls.enabled") + private boolean eventMeshServerUseTls = false; + + @ConfigField(field = "admin.ssl.protocol") + private String eventMeshServerSSLProtocol = "TLSv1.3"; + + @ConfigField(field = "admin.ssl.cer") + private String eventMeshServerSSLCer = "admin-server.jks"; + + @ConfigField(field = "admin.ssl.pass") + private String eventMeshServerSSLPass = "eventmesh-admin-server"; + + @ConfigField(field = "admin.blacklist.ipv4") + private List eventMeshIpv4BlackList = Collections.emptyList(); // TODO implement after merging #4835 + + @ConfigField(field = "admin.blacklist.ipv6") + private List eventMeshIpv6BlackList = Collections.emptyList(); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfiguration.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfiguration.java index 65142f6326..924a07ab01 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfiguration.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfiguration.java @@ -18,240 +18,92 @@ package org.apache.eventmesh.runtime.configuration; import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.config.ConfigurationWrapper; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.commons.lang3.StringUtils; - -import com.google.common.base.Preconditions; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Config(prefix = "eventMesh.server") public class EventMeshGrpcConfiguration extends CommonConfiguration { - public int grpcServerPort = 10205; - - public int eventMeshSessionExpiredInMills = 60000; - - public boolean eventMeshServerBatchMsgBatchEnabled = Boolean.TRUE; - - public int eventMeshServerBatchMsgThreadNum = 10; - - public int eventMeshServerSendMsgThreadNum = 8; - - public int eventMeshServerPushMsgThreadNum = 8; - - public int eventMeshServerReplyMsgThreadNum = 8; - - public int eventMeshServerSubscribeMsgThreadNum = 4; - - public int eventMeshServerRegistryThreadNum = 10; - - public int eventMeshServerAdminThreadNum = 2; - - public int eventMeshServerRetryThreadNum = 2; - - public int eventMeshServerPullRegistryInterval = 30000; - - public int eventMeshServerAsyncAccumulationThreshold = 1000; - - public int eventMeshServerRetryBlockQueueSize = 10000; - - public int eventMeshServerBatchBlockQueueSize = 1000; - - public int eventMeshServerSendMsgBlockQueueSize = 1000; - - public int eventMeshServerPushMsgBlockQueueSize = 1000; - - public int eventMeshServerSubscribeMsgBlockQueueSize = 1000; - - public int eventMeshServerBusyCheckInterval = 1000; - - public boolean eventMeshServerConsumerEnabled = false; - - public boolean eventMeshServerUseTls = false; - - public int eventMeshBatchMsgRequestNumPerSecond = 20000; - - public int eventMeshMsgReqNumPerSecond = 15000; - - public String eventMeshIp = IPUtils.getLocalAddress(); - - public EventMeshGrpcConfiguration(ConfigurationWrapper configurationWrapper) { - super(configurationWrapper); - } - - @Override - public void init() { - super.init(); - - if (configurationWrapper != null) { - String httpServerPortStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_SERVER_GRPC_PORT); - Preconditions.checkState(StringUtils.isNotEmpty(httpServerPortStr) && StringUtils.isNumeric(httpServerPortStr), - String.format("%s error", ConfKeys.KEYS_EVENTMESH_SERVER_GRPC_PORT)); - grpcServerPort = Integer.parseInt(StringUtils.deleteWhitespace(httpServerPortStr)); - - String eventMeshServerBatchMsgThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_BATCHMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerBatchMsgThreadNumStr) && StringUtils.isNumeric(eventMeshServerBatchMsgThreadNumStr)) { - eventMeshServerBatchMsgThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerBatchMsgThreadNumStr)); - } - - String eventMeshTcpSessionExpiredInMillsStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_SERVER_SESSION_EXPIRED_TIME); - if (StringUtils.isNotEmpty(eventMeshTcpSessionExpiredInMillsStr) && StringUtils.isNumeric(eventMeshTcpSessionExpiredInMillsStr)) { - eventMeshSessionExpiredInMills = Integer.parseInt(eventMeshTcpSessionExpiredInMillsStr); - } - - String eventMeshServerBatchMsgReqNumPerSecondStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_BATCHMSG_REQ_NUM_PER_SECOND); - if (StringUtils.isNotEmpty(eventMeshServerBatchMsgReqNumPerSecondStr) - && StringUtils.isNumeric(eventMeshServerBatchMsgReqNumPerSecondStr)) { - eventMeshBatchMsgRequestNumPerSecond = Integer.parseInt(eventMeshServerBatchMsgReqNumPerSecondStr); - } - - String eventMeshServerBatchMsgBatchEnableStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_BATCHMSG_BATCH_ENABLED); - if (StringUtils.isNotBlank(eventMeshServerBatchMsgBatchEnableStr)) { - eventMeshServerBatchMsgBatchEnabled = Boolean.parseBoolean(eventMeshServerBatchMsgBatchEnableStr); - } - - String eventMeshServerAsyncAccumulationThresholdStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ASYNC_ACCUMULATION_THRESHOLD); - if (StringUtils.isNotEmpty(eventMeshServerAsyncAccumulationThresholdStr) - && StringUtils.isNumeric(eventMeshServerAsyncAccumulationThresholdStr)) { - eventMeshServerAsyncAccumulationThreshold = Integer.parseInt( - StringUtils.deleteWhitespace(eventMeshServerAsyncAccumulationThresholdStr)); - } - - String eventMeshServerSendMsgThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_SENDMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerSendMsgThreadNumStr) && StringUtils.isNumeric(eventMeshServerSendMsgThreadNumStr)) { - eventMeshServerSendMsgThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerSendMsgThreadNumStr)); - } - - String eventMeshServerReplyMsgThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REPLYMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerReplyMsgThreadNumStr) && StringUtils.isNumeric(eventMeshServerReplyMsgThreadNumStr)) { - eventMeshServerReplyMsgThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerReplyMsgThreadNumStr)); - } - - String eventMeshServerPushMsgThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_PUSHMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerPushMsgThreadNumStr) && StringUtils.isNumeric(eventMeshServerPushMsgThreadNumStr)) { - eventMeshServerPushMsgThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerPushMsgThreadNumStr)); - } - - String eventMeshServerRegistryThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REGISTRY_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerRegistryThreadNumStr) && StringUtils.isNumeric(eventMeshServerRegistryThreadNumStr)) { - eventMeshServerRegistryThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRegistryThreadNumStr)); - } - - String eventMeshServerClientManageThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_CLIENTMANAGE_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerClientManageThreadNumStr) && StringUtils.isNumeric(eventMeshServerClientManageThreadNumStr)) { - eventMeshServerSubscribeMsgThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerClientManageThreadNumStr)); - } - - String eventMeshServerPullRegistryIntervalStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_PULL_REGISTRY_INTERVAL); - if (StringUtils.isNotEmpty(eventMeshServerPullRegistryIntervalStr) && StringUtils.isNumeric(eventMeshServerPullRegistryIntervalStr)) { - eventMeshServerPullRegistryInterval = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerPullRegistryIntervalStr)); - } - - String eventMeshServerAdminThreadNumStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ADMIN_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerAdminThreadNumStr) && StringUtils.isNumeric(eventMeshServerAdminThreadNumStr)) { - eventMeshServerAdminThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerAdminThreadNumStr)); - } - - String eventMeshServerRetryBlockQueueSizeStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_RETRY_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerRetryBlockQueueSizeStr) && StringUtils.isNumeric(eventMeshServerRetryBlockQueueSizeStr)) { - eventMeshServerRetryBlockQueueSize = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRetryBlockQueueSizeStr)); - } - - String eventMeshServerBatchBlockQueueSizeStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_BATCHMSG_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerBatchBlockQueueSizeStr) && StringUtils.isNumeric(eventMeshServerBatchBlockQueueSizeStr)) { - eventMeshServerBatchBlockQueueSize = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerBatchBlockQueueSizeStr)); - } - - String eventMeshServerSendMsgBlockQueueSizeStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SENDMSG_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerSendMsgBlockQueueSizeStr) && StringUtils.isNumeric(eventMeshServerSendMsgBlockQueueSizeStr)) { - eventMeshServerSendMsgBlockQueueSize = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerSendMsgBlockQueueSizeStr)); - } - - String eventMeshServerPushMsgBlockQueueSizeStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_PUSHMSG_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerPushMsgBlockQueueSizeStr) && StringUtils.isNumeric(eventMeshServerPushMsgBlockQueueSizeStr)) { - eventMeshServerPushMsgBlockQueueSize = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerPushMsgBlockQueueSizeStr)); - } - - String eventMeshServerClientManageBlockQueueSizeStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_CLIENTM_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerClientManageBlockQueueSizeStr) - && StringUtils.isNumeric(eventMeshServerClientManageBlockQueueSizeStr)) { - eventMeshServerSubscribeMsgBlockQueueSize = Integer.parseInt( - StringUtils.deleteWhitespace(eventMeshServerClientManageBlockQueueSizeStr)); - } - - String eventMeshServerBusyCheckIntervalStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_BUSY_CHECK_INTERVAL); - if (StringUtils.isNotEmpty(eventMeshServerBusyCheckIntervalStr) && StringUtils.isNumeric(eventMeshServerBusyCheckIntervalStr)) { - eventMeshServerBusyCheckInterval = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerBusyCheckIntervalStr)); - } - - String eventMeshServerConsumerEnabledStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_CONSUMER_ENABLED); - if (StringUtils.isNotEmpty(eventMeshServerConsumerEnabledStr)) { - eventMeshServerConsumerEnabled = Boolean.parseBoolean(StringUtils.deleteWhitespace(eventMeshServerConsumerEnabledStr)); - } - - String eventMeshServerRetryThreadNumStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_RETRY_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerRetryThreadNumStr) && StringUtils.isNumeric(eventMeshServerRetryThreadNumStr)) { - eventMeshServerRetryThreadNum = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRetryThreadNumStr)); - } - - String eventMeshServerUseTlsStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_TLS_ENABLED); - if (StringUtils.isNotEmpty(eventMeshServerUseTlsStr)) { - eventMeshServerUseTls = Boolean.parseBoolean(StringUtils.deleteWhitespace(eventMeshServerUseTlsStr)); - } - - String eventMeshMsgReqNumPerSecondStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SERVER_MSG_REQ_NUM_PER_SECOND); - if (StringUtils.isNotEmpty(eventMeshMsgReqNumPerSecondStr) && StringUtils.isNumeric(eventMeshMsgReqNumPerSecondStr)) { - eventMeshMsgReqNumPerSecond = Integer.parseInt(eventMeshMsgReqNumPerSecondStr); - } - } - } + @ConfigField(field = "grpc.port", notNull = true, beNumber = true) + private int grpcServerPort = 10205; - static class ConfKeys { + @ConfigField(field = "session.expiredInMills") + private int eventMeshSessionExpiredInMills = 60000; - public static final String KEYS_EVENTMESH_SERVER_GRPC_PORT = "eventMesh.server.grpc.port"; + @ConfigField(field = "batchmsg.batch.enabled") + private boolean eventMeshServerBatchMsgBatchEnabled = Boolean.TRUE; - public static final String KEYS_EVENTMESH_SERVER_SESSION_EXPIRED_TIME = "eventMesh.server.session.expiredInMills"; + @ConfigField(field = "batchmsg.threads.num") + private int eventMeshServerBatchMsgThreadNum = 10; - public static final String KEYS_EVENTMESH_BATCHMSG_THREAD_NUM = "eventMesh.server.batchmsg.threads.num"; + @ConfigField(field = "sendmsg.threads.num") + private int eventMeshServerSendMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_BATCHMSG_REQ_NUM_PER_SECOND = "eventMesh.server.batchmsg.reqNumPerSecond"; + @ConfigField(field = "pushmsg.threads.num") + private int eventMeshServerPushMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_BATCHMSG_BATCH_ENABLED = "eventMesh.server.batchmsg.batch.enabled"; + @ConfigField(field = "replymsg.threads.num") + private int eventMeshServerReplyMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_ASYNC_ACCUMULATION_THRESHOLD = "eventMesh.server.async.accumulation.threshold"; + @ConfigField(field = "clientmanage.threads.num") + private int eventMeshServerSubscribeMsgThreadNum = 4; - public static final String KEY_EVENTMESH_BUSY_CHECK_INTERVAL = "eventMesh.server.busy.check.interval"; + @ConfigField(field = "metaStorage.threads.num") + private int eventMeshServerMetaStorageThreadNum = 10; - public static final String KEYS_EVENTMESH_SENDMSG_THREAD_NUM = "eventMesh.server.sendmsg.threads.num"; + @ConfigField(field = "retry.threads.num") + private int eventMeshServerRetryThreadNum = 2; - public static final String KEYS_EVENTMESH_REPLYMSG_THREAD_NUM = "eventMesh.server.replymsg.threads.num"; + @ConfigField(field = "pull.metaStorage.interval") + private int eventMeshServerPullMetaStorageInterval = 30000; - public static final String KEYS_EVENTMESH_PUSHMSG_THREAD_NUM = "eventMesh.server.pushmsg.threads.num"; + @ConfigField(field = "async.accumulation.threshold") + private int eventMeshServerAsyncAccumulationThreshold = 1000; - public static final String KEYS_EVENTMESH_REGISTRY_THREAD_NUM = "eventMesh.server.registry.threads.num"; + @ConfigField(field = "retry.blockQ.size") + private int eventMeshServerRetryBlockQueueSize = 10000; - public static final String KEYS_EVENTMESH_CLIENTMANAGE_THREAD_NUM = "eventMesh.server.clientmanage.threads.num"; + @ConfigField(field = "batchmsg.blockQ.size") + private int eventMeshServerBatchBlockQueueSize = 1000; - public static final String KEYS_EVENTMESH_ADMIN_THREAD_NUM = "eventMesh.server.admin.threads.num"; + @ConfigField(field = "sendmsg.blockQ.size") + private int eventMeshServerSendMsgBlockQueueSize = 1000; - public static final String KEY_EVENTMESH_RETRY_THREAD_NUM = "eventMesh.server.retry.threads.num"; + @ConfigField(field = "pushmsg.blockQ.size") + private int eventMeshServerPushMsgBlockQueueSize = 1000; - public static final String KEYS_EVENTMESH_PULL_REGISTRY_INTERVAL = "eventMesh.server.pull.registry.interval"; + @ConfigField(field = "clientM.blockQ.size") + private int eventMeshServerSubscribeMsgBlockQueueSize = 1000; - public static final String KEY_EVENTMESH_RETRY_BLOCKQ_SIZE = "eventMesh.server.retry.blockQ.size"; + @ConfigField(field = "busy.check.interval") + private int eventMeshServerBusyCheckInterval = 1000; - public static final String KEY_EVENTMESH_BATCHMSG_BLOCKQ_SIZE = "eventMesh.server.batchmsg.blockQ.size"; + @ConfigField(field = "consumer.enabled") + private boolean eventMeshServerConsumerEnabled = false; - public static final String KEY_EVENTMESH_SENDMSG_BLOCKQ_SIZE = "eventMesh.server.sendmsg.blockQ.size"; + @ConfigField(field = "useTls.enabled") + private boolean eventMeshServerUseTls = false; - public static final String KEY_EVENTMESH_PUSHMSG_BLOCKQ_SIZE = "eventMesh.server.pushmsg.blockQ.size"; + @ConfigField(field = "batchmsg.reqNumPerSecond") + private int eventMeshBatchMsgRequestNumPerSecond = 20000; - public static final String KEY_EVENTMESH_CLIENTM_BLOCKQ_SIZE = "eventMesh.server.clientM.blockQ.size"; + @ConfigField(field = "http.msgReqnumPerSecond") + private int eventMeshMsgReqNumPerSecond = 15000; - public static final String KEY_EVENTMESH_CONSUMER_ENABLED = "eventMesh.server.consumer.enabled"; + @ConfigField(field = "", reload = true) + private String eventMeshIp; - public static final String KEY_EVENTMESH_TLS_ENABLED = "eventMesh.server.useTls.enabled"; + public void reload() { + super.reload(); - public static final String KEY_EVENTMESH_SERVER_MSG_REQ_NUM_PER_SECOND = "eventMesh.server.http.msgReqnumPerSecond"; + this.eventMeshIp = IPUtils.getLocalAddress(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfiguration.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfiguration.java index 287fce915a..389a677052 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfiguration.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfiguration.java @@ -18,363 +18,111 @@ package org.apache.eventmesh.runtime.configuration; import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.config.ConfigurationWrapper; - -import org.apache.commons.lang3.StringUtils; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; import java.util.Collections; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import inet.ipaddr.IPAddress; -import inet.ipaddr.IPAddressString; +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Config(prefix = "eventMesh.server") public class EventMeshHTTPConfiguration extends CommonConfiguration { - public static Logger logger = LoggerFactory.getLogger(EventMeshHTTPConfiguration.class); - - public int httpServerPort = 10105; - - public boolean eventMeshServerBatchMsgBatchEnabled = Boolean.TRUE; - - public int eventMeshServerBatchMsgThreadNum = 10; - - public int eventMeshServerSendMsgThreadNum = 8; - - public int eventMeshServerRemoteMsgThreadNum = 8; - - public int eventMeshServerPushMsgThreadNum = 8; - - public int eventMeshServerReplyMsgThreadNum = 8; - - public int eventMeshServerClientManageThreadNum = 4; - - public int eventMeshServerRegistryThreadNum = 10; - - public int eventMeshServerAdminThreadNum = 2; - - public int eventMeshServerRetryThreadNum = 2; - - public int eventMeshServerWebhookThreadNum = 4; - - public int eventMeshServerPullRegistryInterval = 30000; - - public int eventMeshServerAsyncAccumulationThreshold = 1000; - - public int eventMeshServerRetryBlockQSize = 10000; - - public int eventMeshServerBatchBlockQSize = 1000; - - public int eventMeshServerSendMsgBlockQSize = 1000; - - public int eventMeshServerRemoteMsgBlockQSize = 1000; - - public int eventMeshServerPushMsgBlockQSize = 1000; - - public int eventMeshServerClientManageBlockQSize = 1000; - - public int eventMeshServerBusyCheckInterval = 1000; - - public boolean eventMeshServerConsumerEnabled = false; - - public boolean eventMeshServerUseTls = false; - - public int eventMeshHttpMsgReqNumPerSecond = 15000; - - public int eventMeshBatchMsgRequestNumPerSecond = 20000; - - public int eventMeshEventSize = 1000; - - public int eventMeshEventBatchSize = 10; - - public List eventMeshIpv4BlackList = Collections.emptyList(); - - public List eventMeshIpv6BlackList = Collections.emptyList(); - - public EventMeshHTTPConfiguration(ConfigurationWrapper configurationWrapper) { - super(configurationWrapper); - } - - @Override - public void init() { - super.init(); - - if (configurationWrapper != null) { - String httpServerPortStr = configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_SERVER_HTTP_PORT); - Preconditions.checkState(StringUtils.isNotEmpty(httpServerPortStr) - && StringUtils.isNumeric(httpServerPortStr), String.format("%s error", ConfKeys.KEYS_EVENTMESH_SERVER_HTTP_PORT)); - httpServerPort = Integer.parseInt(StringUtils.deleteWhitespace(httpServerPortStr)); - - String eventMeshServerBatchMsgThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_BATCHMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerBatchMsgThreadNumStr) - && StringUtils.isNumeric(eventMeshServerBatchMsgThreadNumStr)) { - eventMeshServerBatchMsgThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerBatchMsgThreadNumStr)); - } - - String eventMeshServerBatchMsgReqNumPerSecondStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_BATCHMSG_REQ_NUM_PER_SECOND); - if (StringUtils.isNotEmpty(eventMeshServerBatchMsgReqNumPerSecondStr) - && StringUtils.isNumeric(eventMeshServerBatchMsgReqNumPerSecondStr)) { - eventMeshBatchMsgRequestNumPerSecond = Integer.parseInt(eventMeshServerBatchMsgReqNumPerSecondStr); - } - - String eventMeshServerBatchMsgBatchEnableStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_BATCHMSG_BATCH_ENABLED); - if (StringUtils.isNotBlank(eventMeshServerBatchMsgBatchEnableStr)) { - eventMeshServerBatchMsgBatchEnabled = Boolean.parseBoolean(eventMeshServerBatchMsgBatchEnableStr); - } - - String eventMeshServerAsyncAccumulationThresholdStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ASYNC_ACCUMULATION_THRESHOLD); - if (StringUtils.isNotEmpty(eventMeshServerAsyncAccumulationThresholdStr) - && StringUtils.isNumeric(eventMeshServerAsyncAccumulationThresholdStr)) { - eventMeshServerAsyncAccumulationThreshold = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerAsyncAccumulationThresholdStr)); - } - - String eventMeshServerSendMsgThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_SENDMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerSendMsgThreadNumStr) - && StringUtils.isNumeric(eventMeshServerSendMsgThreadNumStr)) { - eventMeshServerSendMsgThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerSendMsgThreadNumStr)); - } - - String eventMeshServerRemoteMsgThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REMOTEMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerRemoteMsgThreadNumStr) - && StringUtils.isNumeric(eventMeshServerRemoteMsgThreadNumStr)) { - eventMeshServerRemoteMsgThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRemoteMsgThreadNumStr)); - } - - String eventMeshServerReplyMsgThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REPLYMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerReplyMsgThreadNumStr) - && StringUtils.isNumeric(eventMeshServerReplyMsgThreadNumStr)) { - eventMeshServerReplyMsgThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerReplyMsgThreadNumStr)); - } - - String eventMeshServerPushMsgThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_PUSHMSG_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerPushMsgThreadNumStr) - && StringUtils.isNumeric(eventMeshServerPushMsgThreadNumStr)) { - eventMeshServerPushMsgThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerPushMsgThreadNumStr)); - } - - String eventMeshServerRegistryThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_REGISTRY_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerRegistryThreadNumStr) - && StringUtils.isNumeric(eventMeshServerRegistryThreadNumStr)) { - eventMeshServerRegistryThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRegistryThreadNumStr)); - } - - String eventMeshServerClientManageThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_CLIENTMANAGE_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerClientManageThreadNumStr) - && StringUtils.isNumeric(eventMeshServerClientManageThreadNumStr)) { - eventMeshServerClientManageThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerClientManageThreadNumStr)); - } - - String eventMeshServerPullRegistryIntervalStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_PULL_REGISTRY_INTERVAL); - if (StringUtils.isNotEmpty(eventMeshServerPullRegistryIntervalStr) - && StringUtils.isNumeric(eventMeshServerPullRegistryIntervalStr)) { - eventMeshServerPullRegistryInterval = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerPullRegistryIntervalStr)); - } - - String eventMeshServerAdminThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEYS_EVENTMESH_ADMIN_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerAdminThreadNumStr) - && StringUtils.isNumeric(eventMeshServerAdminThreadNumStr)) { - eventMeshServerAdminThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerAdminThreadNumStr)); - } - - String eventMeshServerRetryBlockQSizeStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_RETRY_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerRetryBlockQSizeStr) - && StringUtils.isNumeric(eventMeshServerRetryBlockQSizeStr)) { - eventMeshServerRetryBlockQSize = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRetryBlockQSizeStr)); - } - - String eventMeshServerBatchBlockQSizeStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_BATCHMSG_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerBatchBlockQSizeStr) - && StringUtils.isNumeric(eventMeshServerBatchBlockQSizeStr)) { - eventMeshServerBatchBlockQSize = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerBatchBlockQSizeStr)); - } - - String eventMeshServerSendMsgBlockQSizeStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SENDMSG_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerSendMsgBlockQSizeStr) - && StringUtils.isNumeric(eventMeshServerSendMsgBlockQSizeStr)) { - eventMeshServerSendMsgBlockQSize = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerSendMsgBlockQSizeStr)); - } - - String eventMeshServerPushMsgBlockQSizeStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_PUSHMSG_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerPushMsgBlockQSizeStr) - && StringUtils.isNumeric(eventMeshServerPushMsgBlockQSizeStr)) { - eventMeshServerPushMsgBlockQSize = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerPushMsgBlockQSizeStr)); - } - - String eventMeshServerClientManageBlockQSizeStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_CLIENTM_BLOCKQ_SIZE); - if (StringUtils.isNotEmpty(eventMeshServerClientManageBlockQSizeStr) - && StringUtils.isNumeric(eventMeshServerClientManageBlockQSizeStr)) { - eventMeshServerClientManageBlockQSize = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerClientManageBlockQSizeStr)); - } - - String eventMeshServerBusyCheckIntervalStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_BUSY_CHECK_INTERVAL); - if (StringUtils.isNotEmpty(eventMeshServerBusyCheckIntervalStr) - && StringUtils.isNumeric(eventMeshServerBusyCheckIntervalStr)) { - eventMeshServerBusyCheckInterval = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerBusyCheckIntervalStr)); - - } - - String eventMeshServerConsumerEnabledStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_CONSUMER_ENABLED); - if (StringUtils.isNotEmpty(eventMeshServerConsumerEnabledStr)) { - eventMeshServerConsumerEnabled = - Boolean.parseBoolean(StringUtils.deleteWhitespace(eventMeshServerConsumerEnabledStr)); - } - - - String eventMeshServerRetryThreadNumStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_RETRY_THREAD_NUM); - if (StringUtils.isNotEmpty(eventMeshServerRetryThreadNumStr) - && StringUtils.isNumeric(eventMeshServerRetryThreadNumStr)) { - eventMeshServerRetryThreadNum = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshServerRetryThreadNumStr)); - - } - - String eventMeshServerUseTlsStr = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_HTTPS_ENABLED); - if (StringUtils.isNotEmpty(eventMeshServerUseTlsStr)) { - eventMeshServerUseTls = Boolean.parseBoolean(StringUtils.deleteWhitespace(eventMeshServerUseTlsStr)); - } - - - String eventMeshHttpMsgReqNumPerSecondStr = - configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SERVER_MSG_REQ_NUM_PER_SECOND); - if (StringUtils.isNotEmpty(eventMeshHttpMsgReqNumPerSecondStr) - && StringUtils.isNumeric(eventMeshHttpMsgReqNumPerSecondStr)) { - eventMeshHttpMsgReqNumPerSecond = Integer.parseInt(eventMeshHttpMsgReqNumPerSecondStr); - - } - - String eventSize = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SERVER_EVENTSIZE); - if (StringUtils.isNotEmpty(eventSize) && StringUtils.isNumeric(eventSize)) { - eventMeshEventSize = Integer.parseInt(eventSize); - } - - String eventBatchSize = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SERVER_EVENT_BATCHSIZE); - if (StringUtils.isNotEmpty(eventBatchSize) && StringUtils.isNumeric(eventBatchSize)) { - eventMeshEventBatchSize = Integer.parseInt(eventBatchSize); - } - - String ipv4BlackList = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SERVER_IPV4_BLACK_LIST); - if (StringUtils.isNotEmpty(ipv4BlackList)) { - eventMeshIpv4BlackList = getBlacklist(ipv4BlackList); - } - - String ipv6BlackList = configurationWrapper.getProp(ConfKeys.KEY_EVENTMESH_SERVER_IPV6_BLACK_LIST); - if (StringUtils.isNotEmpty(ipv6BlackList)) { - eventMeshIpv6BlackList = getBlacklist(ipv6BlackList); - } - } - } - - private static List getBlacklist(String cidrs) { - List cidrList = Splitter.on(",").omitEmptyStrings() - .trimResults().splitToList(cidrs); + @ConfigField(field = "http.port", notNull = true, beNumber = true) + private int httpServerPort = 10105; - List ipAddresses = Lists.newArrayList(); - for (String cidr : cidrList) { - try { - ipAddresses.add(new IPAddressString(cidr).toAddress()); - } catch (Exception e) { - logger.warn("Invalid cidr={}", cidr, e); - } - } - return ipAddresses; - } + @ConfigField(field = "batchmsg.batch.enabled") + private boolean eventMeshServerBatchMsgBatchEnabled = Boolean.TRUE; - static class ConfKeys { + @ConfigField(field = "batchmsg.threads.num") + private int eventMeshServerBatchMsgThreadNum = 10; - public static final String KEYS_EVENTMESH_SERVER_HTTP_PORT = "eventMesh.server.http.port"; + @ConfigField(field = "sendmsg.threads.num") + private int eventMeshServerSendMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_BATCHMSG_THREAD_NUM = "eventMesh.server.batchmsg.threads.num"; + @ConfigField(field = "remotemsg.threads.num") + private int eventMeshServerRemoteMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_BATCHMSG_REQ_NUM_PER_SECOND = "eventMesh.server.batchmsg.reqNumPerSecond"; + @ConfigField(field = "pushmsg.threads.num") + private int eventMeshServerPushMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_BATCHMSG_BATCH_ENABLED = "eventMesh.server.batchmsg.batch.enabled"; + @ConfigField(field = "replymsg.threads.num") + private int eventMeshServerReplyMsgThreadNum = 8; - public static final String KEYS_EVENTMESH_ASYNC_ACCUMULATION_THRESHOLD = "eventMesh.server.async.accumulation.threshold"; + @ConfigField(field = "clientmanage.threads.num") + private int eventMeshServerClientManageThreadNum = 4; - public static final String KEY_EVENTMESH_BUSY_CHECK_INTERVAL = "eventMesh.server.busy.check.interval"; + @ConfigField(field = "metaStorage.threads.num") + private int eventMeshServerMetaStorageThreadNum = 10; - public static final String KEYS_EVENTMESH_SENDMSG_THREAD_NUM = "eventMesh.server.sendmsg.threads.num"; + @ConfigField(field = "retry.threads.num") + private int eventMeshServerRetryThreadNum = 2; - public static final String KEYS_EVENTMESH_REMOTEMSG_THREAD_NUM = "eventMesh.server.remotemsg.threads.num"; + @ConfigField(field = "pull.metaStorage.interval") + private int eventMeshServerPullMetaStorageInterval = 30000; - public static final String KEYS_EVENTMESH_REPLYMSG_THREAD_NUM = "eventMesh.server.replymsg.threads.num"; + @ConfigField(field = "async.accumulation.threshold") + private int eventMeshServerAsyncAccumulationThreshold = 1000; - public static final String KEYS_EVENTMESH_PUSHMSG_THREAD_NUM = "eventMesh.server.pushmsg.threads.num"; + @ConfigField(field = "retry.blockQ.size") + private int eventMeshServerRetryBlockQSize = 10000; - public static final String KEYS_EVENTMESH_REGISTRY_THREAD_NUM = "eventMesh.server.registry.threads.num"; + @ConfigField(field = "batchmsg.blockQ.size") + private int eventMeshServerBatchBlockQSize = 1000; - public static final String KEYS_EVENTMESH_CLIENTMANAGE_THREAD_NUM = "eventMesh.server.clientmanage.threads.num"; + @ConfigField(field = "sendmsg.blockQ.size") + private int eventMeshServerSendMsgBlockQSize = 1000; - public static final String KEYS_EVENTMESH_ADMIN_THREAD_NUM = "eventMesh.server.admin.threads.num"; + @ConfigField(field = "") + private int eventMeshServerRemoteMsgBlockQSize = 1000; - public static final String KEY_EVENTMESH_RETRY_THREAD_NUM = "eventMesh.server.retry.threads.num"; + @ConfigField(field = "pushmsg.blockQ.size") + private int eventMeshServerPushMsgBlockQSize = 1000; - public static final String KEYS_EVENTMESH_PULL_REGISTRY_INTERVAL = "eventMesh.server.pull.registry.interval"; + @ConfigField(field = "clientM.blockQ.size") + private int eventMeshServerClientManageBlockQSize = 1000; - public static final String KEY_EVENTMESH_RETRY_BLOCKQ_SIZE = "eventMesh.server.retry.blockQ.size"; + @ConfigField(field = "busy.check.interval") + private int eventMeshServerBusyCheckInterval = 1000; - public static final String KEY_EVENTMESH_BATCHMSG_BLOCKQ_SIZE = "eventMesh.server.batchmsg.blockQ.size"; + @ConfigField(field = "consumer.enabled") + private boolean eventMeshServerConsumerEnabled = false; - public static final String KEY_EVENTMESH_SENDMSG_BLOCKQ_SIZE = "eventMesh.server.sendmsg.blockQ.size"; + @ConfigField(field = "useTls.enabled") + private boolean eventMeshServerUseTls = false; - public static final String KEY_EVENTMESH_PUSHMSG_BLOCKQ_SIZE = "eventMesh.server.pushmsg.blockQ.size"; + @ConfigField(field = "ssl.protocol") + private String eventMeshServerSSLProtocol = "TLSv1.1"; - public static final String KEY_EVENTMESH_CLIENTM_BLOCKQ_SIZE = "eventMesh.server.clientM.blockQ.size"; + @ConfigField(field = "ssl.cer") + private String eventMeshServerSSLCer = "sChat2.jks"; - public static final String KEY_EVENTMESH_CONSUMER_ENABLED = "eventMesh.server.consumer.enabled"; + @ConfigField(field = "ssl.pass") + private String eventMeshServerSSLPass = "sNetty"; - public static final String KEY_EVENTMESH_HTTPS_ENABLED = "eventMesh.server.useTls.enabled"; + @ConfigField(field = "http.msgReqnumPerSecond") + private int eventMeshHttpMsgReqNumPerSecond = 15000; - public static final String KEY_EVENTMESH_SERVER_MSG_REQ_NUM_PER_SECOND = "eventMesh.server.http.msgReqnumPerSecond"; + @ConfigField(field = "batchmsg.reqNumPerSecond") + private int eventMeshBatchMsgRequestNumPerSecond = 20000; - public static final String KEY_EVENTMESH_SERVER_EVENTSIZE = "eventMesh.server.maxEventSize"; + @ConfigField(field = "maxEventSize") + private int eventMeshEventSize = 1000; - public static final String KEY_EVENTMESH_SERVER_EVENT_BATCHSIZE = "eventMesh.server.maxEventBatchSize"; + @ConfigField(field = "maxEventBatchSize") + private int eventMeshEventBatchSize = 10; - public static final String KEY_EVENTMESH_SERVER_IPV4_BLACK_LIST = "eventMesh.server.blacklist.ipv4"; + @ConfigField(field = "blacklist.ipv4") + private List eventMeshIpv4BlackList = Collections.emptyList(); - public static final String KEY_EVENTMESH_SERVER_IPV6_BLACK_LIST = "eventMesh.server.blacklist.ipv6"; - } -} \ No newline at end of file + @ConfigField(field = "blacklist.ipv6") + private List eventMeshIpv6BlackList = Collections.emptyList(); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfiguration.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfiguration.java index 3bf071fa2d..907d80f686 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfiguration.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfiguration.java @@ -18,254 +18,129 @@ package org.apache.eventmesh.runtime.configuration; import org.apache.eventmesh.common.config.CommonConfiguration; -import org.apache.eventmesh.common.config.ConfigurationWrapper; - +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Config(prefix = "eventMesh.server") public class EventMeshTCPConfiguration extends CommonConfiguration { - public int eventMeshTcpServerPort = 10000; - public int eventMeshTcpIdleAllSeconds = 60; + @ConfigField(field = "tcp.port") + private int eventMeshTcpServerPort = 10000; - public int eventMeshTcpIdleWriteSeconds = 60; + @ConfigField(field = "tcp.allIdleSeconds") + private int eventMeshTcpIdleAllSeconds = 60; - public int eventMeshTcpIdleReadSeconds = 60; + @ConfigField(field = "tcp.writerIdleSeconds") + private int eventMeshTcpIdleWriteSeconds = 60; - public Integer eventMeshTcpMsgReqnumPerSecond = 15000; + @ConfigField(field = "tcp.readerIdleSeconds") + private int eventMeshTcpIdleReadSeconds = 60; - /** - * TCP Server allows max client num - */ - public int eventMeshTcpClientMaxNum = 10000; + @ConfigField(field = "tcp.msgReqnumPerSecond") + private Integer eventMeshTcpMsgReqnumPerSecond = 15000; - //======================================= New add config ================================= /** - * whether enable TCP Serer + * TCP Server allows max client num */ - public boolean eventMeshTcpServerEnabled = Boolean.FALSE; - - public int eventMeshTcpGlobalScheduler = 5; - - public int eventMeshTcpTaskHandleExecutorPoolSize = Runtime.getRuntime().availableProcessors(); - - public int eventMeshTcpMsgDownStreamExecutorPoolSize = Math.max(Runtime.getRuntime().availableProcessors(), 8); - - public int eventMeshTcpSessionExpiredInMills = 60000; - - public int eventMeshTcpSessionUpstreamBufferSize = 100; - - public int eventMeshTcpMsgAsyncRetryTimes = 3; - - public int eventMeshTcpMsgSyncRetryTimes = 1; - - public int eventMeshTcpMsgRetrySyncDelayInMills = 500; - - public int eventMeshTcpMsgRetryAsyncDelayInMills = 500; - - public int eventMeshTcpMsgRetryQueueSize = 10000; - - public Integer eventMeshTcpRebalanceIntervalInMills = 30 * 1000; - - public int eventMeshServerAdminPort = 10106; + @ConfigField(field = "tcp.clientMaxNum") + private int eventMeshTcpClientMaxNum = 10000; - public boolean eventMeshTcpSendBackEnabled = Boolean.TRUE; + // ======================================= New add config ================================= - public int eventMeshTcpSendBackMaxTimes = 3; + @ConfigField(field = "global.scheduler") + private int eventMeshTcpGlobalScheduler = 5; - public int eventMeshTcpPushFailIsolateTimeInMills = 30 * 1000; + @ConfigField(field = "tcp.taskHandleExecutorPoolSize") + private int eventMeshTcpTaskHandleExecutorPoolSize = 2 * Runtime.getRuntime().availableProcessors(); - public int gracefulShutdownSleepIntervalInMills = 1000; + @ConfigField(field = "tcp.sendExecutorPoolSize") + private int eventMeshTcpMsgSendExecutorPoolSize = 2 * Runtime.getRuntime().availableProcessors(); - public int sleepIntervalInRebalanceRedirectMills = 200; + @ConfigField(field = "tcp.replyExecutorPoolSize") + private int eventMeshTcpMsgReplyExecutorPoolSize = 2 * Runtime.getRuntime().availableProcessors(); - public int eventMeshEventSize = 1000; + @ConfigField(field = "tcp.ackExecutorPoolSize") + private int eventMeshTcpMsgAckExecutorPoolSize = 2 * Runtime.getRuntime().availableProcessors(); - public int eventMeshEventBatchSize = 10; + @ConfigField(field = "tcp.taskHandleExecutorQueueSize") + private int eventMeshTcpTaskHandleExecutorQueueSize = 10000; - private TrafficShapingConfig gtc = new TrafficShapingConfig(0, 10_000, 1_000, 2000); - private TrafficShapingConfig ctc = new TrafficShapingConfig(0, 2_000, 1_000, 10_000); + @ConfigField(field = "tcp.sendExecutorQueueSize") + private int eventMeshTcpMsgSendExecutorQueueSize = 10000; - public EventMeshTCPConfiguration(ConfigurationWrapper configurationWrapper) { - super(configurationWrapper); - } - - @Override - public void init() { - super.init(); - eventMeshTcpServerPort = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_TCP_PORT, eventMeshTcpServerPort); - - eventMeshTcpIdleReadSeconds = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_READER_IDLE_SECONDS, - eventMeshTcpIdleReadSeconds); - - eventMeshTcpIdleWriteSeconds = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_WRITER_IDLE_SECONDS, - eventMeshTcpIdleWriteSeconds); - - eventMeshTcpIdleAllSeconds = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_ALL_IDLE_SECONDS, - eventMeshTcpIdleAllSeconds); + @ConfigField(field = "tcp.replyExecutorQueueSize") + private int eventMeshTcpMsgReplyExecutorQueueSize = 10000; - eventMeshTcpMsgReqnumPerSecond = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_MSG_REQ_NUM_PER_SECONDS, - eventMeshTcpMsgReqnumPerSecond); + @ConfigField(field = "tcp.ackExecutorQueueSize") + private int eventMeshTcpMsgAckExecutorQueueSize = 10000; - eventMeshTcpClientMaxNum = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_CLIENT_MAX_NUM, - eventMeshTcpClientMaxNum); + @ConfigField(field = "tcp.msgDownStreamExecutorPoolSize") + private int eventMeshTcpMsgDownStreamExecutorPoolSize = Math.max(Runtime.getRuntime().availableProcessors(), 8); - eventMeshTcpServerEnabled = configurationWrapper.getBoolProp(ConfKeys.KEYS_EVENTMESH_TCP_SERVER_ENABLED, - eventMeshTcpServerEnabled); + @ConfigField(field = "session.expiredInMills") + private int eventMeshTcpSessionExpiredInMills = 60000; - eventMeshTcpGlobalScheduler = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_GLOBAL_SCHEDULER, - eventMeshTcpGlobalScheduler); + @ConfigField(field = "session.upstreamBufferSize") + private int eventMeshTcpSessionUpstreamBufferSize = 100; - eventMeshTcpTaskHandleExecutorPoolSize = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_TCP_TASK_HANDLE_POOL_SIZE, eventMeshTcpTaskHandleExecutorPoolSize); + @ConfigField(field = "retry.async.pushRetryTimes") + private int eventMeshTcpMsgAsyncRetryTimes = 3; - eventMeshTcpMsgDownStreamExecutorPoolSize = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_TCP_MSG_DOWNSTREAM_POOL_SIZE, eventMeshTcpMsgDownStreamExecutorPoolSize); + @ConfigField(field = "retry.sync.pushRetryTimes") + private int eventMeshTcpMsgSyncRetryTimes = 1; - eventMeshTcpSessionExpiredInMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_SESSION_EXPIRED_TIME, eventMeshTcpSessionExpiredInMills); + @ConfigField(field = "retry.sync.pushRetryDelayInMills") + private int eventMeshTcpMsgRetrySyncDelayInMills = 500; - eventMeshTcpSessionUpstreamBufferSize = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_SESSION_UPSTREAM_BUFFER_SIZE, eventMeshTcpSessionUpstreamBufferSize); + @ConfigField(field = "retry.async.pushRetryDelayInMills") + private int eventMeshTcpMsgRetryAsyncDelayInMills = 500; - //========================================eventMesh retry config=============================================// - eventMeshTcpMsgAsyncRetryTimes = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_RETRY_ASYNC_PUSH_RETRY_TIMES, eventMeshTcpMsgAsyncRetryTimes); + @ConfigField(field = "retry.pushRetryQueueSize") + private int eventMeshTcpMsgRetryQueueSize = 10000; - eventMeshTcpMsgSyncRetryTimes = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_RETRY_SYNC_PUSH_RETRY_TIMES, eventMeshTcpMsgSyncRetryTimes); + @ConfigField(field = "tcp.RebalanceIntervalInMills") + private Integer eventMeshTcpRebalanceIntervalInMills = 30 * 1000; - eventMeshTcpMsgRetryAsyncDelayInMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_RETRY_ASYNC_PUSH_RETRY_DELAY, eventMeshTcpMsgRetryAsyncDelayInMills); + @ConfigField(field = "tcp.sendBack.enabled") + private boolean eventMeshTcpSendBackEnabled = Boolean.TRUE; - eventMeshTcpMsgRetrySyncDelayInMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_RETRY_SYNC_PUSH_RETRY_DELAY, eventMeshTcpMsgRetrySyncDelayInMills); + @ConfigField(field = "tcp.SendBackMaxTimes") + private int eventMeshTcpSendBackMaxTimes = 3; - eventMeshTcpMsgRetryQueueSize = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_RETRY_PUSH_RETRY_QUEUE_SIZE, eventMeshTcpMsgRetryQueueSize); + @ConfigField(field = "tcp.pushFailIsolateTimeInMills") + private int eventMeshTcpPushFailIsolateTimeInMills = 30 * 1000; - eventMeshTcpRebalanceIntervalInMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_TCP_REBALANCE_INTERVAL, eventMeshTcpRebalanceIntervalInMills); + @ConfigField(field = "gracefulShutdown.sleepIntervalInMills") + private int gracefulShutdownSleepIntervalInMills = 1000; - eventMeshServerAdminPort = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_ADMIN_HTTP_PORT, eventMeshServerAdminPort); + @ConfigField(field = "rebalanceRedirect.sleepIntervalInM") + private int sleepIntervalInRebalanceRedirectMills = 200; - eventMeshTcpSendBackEnabled = configurationWrapper.getBoolProp( - ConfKeys.KEYS_EVENTMESH_TCP_SEND_BACK_ENABLED, eventMeshTcpSendBackEnabled); + @ConfigField(field = "maxEventSize") + private int eventMeshEventSize = 1000; - eventMeshTcpPushFailIsolateTimeInMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_PUSH_FAIL_ISOLATE_TIME, eventMeshTcpPushFailIsolateTimeInMills); + @ConfigField(field = "maxEventBatchSize") + private int eventMeshEventBatchSize = 10; - gracefulShutdownSleepIntervalInMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_GRACEFUL_SHUTDOWN_SLEEP_TIME, gracefulShutdownSleepIntervalInMills); - - sleepIntervalInRebalanceRedirectMills = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_REBALANCE_REDIRECT_SLEEP_TIME, sleepIntervalInRebalanceRedirectMills); - - eventMeshEventSize = configurationWrapper.getIntProp(ConfKeys.KEYS_EVENTMESH_SERVER_EVENTSIZE, eventMeshEventSize); - - eventMeshEventBatchSize = configurationWrapper.getIntProp( - ConfKeys.KEYS_EVENTMESH_SERVER_EVENT_BATCHSIZE, eventMeshEventBatchSize); - } - - public TrafficShapingConfig getGtc() { - return gtc; - } - - public TrafficShapingConfig getCtc() { - return ctc; - } - - static class ConfKeys { - - public static final String KEYS_EVENTMESH_SERVER_TCP_PORT = "eventMesh.server.tcp.port"; - public static final String KEYS_EVENTMESH_SERVER_READER_IDLE_SECONDS = "eventMesh.server.tcp.readerIdleSeconds"; - public static final String KEYS_EVENTMESH_SERVER_WRITER_IDLE_SECONDS = "eventMesh.server.tcp.writerIdleSeconds"; - public static final String KEYS_EVENTMESH_SERVER_ALL_IDLE_SECONDS = "eventMesh.server.tcp.allIdleSeconds"; - public static final String KEYS_EVENTMESH_SERVER_CLIENT_MAX_NUM = "eventMesh.server.tcp.clientMaxNum"; - public static final String KEYS_EVENTMESH_SERVER_MSG_REQ_NUM_PER_SECONDS = "eventMesh.server.tcp.msgReqnumPerSecond"; - public static final String KEYS_EVENTMESH_SERVER_TCP_REBALANCE_INTERVAL = "eventMesh.server.tcp.RebalanceIntervalInMills"; - public static final String KEYS_EVENTMESH_SERVER_GLOBAL_SCHEDULER = "eventMesh.server.global.scheduler"; - public static final String KEYS_EVENTMESH_SERVER_TCP_TASK_HANDLE_POOL_SIZE = "eventMesh.server.tcp.taskHandleExecutorPoolSize"; - public static final String KEYS_EVENTMESH_SERVER_TCP_MSG_DOWNSTREAM_POOL_SIZE = "eventMesh.server.tcp.msgDownStreamExecutorPoolSize"; - public static final String KEYS_EVENTMESH_SERVER_SESSION_EXPIRED_TIME = "eventMesh.server.session.expiredInMills"; - public static final String KEYS_EVENTMESH_SERVER_SESSION_UPSTREAM_BUFFER_SIZE = "eventMesh.server.session.upstreamBufferSize"; - public static final String KEYS_EVENTMESH_SERVER_SESSION_DOWNSTREAM_UNACK_SIZE = "eventMesh.server.session.downstreamUnackSize"; - public static final String KEYS_EVENTMESH_SERVER_RETRY_ASYNC_PUSH_RETRY_TIMES = "eventMesh.server.retry.async.pushRetryTimes"; - public static final String KEYS_EVENTMESH_SERVER_RETRY_SYNC_PUSH_RETRY_TIMES = "eventMesh.server.retry.sync.pushRetryTimes"; - public static final String KEYS_EVENTMESH_SERVER_RETRY_ASYNC_PUSH_RETRY_DELAY = "eventMesh.server.retry.async.pushRetryDelayInMills"; - public static final String KEYS_EVENTMESH_SERVER_RETRY_SYNC_PUSH_RETRY_DELAY = "eventMesh.server.retry.sync.pushRetryDelayInMills"; - public static final String KEYS_EVENTMESH_SERVER_RETRY_PUSH_RETRY_QUEUE_SIZE = "eventMesh.server.retry.pushRetryQueueSize"; - public static final String KEYS_EVENTMESH_SERVER_ADMIN_HTTP_PORT = "eventMesh.server.admin.http.port"; - public static final String KEYS_EVENTMESH_TCP_SERVER_ENABLED = "eventMesh.server.tcp.enabled"; - public static final String KEYS_EVENTMESH_TCP_SEND_BACK_ENABLED = "eventMesh.server.tcp.sendBack.enabled"; - public static final String KEYS_EVENTMESH_SERVER_PUSH_FAIL_ISOLATE_TIME = "eventMesh.server.tcp.pushFailIsolateTimeInMills"; - public static final String KEYS_EVENTMESH_SERVER_GRACEFUL_SHUTDOWN_SLEEP_TIME = "eventMesh.server.gracefulShutdown.sleepIntervalInMills"; - public static final String KEYS_EVENTMESH_SERVER_REBALANCE_REDIRECT_SLEEP_TIME = "eventMesh.server.rebalanceRedirect.sleepIntervalInM"; - public static final String KEYS_EVENTMESH_SERVER_EVENTSIZE = "eventMesh.server.maxEventSize"; - public static final String KEYS_EVENTMESH_SERVER_EVENT_BATCHSIZE = "eventMesh.server.maxEventBatchSize"; - } + private final TrafficShapingConfig gtc = new TrafficShapingConfig(0, 10_000, 1_000, 2_000); + private final TrafficShapingConfig ctc = new TrafficShapingConfig(0, 2_000, 1_000, 10_000); + @Data + @NoArgsConstructor + @AllArgsConstructor public static class TrafficShapingConfig { - long writeLimit = 0; - long readLimit = 1000; - long checkInterval = 1000; - long maxTime = 5000; - - public TrafficShapingConfig(long writeLimit, long readLimit, long checkInterval, long maxTime) { - this.writeLimit = writeLimit; - this.readLimit = readLimit; - this.checkInterval = checkInterval; - this.maxTime = maxTime; - } - - public TrafficShapingConfig() { - - } - - public long getWriteLimit() { - return writeLimit; - } - - public void setWriteLimit(long writeLimit) { - this.writeLimit = writeLimit; - } - - public long getReadLimit() { - return readLimit; - } - - public void setReadLimit(long readLimit) { - this.readLimit = readLimit; - } - - public long getCheckInterval() { - return checkInterval; - } - - public void setCheckInterval(long checkInterval) { - this.checkInterval = checkInterval; - } - - public long getMaxTime() { - return maxTime; - } - - public void setMaxTime(long maxTime) { - this.maxTime = maxTime; - } - - @Override - public String toString() { - return "TrafficShapingConfig{" - + - "writeLimit=" + writeLimit - + - ", readLimit=" + readLimit - + - ", checkInterval=" + checkInterval - + - ", maxTime=" + maxTime - + - '}'; - } - } + private long writeLimit = 0; + private long readLimit = 1000; + private long checkInterval = 1000; + private long maxTime = 5000; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorResource.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorResource.java deleted file mode 100644 index f47352eaed..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/connector/ConnectorResource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.connector; - -import org.apache.eventmesh.api.connector.ConnectorResourceService; -import org.apache.eventmesh.spi.EventMeshExtensionFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConnectorResource { - - private static final Logger logger = LoggerFactory.getLogger(ConnectorResource.class); - private static ConnectorResourceService connectorResourceService; - - public void init(String connectorResourcePluginType) throws Exception { - connectorResourceService = EventMeshExtensionFactory.getExtension(ConnectorResourceService.class, connectorResourcePluginType); - if (connectorResourceService == null) { - logger.error("can't load the connectorResourceService plugin, please check."); - throw new RuntimeException("doesn't load the connectorResourceService plugin, please check."); - } - connectorResourceService.init(); - } - - public void release() throws Exception { - connectorResourceService.release(); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshConstants.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshConstants.java index ee84c2993b..2830ae9596 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshConstants.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshConstants.java @@ -21,21 +21,19 @@ public class EventMeshConstants { - public static final String EVENT_STORE_PROPERTIES = "eventstore"; - - public static final String EVENT_STORE_ENV = "EVENT_STORE"; - public static final String PROTOCOL_HTTP = "http"; public static final String PROTOCOL_TCP = "tcp"; public static final String PROTOCOL_GRPC = "grpc"; - public static final String DEFAULT_CHARSET = "UTF-8"; + public static final String DEFAULT_CHARSET = Constants.DEFAULT_CHARSET.name(); public static final String IP_PORT_SEPARATOR = ":"; - public static final String EVENTMESH_CONF_HOME = System.getProperty("confPath", System.getenv("confPath")); + public static final String CONF_ENV = "confPath"; + + public static final String EVENTMESH_CONF_HOME = System.getProperty(CONF_ENV, System.getenv(CONF_ENV)); public static final String EVENTMESH_CONF_FILE = "eventmesh.properties"; @@ -64,7 +62,7 @@ public class EventMeshConstants { public static final String REQ_IDC = "req0idc"; public static final String REQ_GROUP = "req0group"; - //default TTL 4 hours + // default TTL 4 hours public static final Integer DEFAULT_MSG_TTL_MILLS = 14400000; public static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; @@ -76,14 +74,14 @@ public class EventMeshConstants { public static final int DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS = 3000; public static final String PURPOSE_PUB = "pub"; - + public static final String PURPOSE_PUB_UPPER_CASE = "PUB"; public static final String PURPOSE_SUB = "sub"; + public static final String PURPOSE_SUB_UPPER_CASE = "SUB"; public static final String PURPOSE_ALL = "all"; public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; - public static final String BORN_TIMESTAMP = "BORN_TIME"; public static final String STORE_TIMESTAMP = "STORE_TIME"; public static final String LEAVE_TIMESTAMP = "LEAVE_TIME"; @@ -105,8 +103,8 @@ public class EventMeshConstants { public static final String MANAGE_GROUP = "group"; public static final String MANAGE_PURPOSE = "purpose"; public static final String MANAGE_TOPIC = "topic"; - - public static final String EVENTMESH_SEND_BACK_TIMES = "eventmeshdendbacktimes"; + public static final String MANAGE_MSG = "msg"; + public static final String EVENTMESH_SEND_BACK_TIMES = "eventmeshsendbacktimes"; public static final String EVENTMESH_SEND_BACK_IP = "eventmeshsendbackip"; @@ -122,13 +120,42 @@ public class EventMeshConstants { public static final String PROPERTY_MESSAGE_KEYS = "keys"; - public static final String PROPERTY_MESSAGE_REPLY_TO = "REPLY_TO"; //requester clientId + public static final String PROPERTY_MESSAGE_REPLY_TO = "REPLY_TO"; // requester clientId public static final String PROPERTY_RR_REQUEST_ID = "RR_REQUEST_UNIQ_ID"; - public static final String LEAVE_TIME = "leave" + Constants.MESSAGE_PROP_SEPARATOR + "time"; //leaveBrokerTime + public static final String LEAVE_TIME = "leave" + Constants.MESSAGE_PROP_SEPARATOR + "time"; // leaveBrokerTime public static final String ARRIVE_TIME = "arrive" + Constants.MESSAGE_PROP_SEPARATOR + "time"; public static final String STORE_TIME = "store" + Constants.MESSAGE_PROP_SEPARATOR + "time"; - - + public static final String PRODUCER_GROUP = "producerGroup"; + public static final String CONSUMER_GROUP = "consumerGroup"; + public static final String INSTANCE_NAME = "instanceName"; + public static final String EVENT_MESH_IDC = "eventMeshIDC"; + public static final String IS_BROADCAST = "isBroadcast"; + + public static final String RESP_CODE = "respCode"; + public static final String RESP_MSG = "respMsg"; + public static final String BLANK_SPACE = " "; + + public static final String CONTENT_TYPE = "Content-Type"; + public static final String APPLICATION_JSON = "application/json"; + + public static final String URL = "url"; + public static final String RET_CODE = "retCode"; + public static final String RET_MSG = "retMsg"; + public static final String USER_NAME = "eventmesh"; + public static final String PASSWD = "pass"; + public static final String MESSAGE = "message"; + public static final String CMD = "cmd"; + public static final String ACL = "acl"; + public static final String BATCH_MSG = "batchMessage"; + public static final String TCP_MONITOR = "tcpMonitor"; + public static final String APP_MONITOR = "appMonitor"; + public static final String MSG_TYPE = "msgtype"; + public static final String PERSISTENT = "persistent"; + public static final String HANDLER_ORIGIN = "Access-Control-Allow-Origin"; + public static final String HANDLER_METHODS = "Access-Control-Allow-Methods"; + public static final String HANDLER_HEADERS = "Access-Control-Allow-Headers"; + public static final String HANDLER_AGE = "Access-Control-Max-Age"; + public static final String MAX_AGE = "86400"; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshVersion.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshVersion.java index 91cc68475f..b31b9c3c54 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshVersion.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/constants/EventMeshVersion.java @@ -17,21 +17,137 @@ package org.apache.eventmesh.runtime.constants; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.util.Objects; +import java.util.Properties; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class EventMeshVersion { - public static final String CURRENT_VERSION = Version.V3_0_0.name(); + private static String CURRENT_VERSION = ""; + + private static final String VERSION_KEY = "Implementation-Version"; + private static final String SPEC_VERSION_KEY = "Specification-Version"; + + /** + * The version pattern in build.gradle. In general, it is like version='0.0.1' or version="0.0.1" if exists. + */ + private static final String VERSION_PATTERN = "version\\s*=\\s*['\"](.+)['\"]"; + + /** + * @return Eg: "v0.0.1-release" + */ public static String getCurrentVersionDesc() { - return CURRENT_VERSION.replaceAll("V", "") - .replaceAll("_", ".") - .replaceAll("_SNAPSHOT", "-SNAPSHOT"); + if (StringUtils.isNotBlank(getCurrentVersion())) { + return "v" + CURRENT_VERSION; + } + return ""; + } + + /** + * @return Eg: "0.0.1-release" + */ + public static String getCurrentVersion() { + if (StringUtils.isNotBlank(CURRENT_VERSION)) { + return CURRENT_VERSION; + } + // get version from jar. + getVersionFromJarFile(); + // get version from build file. + if (StringUtils.isBlank(CURRENT_VERSION)) { + getVersionFromBuildFile(); + } + return CURRENT_VERSION; + } + + private static void getVersionFromJarFile() { + // get version from MANIFEST.MF in jar. + CodeSource codeSource = EventMeshVersion.class.getProtectionDomain().getCodeSource(); + if (Objects.isNull(codeSource)) { + log.warn("Failed to get CodeSource for EventMeshVersion.class"); + return; + } + URL url = codeSource.getLocation(); + if (Objects.isNull(url)) { + log.warn("Failed to get URL for EventMeshVersion.class"); + return; + } + try (JarFile jarFile = new JarFile(url.getPath())) { + Manifest manifest = jarFile.getManifest(); + Attributes attributes = manifest.getMainAttributes(); + CURRENT_VERSION = StringUtils.isBlank(attributes.getValue(VERSION_KEY)) + ? attributes.getValue(SPEC_VERSION_KEY) : attributes.getValue(VERSION_KEY); + + // get version from the file name of jar. + if (StringUtils.isBlank(CURRENT_VERSION)) { + getVersionFromJarFileName(url.getFile()); + } + } catch (IOException e) { + log.error("Failed to load project version from MANIFEST.MF due to IOException {}.", e.getMessage()); + } + } + + private static void getVersionFromBuildFile() { + String projectDir = System.getProperty("user.dir"); + + String gradlePropertiesPath = projectDir + File.separator + "gradle.properties"; + Properties properties = new Properties(); + try (FileInputStream fis = new FileInputStream(gradlePropertiesPath)) { + properties.load(fis); + CURRENT_VERSION = properties.getProperty("version"); + } catch (IOException e) { + log.error("Failed to load version from gradle.properties due to IOException {}.", e.getMessage()); + } + + if (StringUtils.isBlank(CURRENT_VERSION)) { + String buildGradlePath = projectDir + File.separator + "build.gradle"; + try { + File buildFile = new File(buildGradlePath); + String content = new String(Files.readAllBytes(buildFile.toPath())); + Pattern pattern = Pattern.compile(VERSION_PATTERN); + Matcher matcher = pattern.matcher(content); + if (matcher.find()) { + CURRENT_VERSION = matcher.group(1); + } else { + log.warn("Failed to load version from build.gradle due to missing the configuration of \"version='xxx'\"."); + } + } catch (IOException e) { + log.error("Failed to load version from build.gradle due to IOException {}.", e.getMessage()); + } + } } - public enum Version { - V3_0_0, - V3_0_1, - V3_1_0, - V3_2_0, - V3_3_0 + // path: /.../.../eventmesh-runtime-0.0.1-xxx.jar, version: 0.0.1-xxx + private static void getVersionFromJarFileName(String path) { + if (!StringUtils.isEmpty(path) && path.endsWith(".jar")) { + Path filePath = Paths.get(path); + String fileName = filePath.getFileName().toString(); + fileName = fileName.replace(".jar", ""); + Pattern pattern = Pattern.compile("-\\d"); + Matcher matcher = pattern.matcher(fileName); + if (matcher.find()) { + int index = matcher.start(); + CURRENT_VERSION = fileName.substring(index + 1); + } else { + log.info("Failed to load version from jar name due to missing related info."); + } + } } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumer/ClientInfo.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumer/ClientInfo.java new file mode 100644 index 0000000000..7907b0a2ca --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumer/ClientInfo.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.consumer; + +public class ClientInfo { + + private String env; + + private String idc; + + private String sys; + + private String pid; + + private String ip; + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getIdc() { + return idc; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public String getSys() { + return sys; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumer/SubscriptionManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumer/SubscriptionManager.java new file mode 100644 index 0000000000..55c235bd39 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumer/SubscriptionManager.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.consumer; + +import org.apache.eventmesh.api.meta.config.EventMeshMetaConfig; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupMetadata; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicMetadata; +import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SubscriptionManager { + + private final boolean isEventMeshServerMetaStorageEnable; + + private final MetaStorage metaStorage; + + /** + * key: group + */ + private final ConcurrentHashMap localConsumerGroupMapping = new ConcurrentHashMap<>(64); + + /** + * key: group@topic + */ + private final ConcurrentHashMap> localClientInfoMapping = new ConcurrentHashMap<>(64); + + public SubscriptionManager(boolean isEventMeshServerMetaStorageEnable, MetaStorage metaStorage) { + this.isEventMeshServerMetaStorageEnable = isEventMeshServerMetaStorageEnable; + this.metaStorage = metaStorage; + } + + public ConcurrentHashMap getLocalConsumerGroupMapping() { + return localConsumerGroupMapping; + } + + public ConcurrentHashMap> getLocalClientInfoMapping() { + return localClientInfoMapping; + } + + public void registerClient(final ClientInfo clientInfo, final String consumerGroup, + final List subscriptionItems, final String url) { + for (final SubscriptionItem subscription : subscriptionItems) { + final String groupTopicKey = consumerGroup + "@" + subscription.getTopic(); + + List localClients = localClientInfoMapping.get(groupTopicKey); + + if (localClients == null) { + localClientInfoMapping.putIfAbsent(groupTopicKey, new ArrayList<>()); + localClients = localClientInfoMapping.get(groupTopicKey); + } + + Client newClient = new Client(); + newClient.setEnv(clientInfo.getEnv()); + newClient.setIdc(clientInfo.getIdc()); + newClient.setSys(clientInfo.getSys()); + newClient.setIp(clientInfo.getIp()); + newClient.setPid(clientInfo.getPid()); + newClient.setConsumerGroup(consumerGroup); + newClient.setTopic(subscription.getTopic()); + newClient.setUrl(url); + newClient.setLastUpTime(new Date()); + + boolean isContains = false; + for (final Client localClient : localClients) { + if (localClient.equals(newClient)) { + isContains = true; + localClient.setLastUpTime(newClient.getLastUpTime()); + break; + } + } + + if (!isContains) { + localClients.add(newClient); + } + } + } + + public void updateSubscription(ClientInfo clientInfo, String consumerGroup, + String url, List subscriptionList) { + for (final SubscriptionItem subscription : subscriptionList) { + final List groupTopicClients = localClientInfoMapping + .get(consumerGroup + "@" + subscription.getTopic()); + + if (CollectionUtils.isEmpty(groupTopicClients)) { + log.error("group {} topic {} clients is empty", consumerGroup, subscription); + } + + ConsumerGroupConf consumerGroupConf = localConsumerGroupMapping.get(consumerGroup); + if (consumerGroupConf == null) { + // new subscription + ConsumerGroupConf prev = localConsumerGroupMapping.putIfAbsent(consumerGroup, new ConsumerGroupConf(consumerGroup)); + if (prev == null) { + log.info("add new subscription, consumer group: {}", consumerGroup); + } + consumerGroupConf = localConsumerGroupMapping.get(consumerGroup); + } + + ConsumerGroupTopicConf consumerGroupTopicConf = consumerGroupConf.getConsumerGroupTopicConf() + .get(subscription.getTopic()); + if (consumerGroupTopicConf == null) { + consumerGroupConf.getConsumerGroupTopicConf().computeIfAbsent(subscription.getTopic(), (topic) -> { + ConsumerGroupTopicConf newTopicConf = new ConsumerGroupTopicConf(); + newTopicConf.setConsumerGroup(consumerGroup); + newTopicConf.setTopic(topic); + newTopicConf.setSubscriptionItem(subscription); + log.info("add new {}", newTopicConf); + return newTopicConf; + }); + consumerGroupTopicConf = consumerGroupConf.getConsumerGroupTopicConf().get(subscription.getTopic()); + } + + consumerGroupTopicConf.getUrls().add(url); + if (!consumerGroupTopicConf.getIdcUrls().containsKey(clientInfo.getIdc())) { + consumerGroupTopicConf.getIdcUrls().putIfAbsent(clientInfo.getIdc(), new CopyOnWriteArrayList<>()); + } + consumerGroupTopicConf.getIdcUrls().get(clientInfo.getIdc()).add(url); + } + } + + public void updateMetaData() { + if (!isEventMeshServerMetaStorageEnable) { + return; + } + try { + Map metadata = new HashMap<>(1 << 4); + for (Map.Entry consumerGroupMap : getLocalConsumerGroupMapping().entrySet()) { + String consumerGroupKey = consumerGroupMap.getKey(); + ConsumerGroupConf consumerGroupConf = consumerGroupMap.getValue(); + + ConsumerGroupMetadata consumerGroupMetadata = new ConsumerGroupMetadata(); + consumerGroupMetadata.setConsumerGroup(consumerGroupKey); + + Map consumerGroupTopicMetadataMap = + new HashMap<>(1 << 4); + for (Map.Entry consumerGroupTopicConfEntry : consumerGroupConf.getConsumerGroupTopicConf() + .entrySet()) { + final String topic = consumerGroupTopicConfEntry.getKey(); + ConsumerGroupTopicConf consumerGroupTopicConf = consumerGroupTopicConfEntry.getValue(); + ConsumerGroupTopicMetadata consumerGroupTopicMetadata = new ConsumerGroupTopicMetadata(); + consumerGroupTopicMetadata.setConsumerGroup(consumerGroupTopicConf.getConsumerGroup()); + consumerGroupTopicMetadata.setTopic(consumerGroupTopicConf.getTopic()); + consumerGroupTopicMetadata.setUrls(consumerGroupTopicConf.getUrls()); + + consumerGroupTopicMetadataMap.put(topic, consumerGroupTopicMetadata); + } + + consumerGroupMetadata.setConsumerGroupTopicMetadataMap(consumerGroupTopicMetadataMap); + metadata.put(consumerGroupKey, JsonUtils.toJSONString(consumerGroupMetadata)); + } + metadata.put(EventMeshMetaConfig.EVENT_MESH_PROTO, "http"); + + metaStorage.updateMetaData(metadata); + + } catch (Exception e) { + log.error("update eventmesh metadata error", e); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupConf.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupConf.java index 2c44b5958e..3e01eac9d1 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupConf.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupConf.java @@ -20,14 +20,15 @@ import java.io.Serializable; import java.util.Map; import java.util.Objects; - -import com.google.common.collect.Maps; +import java.util.concurrent.ConcurrentHashMap; public class ConsumerGroupConf implements Serializable { - //eg . 5013-1A0 + + // eg . 5013-1A0 private String consumerGroup; - private Map consumerGroupTopicConf = Maps.newConcurrentMap(); + private final ConcurrentHashMap consumerGroupTopicConf = + new ConcurrentHashMap(); public ConsumerGroupConf(String consumerGroup) { this.consumerGroup = consumerGroup; @@ -45,10 +46,6 @@ public Map getConsumerGroupTopicConf() { return consumerGroupTopicConf; } - public void setConsumerGroupTopicConf(Map consumerGroupTopicConf) { - this.consumerGroupTopicConf = consumerGroupTopicConf; - } - @Override public boolean equals(Object o) { if (this == o) { @@ -60,8 +57,8 @@ public boolean equals(Object o) { ConsumerGroupConf that = (ConsumerGroupConf) o; return consumerGroup.equals(that.consumerGroup) - && - Objects.equals(consumerGroupTopicConf, that.consumerGroupTopicConf); + && + Objects.equals(consumerGroupTopicConf, that.consumerGroupTopicConf); } @Override @@ -73,8 +70,8 @@ public int hashCode() { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("consumerGroupConfig={") - .append("groupName=").append(consumerGroup).append(",") - .append(",consumerGroupTopicConf=").append(consumerGroupTopicConf).append("}"); + .append("groupName=").append(consumerGroup).append(",") + .append(",consumerGroupTopicConf=").append(consumerGroupTopicConf).append("}"); return sb.toString(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupMetadata.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupMetadata.java index 2644ccd411..4c24605039 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupMetadata.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupMetadata.java @@ -33,7 +33,6 @@ public class ConsumerGroupMetadata { */ private Map consumerGroupTopicMetadataMap = Maps.newConcurrentMap(); - public String getConsumerGroup() { return consumerGroup; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicConf.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicConf.java index 1bc73e1b20..9b034d183f 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicConf.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicConf.java @@ -25,15 +25,12 @@ import java.util.Objects; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.common.collect.Maps; import com.google.common.collect.Sets; public class ConsumerGroupTopicConf implements Serializable { - public static Logger logger = LoggerFactory.getLogger(ConsumerGroupTopicConf.class); + private static final long serialVersionUID = 4548889791666411923L; private String consumerGroup; @@ -45,8 +42,7 @@ public class ConsumerGroupTopicConf implements Serializable { private SubscriptionItem subscriptionItem; /** - * PUSH URL - * Map key:IDC value:URL list in IDC + * PUSH URL Map key:IDC value:URL list in IDC */ private Map> idcUrls = Maps.newConcurrentMap(); @@ -58,24 +54,24 @@ public class ConsumerGroupTopicConf implements Serializable { /** * url auth type */ - private Map httpAuthTypeMap = Maps.newConcurrentMap(); + private final Map httpAuthTypeMap = Maps.newConcurrentMap(); @Override - public boolean equals(Object o) { + public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } - ConsumerGroupTopicConf that = (ConsumerGroupTopicConf) o; + final ConsumerGroupTopicConf that = (ConsumerGroupTopicConf) o; return consumerGroup.equals(that.consumerGroup) - && - Objects.equals(topic, that.topic) - && - Objects.equals(subscriptionItem, that.subscriptionItem) - && - Objects.equals(idcUrls, that.idcUrls); + && + Objects.equals(topic, that.topic) + && + Objects.equals(subscriptionItem, that.subscriptionItem) + && + Objects.equals(idcUrls, that.idcUrls); } @Override @@ -85,11 +81,11 @@ public int hashCode() { @Override public String toString() { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(120); sb.append("consumeTopicConfig={consumerGroup=").append(consumerGroup) - .append(",topic=").append(topic) - .append(",subscriptionMode=").append(subscriptionItem) - .append(",idcUrls=").append(idcUrls).append("}"); + .append(",topic=").append(topic) + .append(",subscriptionMode=").append(subscriptionItem) + .append(",idcUrls=").append(idcUrls).append('}'); return sb.toString(); } @@ -97,7 +93,7 @@ public String getConsumerGroup() { return consumerGroup; } - public void setConsumerGroup(String consumerGroup) { + public void setConsumerGroup(final String consumerGroup) { this.consumerGroup = consumerGroup; } @@ -105,7 +101,7 @@ public String getTopic() { return topic; } - public void setTopic(String topic) { + public void setTopic(final String topic) { this.topic = topic; } @@ -113,7 +109,7 @@ public SubscriptionItem getSubscriptionItem() { return subscriptionItem; } - public void setSubscriptionItem(SubscriptionItem subscriptionItem) { + public void setSubscriptionItem(final SubscriptionItem subscriptionItem) { this.subscriptionItem = subscriptionItem; } @@ -121,7 +117,7 @@ public Map> getIdcUrls() { return idcUrls; } - public void setIdcUrls(Map> idcUrls) { + public void setIdcUrls(final Map> idcUrls) { this.idcUrls = idcUrls; } @@ -129,7 +125,7 @@ public Set getUrls() { return urls; } - public void setUrls(Set urls) { + public void setUrls(final Set urls) { this.urls = urls; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicMetadata.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicMetadata.java index 3536500144..8e19d91de0 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicMetadata.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ConsumerGroupTopicMetadata.java @@ -19,10 +19,10 @@ import java.util.Set; - import com.google.common.collect.Sets; public class ConsumerGroupTopicMetadata { + /** * consumer group */ @@ -38,7 +38,6 @@ public class ConsumerGroupTopicMetadata { */ private Set urls = Sets.newConcurrentHashSet(); - public String getConsumerGroup() { return consumerGroup; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ProducerGroupConf.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ProducerGroupConf.java index e121755bca..a04bc78e69 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ProducerGroupConf.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/ProducerGroupConf.java @@ -20,21 +20,33 @@ import java.util.Objects; public class ProducerGroupConf { + private String groupName; + private String token; + public ProducerGroupConf(String groupName) { this.groupName = groupName; } + public ProducerGroupConf(String groupName, String token) { + this.groupName = groupName; + this.token = token; + } + public String getGroupName() { return groupName; } + public String getToken() { + return token; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("producerGroupConfig={") - .append("groupName=").append(groupName).append("}"); + .append("groupName=").append(groupName).append("}"); return sb.toString(); } @@ -48,13 +60,7 @@ public boolean equals(Object o) { } ProducerGroupConf that = (ProducerGroupConf) o; - if (groupName == that.groupName) { - return true; - } - if (groupName == null) { - return false; - } - return groupName.equals(that.groupName); + return Objects.equals(groupName, that.groupName); } @Override diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupStateEvent.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupStateEvent.java index fbf06125d3..9b5e7c827f 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupStateEvent.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupStateEvent.java @@ -19,22 +19,26 @@ import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; +import lombok.Data; + +@Data public class ConsumerGroupStateEvent { - public String consumerGroup; - public ConsumerGroupStateAction action; - public ConsumerGroupConf consumerGroupConfig; + private String consumerGroup; + + private ConsumerGroupStateAction action; + + private ConsumerGroupConf consumerGroupConfig; @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("consumerGroupStateEvent={") - .append("consumerGroup=").append(consumerGroup) - .append(",action=").append(action).append("}"); + .append("consumerGroup=").append(consumerGroup) + .append(",action=").append(action).append("}"); return sb.toString(); } - public enum ConsumerGroupStateAction { NEW, CHANGE, diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java index 7b19ffb041..bfbb608c4c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/consumergroup/event/ConsumerGroupTopicConfChangeEvent.java @@ -19,23 +19,26 @@ import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; +import lombok.Data; + +@Data public class ConsumerGroupTopicConfChangeEvent { - public ConsumerGroupTopicConfChangeAction action; + private ConsumerGroupTopicConfChangeAction action; - public String topic; + private String topic; - public String consumerGroup; + private String consumerGroup; - public ConsumerGroupTopicConf newTopicConf; + private ConsumerGroupTopicConf newTopicConf; @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("consumerGroupTopicConfChangeEvent={") - .append("consumerGroup=").append(consumerGroup).append(",") - .append("topic=").append(topic).append(",") - .append("action=").append(action).append("}"); + .append("consumerGroup=").append(consumerGroup).append(",") + .append("topic=").append(topic).append(",") + .append("action=").append(action).append("}"); return sb.toString(); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQAdminWrapper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQAdminWrapper.java new file mode 100644 index 0000000000..7676c426ce --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQAdminWrapper.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.plugin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.api.factory.StoragePluginFactory; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MQAdminWrapper extends MQWrapper { + + protected Admin meshMQAdmin; + + public MQAdminWrapper(String storagePluginType) { + this.meshMQAdmin = StoragePluginFactory.getMeshMQAdmin(storagePluginType); + if (meshMQAdmin == null) { + log.error("can't load the meshMQAdmin plugin, please check."); + throw new RuntimeException("doesn't load the meshMQAdmin plugin, please check."); + } + } + + public synchronized void init(Properties keyValue) throws Exception { + if (inited.get()) { + return; + } + + meshMQAdmin.init(keyValue); + inited.compareAndSet(false, true); + } + + public synchronized void start() throws Exception { + if (started.get()) { + return; + } + + meshMQAdmin.start(); + + started.compareAndSet(false, true); + } + + public synchronized void shutdown() throws Exception { + if (!inited.get()) { + return; + } + + if (!started.get()) { + return; + } + + meshMQAdmin.shutdown(); + + inited.compareAndSet(true, false); + started.compareAndSet(true, false); + } + + public Admin getMeshMQAdmin() { + return meshMQAdmin; + } + + public List getTopic() throws Exception { + return meshMQAdmin.getTopic(); + } + + public void createTopic(String topicName) throws Exception { + meshMQAdmin.createTopic(topicName); + } + + public void deleteTopic(String topicName) throws Exception { + meshMQAdmin.deleteTopic(topicName); + } + + public List getEvent(String topicName, int offset, int length) throws Exception { + return meshMQAdmin.getEvent(topicName, offset, length); + } + + public void publish(CloudEvent cloudEvent) throws Exception { + meshMQAdmin.publish(cloudEvent); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQConsumerWrapper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQConsumerWrapper.java index 6bd8875f89..b9971e264f 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQConsumerWrapper.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQConsumerWrapper.java @@ -20,26 +20,24 @@ import org.apache.eventmesh.api.AbstractContext; import org.apache.eventmesh.api.EventListener; import org.apache.eventmesh.api.consumer.Consumer; -import org.apache.eventmesh.api.factory.ConnectorPluginFactory; +import org.apache.eventmesh.api.factory.StoragePluginFactory; import java.util.List; import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; -public class MQConsumerWrapper extends MQWrapper { +import lombok.extern.slf4j.Slf4j; - public final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class MQConsumerWrapper extends MQWrapper { protected Consumer meshMQPushConsumer; - public MQConsumerWrapper(String connectorPluginType) { - this.meshMQPushConsumer = ConnectorPluginFactory.getMeshMQPushConsumer(connectorPluginType); + public MQConsumerWrapper(String storagePluginType) { + this.meshMQPushConsumer = StoragePluginFactory.getMeshMQPushConsumer(storagePluginType); if (meshMQPushConsumer == null) { - logger.error("can't load the meshMQPushConsumer plugin, please check."); + log.error("can't load the meshMQPushConsumer plugin, please check."); throw new RuntimeException("doesn't load the meshMQPushConsumer plugin, please check."); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQProducerWrapper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQProducerWrapper.java index 73411a6fc2..84b0079f4b 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQProducerWrapper.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQProducerWrapper.java @@ -19,26 +19,24 @@ import org.apache.eventmesh.api.RequestReplyCallback; import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.factory.ConnectorPluginFactory; +import org.apache.eventmesh.api.factory.StoragePluginFactory; import org.apache.eventmesh.api.producer.Producer; import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; -public class MQProducerWrapper extends MQWrapper { +import lombok.extern.slf4j.Slf4j; - public Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class MQProducerWrapper extends MQWrapper { protected Producer meshMQProducer; - public MQProducerWrapper(String connectorPluginType) { - this.meshMQProducer = ConnectorPluginFactory.getMeshMQProducer(connectorPluginType); + public MQProducerWrapper(String storagePluginType) { + this.meshMQProducer = StoragePluginFactory.getMeshMQProducer(storagePluginType); if (meshMQProducer == null) { - logger.error("can't load the meshMQProducer plugin, please check."); + log.error("can't load the meshMQProducer plugin, please check."); throw new RuntimeException("doesn't load the meshMQProducer plugin, please check."); } } @@ -82,7 +80,7 @@ public void send(CloudEvent cloudEvent, SendCallback sendCallback) throws Except } public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) - throws Exception { + throws Exception { meshMQProducer.request(cloudEvent, rrCallback, timeout); } @@ -93,5 +91,4 @@ public boolean reply(final CloudEvent cloudEvent, final SendCallback sendCallbac public Producer getMeshMQProducer() { return meshMQProducer; } - } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQWrapper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQWrapper.java index c77d18e787..e0828d460f 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQWrapper.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/plugin/MQWrapper.java @@ -1,49 +1,27 @@ /* - * Licensed to 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. Apache Software Foundation (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 + * 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. + * 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. */ package org.apache.eventmesh.runtime.core.plugin; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; - -import org.apache.commons.lang3.StringUtils; - import java.util.concurrent.atomic.AtomicBoolean; public abstract class MQWrapper { - public static final String EVENT_STORE_ROCKETMQ = "rocketmq"; - - public static final String EVENT_STORE_DEFIBUS = "defibus"; - - public static String CURRENT_EVENT_STORE = EVENT_STORE_DEFIBUS; - - public static final String EVENT_STORE_CONF = System.getProperty(EventMeshConstants.EVENT_STORE_PROPERTIES, - System.getenv(EventMeshConstants.EVENT_STORE_ENV)); - - static { - if (StringUtils.isNotBlank(EVENT_STORE_CONF)) { - CURRENT_EVENT_STORE = EVENT_STORE_CONF; - } - } - public AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); public AtomicBoolean inited = new AtomicBoolean(Boolean.FALSE); - } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/RetryContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/RetryContext.java new file mode 100644 index 0000000000..ca796dc330 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/RetryContext.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.retry.api.conf.RetryConfiguration; +import org.apache.eventmesh.retry.api.strategy.RetryStrategy; +import org.apache.eventmesh.retry.api.timer.TimerTask; +import org.apache.eventmesh.runtime.core.protocol.consumer.HandleMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import io.cloudevents.CloudEvent; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class RetryContext implements TimerTask { + + private static final Set RETRY_STRATEGY_PROCESSED_EVENT_LIST = Collections.synchronizedSet(new HashSet<>()); + + public CloudEvent event; + + public String seq; + + public int retryTimes; + + public CommonConfiguration commonConfiguration; + + public long executeTime = System.currentTimeMillis(); + + public void setEvent(CloudEvent event) { + this.event = event; + } + + @Override + public void setExecuteTimeHook(long executeTime) { + this.executeTime = executeTime; + } + + @Override + public final void run() throws Exception { + String eventMeshRetryPluginType = Optional.ofNullable(commonConfiguration.getEventMeshRetryPluginType()) + .orElse(Constants.DEFAULT); + if (Constants.DEFAULT.equals(eventMeshRetryPluginType)) { + log.warn("Because eventmesh retry plugin is default, retry in memory."); + doRun(); + return; + } + if (!eventMeshRetryPluginType.equals(commonConfiguration.getEventMeshStoragePluginType())) { + log.warn("Because eventmesh retry plugin type mismatched with storage plugin type, retry in memory."); + doRun(); + return; + } + Optional retryStrategy = Optional.ofNullable( + EventMeshExtensionFactory.getExtension(RetryStrategy.class, + commonConfiguration.getEventMeshRetryPluginType())); + if (!retryStrategy.isPresent()) { + log.warn("Storage retry SPI not found, retry in memory."); + doRun(); + return; + } + if (!RETRY_STRATEGY_PROCESSED_EVENT_LIST.contains(event.getId())) { + String consumerGroupName = getHandleMessageContext().getConsumerGroup(); + EventMeshProducer producer = getProducerManager().getEventMeshProducer(consumerGroupName); + RetryConfiguration retryConfiguration = RetryConfiguration.builder() + .event(event) + .consumerGroupName(consumerGroupName) + .producer(producer.getMqProducerWrapper().getMeshMQProducer()) + .topic(getHandleMessageContext().getTopic()) + .build(); + retryStrategy.get().retry(retryConfiguration); + RETRY_STRATEGY_PROCESSED_EVENT_LIST.add(event.getId()); + } else { + RETRY_STRATEGY_PROCESSED_EVENT_LIST.remove(event.getId()); + getHandleMessageContext().finish(); + } + } + + protected HandleMessageContext getHandleMessageContext() throws Exception { + throw new IllegalAccessException("method not supported."); + } + + public abstract void doRun() throws Exception; + + @SneakyThrows + protected ProducerManager getProducerManager() { + throw new IllegalAccessException("method not supported."); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/consumer/HandleMessageContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/consumer/HandleMessageContext.java new file mode 100644 index 0000000000..6ba20f3768 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/consumer/HandleMessageContext.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.consumer; + +/** + * Handle message context + */ +public interface HandleMessageContext { + + void finish(); + + String getTopic(); + + String getConsumerGroup(); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/ConsumerManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/ConsumerManager.java index 1f88115324..b29e03b88c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/ConsumerManager.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/ConsumerManager.java @@ -17,12 +17,12 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.consumer; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.common.ServiceState; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupClient; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -31,7 +31,6 @@ import java.util.Date; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -39,14 +38,13 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class ConsumerManager { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final EventMeshGrpcServer eventMeshGrpcServer; private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); @@ -57,63 +55,62 @@ public class ConsumerManager { // key: ConsumerGroup private final Map consumerTable = new ConcurrentHashMap<>(); - public ConsumerManager(EventMeshGrpcServer eventMeshGrpcServer) { + public ConsumerManager(final EventMeshGrpcServer eventMeshGrpcServer) { this.eventMeshGrpcServer = eventMeshGrpcServer; } + public Map> getClientTable() { + return clientTable; + } + public void init() throws Exception { - logger.info("Grpc ConsumerManager initialized......"); + log.info("Grpc ConsumerManager initialized."); } public void start() throws Exception { startClientCheck(); - logger.info("Grpc ConsumerManager started......"); + log.info("Grpc ConsumerManager started."); } public void shutdown() throws Exception { - for (EventMeshConsumer consumer : consumerTable.values()) { + for (final EventMeshConsumer consumer : consumerTable.values()) { consumer.shutdown(); } scheduledExecutorService.shutdown(); - logger.info("Grpc ConsumerManager shutdown......"); + log.info("Grpc ConsumerManager shutdown."); } - public EventMeshConsumer getEventMeshConsumer(String consumerGroup) { - EventMeshConsumer consumer = consumerTable.get(consumerGroup); - if (consumer == null) { - consumer = new EventMeshConsumer(eventMeshGrpcServer, consumerGroup); - consumerTable.put(consumerGroup, consumer); - } - return consumer; + public EventMeshConsumer getEventMeshConsumer(final String consumerGroup) { + return consumerTable.computeIfAbsent(consumerGroup, key -> new EventMeshConsumer(eventMeshGrpcServer, consumerGroup)); } - public synchronized void registerClient(ConsumerGroupClient newClient) { - String consumerGroup = newClient.getConsumerGroup(); - String topic = newClient.getTopic(); - GrpcType grpcType = newClient.getGrpcType(); - String url = newClient.getUrl(); - String ip = newClient.getIp(); - String pid = newClient.getPid(); - SubscriptionMode subscriptionMode = newClient.getSubscriptionMode(); - List localClients = clientTable.get(consumerGroup); + public synchronized void registerClient(final ConsumerGroupClient newClient) { + final String consumerGroup = newClient.getConsumerGroup(); + final String topic = newClient.getTopic(); + final GrpcType grpcType = newClient.getGrpcType(); + final String url = newClient.getUrl(); + final String ip = newClient.getIp(); + final String pid = newClient.getPid(); + final SubscriptionMode subscriptionMode = newClient.getSubscriptionMode(); + List localClients = clientTable.get(consumerGroup); if (localClients == null) { localClients = new ArrayList<>(); localClients.add(newClient); - clientTable.put(consumerGroup, localClients); + clientTable.putIfAbsent(consumerGroup, localClients); } else { boolean isContains = false; - for (ConsumerGroupClient localClient : localClients) { - if (GrpcType.WEBHOOK.equals(grpcType) && StringUtils.equals(localClient.getTopic(), topic) + for (final ConsumerGroupClient localClient : localClients) { + if (GrpcType.WEBHOOK == grpcType && StringUtils.equals(localClient.getTopic(), topic) && StringUtils.equals(localClient.getUrl(), url) - && localClient.getSubscriptionMode().equals(subscriptionMode)) { + && localClient.getSubscriptionMode() == subscriptionMode) { isContains = true; localClient.setUrl(newClient.getUrl()); localClient.setLastUpTime(newClient.getLastUpTime()); break; - } else if (GrpcType.STREAM.equals(grpcType) && StringUtils.equals(localClient.getTopic(), topic) + } else if (GrpcType.STREAM == grpcType && StringUtils.equals(localClient.getTopic(), topic) && StringUtils.equals(localClient.getIp(), ip) && StringUtils.equals(localClient.getPid(), pid) - && localClient.getSubscriptionMode().equals(subscriptionMode)) { + && localClient.getSubscriptionMode() == subscriptionMode) { isContains = true; localClient.setEventEmitter(newClient.getEventEmitter()); localClient.setLastUpTime(newClient.getLastUpTime()); @@ -126,112 +123,122 @@ public synchronized void registerClient(ConsumerGroupClient newClient) { } } - public void updateClientTime(ConsumerGroupClient client) { - String consumerGroup = client.getConsumerGroup(); - List localClients = clientTable.get(consumerGroup); + public boolean updateClientTime(final ConsumerGroupClient client) { + final List localClients = clientTable.get(client.getConsumerGroup()); if (CollectionUtils.isEmpty(localClients)) { - return; + return false; } - for (ConsumerGroupClient localClient : localClients) { + + for (final ConsumerGroupClient localClient : localClients) { if (StringUtils.equals(localClient.getIp(), client.getIp()) && StringUtils.equals(localClient.getPid(), client.getPid()) && StringUtils.equals(localClient.getSys(), client.getSys()) && StringUtils.equals(localClient.getTopic(), client.getTopic())) { localClient.setLastUpTime(new Date()); - break; + return true; } } + + return false; } - public synchronized void deregisterClient(ConsumerGroupClient client) { - String consumerGroup = client.getConsumerGroup(); - List localClients = clientTable.get(consumerGroup); + public synchronized void deregisterClient(final ConsumerGroupClient client) { + final String consumerGroup = client.getConsumerGroup(); + final List localClients = clientTable.get(consumerGroup); if (CollectionUtils.isEmpty(localClients)) { return; } - Iterator iterator = localClients.iterator(); - while (iterator.hasNext()) { - ConsumerGroupClient localClient = iterator.next(); - if (StringUtils.equals(localClient.getTopic(), client.getTopic()) - && localClient.getSubscriptionMode().equals(client.getSubscriptionMode())) { - - // close the GRPC client stream before removing it - closeEventStream(localClient); - iterator.remove(); + final Iterator iterator = localClients.iterator(); + synchronized (clientTable) { + while (iterator.hasNext()) { + final ConsumerGroupClient localClient = iterator.next(); + if (StringUtils.equals(localClient.getTopic(), client.getTopic()) + && localClient.getSubscriptionMode() == client.getSubscriptionMode()) { + // close the GRPC client stream before removing it + closeEventStream(localClient); + iterator.remove(); + } } } - if (localClients.size() == 0) { + if (CollectionUtils.isEmpty(localClients)) { clientTable.remove(consumerGroup); } + } - private void closeEventStream(ConsumerGroupClient client) { + private void closeEventStream(final ConsumerGroupClient client) { if (client.getEventEmitter() != null) { client.getEventEmitter().onCompleted(); } } - public synchronized void restartEventMeshConsumer(String consumerGroup) throws Exception { - EventMeshConsumer eventMeshConsumer = consumerTable.get(consumerGroup); + public synchronized void restartEventMeshConsumer(final String consumerGroup) throws Exception { + final EventMeshConsumer eventMeshConsumer = consumerTable.get(consumerGroup); if (eventMeshConsumer == null) { return; } - if (ServiceState.RUNNING.equals(eventMeshConsumer.getStatus())) { + if (ServiceState.RUNNING == eventMeshConsumer.getStatus()) { eventMeshConsumer.shutdown(); } eventMeshConsumer.init(); eventMeshConsumer.start(); - if (!ServiceState.RUNNING.equals(eventMeshConsumer.getStatus())) { + if (ServiceState.RUNNING != eventMeshConsumer.getStatus()) { consumerTable.remove(consumerGroup); } } private void startClientCheck() { - int clientTimeout = eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshSessionExpiredInMills; + final int clientTimeout = eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshSessionExpiredInMills(); if (clientTimeout > 0) { scheduledExecutorService.scheduleAtFixedRate(() -> { - logger.info("grpc client info check"); - List clientList = new LinkedList<>(); - for (List clients : clientTable.values()) { - clientList.addAll(clients); - } - if (logger.isDebugEnabled()) { - logger.debug("total number of ConsumerGroupClients: {}", clientList.size()); - } + log.debug("grpc client info check"); + + final List clientList = new ArrayList<>(); + clientTable.values().forEach(clientList::addAll); - if (clientList.isEmpty()) { + log.debug("total number of ConsumerGroupClients: {}", clientList.size()); + + if (CollectionUtils.isEmpty(clientList)) { return; } - Set consumerGroupRestart = new HashSet<>(); - for (ConsumerGroupClient client : clientList) { + + final Set consumerGroupRestart = new HashSet<>(); + clientList.forEach(client -> { if (System.currentTimeMillis() - client.getLastUpTime().getTime() > clientTimeout) { - logger.warn("client {} lastUpdate time {} over three heartbeat cycles. Removing it", - JsonUtils.serialize(client), client.getLastUpTime()); - String consumerGroup = client.getConsumerGroup(); - EventMeshConsumer consumer = getEventMeshConsumer(consumerGroup); + log.warn("client {} lastUpdate time {} over three heartbeat cycles. Removing it", + JsonUtils.toJSONString(client), client.getLastUpTime()); deregisterClient(client); - if (consumer.deregisterClient(client)) { - consumerGroupRestart.add(consumerGroup); + if (getEventMeshConsumer(client.getConsumerGroup()).deregisterClient(client)) { + consumerGroupRestart.add(client.getConsumerGroup()); } } - } + }); // restart EventMeshConsumer for the group - for (String consumerGroup : consumerGroupRestart) { + consumerGroupRestart.forEach(consumerGroup -> { try { restartEventMeshConsumer(consumerGroup); } catch (Exception e) { - logger.error("Error in restarting EventMeshConsumer [{}]", consumerGroup, e); + log.error("Error in restarting EventMeshConsumer [{}]", consumerGroup, e); } - } - }, 10000, 10000, TimeUnit.MILLISECONDS); + }); + }, 10_000, 10_000, TimeUnit.MILLISECONDS); } } -} \ No newline at end of file + + public List getAllConsumerTopic() { + return clientTable.values() + .stream() + .flatMap(List::stream) + .map(ConsumerGroupClient::getTopic) + .distinct() + .collect(Collectors.toList()); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/EventMeshConsumer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/EventMeshConsumer.java index 6324619e9a..6a70458b00 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/EventMeshConsumer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/EventMeshConsumer.java @@ -17,6 +17,11 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.consumer; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.CONSUMER_GROUP; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.EVENT_MESH_IDC; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.INSTANCE_NAME; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.IS_BROADCAST; + import org.apache.eventmesh.api.AbstractContext; import org.apache.eventmesh.api.EventListener; import org.apache.eventmesh.api.EventMeshAction; @@ -24,37 +29,49 @@ import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.meta.config.EventMeshMetaConfig; import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.common.ServiceState; import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupMetadata; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicMetadata; import org.apache.eventmesh.runtime.core.plugin.MQConsumerWrapper; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupClient; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupTopicConfig; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.StreamTopicConfig; +import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.WebhookTopicConfig; import org.apache.eventmesh.runtime.core.protocol.grpc.push.HandleMsgContext; import org.apache.eventmesh.runtime.core.protocol.grpc.push.MessageHandler; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.commons.collections4.MapUtils; + +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Properties; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.TimeUnit; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; -public class EventMeshConsumer { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class EventMeshConsumer { private final String consumerGroup; @@ -71,18 +88,17 @@ public class EventMeshConsumer { private ServiceState serviceState; /** - * Key: topic - * Value: ConsumerGroupTopicConfig + * Key: topic Value: ConsumerGroupTopicConfig **/ private final Map consumerGroupTopicConfig = new ConcurrentHashMap<>(); - public EventMeshConsumer(EventMeshGrpcServer eventMeshGrpcServer, String consumerGroup) { + public EventMeshConsumer(final EventMeshGrpcServer eventMeshGrpcServer, final String consumerGroup) { this.eventMeshGrpcServer = eventMeshGrpcServer; this.eventMeshGrpcConfiguration = eventMeshGrpcServer.getEventMeshGrpcConfiguration(); this.consumerGroup = consumerGroup; this.messageHandler = new MessageHandler(consumerGroup, eventMeshGrpcServer.getPushMsgExecutor()); - this.persistentMqConsumer = new MQConsumerWrapper(eventMeshGrpcConfiguration.eventMeshConnectorPluginType); - this.broadcastMqConsumer = new MQConsumerWrapper(eventMeshGrpcConfiguration.eventMeshConnectorPluginType); + this.persistentMqConsumer = new MQConsumerWrapper(eventMeshGrpcConfiguration.getEventMeshStoragePluginType()); + this.broadcastMqConsumer = new MQConsumerWrapper(eventMeshGrpcConfiguration.getEventMeshStoragePluginType()); } /** @@ -91,19 +107,18 @@ public EventMeshConsumer(EventMeshGrpcServer eventMeshGrpcServer, String consume * @param client ConsumerGroupClient * @return true if the underlining EventMeshConsumer needs to restart later; false otherwise */ - public synchronized boolean registerClient(ConsumerGroupClient client) { + public synchronized boolean registerClient(final ConsumerGroupClient client) { boolean requireRestart = false; - GrpcType grpcType = client.getGrpcType(); - String topic = client.getTopic(); - SubscriptionMode subscriptionMode = client.getSubscriptionMode(); - ConsumerGroupTopicConfig topicConfig = consumerGroupTopicConfig.get(topic); + ConsumerGroupTopicConfig topicConfig = consumerGroupTopicConfig.get(client.getTopic()); if (topicConfig == null) { - topicConfig = ConsumerGroupTopicConfig.buildTopicConfig(consumerGroup, topic, subscriptionMode, grpcType); - consumerGroupTopicConfig.put(topic, topicConfig); + topicConfig = ConsumerGroupTopicConfig.buildTopicConfig(consumerGroup, client.getTopic(), + client.getSubscriptionMode(), client.getGrpcType()); + consumerGroupTopicConfig.put(client.getTopic(), topicConfig); requireRestart = true; } topicConfig.registerClient(client); + updateMetaData(); return requireRestart; } @@ -113,186 +128,250 @@ public synchronized boolean registerClient(ConsumerGroupClient client) { * @param client ConsumerGroupClient * @return true if the underlining EventMeshConsumer needs to restart later; false otherwise */ - public synchronized boolean deregisterClient(ConsumerGroupClient client) { + public synchronized boolean deregisterClient(final ConsumerGroupClient client) { boolean requireRestart = false; - String topic = client.getTopic(); - ConsumerGroupTopicConfig topicConfig = consumerGroupTopicConfig.get(topic); + + final ConsumerGroupTopicConfig topicConfig = consumerGroupTopicConfig.get(client.getTopic()); if (topicConfig != null) { topicConfig.deregisterClient(client); if (topicConfig.getSize() == 0) { - consumerGroupTopicConfig.remove(topic); + consumerGroupTopicConfig.remove(client.getTopic()); requireRestart = true; } } + updateMetaData(); return requireRestart; } + public void updateMetaData() { + if (!eventMeshGrpcConfiguration.isEventMeshServerMetaStorageEnable()) { + return; + } + try { + Map metadata = new HashMap<>(1 << 4); + for (Map.Entry consumerGroupMap : consumerGroupTopicConfig.entrySet()) { + String topic = consumerGroupMap.getKey(); + + ConsumerGroupTopicConfig cgtConfig = consumerGroupMap.getValue(); + + GrpcType grpcType = cgtConfig.getGrpcType(); + String consumerGroupKey = cgtConfig.getConsumerGroup(); + ConsumerGroupMetadata consumerGroupMetadata = new ConsumerGroupMetadata(); + Map consumerGroupTopicMetadataMap = + new HashMap<>(1 << 4); + consumerGroupMetadata.setConsumerGroup(consumerGroupKey); + if (GrpcType.STREAM == grpcType) { + StreamTopicConfig streamTopicConfig = (StreamTopicConfig) cgtConfig; + ConsumerGroupTopicMetadata consumerGroupTopicMetadata = new ConsumerGroupTopicMetadata(); + consumerGroupTopicMetadata.setConsumerGroup(streamTopicConfig.getConsumerGroup()); + consumerGroupTopicMetadata.setTopic(streamTopicConfig.getTopic()); + Set clientSet = new HashSet<>(); + streamTopicConfig.getIdcEmitterMap().values().forEach(stringEmitterMap -> { + clientSet.addAll(stringEmitterMap.keySet()); + }); + + consumerGroupTopicMetadata.setUrls(clientSet); + consumerGroupTopicMetadataMap.put(topic, consumerGroupTopicMetadata); + } else { + WebhookTopicConfig webhookTopicConfig = (WebhookTopicConfig) cgtConfig; + ConsumerGroupTopicMetadata consumerGroupTopicMetadata = new ConsumerGroupTopicMetadata(); + consumerGroupTopicMetadata.setConsumerGroup(webhookTopicConfig.getConsumerGroup()); + consumerGroupTopicMetadata.setTopic(webhookTopicConfig.getTopic()); + Set set = new HashSet<>(webhookTopicConfig.getTotalUrls()); + consumerGroupTopicMetadata.setUrls(set); + consumerGroupTopicMetadataMap.put(topic, consumerGroupTopicMetadata); + } + + consumerGroupMetadata.setConsumerGroupTopicMetadataMap(consumerGroupTopicMetadataMap); + metadata.put(consumerGroupKey, JsonUtils.toJSONString(consumerGroupMetadata)); + } + metadata.put(EventMeshMetaConfig.EVENT_MESH_PROTO, "grpc"); + + eventMeshGrpcServer.getMetaStorage().updateMetaData(metadata); + + } catch (Exception e) { + log.error("update eventmesh metadata error", e); + } + } + public synchronized void init() throws Exception { - if (consumerGroupTopicConfig.size() == 0) { + if (MapUtils.isEmpty(consumerGroupTopicConfig)) { // no topics, don't init the consumer return; } - Properties keyValue = new Properties(); - keyValue.put("isBroadcast", "false"); - keyValue.put("consumerGroup", consumerGroup); - keyValue.put("eventMeshIDC", eventMeshGrpcConfiguration.eventMeshIDC); - keyValue.put("instanceName", EventMeshUtil.buildMeshClientID(consumerGroup, - eventMeshGrpcConfiguration.eventMeshCluster)); + final Properties keyValue = new Properties(); + keyValue.put(IS_BROADCAST, "false"); + keyValue.put(CONSUMER_GROUP, consumerGroup); + keyValue.put(EVENT_MESH_IDC, eventMeshGrpcConfiguration.getEventMeshIDC()); + keyValue.put(INSTANCE_NAME, EventMeshUtil.buildMeshClientID(consumerGroup, + eventMeshGrpcConfiguration.getEventMeshCluster())); persistentMqConsumer.init(keyValue); - EventListener clusterEventListner = createEventListener(SubscriptionMode.CLUSTERING); - persistentMqConsumer.registerEventListener(clusterEventListner); - - Properties broadcastKeyValue = new Properties(); - broadcastKeyValue.put("isBroadcast", "true"); - broadcastKeyValue.put("consumerGroup", consumerGroup); - broadcastKeyValue.put("eventMeshIDC", eventMeshGrpcConfiguration.eventMeshIDC); - broadcastKeyValue.put("instanceName", EventMeshUtil.buildMeshClientID(consumerGroup, - eventMeshGrpcConfiguration.eventMeshCluster)); + persistentMqConsumer.registerEventListener(createEventListener(SubscriptionMode.CLUSTERING)); + + final Properties broadcastKeyValue = new Properties(); + broadcastKeyValue.put(IS_BROADCAST, "true"); + broadcastKeyValue.put(CONSUMER_GROUP, consumerGroup); + broadcastKeyValue.put(EVENT_MESH_IDC, eventMeshGrpcConfiguration.getEventMeshIDC()); + broadcastKeyValue.put(INSTANCE_NAME, EventMeshUtil.buildMeshClientID(consumerGroup, + eventMeshGrpcConfiguration.getEventMeshCluster())); broadcastMqConsumer.init(broadcastKeyValue); - EventListener broadcastEventListner = createEventListener(SubscriptionMode.BROADCASTING); - broadcastMqConsumer.registerEventListener(broadcastEventListner); + broadcastMqConsumer.registerEventListener(createEventListener(SubscriptionMode.BROADCASTING)); serviceState = ServiceState.INITED; - logger.info("EventMeshConsumer [{}] initialized.............", consumerGroup); + log.info("EventMeshConsumer [{}] initialized.............", consumerGroup); } public synchronized void start() throws Exception { - if (consumerGroupTopicConfig.size() == 0) { + if (MapUtils.isEmpty(consumerGroupTopicConfig)) { // no topics, don't start the consumer return; } - for (Map.Entry entry : consumerGroupTopicConfig.entrySet()) { - subscribe(entry.getKey(), entry.getValue().getSubscriptionMode()); - } + consumerGroupTopicConfig.forEach((k, v) -> { + try { + subscribe(k, v.getSubscriptionMode()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); persistentMqConsumer.start(); broadcastMqConsumer.start(); serviceState = ServiceState.RUNNING; - logger.info("EventMeshConsumer [{}] started..........", consumerGroup); + log.info("EventMeshConsumer [{}] started..........", consumerGroup); } public synchronized void shutdown() throws Exception { persistentMqConsumer.shutdown(); broadcastMqConsumer.shutdown(); - serviceState = ServiceState.STOPED; - logger.info("EventMeshConsumer [{}] shutdown.........", consumerGroup); + serviceState = ServiceState.STOPPED; + log.info("EventMeshConsumer [{}] shutdown.........", consumerGroup); } public ServiceState getStatus() { return serviceState; } - public void subscribe(String topic, SubscriptionMode subscriptionMode) throws Exception { - if (SubscriptionMode.CLUSTERING.equals(subscriptionMode)) { - persistentMqConsumer.subscribe(topic); - } else if (SubscriptionMode.BROADCASTING.equals(subscriptionMode)) { - broadcastMqConsumer.subscribe(topic); - } else { - logger.error("Subscribe Failed. Incorrect Subscription Mode"); - throw new Exception("Subscribe Failed. Incorrect Subscription Mode"); + public void subscribe(final String topic, final SubscriptionMode subscriptionMode) throws Exception { + switch (subscriptionMode) { + case CLUSTERING: + persistentMqConsumer.subscribe(topic); + break; + case BROADCASTING: + broadcastMqConsumer.subscribe(topic); + break; + default: + throw new Exception("Subscribe Failed. Incorrect Subscription Mode"); } } - public void unsubscribe(Subscription.SubscriptionItem subscriptionItem) throws Exception { - SubscriptionMode mode = subscriptionItem.getMode(); - String topic = subscriptionItem.getTopic(); - if (SubscriptionMode.CLUSTERING.equals(mode)) { - persistentMqConsumer.unsubscribe(topic); - } else if (SubscriptionMode.BROADCASTING.equals(mode)) { - broadcastMqConsumer.unsubscribe(topic); - } else { - logger.error("Unsubscribe Failed. Incorrect Subscription Mode"); - throw new Exception("Unsubscribe Failed. Incorrect Subscription Mode"); + public void unsubscribe(final SubscriptionItem subscriptionItem) throws Exception { + final SubscriptionMode mode = subscriptionItem.getMode(); + final String topic = subscriptionItem.getTopic(); + switch (mode) { + case CLUSTERING: + persistentMqConsumer.unsubscribe(topic); + break; + case BROADCASTING: + broadcastMqConsumer.unsubscribe(topic); + break; + default: + throw new Exception("Unsubscribe Failed. Incorrect Subscription Mode"); } } - public void updateOffset(SubscriptionMode subscriptionMode, List events, - AbstractContext context) throws Exception { - if (SubscriptionMode.CLUSTERING.equals(subscriptionMode)) { - persistentMqConsumer.updateOffset(events, context); - } else if (SubscriptionMode.BROADCASTING.equals(subscriptionMode)) { - broadcastMqConsumer.updateOffset(events, context); - } else { - logger.error("Subscribe Failed. Incorrect Subscription Mode"); - throw new Exception("Subscribe Failed. Incorrect Subscription Mode"); + public void updateOffset(final SubscriptionMode subscriptionMode, final List events, final AbstractContext context) + throws Exception { + switch (subscriptionMode) { + case CLUSTERING: + persistentMqConsumer.updateOffset(events, context); + break; + case BROADCASTING: + broadcastMqConsumer.updateOffset(events, context); + break; + default: + throw new Exception("Subscribe Failed. Incorrect Subscription Mode"); } } - private EventListener createEventListener(SubscriptionMode subscriptionMode) { + private EventListener createEventListener(final SubscriptionMode subscriptionMode) { return (event, context) -> { - event = CloudEventBuilder.from(event) - .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) + .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, + String.valueOf(System.currentTimeMillis())) .build(); - String topic = event.getSubject(); - Object bizSeqNo = event.getExtension(Constants.PROPERTY_MESSAGE_SEARCH_KEYS); - String strBizSeqNo = bizSeqNo == null ? "" : bizSeqNo.toString(); - - Object uniqueId = event.getExtension(Constants.RMB_UNIQ_ID); - String strUniqueId = uniqueId == null ? "" : uniqueId.toString(); + final String topic = event.getSubject(); + final String bizSeqNo = Optional.ofNullable( + (String) event.getExtension(Constants.PROPERTY_MESSAGE_SEARCH_KEYS)) + .orElse(""); + final String uniqueId = Optional.ofNullable((String) event.getExtension(Constants.RMB_UNIQ_ID)) + .orElse(""); - if (logger.isDebugEnabled()) { - logger.debug("message|mq2eventMesh|topic={}|msg={}", topic, event); + if (log.isDebugEnabled()) { + log.debug("message|mq2eventMesh|topic={}|msg={}", topic, event); } else { - logger.info("message|mq2eventMesh|topic={}|bizSeqNo={}|uniqueId={}", topic, bizSeqNo, uniqueId); + log.info("message|mq2eventMesh|topic={}|bizSeqNo={}|uniqueId={}", topic, bizSeqNo, uniqueId); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromQueue(); } - EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = (EventMeshAsyncConsumeContext) context; + final EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = (EventMeshAsyncConsumeContext) context; - ConsumerGroupTopicConfig topicConfig = consumerGroupTopicConfig.get(topic); + final ConsumerGroupTopicConfig topicConfig = consumerGroupTopicConfig.get(topic); if (topicConfig != null) { - GrpcType grpcType = topicConfig.getGrpcType(); - HandleMsgContext handleMsgContext = new HandleMsgContext(consumerGroup, event, subscriptionMode, grpcType, - eventMeshAsyncConsumeContext.getAbstractContext(), eventMeshGrpcServer, this, topicConfig); + final HandleMsgContext handleMsgContext = + new HandleMsgContext(consumerGroup, event, subscriptionMode, topicConfig.getGrpcType(), + eventMeshAsyncConsumeContext.getAbstractContext(), eventMeshGrpcServer, + this, + topicConfig); if (messageHandler.handle(handleMsgContext)) { eventMeshAsyncConsumeContext.commit(EventMeshAction.ManualAck); return; } else { // can not handle the message due to the capacity limit is reached - // wait for sometime and send this message back to mq and consume again + // wait for some time and send this message back to mq and consume again try { - Thread.sleep(5000); - sendMessageBack(consumerGroup, event, strUniqueId, strBizSeqNo); + ThreadUtils.sleep(5, TimeUnit.SECONDS); + sendMessageBack(consumerGroup, event, uniqueId, bizSeqNo); } catch (Exception ignored) { // ignore exception } } } else { - if (logger.isDebugEnabled()) { - logger.debug("no active consumer for topic={}|msg={}", topic, event); - } + log.debug("no active consumer for topic={}|msg={}", topic, event); } + eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); }; } - public void sendMessageBack(String consumerGroup, final CloudEvent event, final String uniqueId, String bizSeqNo) throws Exception { - EventMeshProducer producer - = eventMeshGrpcServer.getProducerManager().getEventMeshProducer(consumerGroup); + public void sendMessageBack(final String consumerGroup, final CloudEvent event, + final String uniqueId, final String bizSeqNo) throws Exception { + final EventMeshProducer producer = eventMeshGrpcServer.getProducerManager().getEventMeshProducer(consumerGroup); if (producer == null) { - logger.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", consumerGroup, bizSeqNo, uniqueId); + log.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", consumerGroup, bizSeqNo, uniqueId); return; } - final SendMessageContext sendMessageBackContext = new SendMessageContext(bizSeqNo, event, producer, eventMeshGrpcServer); + final SendMessageContext sendMessageBackContext = new SendMessageContext(bizSeqNo, event, + producer, eventMeshGrpcServer); producer.send(sendMessageBackContext, new SendCallback() { + @Override - public void onSuccess(SendResult sendResult) { + public void onSuccess(final SendResult sendResult) { } @Override - public void onException(OnExceptionContext context) { - logger.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", consumerGroup, bizSeqNo, uniqueId); + public void onException(final OnExceptionContext context) { + log.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", consumerGroup, bizSeqNo, uniqueId); } }); } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupClient.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupClient.java index 679ed51779..6d185803e0 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupClient.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupClient.java @@ -1,26 +1,25 @@ /* - * Licensed to 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. Apache Software Foundation (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 + * 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. + * 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. */ package org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; import java.util.Date; @@ -32,31 +31,31 @@ @Getter public class ConsumerGroupClient { - private final String env; + public final String env; - private final String idc; + public final String idc; - private final String consumerGroup; + public final String consumerGroup; - private final String topic; + public final String topic; private final GrpcType grpcType; - private String url; + public String url; - private EventEmitter eventEmitter; + private EventEmitter eventEmitter; private final SubscriptionMode subscriptionMode; - private final String sys; + public final String sys; - private final String ip; + public final String ip; - private final String pid; + public final String pid; - private final String hostname; + public final String hostname; - private final String apiVersion; + public final String apiVersion; private Date lastUpTime; @@ -64,7 +63,7 @@ public void setUrl(String url) { this.url = url; } - public void setEventEmitter(EventEmitter emitter) { + public void setEventEmitter(EventEmitter emitter) { this.eventEmitter = emitter; } @@ -88,4 +87,3 @@ public String toString() { + ",lastUpTime=" + lastUpTime + "}"; } } - diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupTopicConfig.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupTopicConfig.java index 1e4c608959..a166dab290 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupTopicConfig.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/ConsumerGroupTopicConfig.java @@ -17,13 +17,10 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; public abstract class ConsumerGroupTopicConfig { - private final Logger logger = LoggerFactory.getLogger(ConsumerGroupTopicConfig.class); protected final String consumerGroup; @@ -41,8 +38,8 @@ protected ConsumerGroupTopicConfig(String consumerGroup, String topic, Subscript } public static ConsumerGroupTopicConfig buildTopicConfig(String consumerGroup, String topic, SubscriptionMode subscriptionMode, - GrpcType grpcType) { - if (GrpcType.STREAM.equals(grpcType)) { + GrpcType grpcType) { + if (GrpcType.STREAM == grpcType) { return new StreamTopicConfig(consumerGroup, topic, subscriptionMode); } else { return new WebhookTopicConfig(consumerGroup, topic, subscriptionMode); @@ -70,4 +67,4 @@ public SubscriptionMode getSubscriptionMode() { public GrpcType getGrpcType() { return grpcType; } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/StreamTopicConfig.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/StreamTopicConfig.java index b9f3d86615..a01058dcf5 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/StreamTopicConfig.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/StreamTopicConfig.java @@ -17,74 +17,80 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; +import org.apache.commons.collections4.MapUtils; + +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class StreamTopicConfig extends ConsumerGroupTopicConfig { - private final Logger logger = LoggerFactory.getLogger(StreamTopicConfig.class); /** - * Key: IDC - * Value: list of emitters with Client_IP:port + * Key: IDC Value: list of emitters with Client_IP:port */ - private final Map>> idcEmitterMap = new ConcurrentHashMap<>(); + private final Map>> idcEmitterMap = new ConcurrentHashMap<>(); /** - * Key: IDC - * Value: list of emitters + * Key: IDC Value: list of emitters */ - private Map>> idcEmitters = new ConcurrentHashMap<>(); + private Map>> idcEmitters = new ConcurrentHashMap<>(); - private List> totalEmitters = new LinkedList<>(); + private List> totalEmitters = new ArrayList<>(); - public StreamTopicConfig(String consumerGroup, String topic, SubscriptionMode subscriptionMode) { + public StreamTopicConfig(final String consumerGroup, final String topic, final SubscriptionMode subscriptionMode) { super(consumerGroup, topic, subscriptionMode, GrpcType.STREAM); } + private String concatKey(String ip, String pid) { + return ip.concat(":").concat(pid); + } + @Override - public synchronized void registerClient(ConsumerGroupClient client) { - if (!client.getGrpcType().equals(grpcType)) { - logger.warn("Invalid grpc type: {}, expecting grpc type: {}, can not register client {}", - client.getGrpcType(), grpcType, client.toString()); + public synchronized void registerClient(final ConsumerGroupClient client) { + Objects.requireNonNull(client, "ConsumerGroupClient can not be null"); + + if (client.getGrpcType() != grpcType) { + log.warn("Invalid grpc type: {}, expecting grpc type: {}, can not register client {}", client.getGrpcType(), grpcType, client); return; } - String idc = client.getIdc(); - String clientIp = client.getIp(); - String clientPid = client.getPid(); - EventEmitter emitter = client.getEventEmitter(); - Map> emitters = idcEmitterMap.computeIfAbsent(idc, k -> new HashMap<>()); - emitters.put(clientIp + ":" + clientPid, emitter); - - idcEmitters = buildIdcEmitter(); - totalEmitters = buildTotalEmitter(); + + idcEmitterMap.computeIfAbsent(client.getIdc(), k -> new HashMap<>()) + .put(concatKey(client.getIp(), client.getPid()), client.getEventEmitter()); + + idcEmitters = buildIdcEmitter(idcEmitterMap); + totalEmitters = buildTotalEmitter(idcEmitters); } @Override - public void deregisterClient(ConsumerGroupClient client) { - String idc = client.getIdc(); - String clientIp = client.getIp(); - String clientPid = client.getPid(); + public void deregisterClient(final ConsumerGroupClient client) { + final String idc = client.getIdc(); + final String clientIp = client.getIp(); + final String clientPid = client.getPid(); - Map> emitters = idcEmitterMap.get(idc); - if (emitters == null) { + final Map> emitters = idcEmitterMap.get(idc); + if (MapUtils.isEmpty(emitters)) { return; } + emitters.remove(clientIp + ":" + clientPid); - if (emitters.size() == 0) { + if (emitters.isEmpty()) { idcEmitterMap.remove(idc); } - idcEmitters = buildIdcEmitter(); - totalEmitters = buildTotalEmitter(); + + idcEmitters = buildIdcEmitter(idcEmitterMap); + totalEmitters = buildTotalEmitter(idcEmitters); } @Override @@ -99,44 +105,29 @@ public String toString() { + ",topic=" + topic + "}"; } - public String getConsumerGroup() { - return consumerGroup; + public Map>> getIdcEmitterMap() { + return idcEmitterMap; } - public String getTopic() { - return topic; - } - - public SubscriptionMode getSubscriptionMode() { - return subscriptionMode; - } - - public GrpcType getGrpcType() { - return grpcType; - } - - public Map>> getIdcEmitters() { + public Map>> getIdcEmitters() { return idcEmitters; } - public List> getTotalEmitters() { + public List> getTotalEmitters() { return totalEmitters; } - private Map>> buildIdcEmitter() { - Map>> result = new HashMap<>(); - for (Map.Entry>> entry : idcEmitterMap.entrySet()) { - List> emitterList = new LinkedList<>(entry.getValue().values()); - result.put(entry.getKey(), emitterList); - } + private static Map>> buildIdcEmitter( + final Map>> idcEmitterMap) { + final Map>> result = new HashMap<>(); + idcEmitterMap.forEach((k, v) -> result.put(k, new LinkedList<>(v.values()))); return result; } - private List> buildTotalEmitter() { - List> emitterList = new LinkedList<>(); - for (List> emitters : idcEmitters.values()) { - emitterList.addAll(emitters); - } + private static List> buildTotalEmitter( + final Map>> idcEmitters) { + final List> emitterList = new LinkedList<>(); + idcEmitters.values().forEach(emitterList::addAll); return emitterList; } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/WebhookTopicConfig.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/WebhookTopicConfig.java index 018f1fee74..818efd8dc6 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/WebhookTopicConfig.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/consumer/consumergroup/WebhookTopicConfig.java @@ -17,7 +17,8 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import java.util.ArrayList; import java.util.HashSet; @@ -27,17 +28,15 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class WebhookTopicConfig extends ConsumerGroupTopicConfig { - private final Logger logger = LoggerFactory.getLogger(WebhookTopicConfig.class); /** * PUSH URL *

- * Key: IDC - * Value: list of URls + * Key: IDC Value: list of URls */ private final Map> idcUrls = new ConcurrentHashMap<>(); @@ -49,8 +48,8 @@ public WebhookTopicConfig(String consumerGroup, String topic, SubscriptionMode s @Override public synchronized void registerClient(ConsumerGroupClient client) { - if (!client.getGrpcType().equals(grpcType)) { - logger.warn("Invalid grpc type: {}, expecting grpc type: {}, can not register client {}", + if (client.getGrpcType() != grpcType) { + log.warn("Invalid grpc type: {}, expecting grpc type: {}, can not register client {}", client.getGrpcType(), grpcType, client.toString()); return; } @@ -73,7 +72,7 @@ public void deregisterClient(ConsumerGroupClient client) { return; } urls.remove(url); - if (urls.size() == 0) { + if (urls.isEmpty()) { idcUrls.remove(idc); } totalUrls = buildTotalUrls(); @@ -123,4 +122,4 @@ private List buildTotalUrls() { public List getTotalUrls() { return totalUrls; } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/AbstractPublishBatchCloudEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/AbstractPublishBatchCloudEventProcessor.java new file mode 100644 index 0000000000..43cdb9a3cf --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/AbstractPublishBatchCloudEventProcessor.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.processor; + +import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractPublishBatchCloudEventProcessor implements PublishProcessor { + + private static final Logger aclLogger = LoggerFactory.getLogger("acl"); + + protected final EventMeshGrpcServer eventMeshGrpcServer; + + protected final Acl acl; + + public AbstractPublishBatchCloudEventProcessor(final EventMeshGrpcServer eventMeshGrpcServer, final Acl acl) { + this.eventMeshGrpcServer = eventMeshGrpcServer; + this.acl = acl; + } + + @Override + public void process(CloudEventBatch cloudEvent, EventEmitter emitter) throws Exception { + + // control flow rate limit + if (!eventMeshGrpcServer.getMsgRateLimiter().tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + log.error("Send message speed over limit."); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_SEND_MESSAGE_SPEED_OVER_LIMIT_ERR, emitter); + return; + } + + StatusCode cloudEventCheck = cloudEventBatchCheck(cloudEvent); + if (cloudEventCheck != StatusCode.SUCCESS) { + ServiceUtils.sendResponseCompleted(cloudEventCheck, emitter); + return; + } + StatusCode aclCheck = this.aclCheck(cloudEvent.getEvents(0)); + if (aclCheck != StatusCode.SUCCESS) { + ServiceUtils.sendResponseCompleted(aclCheck, emitter); + return; + } + handleCloudEvent(cloudEvent, emitter); + } + + public StatusCode cloudEventBatchCheck(CloudEventBatch cloudEventBatch) { + if (!ServiceUtils.validateCloudEventBatchAttributes(cloudEventBatch)) { + return StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR; + } + + if (!ServiceUtils.validateCloudEventBatchData(cloudEventBatch)) { + return StatusCode.EVENTMESH_PROTOCOL_BODY_ERR; + } + return StatusCode.SUCCESS; + } + + public StatusCode aclCheck(CloudEvent cloudEvent) { + try { + if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAdd = EventMeshCloudEventUtils.getIp(cloudEvent); + String user = EventMeshCloudEventUtils.getUserName(cloudEvent); + String pass = EventMeshCloudEventUtils.getPassword(cloudEvent); + String subsystem = EventMeshCloudEventUtils.getSys(cloudEvent); + String topic = EventMeshCloudEventUtils.getSubject(cloudEvent); + this.acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.MSG_SEND_ASYNC.getRequestCode()); + } + } catch (AclException e) { + aclLogger.warn("Client has no permission,AbstructPublishCloudEventProcessor send failed", e); + return StatusCode.EVENTMESH_ACL_ERR; + } + return StatusCode.SUCCESS; + } + + abstract void handleCloudEvent(CloudEventBatch cloudEventBatch, EventEmitter emitter) throws Exception; +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/AbstractPublishCloudEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/AbstractPublishCloudEventProcessor.java new file mode 100644 index 0000000000..2f46f2f067 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/AbstractPublishCloudEventProcessor.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.processor; + +import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractPublishCloudEventProcessor implements PublishProcessor { + + private static final Logger aclLogger = LoggerFactory.getLogger("acl"); + + protected final EventMeshGrpcServer eventMeshGrpcServer; + + protected final Acl acl; + + public AbstractPublishCloudEventProcessor(final EventMeshGrpcServer eventMeshGrpcServer, final Acl acl) { + this.eventMeshGrpcServer = eventMeshGrpcServer; + this.acl = acl; + } + + @Override + public void process(CloudEvent cloudEvent, EventEmitter emitter) throws Exception { + + // control flow rate limit + if (!eventMeshGrpcServer.getMsgRateLimiter().tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + log.error("Send message speed over limit."); + ServiceUtils.sendStreamResponseCompleted(cloudEvent, StatusCode.EVENTMESH_SEND_MESSAGE_SPEED_OVER_LIMIT_ERR, emitter); + return; + } + + StatusCode cloudEventCheck = cloudEventCheck(cloudEvent); + if (cloudEventCheck != StatusCode.SUCCESS) { + ServiceUtils.sendResponseCompleted(cloudEventCheck, emitter); + return; + } + StatusCode aclCheck = this.aclCheck(cloudEvent); + if (aclCheck != StatusCode.SUCCESS) { + ServiceUtils.sendResponseCompleted(aclCheck, emitter); + return; + } + handleCloudEvent(cloudEvent, emitter); + } + + public StatusCode cloudEventCheck(CloudEvent cloudEvent) { + if (!ServiceUtils.validateCloudEventAttributes(cloudEvent)) { + return StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR; + } + + if (!ServiceUtils.validateCloudEventData(cloudEvent)) { + return StatusCode.EVENTMESH_PROTOCOL_BODY_ERR; + } + return StatusCode.SUCCESS; + } + + public StatusCode aclCheck(CloudEvent cloudEvent) { + try { + if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAdd = EventMeshCloudEventUtils.getIp(cloudEvent); + String user = EventMeshCloudEventUtils.getUserName(cloudEvent); + String pass = EventMeshCloudEventUtils.getPassword(cloudEvent); + String subsystem = EventMeshCloudEventUtils.getSys(cloudEvent); + String topic = EventMeshCloudEventUtils.getSubject(cloudEvent); + this.acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.MSG_SEND_ASYNC.getRequestCode()); + } + } catch (AclException e) { + aclLogger.warn("Client has no permission,AbstructPublishCloudEventProcessor send failed", e); + return StatusCode.EVENTMESH_ACL_ERR; + } + return StatusCode.SUCCESS; + } + + abstract void handleCloudEvent(CloudEvent cloudEvent, EventEmitter emitter) throws Exception; +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/BatchPublishCloudEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/BatchPublishCloudEventProcessor.java new file mode 100644 index 0000000000..a83083aec4 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/BatchPublishCloudEventProcessor.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.processor; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.BatchEventMeshCloudEventWrapper; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.protocol.api.ProtocolAdaptor; +import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class BatchPublishCloudEventProcessor extends AbstractPublishBatchCloudEventProcessor { + + public BatchPublishCloudEventProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { + super(eventMeshGrpcServer, eventMeshGrpcServer.getAcl()); + } + + public void handleCloudEvent(CloudEventBatch cloudEventBatch, EventEmitter emitter) throws Exception { + + CloudEvent cloudEvent = cloudEventBatch.getEvents(0); + String topic = EventMeshCloudEventUtils.getSubject(cloudEvent); + String producerGroup = EventMeshCloudEventUtils.getProducerGroup(cloudEvent); + + String protocolType = EventMeshCloudEventUtils.getProtocolType(cloudEvent); + ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + List cloudEvents = grpcCommandProtocolAdaptor.toBatchCloudEvent( + new BatchEventMeshCloudEventWrapper(cloudEventBatch)); + + for (io.cloudevents.CloudEvent event : cloudEvents) { + String seqNum = event.getId(); + String uniqueId = (event.getExtension(ProtocolKey.UNIQUE_ID) == null) ? "" : event.getExtension(ProtocolKey.UNIQUE_ID).toString(); + ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); + EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); + + SendMessageContext sendMessageContext = new SendMessageContext(seqNum, event, eventMeshProducer, eventMeshGrpcServer); + + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordSendMsgToQueue(); + long startTime = System.currentTimeMillis(); + eventMeshProducer.send(sendMessageContext, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + long endTime = System.currentTimeMillis(); + log.info("message|eventMesh2mq|REQ|BatchSend|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId); + } + + @Override + public void onException(OnExceptionContext context) { + long endTime = System.currentTimeMillis(); + log.error("message|eventMesh2mq|REQ|BatchSend|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId, context.getException()); + } + }); + } + ServiceUtils.sendResponseCompleted(StatusCode.SUCCESS, "batch publish success", emitter); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/BatchPublishMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/BatchPublishMessageProcessor.java deleted file mode 100644 index 2f2d5062d4..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/BatchPublishMessageProcessor.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.processor; - -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.AclException; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.BatchMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.protocol.api.ProtocolAdaptor; -import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.ProducerManager; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.SendMessageContext; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class BatchPublishMessageProcessor { - - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - private final Logger aclLogger = LoggerFactory.getLogger("acl"); - - private final EventMeshGrpcServer eventMeshGrpcServer; - - public BatchPublishMessageProcessor(EventMeshGrpcServer eventMeshGrpcServer) { - this.eventMeshGrpcServer = eventMeshGrpcServer; - } - - public void process(BatchMessage message, EventEmitter emitter) throws Exception { - RequestHeader requestHeader = message.getHeader(); - - if (!ServiceUtils.validateHeader(requestHeader)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); - return; - } - - if (!ServiceUtils.validateBatchMessage(message)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); - return; - } - - try { - doAclCheck(message); - } catch (Exception e) { - aclLogger.warn("CLIENT HAS NO PERMISSION,BatchSendMessageProcessor send failed", e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); - return; - } - - // control flow rate limit - if (!eventMeshGrpcServer.getMsgRateLimiter() - .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - logger.error("Send message speed over limit."); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR, emitter); - return; - } - - String topic = message.getTopic(); - String producerGroup = message.getProducerGroup(); - - String protocolType = requestHeader.getProtocolType(); - ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - List cloudEvents = grpcCommandProtocolAdaptor.toBatchCloudEvent(new BatchMessageWrapper(message)); - - for (CloudEvent event : cloudEvents) { - String seqNum = event.getId(); - String uniqueId = event.getExtension(ProtocolKey.UNIQUE_ID).toString(); - ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); - EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); - - SendMessageContext sendMessageContext = new SendMessageContext(seqNum, event, eventMeshProducer, eventMeshGrpcServer); - - long startTime = System.currentTimeMillis(); - eventMeshProducer.send(sendMessageContext, new SendCallback() { - @Override - public void onSuccess(SendResult sendResult) { - long endTime = System.currentTimeMillis(); - logger.info("message|eventMesh2mq|REQ|BatchSend|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId); - } - - @Override - public void onException(OnExceptionContext context) { - long endTime = System.currentTimeMillis(); - logger.error("message|eventMesh2mq|REQ|BatchSend|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId, context.getException()); - } - }); - } - ServiceUtils.sendRespAndDone(StatusCode.SUCCESS, "batch publish success", emitter); - } - - private void doAclCheck(BatchMessage message) throws AclException { - RequestHeader requestHeader = message.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = requestHeader.getIp(); - String user = requestHeader.getUsername(); - String pass = requestHeader.getPassword(); - String subsystem = requestHeader.getSys(); - String topic = message.getTopic(); - Acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.MSG_SEND_ASYNC.getRequestCode()); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/HeartbeatProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/HeartbeatProcessor.java index 684fcb26d6..a08601dc0c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/HeartbeatProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/HeartbeatProcessor.java @@ -18,95 +18,116 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.processor; import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.common.protocol.HeartbeatItem; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat; -import org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat.ClientType; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.ConsumerManager; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupClient; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; import java.util.Date; +import java.util.List; +import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.type.TypeReference; + public class HeartbeatProcessor { - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - private final Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger ACL_LOGGER = LoggerFactory.getLogger(EventMeshConstants.ACL); private final EventMeshGrpcServer eventMeshGrpcServer; - public HeartbeatProcessor(EventMeshGrpcServer eventMeshGrpcServer) { + private final Acl acl; + + public HeartbeatProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { this.eventMeshGrpcServer = eventMeshGrpcServer; + this.acl = eventMeshGrpcServer.getAcl(); } - public void process(Heartbeat heartbeat, EventEmitter emitter) throws Exception { - RequestHeader header = heartbeat.getHeader(); + public void process(CloudEvent heartbeat, EventEmitter emitter) throws Exception { - if (!ServiceUtils.validateHeader(header)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); + if (!ServiceUtils.validateCloudEventAttributes(heartbeat)) { + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); return; } if (!ServiceUtils.validateHeartBeat(heartbeat)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); return; } try { doAclCheck(heartbeat); } catch (AclException e) { - aclLogger.warn("CLIENT HAS NO PERMISSION, HeartbeatProcessor failed", e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); + ACL_LOGGER.warn("CLIENT HAS NO PERMISSION, HeartbeatProcessor failed", e); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); return; } // only handle heartbeat for consumers - ClientType clientType = heartbeat.getClientType(); - if (!ClientType.SUB.equals(clientType)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); + org.apache.eventmesh.common.protocol.grpc.common.ClientType clientType = EventMeshCloudEventUtils.getClientType(heartbeat); + if (org.apache.eventmesh.common.protocol.grpc.common.ClientType.SUB != clientType) { + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); return; } ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); - String consumerGroup = heartbeat.getConsumerGroup(); - + String consumerGroup = EventMeshCloudEventUtils.getConsumerGroup(heartbeat); + final String env = EventMeshCloudEventUtils.getEnv(heartbeat); + final String idc = EventMeshCloudEventUtils.getIdc(heartbeat); + final String sys = EventMeshCloudEventUtils.getSys(heartbeat); + final String ip = EventMeshCloudEventUtils.getIp(heartbeat); + final String pid = EventMeshCloudEventUtils.getPid(heartbeat); // update clients' timestamp in the heartbeat items - for (Heartbeat.HeartbeatItem item : heartbeat.getHeartbeatItemsList()) { + List heartbeatItems = JsonUtils.parseTypeReferenceObject(heartbeat.getTextData(), + new TypeReference>() { + }); + Objects.requireNonNull(heartbeatItems, "heartbeatItems can't be null"); + for (HeartbeatItem item : heartbeatItems) { ConsumerGroupClient hbClient = ConsumerGroupClient.builder() - .env(header.getEnv()) - .idc(header.getIdc()) - .sys(header.getSys()) - .ip(header.getIp()) - .pid(header.getPid()) + .env(env) + .idc(idc) + .sys(sys) + .ip(ip) + .pid(pid) .consumerGroup(consumerGroup) .topic(item.getTopic()) .lastUpTime(new Date()) .build(); - consumerManager.updateClientTime(hbClient); - } - ServiceUtils.sendRespAndDone(StatusCode.SUCCESS, "heartbeat success", emitter); + // consumer group client is lost, and the client needs to resubscribe. + if (!consumerManager.updateClientTime(hbClient)) { + ServiceUtils.sendResponseCompleted(StatusCode.CLIENT_RESUBSCRIBE, emitter); + return; + } + } + ServiceUtils.sendResponseCompleted(StatusCode.SUCCESS, "heartbeat success", emitter); } - private void doAclCheck(Heartbeat heartbeat) throws AclException { - RequestHeader header = heartbeat.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = header.getIp(); - String user = header.getUsername(); - String pass = header.getPassword(); - String sys = header.getSys(); - int requestCode = Integer.valueOf(RequestCode.HEARTBEAT.getRequestCode()); - for (Heartbeat.HeartbeatItem item : heartbeat.getHeartbeatItemsList()) { - Acl.doAclCheckInHttpHeartbeat(remoteAdd, user, pass, sys, item.getTopic(), requestCode); + private void doAclCheck(CloudEvent heartbeat) throws AclException { + + if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAdd = EventMeshCloudEventUtils.getIp(heartbeat); + String user = EventMeshCloudEventUtils.getUserName(heartbeat); + String pass = EventMeshCloudEventUtils.getPassword(heartbeat); + String sys = EventMeshCloudEventUtils.getSys(heartbeat); + int requestCode = RequestCode.HEARTBEAT.getRequestCode(); + List heartbeatItems = JsonUtils.parseTypeReferenceObject(heartbeat.getTextData(), + new TypeReference>() { + }); + for (HeartbeatItem item : heartbeatItems) { + this.acl.doAclCheckInHttpHeartbeat(remoteAdd, user, pass, sys, item.getTopic(), requestCode); } } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/PublishCloudEventsProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/PublishCloudEventsProcessor.java new file mode 100644 index 0000000000..544771efc9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/PublishCloudEventsProcessor.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.processor; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.protocol.api.ProtocolAdaptor; +import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.util.EventMeshUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PublishCloudEventsProcessor extends AbstractPublishCloudEventProcessor { + + public PublishCloudEventsProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { + super(eventMeshGrpcServer, eventMeshGrpcServer.getAcl()); + } + + @Override + public void handleCloudEvent(CloudEvent message, EventEmitter emitter) throws Exception { + + String protocolType = EventMeshCloudEventUtils.getProtocolType(message); + ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + io.cloudevents.CloudEvent cloudEvent = grpcCommandProtocolAdaptor.toCloudEvent(new EventMeshCloudEventWrapper(message)); + + String seqNum = EventMeshCloudEventUtils.getSeqNum(message); + String uniqueId = EventMeshCloudEventUtils.getUniqueId(message); + String topic = EventMeshCloudEventUtils.getSubject(message); + String producerGroup = EventMeshCloudEventUtils.getProducerGroup(message); + + ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); + EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); + + SendMessageContext sendMessageContext = new SendMessageContext(seqNum, cloudEvent, eventMeshProducer, eventMeshGrpcServer); + + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordSendMsgToQueue(); + long startTime = System.currentTimeMillis(); + eventMeshProducer.send(sendMessageContext, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + ServiceUtils.sendResponseCompleted(StatusCode.SUCCESS, sendResult.toString(), emitter); + long endTime = System.currentTimeMillis(); + log.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordSendMsgToClient(EventMeshCloudEventUtils.getIp(message)); + } + + @Override + public void onException(OnExceptionContext context) { + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR, + EventMeshUtil.stackTrace(context.getException(), 2), emitter); + long endTime = System.currentTimeMillis(); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId, context.getException()); + } + }); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/PublishProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/PublishProcessor.java new file mode 100644 index 0000000000..1d5de0b9ff --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/PublishProcessor.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.processor; + +import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; + +/** + * publish processor interface + * @param + * @param + */ +public interface PublishProcessor { + + void process(Request request, EventEmitter emitter) throws Exception; + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/ReplyMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/ReplyMessageProcessor.java index a9bfe05270..e55e15d651 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/ReplyMessageProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/ReplyMessageProcessor.java @@ -22,21 +22,23 @@ import org.apache.eventmesh.api.exception.AclException; import org.apache.eventmesh.api.exception.OnExceptionContext; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.ProducerManager; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.SendMessageContext; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; import java.util.concurrent.TimeUnit; @@ -44,96 +46,100 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.cloudevents.CloudEvent; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class ReplyMessageProcessor { - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - private final Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger ACL_LOGGER = LoggerFactory.getLogger(EventMeshConstants.ACL); private final EventMeshGrpcServer eventMeshGrpcServer; - public ReplyMessageProcessor(EventMeshGrpcServer eventMeshGrpcServer) { + private final Acl acl; + + public ReplyMessageProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { this.eventMeshGrpcServer = eventMeshGrpcServer; + this.acl = eventMeshGrpcServer.getAcl(); } - public void process(SimpleMessage message, EventEmitter emitter) throws Exception { - RequestHeader requestHeader = message.getHeader(); + public void process(CloudEvent message, EventEmitter emitter) throws Exception { - if (!ServiceUtils.validateHeader(requestHeader)) { - ServiceUtils.sendStreamRespAndDone(requestHeader, StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); + if (!ServiceUtils.validateCloudEventAttributes(message)) { + ServiceUtils.sendStreamResponseCompleted(message, StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); return; } - if (!ServiceUtils.validateMessage(message)) { - ServiceUtils.sendStreamRespAndDone(requestHeader, StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); + if (!ServiceUtils.validateCloudEventData(message)) { + ServiceUtils.sendStreamResponseCompleted(message, StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); return; } try { doAclCheck(message); } catch (Exception e) { - aclLogger.warn("CLIENT HAS NO PERMISSION,RequestReplyMessageProcessor reply failed", e); - ServiceUtils.sendStreamRespAndDone(requestHeader, StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); + ACL_LOGGER.warn("CLIENT HAS NO PERMISSION,RequestReplyMessageProcessor reply failed", e); + ServiceUtils.sendStreamResponseCompleted(message, StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); return; } // control flow rate limit if (!eventMeshGrpcServer.getMsgRateLimiter() .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - logger.error("Send message speed over limit."); - ServiceUtils.sendStreamRespAndDone(requestHeader, StatusCode.EVENTMESH_SEND_MESSAGE_SPEED_OVER_LIMIT_ERR, emitter); + log.error("Send message speed over limit."); + ServiceUtils.sendStreamResponseCompleted(message, StatusCode.EVENTMESH_SEND_MESSAGE_SPEED_OVER_LIMIT_ERR, emitter); return; } - String seqNum = message.getSeqNum(); - String uniqueId = message.getUniqueId(); - String producerGroup = message.getProducerGroup(); + String seqNum = EventMeshCloudEventUtils.getSeqNum(message); + String uniqueId = EventMeshCloudEventUtils.getUniqueId(message); + String producerGroup = EventMeshCloudEventUtils.getProducerGroup(message); - // set reply topic for ths message - String mqCluster = message.getPropertiesOrDefault(EventMeshConstants.PROPERTY_MESSAGE_CLUSTER, "defaultCluster"); + // set reply topic for this message + String mqCluster = EventMeshCloudEventUtils.getCluster(message, "defaultCluster"); String replyTopic = mqCluster + "-" + EventMeshConstants.RR_REPLY_TOPIC; - message = SimpleMessage.newBuilder(message).setTopic(replyTopic).build(); + final CloudEvent messageReply = CloudEvent.newBuilder(message) + .putAttributes(ProtocolKey.SUBJECT, CloudEventAttributeValue.newBuilder().setCeString(replyTopic).build()).build(); - String protocolType = requestHeader.getProtocolType(); + String protocolType = EventMeshCloudEventUtils.getProtocolType(messageReply); ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - CloudEvent cloudEvent = grpcCommandProtocolAdaptor.toCloudEvent(new SimpleMessageWrapper(message)); + io.cloudevents.CloudEvent cloudEvent = grpcCommandProtocolAdaptor.toCloudEvent(new EventMeshCloudEventWrapper(messageReply)); ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); - SendMessageContext sendMessageContext = new SendMessageContext(message.getSeqNum(), cloudEvent, eventMeshProducer, eventMeshGrpcServer); + SendMessageContext sendMessageContext = new SendMessageContext(seqNum, cloudEvent, eventMeshProducer, eventMeshGrpcServer); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordSendMsgToQueue(); long startTime = System.currentTimeMillis(); eventMeshProducer.reply(sendMessageContext, new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { long endTime = System.currentTimeMillis(); - logger.info("message|mq2eventmesh|REPLY|ReplyToServer|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + log.info("message|mq2eventmesh|REPLY|ReplyToServer|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, replyTopic, seqNum, uniqueId); } @Override public void onException(OnExceptionContext onExceptionContext) { - ServiceUtils.sendStreamRespAndDone(requestHeader, StatusCode.EVENTMESH_REPLY_MSG_ERR, + ServiceUtils.sendStreamResponseCompleted(messageReply, StatusCode.EVENTMESH_REPLY_MSG_ERR, EventMeshUtil.stackTrace(onExceptionContext.getException(), 2), emitter); long endTime = System.currentTimeMillis(); - logger.error("message|mq2eventmesh|REPLY|ReplyToServer|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + log.error("message|mq2eventmesh|REPLY|ReplyToServer|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, replyTopic, seqNum, uniqueId, onExceptionContext.getException()); } }); } - private void doAclCheck(SimpleMessage message) throws AclException { - RequestHeader requestHeader = message.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = requestHeader.getIp(); - String user = requestHeader.getUsername(); - String pass = requestHeader.getPassword(); - String subsystem = requestHeader.getSys(); - String topic = message.getTopic(); - Acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.REPLY_MESSAGE.getRequestCode()); + private void doAclCheck(CloudEvent message) throws AclException { + + if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAdd = EventMeshCloudEventUtils.getIp(message); + String user = EventMeshCloudEventUtils.getUserName(message); + String pass = EventMeshCloudEventUtils.getPassword(message); + String subsystem = EventMeshCloudEventUtils.getSys(message); + String topic = EventMeshCloudEventUtils.getSubject(message); + this.acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.REPLY_MESSAGE.getRequestCode()); } } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/RequestCloudEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/RequestCloudEventProcessor.java new file mode 100644 index 0000000000..1a6398b93d --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/RequestCloudEventProcessor.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.processor; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.protocol.api.ProtocolAdaptor; +import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; +import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.util.EventMeshUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RequestCloudEventProcessor extends AbstractPublishCloudEventProcessor { + + public RequestCloudEventProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { + super(eventMeshGrpcServer, eventMeshGrpcServer.getAcl()); + } + + @Override + public void handleCloudEvent(CloudEvent message, EventEmitter emitter) throws Exception { + + String protocolType = EventMeshCloudEventUtils.getProtocolType(message); + ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + io.cloudevents.CloudEvent cloudEvent = grpcCommandProtocolAdaptor.toCloudEvent(new EventMeshCloudEventWrapper(message)); + + String seqNum = EventMeshCloudEventUtils.getSeqNum(message); + String uniqueId = EventMeshCloudEventUtils.getUniqueId(message); + String topic = EventMeshCloudEventUtils.getSubject(message); + String producerGroup = EventMeshCloudEventUtils.getProducerGroup(message); + int ttl = Integer.parseInt(EventMeshCloudEventUtils.getTtl(message)); + + ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); + EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); + + SendMessageContext sendMessageContext = new SendMessageContext(seqNum, cloudEvent, eventMeshProducer, eventMeshGrpcServer); + + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordSendMsgToQueue(); + long startTime = System.currentTimeMillis(); + eventMeshProducer.request(sendMessageContext, new RequestReplyCallback() { + + @Override + public void onSuccess(io.cloudevents.CloudEvent event) { + try { + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromQueue(); + EventMeshCloudEventWrapper wrapper = (EventMeshCloudEventWrapper) grpcCommandProtocolAdaptor.fromCloudEvent(event); + + emitter.onNext(wrapper.getMessage()); + emitter.onCompleted(); + + long endTime = System.currentTimeMillis(); + log.info("message|eventmesh2client|REPLY|RequestReply|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordSendMsgToClient(EventMeshCloudEventUtils.getIp(wrapper.getMessage())); + } catch (Exception e) { + ServiceUtils.sendStreamResponseCompleted(message, StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR, EventMeshUtil.stackTrace(e, 2), + emitter); + long endTime = System.currentTimeMillis(); + log.error("message|mq2eventmesh|REPLY|RequestReply|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId, e); + } + } + + @Override + public void onException(Throwable e) { + ServiceUtils.sendStreamResponseCompleted(message, StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR, EventMeshUtil.stackTrace(e, 2), + emitter); + long endTime = System.currentTimeMillis(); + log.error("message|eventMesh2mq|REPLY|RequestReply|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, topic, seqNum, uniqueId, e); + } + }, ttl); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/RequestMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/RequestMessageProcessor.java deleted file mode 100644 index 5935e2ab9d..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/RequestMessageProcessor.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.processor; - -import org.apache.eventmesh.api.RequestReplyCallback; -import org.apache.eventmesh.api.exception.AclException; -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.protocol.api.ProtocolAdaptor; -import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.ProducerManager; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.SendMessageContext; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; -import org.apache.eventmesh.runtime.util.EventMeshUtil; - -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class RequestMessageProcessor { - - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - private final Logger aclLogger = LoggerFactory.getLogger("acl"); - - private final EventMeshGrpcServer eventMeshGrpcServer; - - public RequestMessageProcessor(EventMeshGrpcServer eventMeshGrpcServer) { - this.eventMeshGrpcServer = eventMeshGrpcServer; - } - - public void process(SimpleMessage message, EventEmitter emitter) throws Exception { - RequestHeader requestHeader = message.getHeader(); - - if (!ServiceUtils.validateHeader(requestHeader)) { - ServiceUtils.sendStreamRespAndDone(message.getHeader(), StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); - return; - } - - if (!ServiceUtils.validateMessage(message)) { - ServiceUtils.sendStreamRespAndDone(message.getHeader(), StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); - return; - } - - String seqNum = message.getSeqNum(); - String uniqueId = message.getUniqueId(); - String topic = message.getTopic(); - String producerGroup = message.getProducerGroup(); - - int ttl = Integer.parseInt(message.getTtl()); - try { - doAclCheck(message); - } catch (Exception e) { - aclLogger.warn("CLIENT HAS NO PERMISSION,RequestReplyMessageProcessor send failed", e); - ServiceUtils.sendStreamRespAndDone(message.getHeader(), StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); - return; - } - - // control flow rate limit - if (!eventMeshGrpcServer.getMsgRateLimiter() - .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - logger.error("Send message speed over limit."); - ServiceUtils.sendStreamRespAndDone(message.getHeader(), StatusCode.EVENTMESH_SEND_MESSAGE_SPEED_OVER_LIMIT_ERR, emitter); - return; - } - - String protocolType = requestHeader.getProtocolType(); - ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - CloudEvent cloudEvent = grpcCommandProtocolAdaptor.toCloudEvent(new SimpleMessageWrapper(message)); - - ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); - EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); - - SendMessageContext sendMessageContext = new SendMessageContext(message.getSeqNum(), cloudEvent, eventMeshProducer, eventMeshGrpcServer); - - long startTime = System.currentTimeMillis(); - eventMeshProducer.request(sendMessageContext, new RequestReplyCallback() { - @Override - public void onSuccess(CloudEvent event) { - try { - SimpleMessageWrapper wrapper = (SimpleMessageWrapper) grpcCommandProtocolAdaptor.fromCloudEvent(event); - - emitter.onNext(wrapper.getMessage()); - emitter.onCompleted(); - - long endTime = System.currentTimeMillis(); - logger.info("message|eventmesh2client|REPLY|RequestReply|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId); - } catch (Exception e) { - ServiceUtils.sendStreamRespAndDone(message.getHeader(), StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR, - EventMeshUtil.stackTrace(e, 2), emitter); - - long endTime = System.currentTimeMillis(); - logger.error("message|mq2eventmesh|REPLY|RequestReply|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId, e); - } - } - - @Override - public void onException(Throwable e) { - ServiceUtils.sendStreamRespAndDone(message.getHeader(), StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR, - EventMeshUtil.stackTrace(e, 2), emitter); - long endTime = System.currentTimeMillis(); - logger.error("message|eventMesh2mq|REPLY|RequestReply|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId, e); - } - }, ttl); - } - - private void doAclCheck(SimpleMessage message) throws AclException { - RequestHeader requestHeader = message.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = requestHeader.getIp(); - String user = requestHeader.getUsername(); - String pass = requestHeader.getPassword(); - String subsystem = requestHeader.getSys(); - String topic = message.getTopic(); - Acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.MSG_SEND_ASYNC.getRequestCode()); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SendAsyncMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SendAsyncMessageProcessor.java deleted file mode 100644 index 9558a37d84..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SendAsyncMessageProcessor.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.processor; - -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.AclException; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.protocol.api.ProtocolAdaptor; -import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.ProducerManager; -import org.apache.eventmesh.runtime.core.protocol.grpc.producer.SendMessageContext; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; -import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; -import org.apache.eventmesh.runtime.util.EventMeshUtil; - -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class SendAsyncMessageProcessor { - - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - private final Logger aclLogger = LoggerFactory.getLogger("acl"); - - private final EventMeshGrpcServer eventMeshGrpcServer; - - public SendAsyncMessageProcessor(EventMeshGrpcServer eventMeshGrpcServer) { - this.eventMeshGrpcServer = eventMeshGrpcServer; - } - - public void process(SimpleMessage message, EventEmitter emitter) throws Exception { - RequestHeader requestHeader = message.getHeader(); - - if (!ServiceUtils.validateHeader(requestHeader)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); - return; - } - - if (!ServiceUtils.validateMessage(message)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); - return; - } - - String seqNum = message.getSeqNum(); - String uniqueId = message.getUniqueId(); - String topic = message.getTopic(); - String producerGroup = message.getProducerGroup(); - - try { - doAclCheck(message); - } catch (Exception e) { - aclLogger.warn("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); - return; - } - - // control flow rate limit - if (!eventMeshGrpcServer.getMsgRateLimiter() - .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - logger.error("Send message speed over limit."); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR, emitter); - return; - } - - String protocolType = requestHeader.getProtocolType(); - ProtocolAdaptor grpcCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - CloudEvent cloudEvent = grpcCommandProtocolAdaptor.toCloudEvent(new SimpleMessageWrapper(message)); - - ProducerManager producerManager = eventMeshGrpcServer.getProducerManager(); - EventMeshProducer eventMeshProducer = producerManager.getEventMeshProducer(producerGroup); - - SendMessageContext sendMessageContext = new SendMessageContext(message.getSeqNum(), cloudEvent, eventMeshProducer, eventMeshGrpcServer); - - long startTime = System.currentTimeMillis(); - eventMeshProducer.send(sendMessageContext, new SendCallback() { - @Override - public void onSuccess(SendResult sendResult) { - ServiceUtils.sendRespAndDone(StatusCode.SUCCESS, sendResult.toString(), emitter); - long endTime = System.currentTimeMillis(); - logger.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId); - } - - @Override - public void onException(OnExceptionContext context) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR, - EventMeshUtil.stackTrace(context.getException(), 2), emitter); - long endTime = System.currentTimeMillis(); - logger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, seqNum, uniqueId, context.getException()); - } - }); - } - - private void doAclCheck(SimpleMessage message) throws AclException { - RequestHeader requestHeader = message.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = requestHeader.getIp(); - String user = requestHeader.getUsername(); - String pass = requestHeader.getPassword(); - String subsystem = requestHeader.getSys(); - String topic = message.getTopic(); - Acl.doAclCheckInHttpSend(remoteAdd, user, pass, subsystem, topic, RequestCode.MSG_SEND_ASYNC.getRequestCode()); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeProcessor.java index 7e60cb59a6..613e4b847a 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeProcessor.java @@ -18,77 +18,88 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.processor; import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.ConsumerManager; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.EventMeshConsumer; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupClient; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.type.TypeReference; -public class SubscribeProcessor { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); +@Slf4j +public class SubscribeProcessor { - private final Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final GrpcType grpcType = GrpcType.WEBHOOK; private final EventMeshGrpcServer eventMeshGrpcServer; - private final GrpcType grpcType = GrpcType.WEBHOOK; + private final Acl acl; - public SubscribeProcessor(EventMeshGrpcServer eventMeshGrpcServer) { + public SubscribeProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { this.eventMeshGrpcServer = eventMeshGrpcServer; + this.acl = eventMeshGrpcServer.getAcl(); } - public void process(Subscription subscription, EventEmitter emitter) throws Exception { - RequestHeader header = subscription.getHeader(); + public void process(final CloudEvent subscription, final EventEmitter emitter) throws Exception { + Objects.requireNonNull(subscription, "subscription can not be null"); + Objects.requireNonNull(emitter, "emitter can not be null"); - if (!ServiceUtils.validateHeader(header)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); + if (!ServiceUtils.validateCloudEventAttributes(subscription)) { + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); return; } if (!ServiceUtils.validateSubscription(grpcType, subscription)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); return; } - try { doAclCheck(subscription); } catch (AclException e) { - aclLogger.warn("CLIENT HAS NO PERMISSION to Subscribe. failed", e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); + log.warn("CLIENT HAS NO PERMISSION to Subscribe. failed", e); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); return; } - ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); - - String consumerGroup = subscription.getConsumerGroup(); - String url = subscription.getUrl(); - List subscriptionItems = subscription.getSubscriptionItemsList(); + final ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); + final String consumerGroup = EventMeshCloudEventUtils.getConsumerGroup(subscription); // Collect new clients in the subscription - List newClients = new LinkedList<>(); - for (Subscription.SubscriptionItem item : subscriptionItems) { - ConsumerGroupClient newClient = ConsumerGroupClient.builder() - .env(header.getEnv()) - .idc(header.getIdc()) - .sys(header.getSys()) - .ip(header.getIp()) - .pid(header.getPid()) + List subscriptionItems = JsonUtils.parseTypeReferenceObject(subscription.getTextData(), + new TypeReference>() { + }); + + Objects.requireNonNull(subscriptionItems, "subscriptionItems must not be null"); + final String env = EventMeshCloudEventUtils.getEnv(subscription); + final String idc = EventMeshCloudEventUtils.getIdc(subscription); + final String sys = EventMeshCloudEventUtils.getSys(subscription); + final String ip = EventMeshCloudEventUtils.getIp(subscription); + final String pid = EventMeshCloudEventUtils.getPid(subscription); + final String url = EventMeshCloudEventUtils.getURL(subscription); + final List newClients = new LinkedList<>(); + for (final SubscriptionItem item : subscriptionItems) { + final ConsumerGroupClient newClient = ConsumerGroupClient.builder() + .env(env) + .idc(idc) + .sys(sys) + .ip(ip) + .pid(pid) .consumerGroup(consumerGroup) .topic(item.getTopic()) .grpcType(grpcType) @@ -100,15 +111,13 @@ public void process(Subscription subscription, EventEmitter emitter) t } // register new clients into ConsumerManager - for (ConsumerGroupClient newClient : newClients) { - consumerManager.registerClient(newClient); - } + newClients.forEach(consumerManager::registerClient); // register new clients into EventMeshConsumer - EventMeshConsumer eventMeshConsumer = consumerManager.getEventMeshConsumer(consumerGroup); + final EventMeshConsumer eventMeshConsumer = consumerManager.getEventMeshConsumer(consumerGroup); boolean requireRestart = false; - for (ConsumerGroupClient newClient : newClients) { + for (final ConsumerGroupClient newClient : newClients) { if (eventMeshConsumer.registerClient(newClient)) { requireRestart = true; } @@ -116,26 +125,25 @@ public void process(Subscription subscription, EventEmitter emitter) t // restart consumer group if required if (requireRestart) { - logger.info("ConsumerGroup {} topic info changed, restart EventMesh Consumer", consumerGroup); + log.info("ConsumerGroup {} topic info changed, restart EventMesh Consumer", consumerGroup); consumerManager.restartEventMeshConsumer(consumerGroup); } else { - logger.warn("EventMesh consumer [{}] didn't restart.", consumerGroup); + log.warn("EventMesh consumer [{}] didn't restart.", consumerGroup); } - - ServiceUtils.sendRespAndDone(StatusCode.SUCCESS, "subscribe success", emitter); + ServiceUtils.sendResponseCompleted(StatusCode.SUCCESS, "subscribe success", emitter); } - private void doAclCheck(Subscription subscription) throws AclException { - RequestHeader header = subscription.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = header.getIp(); - String user = header.getUsername(); - String pass = header.getPassword(); - String subsystem = header.getSys(); - for (Subscription.SubscriptionItem item : subscription.getSubscriptionItemsList()) { - Acl.doAclCheckInHttpReceive(remoteAdd, user, pass, subsystem, item.getTopic(), - RequestCode.SUBSCRIBE.getRequestCode()); + private void doAclCheck(final CloudEvent subscription) throws AclException { + List subscriptionItems = JsonUtils.parseTypeReferenceObject(subscription.getTextData(), + new TypeReference>() { + }); + Objects.requireNonNull(subscriptionItems, "subscriptionItems must not be null"); + if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().isEventMeshServerSecurityEnable()) { + for (final SubscriptionItem item : subscriptionItems) { + this.acl.doAclCheckInHttpReceive(EventMeshCloudEventUtils.getConsumerGroup(subscription), + EventMeshCloudEventUtils.getUserName(subscription), EventMeshCloudEventUtils.getPassword(subscription), + EventMeshCloudEventUtils.getSys(subscription), item.getTopic(), RequestCode.SUBSCRIBE.getRequestCode()); } } } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeStreamProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeStreamProcessor.java index d742034126..2cef63b47e 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeStreamProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/SubscribeStreamProcessor.java @@ -18,77 +18,92 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.processor; import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.ConsumerManager; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.EventMeshConsumer; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupClient; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; import org.apache.eventmesh.runtime.core.protocol.grpc.service.ServiceUtils; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class SubscribeStreamProcessor { +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); +@Slf4j +public class SubscribeStreamProcessor { - private final Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger ACL_LOGGER = LoggerFactory.getLogger(EventMeshConstants.ACL); private final EventMeshGrpcServer eventMeshGrpcServer; - private final GrpcType grpcType = GrpcType.STREAM; + private static final GrpcType grpcType = GrpcType.STREAM; - public SubscribeStreamProcessor(EventMeshGrpcServer eventMeshGrpcServer) { + private final Acl acl; + + public SubscribeStreamProcessor(final EventMeshGrpcServer eventMeshGrpcServer) { this.eventMeshGrpcServer = eventMeshGrpcServer; - } + this.acl = eventMeshGrpcServer.getAcl(); - public void process(Subscription subscription, EventEmitter emitter) throws Exception { + } - RequestHeader header = subscription.getHeader(); + public void process(CloudEvent subscription, EventEmitter emitter) throws Exception { - if (!ServiceUtils.validateHeader(header)) { - ServiceUtils.sendStreamRespAndDone(header, StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); + if (!ServiceUtils.validateCloudEventAttributes(subscription)) { + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); return; } if (!ServiceUtils.validateSubscription(grpcType, subscription)) { - ServiceUtils.sendStreamRespAndDone(header, StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); return; } try { doAclCheck(subscription); } catch (AclException e) { - aclLogger.warn("CLIENT HAS NO PERMISSION to Subscribe. failed", e); - ServiceUtils.sendStreamRespAndDone(header, StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); + ACL_LOGGER.warn("CLIENT HAS NO PERMISSION to Subscribe. failed", e); + ServiceUtils.sendStreamResponseCompleted(subscription, StatusCode.EVENTMESH_ACL_ERR, e.getMessage(), emitter); return; } ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); - String consumerGroup = subscription.getConsumerGroup(); - List subscriptionItems = subscription.getSubscriptionItemsList(); + String consumerGroup = EventMeshCloudEventUtils.getConsumerGroup(subscription); // Collect new clients in subscription + final String env = EventMeshCloudEventUtils.getEnv(subscription); + final String idc = EventMeshCloudEventUtils.getIdc(subscription); + final String sys = EventMeshCloudEventUtils.getSys(subscription); + final String ip = EventMeshCloudEventUtils.getIp(subscription); + final String pid = EventMeshCloudEventUtils.getPid(subscription); List newClients = new LinkedList<>(); - for (Subscription.SubscriptionItem item : subscriptionItems) { + List subscriptionItems = JsonUtils.parseTypeReferenceObject(subscription.getTextData(), + new TypeReference>() { + }); + for (SubscriptionItem item : Objects.requireNonNull(subscriptionItems)) { ConsumerGroupClient newClient = ConsumerGroupClient.builder() - .env(header.getEnv()) - .idc(header.getIdc()) - .sys(header.getSys()) - .ip(header.getIp()) - .pid(header.getPid()) + .env(env) + .idc(idc) + .sys(sys) + .ip(ip) + .pid(pid) .consumerGroup(consumerGroup) .topic(item.getTopic()) .subscriptionMode(item.getMode()) @@ -116,26 +131,28 @@ public void process(Subscription subscription, EventEmitter emitt // restart consumer group if required if (requireRestart) { - logger.info("ConsumerGroup {} topic info changed, restart EventMesh Consumer", consumerGroup); + log.info("ConsumerGroup {} topic info changed, restart EventMesh Consumer", consumerGroup); consumerManager.restartEventMeshConsumer(consumerGroup); } else { - logger.warn("EventMesh consumer [{}] didn't restart.", consumerGroup); + log.warn("EventMesh consumer [{}] didn't restart.", consumerGroup); } - ServiceUtils.sendStreamResp(header, StatusCode.SUCCESS, "subscribe success", emitter); + ServiceUtils.sendStreamResponse(subscription, StatusCode.SUCCESS, "subscribe success", emitter); } - private void doAclCheck(Subscription subscription) throws AclException { - RequestHeader header = subscription.getHeader(); - if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshServerSecurityEnable) { - String remoteAdd = header.getIp(); - String user = header.getUsername(); - String pass = header.getPassword(); - String subsystem = header.getSys(); - for (Subscription.SubscriptionItem item : subscription.getSubscriptionItemsList()) { - Acl.doAclCheckInHttpReceive(remoteAdd, user, pass, subsystem, item.getTopic(), - RequestCode.SUBSCRIBE.getRequestCode()); + private void doAclCheck(CloudEvent subscription) throws AclException { + + if (eventMeshGrpcServer.getEventMeshGrpcConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAdd = EventMeshCloudEventUtils.getIp(subscription); + String user = EventMeshCloudEventUtils.getUserName(subscription); + String pass = EventMeshCloudEventUtils.getPassword(subscription); + String subsystem = EventMeshCloudEventUtils.getSys(subscription); + List subscriptionItems = JsonUtils.parseTypeReferenceObject(subscription.getTextData(), + new TypeReference>() { + }); + for (SubscriptionItem item : Objects.requireNonNull(subscriptionItems)) { + this.acl.doAclCheckInHttpReceive(remoteAdd, user, pass, subsystem, item.getTopic(), RequestCode.SUBSCRIBE.getRequestCode()); } } } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/UnsubscribeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/UnsubscribeProcessor.java index e9276d516e..708e3cfee4 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/UnsubscribeProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/processor/UnsubscribeProcessor.java @@ -17,10 +17,11 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.processor; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.ConsumerManager; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.EventMeshConsumer; @@ -32,12 +33,12 @@ import java.util.LinkedList; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.type.TypeReference; -public class UnsubscribeProcessor { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); +@Slf4j +public class UnsubscribeProcessor { private final EventMeshGrpcServer eventMeshGrpcServer; @@ -45,35 +46,39 @@ public UnsubscribeProcessor(EventMeshGrpcServer eventMeshGrpcServer) { this.eventMeshGrpcServer = eventMeshGrpcServer; } - public void process(Subscription subscription, EventEmitter emitter) throws Exception { + public void process(CloudEvent subscription, EventEmitter emitter) throws Exception { - RequestHeader header = subscription.getHeader(); - - if (!ServiceUtils.validateHeader(header)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); + if (!ServiceUtils.validateCloudEventAttributes(subscription)) { + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_HEADER_ERR, emitter); return; } if (!ServiceUtils.validateSubscription(null, subscription)) { - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_PROTOCOL_BODY_ERR, emitter); return; } ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager(); - String consumerGroup = subscription.getConsumerGroup(); - String url = subscription.getUrl(); - List subscriptionItems = subscription.getSubscriptionItemsList(); - + String consumerGroup = EventMeshCloudEventUtils.getConsumerGroup(subscription); + String url = EventMeshCloudEventUtils.getURL(subscription); + List subscriptionItems = JsonUtils.parseTypeReferenceObject(subscription.getTextData(), + new TypeReference>() { + }); + final String env = EventMeshCloudEventUtils.getEnv(subscription); + final String idc = EventMeshCloudEventUtils.getIdc(subscription); + final String sys = EventMeshCloudEventUtils.getSys(subscription); + final String ip = EventMeshCloudEventUtils.getIp(subscription); + final String pid = EventMeshCloudEventUtils.getPid(subscription); // Collect clients to remove in the unsubscribe List removeClients = new LinkedList<>(); - for (Subscription.SubscriptionItem item : subscriptionItems) { + for (SubscriptionItem item : subscriptionItems) { ConsumerGroupClient newClient = ConsumerGroupClient.builder() - .env(header.getEnv()) - .idc(header.getIdc()) - .sys(header.getSys()) - .ip(header.getIp()) - .pid(header.getPid()) + .env(env) + .idc(idc) + .sys(sys) + .ip(ip) + .pid(pid) .consumerGroup(consumerGroup) .topic(item.getTopic()) .subscriptionMode(item.getMode()) @@ -100,12 +105,12 @@ public void process(Subscription subscription, EventEmitter emitter) t // restart consumer group if required if (requireRestart) { - logger.info("ConsumerGroup {} topic info changed, restart EventMesh Consumer", consumerGroup); + log.info("ConsumerGroup {} topic info changed, restart EventMesh Consumer", consumerGroup); consumerManager.restartEventMeshConsumer(consumerGroup); } else { - logger.warn("EventMesh consumer [{}] didn't restart.", consumerGroup); + log.warn("EventMesh consumer [{}] didn't restart.", consumerGroup); } - ServiceUtils.sendRespAndDone(StatusCode.SUCCESS, "unsubscribe success", emitter); + ServiceUtils.sendResponseCompleted(StatusCode.SUCCESS, "unsubscribe success", emitter); } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/EventMeshProducer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/EventMeshProducer.java deleted file mode 100644 index 345576c865..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/EventMeshProducer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.producer; - -import org.apache.eventmesh.api.RequestReplyCallback; -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.runtime.common.ServiceState; -import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; -import org.apache.eventmesh.runtime.core.consumergroup.ProducerGroupConf; -import org.apache.eventmesh.runtime.core.plugin.MQProducerWrapper; -import org.apache.eventmesh.runtime.util.EventMeshUtil; - -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventMeshProducer { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private ProducerGroupConf producerGroupConfig; - - private MQProducerWrapper mqProducerWrapper; - - private ServiceState serviceState; - - public void send(SendMessageContext sendMsgContext, SendCallback sendCallback) - throws Exception { - mqProducerWrapper.send(sendMsgContext.getEvent(), sendCallback); - } - - public void request(SendMessageContext sendMsgContext, RequestReplyCallback rrCallback, long timeout) - throws Exception { - mqProducerWrapper.request(sendMsgContext.getEvent(), rrCallback, timeout); - } - - public void reply(SendMessageContext sendMessageContext, SendCallback sendCallback) throws Exception { - mqProducerWrapper.reply(sendMessageContext.getEvent(), sendCallback); - } - - public synchronized void init(EventMeshGrpcConfiguration eventMeshGrpcConfiguration, - ProducerGroupConf producerGroupConfig) throws Exception { - this.producerGroupConfig = producerGroupConfig; - - Properties keyValue = new Properties(); - keyValue.put("producerGroup", producerGroupConfig.getGroupName()); - keyValue.put("instanceName", EventMeshUtil.buildMeshClientID( - producerGroupConfig.getGroupName(), eventMeshGrpcConfiguration.eventMeshCluster)); - - //TODO for defibus - keyValue.put("eventMeshIDC", eventMeshGrpcConfiguration.eventMeshIDC); - mqProducerWrapper = new MQProducerWrapper( - eventMeshGrpcConfiguration.eventMeshConnectorPluginType); - mqProducerWrapper.init(keyValue); - serviceState = ServiceState.INITED; - logger.info("EventMeshProducer [{}] inited...........", producerGroupConfig.getGroupName()); - } - - public synchronized void start() throws Exception { - if (serviceState == null || ServiceState.RUNNING.equals(serviceState)) { - return; - } - - mqProducerWrapper.start(); - serviceState = ServiceState.RUNNING; - logger.info("EventMeshProducer [{}] started..........", producerGroupConfig.getGroupName()); - } - - public synchronized void shutdown() throws Exception { - if (serviceState == null || ServiceState.INITED.equals(serviceState)) { - return; - } - - mqProducerWrapper.shutdown(); - serviceState = ServiceState.STOPED; - logger.info("EventMeshProducer [{}] shutdown.........", producerGroupConfig.getGroupName()); - } - - public ServiceState getStatus() { - return this.serviceState; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("eventMeshProducer={").append("status=").append(serviceState.name()).append(",").append("producerGroupConfig=") - .append(producerGroupConfig).append("}"); - return sb.toString(); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/ProducerManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/ProducerManager.java deleted file mode 100644 index 3bb566f38e..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/ProducerManager.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.producer; - -import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; -import org.apache.eventmesh.runtime.common.ServiceState; -import org.apache.eventmesh.runtime.core.consumergroup.ProducerGroupConf; - -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ProducerManager { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private EventMeshGrpcServer eventMeshGrpcServer; - - private ConcurrentHashMap producerTable = new ConcurrentHashMap<>(); - - public ProducerManager(EventMeshGrpcServer eventMeshGrpcServer) { - this.eventMeshGrpcServer = eventMeshGrpcServer; - } - - public void init() throws Exception { - logger.info("Grpc ProducerManager inited......"); - } - - public void start() throws Exception { - logger.info("Grpc ProducerManager started......"); - } - - public EventMeshProducer getEventMeshProducer(String producerGroup) throws Exception { - EventMeshProducer eventMeshProducer = null; - if (!producerTable.containsKey(producerGroup)) { - synchronized (producerTable) { - if (!producerTable.containsKey(producerGroup)) { - ProducerGroupConf producerGroupConfig = new ProducerGroupConf(producerGroup); - eventMeshProducer = createEventMeshProducer(producerGroupConfig); - eventMeshProducer.start(); - } - } - } - - eventMeshProducer = producerTable.get(producerGroup); - - if (!ServiceState.RUNNING.equals(eventMeshProducer.getStatus())) { - eventMeshProducer.start(); - } - - return eventMeshProducer; - } - - private synchronized EventMeshProducer createEventMeshProducer( - ProducerGroupConf producerGroupConfig) throws Exception { - if (producerTable.containsKey(producerGroupConfig.getGroupName())) { - return producerTable.get(producerGroupConfig.getGroupName()); - } - EventMeshProducer eventMeshProducer = new EventMeshProducer(); - eventMeshProducer.init(eventMeshGrpcServer.getEventMeshGrpcConfiguration(), - producerGroupConfig); - producerTable.put(producerGroupConfig.getGroupName(), eventMeshProducer); - return eventMeshProducer; - } - - public void shutdown() { - for (EventMeshProducer eventMeshProducer : producerTable.values()) { - try { - eventMeshProducer.shutdown(); - } catch (Exception ex) { - logger.error("shutdown eventMeshProducer[{}] err", eventMeshProducer, ex); - } - } - logger.info("producerManager shutdown......"); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/SendMessageContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/SendMessageContext.java deleted file mode 100644 index 33ce346a86..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/producer/SendMessageContext.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.producer; - -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; -import org.apache.eventmesh.runtime.core.protocol.grpc.retry.RetryContext; - -import org.apache.commons.lang3.time.DateFormatUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class SendMessageContext extends RetryContext { - - public static Logger logger = LoggerFactory.getLogger("retry"); - - private CloudEvent event; - - private String bizSeqNo; - - private EventMeshProducer eventMeshProducer; - - private long createTime = System.currentTimeMillis(); - - public EventMeshGrpcServer eventMeshGrpcServer; - - public SendMessageContext(String bizSeqNo, CloudEvent event, EventMeshProducer eventMeshProducer, - EventMeshGrpcServer eventMeshGrpcServer) { - this.bizSeqNo = bizSeqNo; - this.event = event; - this.eventMeshProducer = eventMeshProducer; - this.eventMeshGrpcServer = eventMeshGrpcServer; - } - - public String getBizSeqNo() { - return bizSeqNo; - } - - public void setBizSeqNo(String bizSeqNo) { - this.bizSeqNo = bizSeqNo; - } - - public CloudEvent getEvent() { - return event; - } - - public void setEvent(CloudEvent event) { - this.event = event; - } - - public EventMeshProducer getEventMeshProducer() { - return eventMeshProducer; - } - - public void setEventMeshProducer(EventMeshProducer eventMeshProducer) { - this.eventMeshProducer = eventMeshProducer; - } - - public long getCreateTime() { - return createTime; - } - - public void setCreateTime(long createTime) { - this.createTime = createTime; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageContext={") - .append("bizSeqNo=").append(bizSeqNo) - .append(",retryTimes=").append(retryTimes) - .append(",producer=") - .append(eventMeshProducer != null ? eventMeshProducer : null) - .append(",executeTime=") - .append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT)) - .append(",createTime=") - .append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); - return sb.toString(); - } - - @Override - public boolean retry() throws Exception { - if (eventMeshProducer == null) { - return false; - } - - if (retryTimes > 0) { //retry once - return false; - } - - retryTimes++; - eventMeshProducer.send(this, new SendCallback() { - - @Override - public void onSuccess(SendResult sendResult) { - } - - @Override - public void onException(OnExceptionContext context) { - logger.warn("", context.getException()); - } - }); - return true; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/AbstractPushRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/AbstractPushRequest.java index 389caa1401..54056c3a11 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/AbstractPushRequest.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/AbstractPushRequest.java @@ -20,35 +20,32 @@ import org.apache.eventmesh.api.AbstractContext; import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.grpc.common.SimpleMessageWrapper; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventWrapper; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.RetryContext; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.EventMeshConsumer; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupTopicConfig; import org.apache.eventmesh.runtime.core.protocol.grpc.retry.GrpcRetryer; -import org.apache.eventmesh.runtime.core.protocol.grpc.retry.RetryContext; import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - import com.google.common.collect.Sets; -public abstract class AbstractPushRequest extends RetryContext { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(ConsumerGroupTopicConfig.class); +@Slf4j +public abstract class AbstractPushRequest extends RetryContext { protected EventMeshGrpcServer eventMeshGrpcServer; protected long createTime = System.currentTimeMillis(); @@ -61,8 +58,8 @@ public abstract class AbstractPushRequest extends RetryContext { protected Map> waitingRequests; protected HandleMsgContext handleMsgContext; - // protected CloudEvent event; - protected SimpleMessage simpleMessage; + // protected CloudEvent event; + protected CloudEvent eventMeshCloudEvent; private final AtomicBoolean complete = new AtomicBoolean(Boolean.FALSE); @@ -74,46 +71,39 @@ public AbstractPushRequest(HandleMsgContext handleMsgContext, Map protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); ProtocolTransportObject protocolTransportObject = protocolAdaptor.fromCloudEvent(cloudEvent); - return ((SimpleMessageWrapper) protocolTransportObject).getMessage(); + return ((EventMeshCloudEventWrapper) protocolTransportObject).getMessage(); } catch (Exception e) { - logger.error("Error in getting EventMeshMessage from CloudEvent", e); + log.error("Error in getting EventMeshMessage from CloudEvent", e); return null; } } - private CloudEvent getCloudEvent(SimpleMessage simpleMessage) { + private io.cloudevents.CloudEvent getCloudEvent(CloudEvent cloudEvent) { try { - String protocolType = Objects.requireNonNull(simpleMessage.getHeader().getProtocolType()); + String protocolType = Objects.requireNonNull(EventMeshCloudEventUtils.getProtocolType(cloudEvent)); ProtocolAdaptor protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - return protocolAdaptor.toCloudEvent(new SimpleMessageWrapper(simpleMessage)); + return protocolAdaptor.toCloudEvent(new EventMeshCloudEventWrapper(cloudEvent)); } catch (Exception e) { - logger.error("Error in getting CloudEvent from EventMeshMessage", e); + log.error("Error in getting CloudEvent from EventMeshMessage", e); return null; } } - @Override - public boolean retry() { - tryPushRequest(); - return true; - } - protected void delayRetry() { if (retryTimes < EventMeshConstants.DEFAULT_PUSH_RETRY_TIMES) { retryTimes++; - delay((long) retryTimes * EventMeshConstants.DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS); - grpcRetryer.pushRetry(this); + grpcRetryer.newTimeout(this, EventMeshConstants.DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS, TimeUnit.MILLISECONDS); } else { complete(); } @@ -126,12 +116,12 @@ protected boolean isComplete() { private void finish() { AbstractContext context = handleMsgContext.getContext(); SubscriptionMode subscriptionMode = handleMsgContext.getSubscriptionMode(); - CloudEvent event = getCloudEvent(simpleMessage); + io.cloudevents.CloudEvent event = getCloudEvent(eventMeshCloudEvent); if (eventMeshConsumer != null && context != null && event != null) { try { eventMeshConsumer.updateOffset(subscriptionMode, Collections.singletonList(event), context); } catch (Exception e) { - logger.error("Error in updating offset in EventMeshConsumer", e); + log.error("Error in updating offset in EventMeshConsumer", e); } } } @@ -142,7 +132,7 @@ protected void complete() { } protected void timeout() { - if (!isComplete() && System.currentTimeMillis() - lastPushTime >= Long.parseLong(simpleMessage.getTtl())) { + if (!isComplete() && System.currentTimeMillis() - lastPushTime >= Long.parseLong(EventMeshCloudEventUtils.getTtl(eventMeshCloudEvent))) { delayRetry(); } } @@ -165,4 +155,9 @@ protected void removeWaitingMap(WebhookPushRequest request) { waitingRequests.get(handleMsgContext.getConsumerGroup()).remove(request); } } -} \ No newline at end of file + + @Override + public void doRun() throws Exception { + tryPushRequest(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/HandleMsgContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/HandleMsgContext.java index f8bc92470c..da666d9422 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/HandleMsgContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/HandleMsgContext.java @@ -18,16 +18,17 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.push; import org.apache.eventmesh.api.AbstractContext; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.EventMeshConsumer; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.ConsumerGroupTopicConfig; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; import org.apache.eventmesh.runtime.util.EventMeshUtil; import io.cloudevents.CloudEvent; public class HandleMsgContext { + private final String msgRandomNo; private final SubscriptionMode subscriptionMode; private final EventMeshGrpcServer eventMeshGrpcServer; @@ -41,8 +42,8 @@ public class HandleMsgContext { private final AbstractContext context; public HandleMsgContext(String consumerGroup, CloudEvent event, SubscriptionMode subscriptionMode, GrpcType grpcType, - AbstractContext context, EventMeshGrpcServer eventMeshGrpcServer, - EventMeshConsumer eventMeshConsumer, ConsumerGroupTopicConfig consumeTopicConfig) { + AbstractContext context, EventMeshGrpcServer eventMeshGrpcServer, + EventMeshConsumer eventMeshConsumer, ConsumerGroupTopicConfig consumeTopicConfig) { this.msgRandomNo = EventMeshUtil.buildPushMsgSeqNo(); this.consumerGroup = consumerGroup; this.grpcType = grpcType; @@ -90,7 +91,6 @@ public GrpcType getGrpcType() { return grpcType; } - @Override public String toString() { return "handleMsgContext={" diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/MessageHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/MessageHandler.java index 5c4a271d1b..15e3ae93df 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/MessageHandler.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/MessageHandler.java @@ -18,7 +18,7 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.push; import org.apache.eventmesh.common.ThreadPoolFactory; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; import org.apache.commons.collections4.MapUtils; @@ -29,15 +29,13 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.common.collect.Maps; import com.google.common.collect.Sets; -public class MessageHandler { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class MessageHandler { private static final ScheduledExecutorService SCHEDULER = ThreadPoolFactory.createSingleScheduledExecutor("eventMesh-pushMsgTimeout-"); @@ -66,14 +64,14 @@ public boolean handle(HandleMsgContext handleMsgContext) { Set waitingRequests4Group = MapUtils.getObject(waitingRequests, handleMsgContext.getConsumerGroup(), Sets.newConcurrentHashSet()); if (waitingRequests4Group.size() > CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD) { - logger.warn("waitingRequests is too many, so reject, this message will be send back to MQ, consumerGroup:{}, threshold:{}", + log.warn("waitingRequests is too many, so reject, this message will be send back to MQ, consumerGroup:{}, threshold:{}", handleMsgContext.getConsumerGroup(), CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD); return false; } try { pushExecutor.submit(() -> { - AbstractPushRequest pushRequest = createHttpPushRequest(handleMsgContext); + AbstractPushRequest pushRequest = createGrpcPushRequest(handleMsgContext); pushRequest.tryPushRequest(); }); return true; @@ -82,9 +80,9 @@ public boolean handle(HandleMsgContext handleMsgContext) { } } - private AbstractPushRequest createHttpPushRequest(HandleMsgContext handleMsgContext) { + private AbstractPushRequest createGrpcPushRequest(HandleMsgContext handleMsgContext) { GrpcType grpcType = handleMsgContext.getGrpcType(); - if (GrpcType.WEBHOOK.equals(grpcType)) { + if (GrpcType.WEBHOOK == grpcType) { return new WebhookPushRequest(handleMsgContext, waitingRequests); } else { return new StreamPushRequest(handleMsgContext, waitingRequests); diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/StreamPushRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/StreamPushRequest.java index 5a7989f7b5..e4c84bdf64 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/StreamPushRequest.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/StreamPushRequest.java @@ -17,8 +17,10 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.push; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.StreamTopicConfig; import org.apache.eventmesh.runtime.core.protocol.grpc.service.EventEmitter; @@ -32,18 +34,16 @@ import java.util.Map; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.grpc.stub.StreamObserver; -public class StreamPushRequest extends AbstractPushRequest { +import lombok.extern.slf4j.Slf4j; - private final Logger messageLogger = LoggerFactory.getLogger("message"); +@Slf4j +public class StreamPushRequest extends AbstractPushRequest { - private final Map>> idcEmitters; + private final Map>> idcEmitters; - private final List> totalEmitters; + private final List> totalEmitters; private final SubscriptionMode subscriptionMode; @@ -61,67 +61,66 @@ public StreamPushRequest(HandleMsgContext handleMsgContext, Map> eventEmitters = selectEmitter(); + List> eventEmitters = selectEmitter(); - for (EventEmitter eventEmitter : eventEmitters) { + for (EventEmitter eventEmitter : eventEmitters) { this.lastPushTime = System.currentTimeMillis(); - simpleMessage = SimpleMessage.newBuilder(simpleMessage) - .putProperties(EventMeshConstants.REQ_EVENTMESH2C_TIMESTAMP, String.valueOf(lastPushTime)) + eventMeshCloudEvent = CloudEvent.newBuilder(eventMeshCloudEvent) + .putAttributes(EventMeshConstants.REQ_EVENTMESH2C_TIMESTAMP, + CloudEventAttributeValue.newBuilder().setCeString(String.valueOf(lastPushTime)).build()) .build(); try { // catch the error and retry, don't use eventEmitter.onNext() to hide the error - StreamObserver emitter = eventEmitter.getEmitter(); + StreamObserver emitter = eventEmitter.getEmitter(); synchronized (emitter) { - emitter.onNext(simpleMessage); + emitter.onNext(eventMeshCloudEvent); } long cost = System.currentTimeMillis() - lastPushTime; - messageLogger.info( - "message|eventMesh2client|emitter|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", simpleMessage.getTopic(), - simpleMessage.getSeqNum(), simpleMessage.getUniqueId(), cost); + log.info("message|eventMesh2client|emitter|topic={}|bizSeqNo={}" + "|uniqueId={}|cost={}", + EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent), EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), + EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent), cost); complete(); } catch (Throwable t) { long cost = System.currentTimeMillis() - lastPushTime; - messageLogger.error( - "message|eventMesh2client|exception={} |emitter|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", t.getMessage(), simpleMessage.getTopic(), - simpleMessage.getSeqNum(), simpleMessage.getUniqueId(), cost, t); + log.error("message|eventMesh2client|exception={} |emitter|topic={}|bizSeqNo={}" + "|uniqueId={}|cost={}", + t.getMessage(), EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent), EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), + EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent), cost, t); delayRetry(); } } } - private List> selectEmitter() { - List> emitterList = MapUtils.getObject(idcEmitters, - eventMeshGrpcConfiguration.eventMeshIDC, null); + private List> selectEmitter() { + List> emitterList = MapUtils.getObject(idcEmitters, + eventMeshGrpcConfiguration.getEventMeshIDC(), null); if (CollectionUtils.isNotEmpty(emitterList)) { - if (subscriptionMode.equals(SubscriptionMode.CLUSTERING)) { - return Collections.singletonList(emitterList.get((startIdx + retryTimes) % emitterList.size())); - } else if (subscriptionMode.equals(SubscriptionMode.BROADCASTING)) { - return emitterList; - } else { - messageLogger.error("Invalid Subscription Mode, no message returning back to subscriber."); - return Collections.emptyList(); - } + return getEventEmitters(emitterList); } + if (CollectionUtils.isNotEmpty(totalEmitters)) { - if (subscriptionMode.equals(SubscriptionMode.CLUSTERING)) { - return Collections.singletonList(totalEmitters.get((startIdx + retryTimes) % totalEmitters.size())); - } else if (subscriptionMode.equals(SubscriptionMode.BROADCASTING)) { - return totalEmitters; - } else { - messageLogger.error("Invalid Subscription Mode, no message returning back to subscriber."); - return Collections.emptyList(); - } + return getEventEmitters(totalEmitters); } - messageLogger.error("No event emitters from subscriber, no message returning."); + + log.error("No event emitters from subscriber, no message returning."); return Collections.emptyList(); } + + private List> getEventEmitters(List> emitterList) { + switch (subscriptionMode) { + case CLUSTERING: + return Collections.singletonList(emitterList.get((startIdx + retryTimes) % emitterList.size())); + case BROADCASTING: + return emitterList; + default: + log.error("Invalid Subscription Mode, no message returning back to subscriber."); + return Collections.emptyList(); + } + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/WebhookPushRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/WebhookPushRequest.java index f5d6bcf0bf..b170257c9e 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/WebhookPushRequest.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/push/WebhookPushRequest.java @@ -18,9 +18,10 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.push; import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription.SubscriptionItem.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; import org.apache.eventmesh.common.protocol.http.body.message.PushMessageRequestBody; import org.apache.eventmesh.common.protocol.http.common.ClientRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; @@ -51,6 +52,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.slf4j.Logger; @@ -60,13 +62,12 @@ public class WebhookPushRequest extends AbstractPushRequest { - private final Logger messageLogger = LoggerFactory.getLogger("message"); + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - private final Logger cmdLogger = LoggerFactory.getLogger("cmd"); + private static final Logger CMD_LOGGER = LoggerFactory.getLogger(EventMeshConstants.CMD); /** - * Key: idc - * Value: list of URLs + * Key: idc Value: list of URLs **/ private final Map> urls; @@ -77,7 +78,7 @@ public class WebhookPushRequest extends AbstractPushRequest { private final SubscriptionMode subscriptionMode; public WebhookPushRequest(HandleMsgContext handleMsgContext, - Map> waitingRequests) { + Map> waitingRequests) { super(handleMsgContext, waitingRequests); WebhookTopicConfig topicConfig = (WebhookTopicConfig) handleMsgContext.getConsumeTopicConfig(); @@ -91,7 +92,7 @@ public WebhookPushRequest(HandleMsgContext handleMsgContext, @Override public void tryPushRequest() { - if (simpleMessage == null) { + if (eventMeshCloudEvent == null) { return; } @@ -106,52 +107,47 @@ public void tryPushRequest() { builder.addHeader(ProtocolKey.REQUEST_CODE, requestCode); builder.addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA); builder.addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); - builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshGrpcConfiguration.eventMeshCluster); - builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshGrpcConfiguration.eventMeshIp); - builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshGrpcConfiguration.eventMeshEnv); - builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshGrpcConfiguration.eventMeshIDC); - - RequestHeader requestHeader = simpleMessage.getHeader(); - builder.addHeader(ProtocolKey.PROTOCOL_TYPE, requestHeader.getProtocolType()); - builder.addHeader(ProtocolKey.PROTOCOL_DESC, requestHeader.getProtocolDesc()); - builder.addHeader(ProtocolKey.PROTOCOL_VERSION, requestHeader.getProtocolVersion()); - builder.addHeader(ProtocolKey.CONTENT_TYPE, simpleMessage.getPropertiesOrDefault(ProtocolKey.CONTENT_TYPE, - "application/cloudevents+json")); + builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, + eventMeshGrpcConfiguration.getEventMeshCluster()); + builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, eventMeshGrpcConfiguration.getEventMeshIp()); + builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshGrpcConfiguration.getEventMeshEnv()); + builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshGrpcConfiguration.getEventMeshIDC()); + + builder.addHeader(ProtocolKey.PROTOCOL_TYPE, EventMeshCloudEventUtils.getProtocolType(eventMeshCloudEvent)); + builder.addHeader(ProtocolKey.PROTOCOL_DESC, EventMeshCloudEventUtils.getProtocolDesc(eventMeshCloudEvent)); + builder.addHeader(ProtocolKey.PROTOCOL_VERSION, EventMeshCloudEventUtils.getProtocolVersion(eventMeshCloudEvent)); + builder.addHeader(ProtocolKey.CONTENT_TYPE, EventMeshCloudEventUtils.getContentType(eventMeshCloudEvent, + Constants.CONTENT_TYPE_CLOUDEVENTS_JSON)); List body = new ArrayList<>(); - body.add(new BasicNameValuePair(PushMessageRequestBody.CONTENT, simpleMessage.getContent())); - body.add(new BasicNameValuePair(PushMessageRequestBody.BIZSEQNO, simpleMessage.getSeqNum())); - body.add(new BasicNameValuePair(PushMessageRequestBody.UNIQUEID, simpleMessage.getUniqueId())); + body.add(new BasicNameValuePair(PushMessageRequestBody.CONTENT, EventMeshCloudEventUtils.getDataContent(eventMeshCloudEvent))); + body.add(new BasicNameValuePair(PushMessageRequestBody.BIZSEQNO, EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent))); + body.add(new BasicNameValuePair(PushMessageRequestBody.UNIQUEID, EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent))); body.add(new BasicNameValuePair(PushMessageRequestBody.RANDOMNO, handleMsgContext.getMsgRandomNo())); - body.add(new BasicNameValuePair(PushMessageRequestBody.TOPIC, simpleMessage.getTopic())); + body.add(new BasicNameValuePair(PushMessageRequestBody.TOPIC, EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent))); body.add(new BasicNameValuePair(PushMessageRequestBody.EXTFIELDS, - JsonUtils.serialize(simpleMessage.getPropertiesMap()))); + JsonUtils.toJSONString(EventMeshCloudEventUtils.getAttributes(eventMeshCloudEvent)))); - simpleMessage = SimpleMessage.newBuilder(simpleMessage) - .putProperties(EventMeshConstants.REQ_EVENTMESH2C_TIMESTAMP, String.valueOf(lastPushTime)) - .build(); + eventMeshCloudEvent = CloudEvent.newBuilder(eventMeshCloudEvent).putAttributes(EventMeshConstants.REQ_EVENTMESH2C_TIMESTAMP, + CloudEventAttributeValue.newBuilder().setCeString(String.valueOf(lastPushTime)).build()).build(); builder.setEntity(new UrlEncodedFormEntity(body, StandardCharsets.UTF_8)); - //eventMeshHTTPServer.metrics.summaryMetrics.recordPushMsg(); - addToWaitingMap(this); - cmdLogger.info("cmd={}|eventMesh2client|from={}|to={}", requestCode, - IPUtils.getLocalAddress(), selectedPushUrl); + CMD_LOGGER.info("cmd={}|eventMesh2client|from={}|to={}", requestCode, IPUtils.getLocalAddress(), selectedPushUrl); try { eventMeshGrpcServer.getHttpClient().execute(builder, handleResponse(selectedPushUrl)); - messageLogger - .info("message|eventMesh2client|url={}|topic={}|bizSeqNo={}|uniqueId={}", - selectedPushUrl, simpleMessage.getTopic(), simpleMessage.getSeqNum(), - simpleMessage.getUniqueId()); + MESSAGE_LOGGER.info("message|eventMesh2client|url={}|topic={}|bizSeqNo={}|uniqueId={}", + selectedPushUrl, EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent), + EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), + EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent)); } catch (IOException e) { long cost = System.currentTimeMillis() - lastPushTime; - messageLogger.error( - "message|eventMesh2client|exception={} |emitter|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", e.getMessage(), simpleMessage.getTopic(), - simpleMessage.getSeqNum(), simpleMessage.getUniqueId(), cost, e); + MESSAGE_LOGGER.error("message|eventMesh2client|exception={} |emitter|topic={}|bizSeqNo={}|uniqueId={}|cost={}", + e.getMessage(), EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent), + EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent), cost, e); removeWaitingMap(this); delayRetry(); } @@ -161,49 +157,52 @@ public void tryPushRequest() { @Override public String toString() { return "asyncPushRequest={" - + "bizSeqNo=" + simpleMessage.getSeqNum() - + ",startIdx=" + startIdx - + ",retryTimes=" + retryTimes - + ",uniqueId=" + simpleMessage.getUniqueId() - + ",executeTime=" - + DateFormatUtils.format(executeTime, Constants.DATE_FORMAT) - + ",lastPushTime=" - + DateFormatUtils.format(lastPushTime, Constants.DATE_FORMAT) - + ",createTime=" - + DateFormatUtils.format(createTime, Constants.DATE_FORMAT) + "}"; + + "bizSeqNo=" + EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent) + + ",startIdx=" + startIdx + + ",retryTimes=" + retryTimes + + ",uniqueId=" + EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent) + + ",executeTime=" + + DateFormatUtils.format(executeTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS) + + ",lastPushTime=" + + DateFormatUtils.format(lastPushTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS) + + ",createTime=" + + DateFormatUtils.format(createTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS) + "}"; } private ResponseHandler handleResponse(String selectedPushUrl) { return response -> { removeWaitingMap(WebhookPushRequest.this); long cost = System.currentTimeMillis() - lastPushTime; - //eventMeshHTTPServer.metrics.summaryMetrics.recordHTTPPushTimeCost(cost); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - //eventMeshHTTPServer.metrics.summaryMetrics.recordHttpPushMsgFailed(); - messageLogger.info( - "message|eventMesh2client|exception|url={}|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", selectedPushUrl, simpleMessage.getTopic(), - simpleMessage.getSeqNum(), simpleMessage.getUniqueId(), cost); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + MESSAGE_LOGGER.info("message|eventMesh2client|exception|url={}|topic={}|bizSeqNo={}|uniqueId={}|cost={}", selectedPushUrl, + EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent), EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), + EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent), cost); delayRetry(); } else { String res = ""; try { res = EntityUtils.toString(response.getEntity(), - Charset.forName(EventMeshConstants.DEFAULT_CHARSET)); + Charset.forName(EventMeshConstants.DEFAULT_CHARSET)); } catch (IOException e) { complete(); return new Object(); } ClientRetCode result = processResponseContent(res, selectedPushUrl); - messageLogger.info( - "message|eventMesh2client|{}|url={}|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", result, selectedPushUrl, simpleMessage.getTopic(), - simpleMessage.getSeqNum(), simpleMessage.getUniqueId(), cost); - if (result == ClientRetCode.OK || result == ClientRetCode.FAIL) { - complete(); - } else if (result == ClientRetCode.RETRY || result == ClientRetCode.NOLISTEN) { - delayRetry(); + MESSAGE_LOGGER.info("message|eventMesh2client|{}|url={}|topic={}|bizSeqNo={}|uniqueId={}|cost={}", + result, selectedPushUrl, EventMeshCloudEventUtils.getSubject(eventMeshCloudEvent), + EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent), cost); + switch (result) { + case OK: + case FAIL: + complete(); + break; + case RETRY: + case NOLISTEN: + delayRetry(); + break; + default: + // do nothing } } return new Object(); @@ -217,16 +216,16 @@ private ClientRetCode processResponseContent(String content, String selectedPush try { Map ret = - JsonUtils.deserialize(content, new TypeReference>() { - }); - Integer retCode = (Integer) ret.get("retCode"); + JsonUtils.parseTypeReferenceObject(content, new TypeReference>() { + }); + Integer retCode = (Integer) Objects.requireNonNull(ret).get("retCode"); if (retCode != null && ClientRetCode.contains(retCode)) { return ClientRetCode.get(retCode); } return ClientRetCode.FAIL; } catch (Exception e) { - messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", selectedPushUrl, - simpleMessage.getSeqNum(), simpleMessage.getUniqueId(), content); + MESSAGE_LOGGER.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", selectedPushUrl, + EventMeshCloudEventUtils.getSeqNum(eventMeshCloudEvent), EventMeshCloudEventUtils.getUniqueId(eventMeshCloudEvent), content); return ClientRetCode.FAIL; } } @@ -234,29 +233,25 @@ private ClientRetCode processResponseContent(String content, String selectedPush @SuppressWarnings("unchecked") private List getUrl() { List localIdcUrl = MapUtils.getObject(urls, - eventMeshGrpcConfiguration.eventMeshIDC, null); + eventMeshGrpcConfiguration.getEventMeshIDC(), null); if (CollectionUtils.isNotEmpty(localIdcUrl)) { - if (subscriptionMode.equals(SubscriptionMode.CLUSTERING)) { - return Collections.singletonList(localIdcUrl.get((startIdx + retryTimes) % localIdcUrl.size())); - } else if (subscriptionMode.equals(SubscriptionMode.BROADCASTING)) { - return localIdcUrl; - } else { - messageLogger.error("Invalid Subscription Mode, no message returning back to subscriber."); - return Collections.emptyList(); - } + return getStringList(localIdcUrl); + } else if (CollectionUtils.isNotEmpty(totalUrls)) { + return getStringList(totalUrls); } + MESSAGE_LOGGER.error("No event emitters from subscriber, no message returning."); + return Collections.emptyList(); + } - if (CollectionUtils.isNotEmpty(totalUrls)) { - if (subscriptionMode.equals(SubscriptionMode.CLUSTERING)) { - return Collections.singletonList(totalUrls.get((startIdx + retryTimes) % totalUrls.size())); - } else if (subscriptionMode.equals(SubscriptionMode.BROADCASTING)) { - return totalUrls; - } else { - messageLogger.error("Invalid Subscription Mode, no message returning back to subscriber."); + private List getStringList(List stringList) { + switch (subscriptionMode) { + case CLUSTERING: + return Collections.singletonList(stringList.get((startIdx + retryTimes) % stringList.size())); + case BROADCASTING: + return stringList; + default: + MESSAGE_LOGGER.error("Invalid Subscription Mode, no message returning back to subscriber."); return Collections.emptyList(); - } } - messageLogger.error("No event emitters from subscriber, no message returning."); - return Collections.EMPTY_LIST; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/DelayRetryable.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/DelayRetryable.java deleted file mode 100644 index 9e4fbd2da5..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/DelayRetryable.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.retry; - -import java.util.concurrent.Delayed; - -/** - */ -public interface DelayRetryable extends Delayed { - boolean retry() throws Exception; -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/GrpcRetryer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/GrpcRetryer.java index f65bfc63d2..dccd782c1f 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/GrpcRetryer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/GrpcRetryer.java @@ -17,100 +17,19 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.retry; +import org.apache.eventmesh.retry.api.AbstractRetryer; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.configuration.EventMeshGrpcConfiguration; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; +import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@Slf4j +public class GrpcRetryer extends AbstractRetryer { -public class GrpcRetryer { - - private Logger retryLogger = LoggerFactory.getLogger("retry"); - - private Logger logger = LoggerFactory.getLogger(this.getClass()); - - private EventMeshGrpcConfiguration grpcConfiguration; + private final EventMeshGrpcConfiguration grpcConfiguration; public GrpcRetryer(EventMeshGrpcServer eventMeshGrpcServer) { this.grpcConfiguration = eventMeshGrpcServer.getEventMeshGrpcConfiguration(); } - private DelayQueue failed = new DelayQueue(); - - private ThreadPoolExecutor pool; - - private Thread dispatcher; - - public void pushRetry(DelayRetryable delayRetryable) { - if (failed.size() >= grpcConfiguration.eventMeshServerRetryBlockQueueSize) { - retryLogger.error("[RETRY-QUEUE] is full!"); - return; - } - failed.offer(delayRetryable); - } - - public void init() { - pool = new ThreadPoolExecutor(grpcConfiguration.eventMeshServerRetryThreadNum, - grpcConfiguration.eventMeshServerRetryThreadNum, - 60000, - TimeUnit.MILLISECONDS, - new ArrayBlockingQueue<>(grpcConfiguration.eventMeshServerRetryBlockQueueSize), - new ThreadFactory() { - private AtomicInteger count = new AtomicInteger(); - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "grpc-retry-" + count.incrementAndGet()); - thread.setPriority(Thread.NORM_PRIORITY); - thread.setDaemon(true); - return thread; - } - }, new ThreadPoolExecutor.AbortPolicy()); - - dispatcher = new Thread(() -> { - try { - DelayRetryable retryObj = null; - while (!Thread.currentThread().isInterrupted() - && (retryObj = failed.take()) != null) { - final DelayRetryable delayRetryable = retryObj; - pool.execute(() -> { - try { - delayRetryable.retry(); - if (retryLogger.isDebugEnabled()) { - retryLogger.debug("retryObj : {}", delayRetryable); - } - } catch (Exception e) { - retryLogger.error("grpc-retry-dispatcher error!", e); - } - }); - } - } catch (Exception e) { - retryLogger.error("grpc-retry-dispatcher error!", e); - } - }, "grpc-retry-dispatcher"); - dispatcher.setDaemon(true); - logger.info("GrpcRetryer inited......"); - } - - public int size() { - return failed.size(); - } - - public void shutdown() { - dispatcher.interrupt(); - pool.shutdown(); - logger.info("GrpcRetryer shutdown......"); - } - - public void start() throws Exception { - dispatcher.start(); - logger.info("GrpcRetryer started......"); - } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/RetryContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/RetryContext.java deleted file mode 100644 index c09f3b9f54..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/retry/RetryContext.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.retry; - -import java.util.concurrent.Delayed; -import java.util.concurrent.TimeUnit; - -public abstract class RetryContext implements DelayRetryable { - - public int retryTimes = 0; - - public long executeTime = System.currentTimeMillis(); - - public RetryContext delay(long delay) { - this.executeTime = System.currentTimeMillis() + delay; - return this; - } - - @Override - public int compareTo(Delayed delayed) { - RetryContext obj = (RetryContext) delayed; - if (this.executeTime > obj.executeTime) { - return 1; - } else if (this.executeTime == obj.executeTime) { - return 0; - } else { - return -1; - } - } - - @Override - public long getDelay(TimeUnit unit) { - return unit.convert(this.executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ConsumerService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ConsumerService.java index ef13de8de0..2c2c501178 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ConsumerService.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ConsumerService.java @@ -17,11 +17,12 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.service; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.grpc.processor.ReplyMessageProcessor; @@ -29,16 +30,17 @@ import org.apache.eventmesh.runtime.core.protocol.grpc.processor.SubscribeStreamProcessor; import org.apache.eventmesh.runtime.core.protocol.grpc.processor.UnsubscribeProcessor; -import java.util.concurrent.ThreadPoolExecutor; +import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.Optional; +import java.util.concurrent.ThreadPoolExecutor; import io.grpc.stub.StreamObserver; -public class ConsumerService extends ConsumerServiceGrpc.ConsumerServiceImplBase { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(ConsumerService.class); +@Slf4j +public class ConsumerService extends ConsumerServiceGrpc.ConsumerServiceImplBase { private final EventMeshGrpcServer eventMeshGrpcServer; @@ -47,118 +49,112 @@ public class ConsumerService extends ConsumerServiceGrpc.ConsumerServiceImplBase private final ThreadPoolExecutor replyThreadPoolExecutor; public ConsumerService(EventMeshGrpcServer eventMeshGrpcServer, - ThreadPoolExecutor subscribeThreadPoolExecutor, - ThreadPoolExecutor replyThreadPoolExecutor) { + ThreadPoolExecutor subscribeThreadPoolExecutor, + ThreadPoolExecutor replyThreadPoolExecutor) { this.eventMeshGrpcServer = eventMeshGrpcServer; this.subscribeThreadPoolExecutor = subscribeThreadPoolExecutor; this.replyThreadPoolExecutor = replyThreadPoolExecutor; } - public void subscribe(Subscription request, StreamObserver responseObserver) { - logger.info("cmd={}|{}|client2eventMesh|from={}|to={}", + @Override + public void subscribe(CloudEvent request, StreamObserver responseObserver) { + String clientIp = EventMeshCloudEventUtils.getIp(request); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "subscribe", EventMeshConstants.PROTOCOL_GRPC, - request.getHeader().getIp(), eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); + EventMeshCloudEventUtils.getIp(request), eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromClient(clientIp); - EventEmitter emitter = new EventEmitter<>(responseObserver); + EventEmitter emitter = new EventEmitter<>(responseObserver); subscribeThreadPoolExecutor.submit(() -> { SubscribeProcessor subscribeProcessor = new SubscribeProcessor(eventMeshGrpcServer); try { subscribeProcessor.process(request, emitter); } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_SUBSCRIBE_ERR.getRetCode(), + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_SUBSCRIBE_ERR.getRetCode(), StatusCode.EVENTMESH_SUBSCRIBE_ERR.getErrMsg(), e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), emitter); } }); } - public StreamObserver subscribeStream(StreamObserver responseObserver) { - EventEmitter emitter = new EventEmitter<>(responseObserver); + @Override + public StreamObserver subscribeStream(StreamObserver responseObserver) { + EventEmitter emitter = new EventEmitter<>(responseObserver); - return new StreamObserver() { - @Override - public void onNext(Subscription subscription) { - if (!subscription.getSubscriptionItemsList().isEmpty()) { - logger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - "subscribeStream", EventMeshConstants.PROTOCOL_GRPC, - subscription.getHeader().getIp(), eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); + return new StreamObserver() { - handleSubscriptionStream(subscription, emitter); + @Override + public void onNext(CloudEvent subscription) { + final String subMessageType = Optional.ofNullable(subscription.getAttributesMap().get(ProtocolKey.SUB_MESSAGE_TYPE)) + .orElse(CloudEventAttributeValue.newBuilder().build()).getCeString(); + String clientId = EventMeshCloudEventUtils.getIp(subscription); + if (StringUtils.equals(subMessageType, ProtocolKey.SUB_REPLY_MESSAGE)) { + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "reply-to-server", EventMeshConstants.PROTOCOL_GRPC, + EventMeshCloudEventUtils.getIp(subscription), eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); + handleSubscribeReply(subscription, emitter); } else { - logger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - "reply-to-server", EventMeshConstants.PROTOCOL_GRPC, - subscription.getHeader().getIp(), eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "subscribeStream", EventMeshConstants.PROTOCOL_GRPC, + EventMeshCloudEventUtils.getIp(subscription), eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); - handleSubscribeReply(subscription, emitter); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromClient(clientId); + handleSubscriptionStream(subscription, emitter); } } @Override public void onError(Throwable t) { - logger.error("Receive error from client: " + t.getMessage()); + log.error("Receive error from client: {}", t.getMessage()); emitter.onCompleted(); } @Override public void onCompleted() { - logger.info("Client finish sending messages"); + log.info("Client finish sending messages"); emitter.onCompleted(); } }; } - private void handleSubscriptionStream(Subscription request, EventEmitter emitter) { + private void handleSubscriptionStream(CloudEvent request, EventEmitter emitter) { subscribeThreadPoolExecutor.submit(() -> { SubscribeStreamProcessor streamProcessor = new SubscribeStreamProcessor(eventMeshGrpcServer); try { streamProcessor.process(request, emitter); } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), e); - ServiceUtils.sendStreamRespAndDone(request.getHeader(), StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), emitter); + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), e); + ServiceUtils.sendStreamResponseCompleted(request, StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), emitter); } }); } - private void handleSubscribeReply(Subscription subscription, EventEmitter emitter) { + private void handleSubscribeReply(CloudEvent subscription, EventEmitter emitter) { replyThreadPoolExecutor.submit(() -> { ReplyMessageProcessor replyMessageProcessor = new ReplyMessageProcessor(eventMeshGrpcServer); try { - replyMessageProcessor.process(buildSimpleMessage(subscription), emitter); + replyMessageProcessor.process(subscription, emitter); } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), e); - ServiceUtils.sendStreamRespAndDone(subscription.getHeader(), StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), emitter); + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), e); + ServiceUtils.sendStreamResponseCompleted(subscription, StatusCode.EVENTMESH_SUBSCRIBE_ERR, e.getMessage(), emitter); } }); } - private SimpleMessage buildSimpleMessage(Subscription subscription) { - Subscription.Reply reply = subscription.getReply(); - return SimpleMessage.newBuilder() - .setHeader(subscription.getHeader()) - .setProducerGroup(reply.getProducerGroup()) - .setContent(reply.getContent()) - .setUniqueId(reply.getUniqueId()) - .setSeqNum(reply.getSeqNum()) - .setTopic(reply.getTopic()) - .setTtl(reply.getTtl()) - .putAllProperties(reply.getPropertiesMap()) - .build(); - } - - public void unsubscribe(Subscription request, StreamObserver responseObserver) { - logger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - "unsubscribe", EventMeshConstants.PROTOCOL_GRPC, - request.getHeader().getIp(), eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); + @Override + public void unsubscribe(CloudEvent request, StreamObserver responseObserver) { + String clientIp = EventMeshCloudEventUtils.getIp(request); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "unsubscribe", EventMeshConstants.PROTOCOL_GRPC, + EventMeshCloudEventUtils.getIp(request), eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromClient(clientIp); - EventEmitter emitter = new EventEmitter<>(responseObserver); + EventEmitter emitter = new EventEmitter<>(responseObserver); subscribeThreadPoolExecutor.submit(() -> { UnsubscribeProcessor unsubscribeProcessor = new UnsubscribeProcessor(eventMeshGrpcServer); try { unsubscribeProcessor.process(request, emitter); } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_UNSUBSCRIBE_ERR.getRetCode(), + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_UNSUBSCRIBE_ERR.getRetCode(), StatusCode.EVENTMESH_UNSUBSCRIBE_ERR.getErrMsg(), e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_UNSUBSCRIBE_ERR, e.getMessage(), emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_UNSUBSCRIBE_ERR, e.getMessage(), emitter); } }); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/EventEmitter.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/EventEmitter.java index 36ff404d85..c4b21106b8 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/EventEmitter.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/EventEmitter.java @@ -17,13 +17,12 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.service; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.grpc.stub.StreamObserver; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class EventEmitter { - private final Logger logger = LoggerFactory.getLogger(EventEmitter.class); private final StreamObserver emitter; @@ -34,24 +33,24 @@ public EventEmitter(StreamObserver emitter) { public synchronized void onNext(T event) { try { emitter.onNext(event); - } catch (Throwable t) { - logger.warn("StreamObserver Error onNext. {}", t.getMessage()); + } catch (Exception e) { + log.warn("StreamObserver Error onNext. {}", e.getMessage()); } } public synchronized void onCompleted() { try { emitter.onCompleted(); - } catch (Throwable t) { - logger.warn("StreamObserver Error onCompleted. {}", t.getMessage()); + } catch (Exception e) { + log.warn("StreamObserver Error onCompleted. {}", e.getMessage()); } } public synchronized void onError(Throwable t) { try { emitter.onError(t); - } catch (Throwable t1) { - logger.warn("StreamObserver Error onError. {}", t1.getMessage()); + } catch (Exception e) { + log.warn("StreamObserver Error onError. {}", e.getMessage()); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/HeartbeatService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/HeartbeatService.java index 94491b6c65..10dbcaf900 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/HeartbeatService.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/HeartbeatService.java @@ -17,49 +17,48 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.service; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.HeartbeatServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat; -import org.apache.eventmesh.common.protocol.grpc.protos.HeartbeatServiceGrpc; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.grpc.processor.HeartbeatProcessor; import java.util.concurrent.ThreadPoolExecutor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.grpc.stub.StreamObserver; -public class HeartbeatService extends HeartbeatServiceGrpc.HeartbeatServiceImplBase { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(ProducerService.class); +@Slf4j +public class HeartbeatService extends HeartbeatServiceGrpc.HeartbeatServiceImplBase { - private final EventMeshGrpcServer eventMeshGrpcServer; + private final transient EventMeshGrpcServer eventMeshGrpcServer; - private final ThreadPoolExecutor threadPoolExecutor; + private final transient ThreadPoolExecutor threadPoolExecutor; - public HeartbeatService(EventMeshGrpcServer eventMeshGrpcServer, - ThreadPoolExecutor threadPoolExecutor) { + public HeartbeatService(final EventMeshGrpcServer eventMeshGrpcServer, + final ThreadPoolExecutor threadPoolExecutor) { this.eventMeshGrpcServer = eventMeshGrpcServer; this.threadPoolExecutor = threadPoolExecutor; } - public void heartbeat(Heartbeat request, StreamObserver responseObserver) { - logger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - "heartbeat", EventMeshConstants.PROTOCOL_GRPC, - request.getHeader().getIp(), eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); + @Override + public void heartbeat(CloudEvent request, StreamObserver responseObserver) { + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", + "heartbeat", EventMeshConstants.PROTOCOL_GRPC, EventMeshCloudEventUtils.getIp(request), + eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); - EventEmitter emitter = new EventEmitter<>(responseObserver); + EventEmitter emitter = new EventEmitter<>(responseObserver); threadPoolExecutor.submit(() -> { HeartbeatProcessor heartbeatProcessor = new HeartbeatProcessor(eventMeshGrpcServer); try { heartbeatProcessor.process(request, emitter); } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_HEARTBEAT_ERR.getRetCode(), + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_HEARTBEAT_ERR.getRetCode(), StatusCode.EVENTMESH_HEARTBEAT_ERR.getErrMsg(), e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_HEARTBEAT_ERR, e.getMessage(), emitter); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_HEARTBEAT_ERR, e.getMessage(), emitter); } }); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ProducerService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ProducerService.java deleted file mode 100644 index 753aa254b0..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ProducerService.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.grpc.service; - -import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.PublisherServiceGrpc; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.grpc.processor.BatchPublishMessageProcessor; -import org.apache.eventmesh.runtime.core.protocol.grpc.processor.RequestMessageProcessor; -import org.apache.eventmesh.runtime.core.protocol.grpc.processor.SendAsyncMessageProcessor; - -import java.util.concurrent.ThreadPoolExecutor; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.grpc.stub.StreamObserver; - -public class ProducerService extends PublisherServiceGrpc.PublisherServiceImplBase { - - private final Logger logger = LoggerFactory.getLogger(ProducerService.class); - - private final Logger cmdLogger = LoggerFactory.getLogger("cmd"); - - private final EventMeshGrpcServer eventMeshGrpcServer; - - private final ThreadPoolExecutor threadPoolExecutor; - - public ProducerService(EventMeshGrpcServer eventMeshGrpcServer, - ThreadPoolExecutor threadPoolExecutor) { - this.eventMeshGrpcServer = eventMeshGrpcServer; - this.threadPoolExecutor = threadPoolExecutor; - } - - public void publish(SimpleMessage request, StreamObserver responseObserver) { - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", "AsyncPublish", - EventMeshConstants.PROTOCOL_GRPC, request.getHeader().getIp(), - eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); - - EventEmitter emitter = new EventEmitter<>(responseObserver); - threadPoolExecutor.submit(() -> { - SendAsyncMessageProcessor sendAsyncMessageProcessor = new SendAsyncMessageProcessor(eventMeshGrpcServer); - try { - sendAsyncMessageProcessor.process(request, emitter); - } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode(), - StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg(), e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR, e.getMessage(), emitter); - } - }); - } - - public void requestReply(SimpleMessage request, StreamObserver responseObserver) { - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", "RequestReply", - EventMeshConstants.PROTOCOL_GRPC, request.getHeader().getIp(), - eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); - - EventEmitter emitter = new EventEmitter<>(responseObserver); - threadPoolExecutor.submit(() -> { - RequestMessageProcessor requestMessageProcessor = new RequestMessageProcessor(eventMeshGrpcServer); - try { - requestMessageProcessor.process(request, emitter); - } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR.getRetCode(), - StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR.getErrMsg(), e); - ServiceUtils.sendStreamRespAndDone(request.getHeader(), StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR, e.getMessage(), emitter); - } - }); - } - - public void batchPublish(BatchMessage request, StreamObserver responseObserver) { - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", "BatchPublish", - EventMeshConstants.PROTOCOL_GRPC, request.getHeader().getIp(), - eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp); - - EventEmitter emitter = new EventEmitter<>(responseObserver); - threadPoolExecutor.submit(() -> { - BatchPublishMessageProcessor batchPublishMessageProcessor = new BatchPublishMessageProcessor(eventMeshGrpcServer); - try { - batchPublishMessageProcessor.process(request, emitter); - } catch (Exception e) { - logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_BATCH_PUBLISH_ERR.getRetCode(), - StatusCode.EVENTMESH_BATCH_PUBLISH_ERR.getErrMsg(), e); - ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_BATCH_PUBLISH_ERR, e.getMessage(), emitter); - } - }); - } - -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/PublisherService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/PublisherService.java new file mode 100644 index 0000000000..3e62ae9215 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/PublisherService.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.grpc.service; + +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.grpc.processor.BatchPublishCloudEventProcessor; +import org.apache.eventmesh.runtime.core.protocol.grpc.processor.PublishCloudEventsProcessor; +import org.apache.eventmesh.runtime.core.protocol.grpc.processor.RequestCloudEventProcessor; + +import java.util.concurrent.ThreadPoolExecutor; + +import io.grpc.stub.StreamObserver; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PublisherService extends PublisherServiceGrpc.PublisherServiceImplBase { + + private final EventMeshGrpcServer eventMeshGrpcServer; + + private final ThreadPoolExecutor threadPoolExecutor; + + public PublisherService(EventMeshGrpcServer eventMeshGrpcServer, + ThreadPoolExecutor threadPoolExecutor) { + this.eventMeshGrpcServer = eventMeshGrpcServer; + this.threadPoolExecutor = threadPoolExecutor; + } + + /** + *
+     * Sync publish event
+     * 
+ * + * @param request + * @param responseObserver + */ + @Override + public void publish(CloudEvent request, StreamObserver responseObserver) { + String clientId = EventMeshCloudEventUtils.getIp(request); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "publish", EventMeshConstants.PROTOCOL_GRPC, + EventMeshCloudEventUtils.getIp(request), eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromClient(clientId); + + EventEmitter emitter = new EventEmitter<>(responseObserver); + threadPoolExecutor.submit(() -> { + PublishCloudEventsProcessor publishCloudEventsProcessor = new PublishCloudEventsProcessor(eventMeshGrpcServer); + try { + publishCloudEventsProcessor.process(request, emitter); + } catch (Exception e) { + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode(), + StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg(), e); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR, e.getMessage(), emitter); + } + }); + } + + /** + *
+     * publish event with reply
+     * 
+ * + * @param request + * @param responseObserver + */ + @Override + public void requestReply(CloudEvent request, StreamObserver responseObserver) { + String clientIp = EventMeshCloudEventUtils.getIp(request); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "RequestReply", + EventMeshConstants.PROTOCOL_GRPC, EventMeshCloudEventUtils.getIp(request), + eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromClient(clientIp); + + EventEmitter emitter = new EventEmitter<>(responseObserver); + threadPoolExecutor.submit(() -> { + RequestCloudEventProcessor requestMessageProcessor = new RequestCloudEventProcessor(eventMeshGrpcServer); + try { + requestMessageProcessor.process(request, emitter); + } catch (Exception e) { + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR.getRetCode(), + StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR.getErrMsg(), e); + ServiceUtils.sendStreamResponseCompleted(request, StatusCode.EVENTMESH_REQUEST_REPLY_MSG_ERR, e.getMessage(), emitter); + } + }); + } + + /** + *
+     * publish batch event
+     * 
+ * + * @param request + * @param responseObserver + */ + @Override + public void batchPublish(CloudEventBatch request, StreamObserver responseObserver) { + String clientIp = EventMeshCloudEventUtils.getIp(request.getEvents(0)); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", "BatchPublish", + EventMeshConstants.PROTOCOL_GRPC, null, + eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshIp()); + eventMeshGrpcServer.getEventMeshGrpcMetricsManager().recordReceiveMsgFromClient(request.getEventsCount(), clientIp); + + EventEmitter emitter = new EventEmitter<>(responseObserver); + threadPoolExecutor.submit(() -> { + BatchPublishCloudEventProcessor batchPublishMessageProcessor = new BatchPublishCloudEventProcessor(eventMeshGrpcServer); + try { + batchPublishMessageProcessor.process(request, emitter); + } catch (Exception e) { + log.error("Error code {}, error message {}", StatusCode.EVENTMESH_BATCH_PUBLISH_ERR.getRetCode(), + StatusCode.EVENTMESH_BATCH_PUBLISH_ERR.getErrMsg(), e); + ServiceUtils.sendResponseCompleted(StatusCode.EVENTMESH_BATCH_PUBLISH_ERR, e.getMessage(), emitter); + } + }); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ServiceUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ServiceUtils.java index 163e8ecc90..5920103009 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ServiceUtils.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/grpc/service/ServiceUtils.java @@ -17,87 +17,137 @@ package org.apache.eventmesh.runtime.core.protocol.grpc.service; +import org.apache.eventmesh.common.protocol.HeartbeatItem; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; +import org.apache.eventmesh.common.protocol.grpc.common.ProtoSupport; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat; -import org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat.ClientType; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.runtime.core.protocol.grpc.consumer.consumergroup.GrpcType; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import java.util.HashMap; -import java.util.Map; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Objects; + +import io.cloudevents.SpecVersion; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; public class ServiceUtils { - public static boolean validateHeader(RequestHeader header) { - return StringUtils.isNotEmpty(header.getIdc()) - && StringUtils.isNotEmpty(header.getEnv()) - && StringUtils.isNotEmpty(header.getIp()) - && StringUtils.isNotEmpty(header.getPid()) - && StringUtils.isNumeric(header.getPid()) - && StringUtils.isNotEmpty(header.getSys()) - && StringUtils.isNotEmpty(header.getUsername()) - && StringUtils.isNotEmpty(header.getPassword()) - && StringUtils.isNotEmpty(header.getLanguage()); + public static boolean validateCloudEventAttributes(CloudEvent cloudEvent) { + return StringUtils.isNotEmpty(EventMeshCloudEventUtils.getIdc(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getEnv(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getIp(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getPid(cloudEvent)) + && StringUtils.isNumeric(EventMeshCloudEventUtils.getPid(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getSys(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getUserName(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getPassword(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getLanguage(cloudEvent)); } - public static boolean validateMessage(SimpleMessage message) { - return StringUtils.isNotEmpty(message.getUniqueId()) - && StringUtils.isNotEmpty(message.getProducerGroup()) - && StringUtils.isNotEmpty(message.getTopic()) - && StringUtils.isNotEmpty(message.getContent()) - && StringUtils.isNotEmpty(message.getTtl()); + public static boolean validateCloudEventBatchAttributes(CloudEventBatch cloudEventBatch) { + if (cloudEventBatch == null || cloudEventBatch.getEventsCount() < 1) { + return false; + } + List eventsList = cloudEventBatch.getEventsList(); + for (CloudEvent cloudEvent : eventsList) { + if (validateCloudEventAttributes(cloudEvent)) { + continue; + } + return false; + } + return true; } - public static boolean validateBatchMessage(BatchMessage batchMessage) { - if (StringUtils.isEmpty(batchMessage.getTopic()) - || StringUtils.isEmpty(batchMessage.getProducerGroup())) { + public static boolean validateCloudEventData(CloudEvent cloudEvent) { + boolean flag = StringUtils.isNotEmpty(EventMeshCloudEventUtils.getUniqueId(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getProducerGroup(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getSubject(cloudEvent)) + && StringUtils.isNotEmpty(EventMeshCloudEventUtils.getTtl(cloudEvent)); + if (!flag) { return false; } - for (BatchMessage.MessageItem item : batchMessage.getMessageItemList()) { - if (StringUtils.isEmpty(item.getContent()) || StringUtils.isEmpty(item.getSeqNum()) - || StringUtils.isEmpty(item.getTtl()) || StringUtils.isEmpty(item.getUniqueId())) { - return false; + final String dataContentType = EventMeshCloudEventUtils.getDataContentType(cloudEvent); + if (ProtoSupport.isTextContent(dataContentType)) { + return flag && (StringUtils.isNotEmpty(cloudEvent.getTextData())); + } + if (ProtoSupport.isProtoContent(dataContentType)) { + return flag && (cloudEvent.getProtoData() != Any.getDefaultInstance()); + } + + return flag && (cloudEvent.getBinaryData() != ByteString.EMPTY); + } + + public static boolean validateCloudEventBatchData(CloudEventBatch cloudEventBatch) { + if (cloudEventBatch == null || cloudEventBatch.getEventsCount() < 1) { + return false; + } + List eventsList = cloudEventBatch.getEventsList(); + for (CloudEvent cloudEvent : eventsList) { + if (validateCloudEventData(cloudEvent)) { + continue; } + return false; } return true; } - public static boolean validateSubscription(GrpcType grpcType, Subscription subscription) { - if (GrpcType.WEBHOOK.equals(grpcType) && StringUtils.isEmpty(subscription.getUrl())) { + public static boolean validateSubscription(GrpcType grpcType, CloudEvent subscription) { + if (GrpcType.WEBHOOK == grpcType && StringUtils.isEmpty(EventMeshCloudEventUtils.getURL(subscription))) { return false; } - if (CollectionUtils.isEmpty(subscription.getSubscriptionItemsList()) - || StringUtils.isEmpty(subscription.getConsumerGroup())) { + List subscriptionItems = JsonUtils.parseTypeReferenceObject(subscription.getTextData(), + new TypeReference>() { + }); + if (CollectionUtils.isEmpty(subscriptionItems) + || StringUtils.isEmpty(EventMeshCloudEventUtils.getConsumerGroup(subscription))) { return false; } - for (Subscription.SubscriptionItem item : subscription.getSubscriptionItemsList()) { + for (SubscriptionItem item : subscriptionItems) { if (StringUtils.isEmpty(item.getTopic()) - || item.getMode() == Subscription.SubscriptionItem.SubscriptionMode.UNRECOGNIZED - || item.getType() == Subscription.SubscriptionItem.SubscriptionType.UNRECOGNIZED) { + || item.getMode() == SubscriptionMode.UNRECOGNIZED + || item.getType() == SubscriptionType.UNRECOGNIZED) { return false; } } return true; } - public static boolean validateHeartBeat(Heartbeat heartbeat) { - if (ClientType.SUB.equals(heartbeat.getClientType()) - && StringUtils.isEmpty(heartbeat.getConsumerGroup())) { + public static boolean validateHeartBeat(CloudEvent heartbeat) { + org.apache.eventmesh.common.protocol.grpc.common.ClientType clientType = EventMeshCloudEventUtils.getClientType(heartbeat); + if (org.apache.eventmesh.common.protocol.grpc.common.ClientType.SUB == clientType && StringUtils.isEmpty( + EventMeshCloudEventUtils.getConsumerGroup(heartbeat))) { return false; } - if (ClientType.PUB.equals(heartbeat.getClientType()) - && StringUtils.isEmpty(heartbeat.getProducerGroup())) { + if (org.apache.eventmesh.common.protocol.grpc.common.ClientType.PUB == clientType && StringUtils.isEmpty( + EventMeshCloudEventUtils.getProducerGroup(heartbeat))) { return false; } - for (Heartbeat.HeartbeatItem item : heartbeat.getHeartbeatItemsList()) { + List heartbeatItems = JsonUtils.parseTypeReferenceObject(heartbeat.getTextData(), + new TypeReference>() { + }); + Objects.requireNonNull(heartbeatItems, "heartbeatItems can't be null"); + for (HeartbeatItem item : heartbeatItems) { if (StringUtils.isEmpty(item.getTopic())) { return false; } @@ -105,55 +155,113 @@ public static boolean validateHeartBeat(Heartbeat heartbeat) { return true; } - public static void sendRespAndDone(StatusCode code, EventEmitter emitter) { - Response response = Response.newBuilder() - .setRespCode(code.getRetCode()) - .setRespMsg(code.getErrMsg()) - .setRespTime(String.valueOf(System.currentTimeMillis())) - .build(); - emitter.onNext(response); + /** + * Sends a completed response event to the given EventEmitter. + * + * @param code The status code for the response. + * @param message The message for the response. + * @param emitter The EventEmitter to send the response event to. + */ + public static void sendResponseCompleted(StatusCode code, String message, EventEmitter emitter) { + + Instant instant = now(); + CloudEvent.Builder builder = CloudEvent.newBuilder().setId(RandomStringUtils.generateUUID()).setSpecVersion(SpecVersion.V1.toString()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, CloudEventAttributeValue.newBuilder().setCeString(code.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, + CloudEventAttributeValue.newBuilder().setCeString(code.getErrMsg() + EventMeshConstants.BLANK_SPACE + message).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + + emitter.onNext(builder.build()); emitter.onCompleted(); } - public static void sendRespAndDone(StatusCode code, String message, EventEmitter emitter) { - Response response = Response.newBuilder() - .setRespCode(code.getRetCode()) - .setRespMsg(code.getErrMsg() + " " + message) - .setRespTime(String.valueOf(System.currentTimeMillis())) - .build(); - emitter.onNext(response); + /** + * Sends a completed response event to the emitter. + * + * @param code The status code of the response + * @param emitter The emitter to send the event to + */ + public static void sendResponseCompleted(StatusCode code, EventEmitter emitter) { + Instant instant = now(); + CloudEvent.Builder builder = CloudEvent.newBuilder().setSpecVersion(SpecVersion.V1.toString()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, CloudEventAttributeValue.newBuilder().setCeString(code.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, CloudEventAttributeValue.newBuilder().setCeString(code.getErrMsg()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + emitter.onNext(builder.build()); emitter.onCompleted(); } - public static void sendStreamResp(RequestHeader header, StatusCode code, String message, EventEmitter emitter) { - Map resp = new HashMap<>(); - resp.put("respCode", code.getRetCode()); - resp.put("respMsg", code.getErrMsg() + " " + message); - - SimpleMessage simpleMessage = SimpleMessage.newBuilder() - .setHeader(header) - .setContent(JsonUtils.serialize(resp)) - .build(); - - emitter.onNext(simpleMessage); + /** + * Sends a completed response event to the emitter for a stream. + * + * @param cloudEvent The original CloudEvent + * @param code The status code of the response + * @param emitter The emitter to send the event to + */ + public static void sendStreamResponseCompleted(CloudEvent cloudEvent, StatusCode code, EventEmitter emitter) { + sendStreamResponse(cloudEvent, code, emitter); + emitter.onCompleted(); } - public static void sendStreamRespAndDone(RequestHeader header, StatusCode code, String message, EventEmitter emitter) { - sendStreamResp(header, code, message, emitter); + /** + * Sends a completed response event to the emitter for a stream with a custom message. + * + * @param cloudEvent The original CloudEvent + * @param code The status code of the response + * @param message The custom message for the response + * @param emitter The emitter to send the event to + */ + public static void sendStreamResponseCompleted(CloudEvent cloudEvent, StatusCode code, String message, EventEmitter emitter) { + sendStreamResponse(cloudEvent, code, message, emitter); emitter.onCompleted(); } - public static void sendStreamRespAndDone(RequestHeader header, StatusCode code, EventEmitter emitter) { - Map resp = new HashMap<>(); - resp.put("respCode", code.getRetCode()); - resp.put("respMsg", code.getErrMsg()); + /** + * Sends a response event to the emitter for a stream. + * + * @param cloudEvent The original CloudEvent + * @param code The status code of the response + * @param emitter The emitter to send the event to + */ + public static void sendStreamResponse(CloudEvent cloudEvent, StatusCode code, EventEmitter emitter) { + Instant instant = now(); + CloudEvent.Builder builder = CloudEvent.newBuilder(cloudEvent) + .putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, CloudEventAttributeValue.newBuilder().setCeString(code.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, CloudEventAttributeValue.newBuilder().setCeString(code.getErrMsg()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); - SimpleMessage simpleMessage = SimpleMessage.newBuilder() - .setHeader(header) - .setContent(JsonUtils.serialize(resp)) - .build(); + emitter.onNext(builder.build()); + } - emitter.onNext(simpleMessage); - emitter.onCompleted(); + /** + * Sends a response event to the emitter for a stream with a custom message. + * + * @param cloudEvent The original CloudEvent + * @param code The status code of the response + * @param message The custom message for the response + * @param emitter The emitter to send the event to + */ + public static void sendStreamResponse(CloudEvent cloudEvent, StatusCode code, String message, EventEmitter emitter) { + Instant instant = OffsetDateTime.now().toInstant(); + CloudEvent.Builder builder = CloudEvent.newBuilder(cloudEvent) + .putAttributes(ProtocolKey.GRPC_RESPONSE_CODE, CloudEventAttributeValue.newBuilder().setCeString(code.getRetCode()).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_MESSAGE, + CloudEventAttributeValue.newBuilder().setCeString(StringUtils.isEmpty(message) ? code.getErrMsg() : message).build()) + .putAttributes(ProtocolKey.GRPC_RESPONSE_TIME, CloudEventAttributeValue.newBuilder() + .setCeTimestamp(Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build()).build()); + + emitter.onNext(builder.build()); + } + + /** + * Returns the current instant. + * + * @return The current instant + */ + private static Instant now() { + return OffsetDateTime.of(LocalDateTime.now(ZoneId.systemDefault()), ZoneOffset.UTC).toInstant(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/async/CompleteHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/async/CompleteHandler.java index 49eeaaf585..98f99744c8 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/async/CompleteHandler.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/async/CompleteHandler.java @@ -23,5 +23,6 @@ * @param */ public interface CompleteHandler { + void onResponse(T t); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerGroupManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerGroupManager.java index 7d4ddab9bd..cca28c72f2 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerGroupManager.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerGroupManager.java @@ -29,31 +29,36 @@ public class ConsumerGroupManager { - protected AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); + private final AtomicBoolean started = new AtomicBoolean(false); - protected AtomicBoolean inited = new AtomicBoolean(Boolean.FALSE); + private final AtomicBoolean inited = new AtomicBoolean(false); - private EventMeshHTTPServer eventMeshHTTPServer; + private final EventMeshHTTPServer eventMeshHTTPServer; - private EventMeshConsumer eventMeshConsumer; + private final EventMeshConsumer eventMeshConsumer; private ConsumerGroupConf consumerGroupConfig; - public ConsumerGroupManager(EventMeshHTTPServer eventMeshHTTPServer, ConsumerGroupConf consumerGroupConfig) { + public ConsumerGroupManager(final EventMeshHTTPServer eventMeshHTTPServer, final ConsumerGroupConf consumerGroupConfig) { this.eventMeshHTTPServer = eventMeshHTTPServer; this.consumerGroupConfig = consumerGroupConfig; - eventMeshConsumer = new EventMeshConsumer(this.eventMeshHTTPServer, this.consumerGroupConfig); + this.eventMeshConsumer = new EventMeshConsumer(this.eventMeshHTTPServer, this.consumerGroupConfig); } - public synchronized void init() throws Exception { + public void init() throws Exception { + if (!inited.compareAndSet(false, true)) { + return; + } eventMeshConsumer.init(); - inited.compareAndSet(false, true); + } - public synchronized void start() throws Exception { + public void start() throws Exception { + if (!started.compareAndSet(false, true)) { + return; + } setupEventMeshConsumer(consumerGroupConfig); eventMeshConsumer.start(); - started.compareAndSet(false, true); } private synchronized void setupEventMeshConsumer(ConsumerGroupConf consumerGroupConfig) throws Exception { @@ -62,12 +67,14 @@ private synchronized void setupEventMeshConsumer(ConsumerGroupConf consumerGroup } } - public synchronized void shutdown() throws Exception { + public void shutdown() throws Exception { + if (!started.compareAndSet(true, false)) { + return; + } eventMeshConsumer.shutdown(); - started.compareAndSet(true, false); } - public synchronized void refresh(ConsumerGroupConf consumerGroupConfig) throws Exception { + public synchronized void refresh(final ConsumerGroupConf consumerGroupConfig) throws Exception { if (consumerGroupConfig == null || this.consumerGroupConfig.equals(consumerGroupConfig)) { return; @@ -78,6 +85,7 @@ public synchronized void refresh(ConsumerGroupConf consumerGroupConfig) throws E } this.consumerGroupConfig = consumerGroupConfig; + this.eventMeshConsumer.setConsumerGroupConf(consumerGroupConfig); init(); start(); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerManager.java index 3e22d3078b..e60f1687ac 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerManager.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/ConsumerManager.java @@ -20,190 +20,69 @@ import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; import org.apache.eventmesh.runtime.core.consumergroup.event.ConsumerGroupStateEvent; import org.apache.eventmesh.runtime.core.consumergroup.event.ConsumerGroupTopicConfChangeEvent; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; import org.apache.eventmesh.runtime.util.EventMeshUtil; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.common.eventbus.Subscribe; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class ConsumerManager { - private EventMeshHTTPServer eventMeshHTTPServer; + private final EventMeshHTTPServer eventMeshHTTPServer; /** * consumerGroup to ConsumerGroupManager. */ - private ConcurrentHashMap consumerTable = - new ConcurrentHashMap<>(); - - private static final int DEFAULT_UPDATE_TIME = 3 * 30 * 1000; - - public Logger logger = LoggerFactory.getLogger(this.getClass()); + private ConcurrentHashMap consumerTable = new ConcurrentHashMap<>(64); - private ScheduledExecutorService scheduledExecutorService = - Executors.newSingleThreadScheduledExecutor(); - - public ConsumerManager(EventMeshHTTPServer eventMeshHTTPServer) { + public ConsumerManager(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; } public void init() throws Exception { eventMeshHTTPServer.getEventBus().register(this); - logger.info("consumerManager inited......"); + log.info("consumerManager inited......"); } public void start() throws Exception { - logger.info("consumerManager started......"); - - // scheduledExecutorService.scheduleAtFixedRate(() -> { - // logger.info("clientInfo check start....."); - // synchronized (eventMeshHTTPServer.localClientInfoMapping) { - // Map> clientInfoMap = - // eventMeshHTTPServer.localClientInfoMapping; - // if (clientInfoMap.size() > 0) { - // for (String key : clientInfoMap.keySet()) { - // String consumerGroup = key.split("@")[0]; - // String topic = key.split("@")[1]; - // List clientList = clientInfoMap.get(key); - // Iterator clientIterator = clientList.iterator(); - // boolean isChange = false; - // while (clientIterator.hasNext()) { - // Client client = clientIterator.next(); - // //The time difference is greater than 3 heartbeat cycles - // if (System.currentTimeMillis() - client.lastUpTime.getTime() - // > DEFAULT_UPDATE_TIME) { - // logger.warn( - // "client {} lastUpdate time {} over three heartbeat cycles", - // JsonUtils.serialize(client), client.lastUpTime); - // clientIterator.remove(); - // isChange = true; - // } - // } - // if (isChange) { - // if (clientList.size() > 0) { - // //change url - // logger.info("consumerGroup {} client info changing", - // consumerGroup); - // Map> idcUrls = new HashMap<>(); - // Set clientUrls = new HashSet<>(); - // for (Client client : clientList) { - // clientUrls.add(client.url); - // if (idcUrls.containsKey(client.idc)) { - // idcUrls.get(client.idc) - // .add(StringUtils.deleteWhitespace(client.url)); - // } else { - // List urls = new ArrayList<>(); - // urls.add(client.url); - // idcUrls.put(client.idc, urls); - // } - // } - // synchronized (eventMeshHTTPServer.localConsumerGroupMapping) { - // ConsumerGroupConf consumerGroupConf = - // eventMeshHTTPServer.localConsumerGroupMapping - // .get(consumerGroup); - // Map map = - // consumerGroupConf.getConsumerGroupTopicConf(); - // for (String topicKey : map.keySet()) { - // if (StringUtils.equals(topic, topicKey)) { - // ConsumerGroupTopicConf latestTopicConf = - // new ConsumerGroupTopicConf(); - // latestTopicConf.setConsumerGroup(consumerGroup); - // latestTopicConf.setTopic(topic); - // latestTopicConf.setSubscriptionItem( - // map.get(topicKey).getSubscriptionItem()); - // latestTopicConf.setUrls(clientUrls); - // - // latestTopicConf.setIdcUrls(idcUrls); - // - // map.put(topic, latestTopicConf); - // } - // } - // eventMeshHTTPServer.localConsumerGroupMapping - // .put(consumerGroup, consumerGroupConf); - // logger.info( - // "consumerGroup {} client info changed, " - // + "consumerGroupConf {}", consumerGroup, - // JsonUtils.serialize(consumerGroupConf)); - // - // try { - // notifyConsumerManager(consumerGroup, consumerGroupConf); - // } catch (Exception e) { - // logger.error("notifyConsumerManager error", e); - // } - // } - // - // } else { - // logger.info("consumerGroup {} client info removed", - // consumerGroup); - // //remove - // try { - // notifyConsumerManager(consumerGroup, null); - // } catch (Exception e) { - // logger.error("notifyConsumerManager error", e); - // } - // - // eventMeshHTTPServer.localConsumerGroupMapping.keySet() - // .removeIf(s -> StringUtils.equals(consumerGroup, s)); - // } - // } - // - // } - // } - // } - // }, 10000, 10000, TimeUnit.MILLISECONDS); - //TODO: update the subscription periodically from registry + log.info("consumerManager started......"); } /** * notify ConsumerManager groupLevel */ - public void notifyConsumerManager(String consumerGroup, - ConsumerGroupConf latestConsumerGroupConfig) - throws Exception { - ConsumerGroupManager cgm = - eventMeshHTTPServer.getConsumerManager().getConsumer(consumerGroup); + public void notifyConsumerManager(String consumerGroup, ConsumerGroupConf latestConsumerGroupConfig) throws Exception { + + ConsumerGroupManager cgm = eventMeshHTTPServer.getConsumerManager().getConsumer(consumerGroup); + if (latestConsumerGroupConfig == null) { ConsumerGroupStateEvent notification = new ConsumerGroupStateEvent(); - notification.action = ConsumerGroupStateEvent.ConsumerGroupStateAction.DELETE; - notification.consumerGroup = consumerGroup; + notification.setAction(ConsumerGroupStateEvent.ConsumerGroupStateAction.DELETE); + notification.setConsumerGroup(consumerGroup); eventMeshHTTPServer.getEventBus().post(notification); return; } if (cgm == null) { ConsumerGroupStateEvent notification = new ConsumerGroupStateEvent(); - notification.action = ConsumerGroupStateEvent.ConsumerGroupStateAction.NEW; - notification.consumerGroup = consumerGroup; - notification.consumerGroupConfig = EventMeshUtil.cloneObject(latestConsumerGroupConfig); + notification.setAction(ConsumerGroupStateEvent.ConsumerGroupStateAction.NEW); + notification.setConsumerGroup(consumerGroup); + notification.setConsumerGroupConfig(EventMeshUtil.cloneObject(latestConsumerGroupConfig)); eventMeshHTTPServer.getEventBus().post(notification); return; } if (!latestConsumerGroupConfig.equals(cgm.getConsumerGroupConfig())) { ConsumerGroupStateEvent notification = new ConsumerGroupStateEvent(); - notification.action = ConsumerGroupStateEvent.ConsumerGroupStateAction.CHANGE; - notification.consumerGroup = consumerGroup; - notification.consumerGroupConfig = EventMeshUtil.cloneObject(latestConsumerGroupConfig); + notification.setAction(ConsumerGroupStateEvent.ConsumerGroupStateAction.CHANGE); + notification.setConsumerGroup(consumerGroup); + notification.setConsumerGroupConfig(EventMeshUtil.cloneObject(latestConsumerGroupConfig)); eventMeshHTTPServer.getEventBus().post(notification); return; } @@ -215,10 +94,10 @@ public void shutdown() { try { consumerGroupManager.shutdown(); } catch (Exception ex) { - logger.error("shutdown consumerGroupManager[{}] err", consumerGroupManager, ex); + log.error("shutdown consumerGroupManager[{}] err", consumerGroupManager, ex); } } - logger.info("consumerManager shutdown......"); + log.info("consumerManager shutdown......"); } public boolean contains(String consumerGroup) { @@ -232,10 +111,8 @@ public boolean contains(String consumerGroup) { * @param consumerGroupConfig * @throws Exception */ - public synchronized void addConsumer(String consumerGroup, - ConsumerGroupConf consumerGroupConfig) throws Exception { - ConsumerGroupManager cgm = - new ConsumerGroupManager(eventMeshHTTPServer, consumerGroupConfig); + public synchronized void addConsumer(String consumerGroup, ConsumerGroupConf consumerGroupConfig) throws Exception { + ConsumerGroupManager cgm = new ConsumerGroupManager(eventMeshHTTPServer, consumerGroupConfig); cgm.init(); cgm.start(); consumerTable.put(consumerGroup, cgm); @@ -244,9 +121,7 @@ public synchronized void addConsumer(String consumerGroup, /** * restart consumer */ - public synchronized void restartConsumer(String consumerGroup, - ConsumerGroupConf consumerGroupConfig) - throws Exception { + public synchronized void restartConsumer(String consumerGroup, ConsumerGroupConf consumerGroupConfig) throws Exception { if (consumerTable.containsKey(consumerGroup)) { ConsumerGroupManager cgm = consumerTable.get(consumerGroup); cgm.refresh(consumerGroupConfig); @@ -256,9 +131,8 @@ public synchronized void restartConsumer(String consumerGroup, /** * get consumer */ - public ConsumerGroupManager getConsumer(String consumerGroup) throws Exception { - ConsumerGroupManager cgm = consumerTable.get(consumerGroup); - return cgm; + public ConsumerGroupManager getConsumer(String consumerGroup) { + return consumerTable.get(consumerGroup); } /** @@ -267,77 +141,77 @@ public ConsumerGroupManager getConsumer(String consumerGroup) throws Exception { * @param consumerGroup */ public synchronized void delConsumer(String consumerGroup) throws Exception { - logger.info("start delConsumer with consumerGroup {}", consumerGroup); + log.info("start delConsumer with consumerGroup {}", consumerGroup); if (consumerTable.containsKey(consumerGroup)) { ConsumerGroupManager cgm = consumerTable.remove(consumerGroup); - logger.info("start unsubscribe topic with consumer group manager {}", - JsonUtils.serialize(cgm)); + log.info("start unsubscribe topic with consumer group manager {}", JsonUtils.toJSONString(cgm)); cgm.unsubscribe(consumerGroup); cgm.shutdown(); } - logger.info("end delConsumer with consumerGroup {}", consumerGroup); + log.info("end delConsumer with consumerGroup {}", consumerGroup); } @Subscribe - public void onChange(ConsumerGroupTopicConfChangeEvent event) { + public void handleConsumerGroupTopicConfChangeEvent(ConsumerGroupTopicConfChangeEvent event) { try { - logger.info("onChange event:{}", event); - if (event.action - == ConsumerGroupTopicConfChangeEvent.ConsumerGroupTopicConfChangeAction.NEW) { - ConsumerGroupManager manager = getConsumer(event.consumerGroup); - if (Objects.isNull(manager)) { - return; + log.info("onChange event:{}", event); + switch (event.getAction()) { + case NEW: { + ConsumerGroupManager manager = getConsumer(event.getConsumerGroup()); + if (Objects.isNull(manager)) { + return; + } + manager.getConsumerGroupConfig().getConsumerGroupTopicConf().put(event.getTopic(), event.getNewTopicConf()); + break; } - manager.getConsumerGroupConfig().getConsumerGroupTopicConf() - .put(event.topic, event.newTopicConf); - return; - } - - if (event.action - == ConsumerGroupTopicConfChangeEvent.ConsumerGroupTopicConfChangeAction.CHANGE) { - ConsumerGroupManager manager = getConsumer(event.consumerGroup); - if (Objects.isNull(manager)) { - return; + case CHANGE: { + ConsumerGroupManager manager = getConsumer(event.getConsumerGroup()); + if (Objects.isNull(manager)) { + return; + } + manager.getConsumerGroupConfig().getConsumerGroupTopicConf().replace(event.getTopic(), event.getNewTopicConf()); + break; } - manager.getConsumerGroupConfig().getConsumerGroupTopicConf() - .replace(event.topic, event.newTopicConf); - return; - } - - if (event.action - == ConsumerGroupTopicConfChangeEvent.ConsumerGroupTopicConfChangeAction.DELETE) { - ConsumerGroupManager manager = getConsumer(event.consumerGroup); - if (Objects.isNull(manager)) { - return; + case DELETE: { + ConsumerGroupManager manager = getConsumer(event.getConsumerGroup()); + if (Objects.isNull(manager)) { + return; + } + manager.getConsumerGroupConfig().getConsumerGroupTopicConf().remove(event.getTopic()); + break; } - manager.getConsumerGroupConfig().getConsumerGroupTopicConf().remove(event.topic); - return; + default: + // do nothing } } catch (Exception ex) { - logger.error("onChange event:{} err", event, ex); + log.error("onChange event:{} err", event, ex); } } @Subscribe - public void onChange(ConsumerGroupStateEvent event) { + public void handleConsumerGroupStateEvent(ConsumerGroupStateEvent event) { try { - logger.info("onChange event:{}", event); - if (event.action == ConsumerGroupStateEvent.ConsumerGroupStateAction.NEW) { - addConsumer(event.consumerGroup, event.consumerGroupConfig); - return; - } - - if (event.action == ConsumerGroupStateEvent.ConsumerGroupStateAction.CHANGE) { - restartConsumer(event.consumerGroup, event.consumerGroupConfig); - return; - } - - if (event.action == ConsumerGroupStateEvent.ConsumerGroupStateAction.DELETE) { - delConsumer(event.consumerGroup); - return; + log.info("onChange event:{}", event); + + switch (event.getAction()) { + case NEW: + addConsumer(event.getConsumerGroup(), event.getConsumerGroupConfig()); + break; + case CHANGE: + restartConsumer(event.getConsumerGroup(), event.getConsumerGroupConfig()); + break; + case DELETE: + delConsumer(event.getConsumerGroup()); + break; + default: + // do nothing } } catch (Exception ex) { - logger.error("onChange event:{} err", event, ex); + log.error("onChange event:{} err", event, ex); } } + + public ConcurrentHashMap getClientTable() { + return consumerTable; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/EventMeshConsumer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/EventMeshConsumer.java index 0af8095274..1f6b974b31 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/EventMeshConsumer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/EventMeshConsumer.java @@ -17,34 +17,41 @@ package org.apache.eventmesh.runtime.core.protocol.http.consumer; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.CONSUMER_GROUP; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.EVENT_MESH_IDC; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.INSTANCE_NAME; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.IS_BROADCAST; + import org.apache.eventmesh.api.AbstractContext; -import org.apache.eventmesh.api.AsyncConsumeContext; import org.apache.eventmesh.api.EventListener; import org.apache.eventmesh.api.EventMeshAction; import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.TopicNameHelper; import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; import org.apache.eventmesh.runtime.core.plugin.MQConsumerWrapper; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; import org.apache.eventmesh.runtime.core.protocol.http.push.HTTPMessageHandler; import org.apache.eventmesh.runtime.core.protocol.http.push.MessageHandler; -import org.apache.eventmesh.runtime.trace.TraceUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.TraceUtils; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; import org.apache.commons.collections4.MapUtils; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; @@ -54,35 +61,35 @@ import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Scope; -public class EventMeshConsumer { +import lombok.extern.slf4j.Slf4j; - private EventMeshHTTPServer eventMeshHTTPServer; +@Slf4j +public class EventMeshConsumer { - private AtomicBoolean started4Persistent = new AtomicBoolean(Boolean.FALSE); + public static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - private AtomicBoolean started4Broadcast = new AtomicBoolean(Boolean.FALSE); + private final EventMeshHTTPServer eventMeshHTTPServer; - private AtomicBoolean inited4Persistent = new AtomicBoolean(Boolean.FALSE); + private final AtomicBoolean started4Persistent = new AtomicBoolean(Boolean.FALSE); - private AtomicBoolean inited4Broadcast = new AtomicBoolean(Boolean.FALSE); + private final AtomicBoolean started4Broadcast = new AtomicBoolean(Boolean.FALSE); - public Logger logger = LoggerFactory.getLogger(this.getClass()); + private final AtomicBoolean inited4Persistent = new AtomicBoolean(Boolean.FALSE); - public Logger messageLogger = LoggerFactory.getLogger("message"); + private final AtomicBoolean inited4Broadcast = new AtomicBoolean(Boolean.FALSE); private ConsumerGroupConf consumerGroupConf; - private MQConsumerWrapper persistentMqConsumer; + private final MQConsumerWrapper persistentMqConsumer; - private MQConsumerWrapper broadcastMqConsumer; + private final MQConsumerWrapper broadcastMqConsumer; public EventMeshConsumer(EventMeshHTTPServer eventMeshHTTPServer, ConsumerGroupConf consumerGroupConf) { this.eventMeshHTTPServer = eventMeshHTTPServer; this.consumerGroupConf = consumerGroupConf; - this.persistentMqConsumer = new MQConsumerWrapper(eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshConnectorPluginType); - this.broadcastMqConsumer = new MQConsumerWrapper(eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshConnectorPluginType); + this.persistentMqConsumer = new MQConsumerWrapper(eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshStoragePluginType()); + this.broadcastMqConsumer = new MQConsumerWrapper(eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshStoragePluginType()); } private MessageHandler httpMessageHandler; @@ -90,165 +97,173 @@ public EventMeshConsumer(EventMeshHTTPServer eventMeshHTTPServer, ConsumerGroupC public synchronized void init() throws Exception { httpMessageHandler = new HTTPMessageHandler(this); Properties keyValue = new Properties(); - keyValue.put("isBroadcast", "false"); - keyValue.put("consumerGroup", consumerGroupConf.getConsumerGroup()); - keyValue.put("eventMeshIDC", eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - keyValue.put("instanceName", EventMeshUtil.buildMeshClientID(consumerGroupConf.getConsumerGroup(), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster)); + keyValue.put(IS_BROADCAST, "false"); + keyValue.put(CONSUMER_GROUP, consumerGroupConf.getConsumerGroup()); + keyValue.put(EVENT_MESH_IDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); + keyValue.put(INSTANCE_NAME, EventMeshUtil.buildMeshClientID(consumerGroupConf.getConsumerGroup(), + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster())); persistentMqConsumer.init(keyValue); - EventListener clusterEventListener = new EventListener() { - @Override - public void consume(CloudEvent event, AsyncConsumeContext context) { - String protocolVersion = - Objects.requireNonNull(event.getSpecVersion()).toString(); - - Span span = TraceUtils.prepareServerSpan( - EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), - EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_SERVER_SPAN, false); - try { - String topic = event.getSubject(); - String bizSeqNo = (String) event.getExtension(Constants.PROPERTY_MESSAGE_SEARCH_KEYS); - String uniqueId = (String) event.getExtension(Constants.RMB_UNIQ_ID); - - event = CloudEventBuilder.from(event) - .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) - .withExtension(EventMeshConstants.REQ_RECEIVE_EVENTMESH_IP, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerIp) - .build(); - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("message|mq2eventMesh|topic={}|event={}", topic, event); - } else { - messageLogger.info("message|mq2eventMesh|topic={}|bizSeqNo={}|uniqueId={}", topic, bizSeqNo, uniqueId); - } + EventListener clusterEventListener = (event, context) -> { + String protocolVersion = + Objects.requireNonNull(event.getSpecVersion()).toString(); + + Span span = TraceUtils.prepareServerSpan( + EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), + EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_SERVER_SPAN, false); + try { + Optional topicNameHelper = + Optional.ofNullable(EventMeshExtensionFactory.getExtension(TopicNameHelper.class, + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshStoragePluginType())); + String topic = event.getSubject(); + String bizSeqNo = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey())).toString(); + String uniqueId = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey())).toString(); + + event = CloudEventBuilder.from(event) + .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) + .withExtension(EventMeshConstants.REQ_RECEIVE_EVENTMESH_IP, + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshServerIp()) + .build(); + if (MESSAGE_LOGGER.isDebugEnabled()) { + MESSAGE_LOGGER.debug("message|mq2eventMesh|topic={}|event={}", topic, event); + } else { + MESSAGE_LOGGER.info("message|mq2eventMesh|topic={}|bizSeqNo={}|uniqueId={}", topic, bizSeqNo, uniqueId); + } - ConsumerGroupTopicConf currentTopicConfig = MapUtils.getObject(consumerGroupConf.getConsumerGroupTopicConf(), - topic, null); - EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = (EventMeshAsyncConsumeContext) context; - - if (currentTopicConfig == null) { - logger.error("no topicConfig found, consumerGroup:{} topic:{}", consumerGroupConf.getConsumerGroup(), topic); - try { - sendMessageBack(event, uniqueId, bizSeqNo); - eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); - return; - } catch (Exception ex) { - //ignore - } + if (topicNameHelper.isPresent() && topicNameHelper.get().isRetryTopic(topic)) { + topic = String.valueOf(event.getExtension(ProtocolKey.TOPIC)); + } + ConsumerGroupTopicConf currentTopicConfig = MapUtils.getObject(consumerGroupConf.getConsumerGroupTopicConf(), + topic, null); + EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = (EventMeshAsyncConsumeContext) context; + + if (currentTopicConfig == null) { + try { + sendMessageBack(event, uniqueId, bizSeqNo); + log.warn("no ConsumerGroupTopicConf found, sendMessageBack success, consumerGroup:{}, topic:{}, bizSeqNo={}, uniqueId={}", + consumerGroupConf.getConsumerGroup(), topic, bizSeqNo, uniqueId); + } catch (Exception ex) { + log.warn("sendMessageBack fail, consumerGroup:{}, topic:{}, bizSeqNo={}, uniqueId={}", + consumerGroupConf.getConsumerGroup(), topic, bizSeqNo, uniqueId, ex); } + eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); + return; + } - SubscriptionItem subscriptionItem = consumerGroupConf.getConsumerGroupTopicConf().get(topic).getSubscriptionItem(); - HandleMsgContext handleMsgContext = new HandleMsgContext(EventMeshUtil.buildPushMsgSeqNo(), - consumerGroupConf.getConsumerGroup(), EventMeshConsumer.this, - topic, event, subscriptionItem, eventMeshAsyncConsumeContext.getAbstractContext(), - consumerGroupConf, eventMeshHTTPServer, bizSeqNo, uniqueId, currentTopicConfig); - - if (httpMessageHandler.handle(handleMsgContext)) { - eventMeshAsyncConsumeContext.commit(EventMeshAction.ManualAck); - } else { - try { - sendMessageBack(event, uniqueId, bizSeqNo); - } catch (Exception e) { - //ignore - } - eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); + SubscriptionItem subscriptionItem = + consumerGroupConf.getConsumerGroupTopicConf().get(topic).getSubscriptionItem(); + HandleMsgContext handleMsgContext = new HandleMsgContext( + EventMeshUtil.buildPushMsgSeqNo(), + consumerGroupConf.getConsumerGroup(), + EventMeshConsumer.this, + topic, event, subscriptionItem, eventMeshAsyncConsumeContext.getAbstractContext(), + consumerGroupConf, eventMeshHTTPServer, bizSeqNo, uniqueId, currentTopicConfig); + + if (httpMessageHandler.handle(handleMsgContext)) { + eventMeshAsyncConsumeContext.commit(EventMeshAction.ManualAck); + } else { + try { + sendMessageBack(event, uniqueId, bizSeqNo); + } catch (Exception e) { + // ignore + log.warn("sendMessageBack fail,topic:{}, bizSeqNo={}, uniqueId={}", topic, bizSeqNo, uniqueId, e); } - } finally { - TraceUtils.finishSpan(span, event); + eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); } + } finally { + TraceUtils.finishSpan(span, event); } }; persistentMqConsumer.registerEventListener(clusterEventListener); - //broacast consumer + // broadcast consumer Properties broadcastKeyValue = new Properties(); - broadcastKeyValue.put("isBroadcast", "true"); - broadcastKeyValue.put("consumerGroup", consumerGroupConf.getConsumerGroup()); - broadcastKeyValue.put("eventMeshIDC", eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - broadcastKeyValue.put("instanceName", EventMeshUtil.buildMeshClientID(consumerGroupConf.getConsumerGroup(), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster)); + broadcastKeyValue.put(IS_BROADCAST, "true"); + broadcastKeyValue.put(CONSUMER_GROUP, consumerGroupConf.getConsumerGroup()); + broadcastKeyValue.put(EVENT_MESH_IDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); + broadcastKeyValue.put(INSTANCE_NAME, EventMeshUtil.buildMeshClientID(consumerGroupConf.getConsumerGroup(), + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster())); broadcastMqConsumer.init(broadcastKeyValue); - EventListener broadcastEventListener = new EventListener() { - @Override - public void consume(CloudEvent event, AsyncConsumeContext context) { - - String protocolVersion = - Objects.requireNonNull(event.getSpecVersion()).toString(); - - Span span = TraceUtils.prepareServerSpan( - EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), - EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_SERVER_SPAN, false); - try { - - event = CloudEventBuilder.from(event) - .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, - String.valueOf(System.currentTimeMillis())) - .withExtension(EventMeshConstants.REQ_RECEIVE_EVENTMESH_IP, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerIp) - .build(); - - String topic = event.getSubject(); - String bizSeqNo = - event.getExtension(Constants.PROPERTY_MESSAGE_SEARCH_KEYS).toString(); - String uniqueId = event.getExtension(Constants.RMB_UNIQ_ID).toString(); - - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("message|mq2eventMesh|topic={}|msg={}", topic, event); - } else { - messageLogger.info("message|mq2eventMesh|topic={}|bizSeqNo={}|uniqueId={}", - topic, bizSeqNo, - uniqueId); - } + EventListener broadcastEventListener = (event, context) -> { - ConsumerGroupTopicConf currentTopicConfig = MapUtils.getObject( - consumerGroupConf.getConsumerGroupTopicConf(), topic, null); - EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = - (EventMeshAsyncConsumeContext) context; - - if (currentTopicConfig == null) { - logger.error("no topicConfig found, consumerGroup:{} topic:{}", - consumerGroupConf.getConsumerGroup(), topic); - try { - sendMessageBack(event, uniqueId, bizSeqNo); - eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); - return; - } catch (Exception ex) { - //ignore - } - } + String protocolVersion = + Objects.requireNonNull(event.getSpecVersion()).toString(); + + Span span = TraceUtils.prepareServerSpan( + EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), + EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_SERVER_SPAN, false); + try { + + event = CloudEventBuilder.from(event) + .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, + String.valueOf(System.currentTimeMillis())) + .withExtension(EventMeshConstants.REQ_RECEIVE_EVENTMESH_IP, + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshServerIp()) + .build(); - SubscriptionItem subscriptionItem = - consumerGroupConf.getConsumerGroupTopicConf().get(topic) - .getSubscriptionItem(); - HandleMsgContext handleMsgContext = - new HandleMsgContext(EventMeshUtil.buildPushMsgSeqNo(), - consumerGroupConf.getConsumerGroup(), EventMeshConsumer.this, - topic, event, subscriptionItem, - eventMeshAsyncConsumeContext.getAbstractContext(), - consumerGroupConf, eventMeshHTTPServer, bizSeqNo, uniqueId, - currentTopicConfig); - - if (httpMessageHandler.handle(handleMsgContext)) { - eventMeshAsyncConsumeContext.commit(EventMeshAction.ManualAck); - } else { - try { - sendMessageBack(event, uniqueId, bizSeqNo); - } catch (Exception e) { - //ignore - } + String topic = event.getSubject(); + String bizSeqNo = getEventExtension(event, ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey()); + String uniqueId = getEventExtension(event, ProtocolKey.ClientInstanceKey.UNIQUEID.getKey()); + + if (MESSAGE_LOGGER.isDebugEnabled()) { + MESSAGE_LOGGER.debug("message|mq2eventMesh|topic={}|msg={}", topic, event); + } else { + MESSAGE_LOGGER.info("message|mq2eventMesh|topic={}|bizSeqNo={}|uniqueId={}", topic, bizSeqNo, uniqueId); + } + + ConsumerGroupTopicConf currentTopicConfig = MapUtils.getObject( + consumerGroupConf.getConsumerGroupTopicConf(), topic, null); + EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = + (EventMeshAsyncConsumeContext) context; + + if (currentTopicConfig == null) { + log.error("no topicConfig found, consumerGroup:{} topic:{}", + consumerGroupConf.getConsumerGroup(), topic); + try { + sendMessageBack(event, uniqueId, bizSeqNo); eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); + return; + } catch (Exception ex) { + // ignore + } + } + + SubscriptionItem subscriptionItem = + consumerGroupConf.getConsumerGroupTopicConf().get(topic) + .getSubscriptionItem(); + HandleMsgContext handleMsgContext = + new HandleMsgContext(EventMeshUtil.buildPushMsgSeqNo(), + consumerGroupConf.getConsumerGroup(), EventMeshConsumer.this, + topic, event, subscriptionItem, + eventMeshAsyncConsumeContext.getAbstractContext(), + consumerGroupConf, eventMeshHTTPServer, bizSeqNo, uniqueId, + currentTopicConfig); + + if (httpMessageHandler.handle(handleMsgContext)) { + eventMeshAsyncConsumeContext.commit(EventMeshAction.ManualAck); + } else { + try { + sendMessageBack(event, uniqueId, bizSeqNo); + } catch (Exception e) { + // ignore } - } finally { - TraceUtils.finishSpan(span, event); + eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); } + } finally { + TraceUtils.finishSpan(span, event); } }; broadcastMqConsumer.registerEventListener(broadcastEventListener); inited4Persistent.compareAndSet(false, true); inited4Broadcast.compareAndSet(false, true); - logger.info("EventMeshConsumer [{}] inited.............", consumerGroupConf.getConsumerGroup()); + log.info("EventMeshConsumer [{}] inited.............", consumerGroupConf.getConsumerGroup()); + } + + private String getEventExtension(CloudEvent event, String protocolKey) { + Object extension = event.getExtension(protocolKey); + return Objects.isNull(extension) ? "" : extension.toString(); } public synchronized void start() throws Exception { @@ -259,7 +274,7 @@ public synchronized void start() throws Exception { } public void subscribe(String topic, SubscriptionItem subscriptionItem) throws Exception { - if (!SubscriptionMode.BROADCASTING.equals(subscriptionItem.getMode())) { + if (SubscriptionMode.BROADCASTING != subscriptionItem.getMode()) { persistentMqConsumer.subscribe(topic); } else { broadcastMqConsumer.subscribe(topic); @@ -267,7 +282,7 @@ public void subscribe(String topic, SubscriptionItem subscriptionItem) throws Ex } public void unsubscribe(String topic, SubscriptionMode subscriptionMode) throws Exception { - if (SubscriptionMode.BROADCASTING.equals(subscriptionMode)) { + if (SubscriptionMode.BROADCASTING == subscriptionMode) { broadcastMqConsumer.unsubscribe(topic); } else { persistentMqConsumer.unsubscribe(topic); @@ -282,8 +297,8 @@ public synchronized void shutdown() throws Exception { } public void updateOffset(String topic, SubscriptionMode subscriptionMode, List events, - AbstractContext context) { - if (SubscriptionMode.BROADCASTING.equals(subscriptionMode)) { + AbstractContext context) { + if (SubscriptionMode.BROADCASTING == subscriptionMode) { broadcastMqConsumer.updateOffset(events, context); } else { persistentMqConsumer.updateOffset(events, context); @@ -294,17 +309,20 @@ public ConsumerGroupConf getConsumerGroupConf() { return consumerGroupConf; } + public void setConsumerGroupConf(ConsumerGroupConf consumerGroupConf) { + this.consumerGroupConf = consumerGroupConf; + } + public EventMeshHTTPServer getEventMeshHTTPServer() { return eventMeshHTTPServer; } public void sendMessageBack(final CloudEvent event, final String uniqueId, String bizSeqNo) throws Exception { - EventMeshProducer sendMessageBack - = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(consumerGroupConf.getConsumerGroup()); + EventMeshProducer sendMessageBack = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(consumerGroupConf.getConsumerGroup()); if (sendMessageBack == null) { - logger.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", + log.warn("consumer:{} consume fail, sendMessageBack, bizSeqNo:{}, uniqueId:{}", consumerGroupConf.getConsumerGroup(), bizSeqNo, uniqueId); return; } @@ -313,13 +331,14 @@ public void sendMessageBack(final CloudEvent event, final String uniqueId, Strin eventMeshHTTPServer); sendMessageBack.send(sendMessageBackContext, new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { } @Override public void onException(OnExceptionContext context) { - logger.warn("consumer:{} consume fail, sendMessageBack, bizSeqno:{}, uniqueId:{}", + log.warn("consumer:{} consume fail, sendMessageBack, bizSeqno:{}, uniqueId:{}", consumerGroupConf.getConsumerGroup(), bizSeqNo, uniqueId); } }); diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HandleMsgContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HandleMsgContext.java index cf0ba7f642..c4046827a7 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HandleMsgContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HandleMsgContext.java @@ -24,22 +24,27 @@ import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; +import org.apache.eventmesh.runtime.core.protocol.consumer.HandleMessageContext; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.cloudevents.CloudEvent; -public class HandleMsgContext { +import lombok.extern.slf4j.Slf4j; - public Logger messageLogger = LoggerFactory.getLogger("message"); +@Slf4j +public class HandleMsgContext implements HandleMessageContext { + + public static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); private String msgRandomNo; @@ -65,16 +70,24 @@ public class HandleMsgContext { private ConsumerGroupConf consumerGroupConfig; - private EventMeshHTTPServer eventMeshHTTPServer; + private final transient EventMeshHTTPServer eventMeshHTTPServer; private ConsumerGroupTopicConf consumeTopicConfig; private Map props; - public HandleMsgContext(String msgRandomNo, String consumerGroup, EventMeshConsumer eventMeshConsumer, - String topic, CloudEvent event, SubscriptionItem subscriptionItem, - AbstractContext context, ConsumerGroupConf consumerGroupConfig, - EventMeshHTTPServer eventMeshHTTPServer, String bizSeqNo, String uniqueId, ConsumerGroupTopicConf consumeTopicConfig) { + public HandleMsgContext(final String msgRandomNo, + final String consumerGroup, + final EventMeshConsumer eventMeshConsumer, + final String topic, + final CloudEvent event, + final SubscriptionItem subscriptionItem, + final AbstractContext context, + final ConsumerGroupConf consumerGroupConfig, + final EventMeshHTTPServer eventMeshHTTPServer, + final String bizSeqNo, + final String uniqueId, + final ConsumerGroupTopicConf consumeTopicConfig) { this.msgRandomNo = msgRandomNo; this.consumerGroup = consumerGroup; this.eventMeshConsumer = eventMeshConsumer; @@ -88,18 +101,18 @@ public HandleMsgContext(String msgRandomNo, String consumerGroup, EventMeshConsu this.uniqueId = uniqueId; this.consumeTopicConfig = consumeTopicConfig; - String ttlStr = (String) event.getExtension(Constants.PROPERTY_MESSAGE_TIMEOUT); + final String ttlStr = (String) event.getExtension(Constants.PROPERTY_MESSAGE_TIMEOUT); this.ttl = StringUtils.isNumeric(ttlStr) ? Integer.parseInt(ttlStr) : EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS; } - public void addProp(String key, String val) { + public void addProp(final String key, final String val) { if (props == null) { props = new HashMap<>(); } props.put(key, val); } - public String getProp(String key) { + public String getProp(final String key) { return props.get(key); } @@ -107,7 +120,7 @@ public String getMsgRandomNo() { return msgRandomNo; } - public void setMsgRandomNo(String msgRandomNo) { + public void setMsgRandomNo(final String msgRandomNo) { this.msgRandomNo = msgRandomNo; } @@ -115,7 +128,7 @@ public ConsumerGroupTopicConf getConsumeTopicConfig() { return consumeTopicConfig; } - public void setConsumeTopicConfig(ConsumerGroupTopicConf consumeTopicConfig) { + public void setConsumeTopicConfig(final ConsumerGroupTopicConf consumeTopicConfig) { this.consumeTopicConfig = consumeTopicConfig; } @@ -123,7 +136,7 @@ public String getBizSeqNo() { return bizSeqNo; } - public void setBizSeqNo(String bizSeqNo) { + public void setBizSeqNo(final String bizSeqNo) { this.bizSeqNo = bizSeqNo; } @@ -131,7 +144,7 @@ public String getConsumerGroup() { return consumerGroup; } - public void setConsumerGroup(String consumerGroup) { + public void setConsumerGroup(final String consumerGroup) { this.consumerGroup = consumerGroup; } @@ -147,7 +160,7 @@ public String getTopic() { return topic; } - public void setTopic(String topic) { + public void setTopic(final String topic) { this.topic = topic; } @@ -155,7 +168,7 @@ public CloudEvent getEvent() { return event; } - public void setEvent(CloudEvent event) { + public void setEvent(final CloudEvent event) { this.event = event; } @@ -163,7 +176,7 @@ public SubscriptionItem getSubscriptionItem() { return subscriptionItem; } - public void setSubscriptionItem(SubscriptionItem subscriptionItem) { + public void setSubscriptionItem(final SubscriptionItem subscriptionItem) { this.subscriptionItem = subscriptionItem; } @@ -171,7 +184,7 @@ public long getCreateTime() { return createTime; } - public void setCreateTime(long createTime) { + public void setCreateTime(final long createTime) { this.createTime = createTime; } @@ -179,7 +192,7 @@ public AbstractContext getContext() { return context; } - public void setContext(AbstractContext context) { + public void setContext(final AbstractContext context) { this.context = context; } @@ -187,7 +200,7 @@ public ConsumerGroupConf getConsumerGroupConfig() { return consumerGroupConfig; } - public void setConsumerGroupConfig(ConsumerGroupConf consumerGroupConfig) { + public void setConsumerGroupConfig(final ConsumerGroupConf consumerGroupConfig) { this.consumerGroupConfig = consumerGroupConfig; } @@ -196,14 +209,11 @@ public EventMeshHTTPServer getEventMeshHTTPServer() { } public void finish() { - if (eventMeshConsumer != null && context != null && event != null) { - if (messageLogger.isDebugEnabled()) { - //messageLogger.debug("messageAcked|topic={}|msgId={}|cluster={}|broker={}|queueId={}|queueOffset={}", topic, - // msg.getMsgId(), msg.getProperty(DeFiBusConstant.PROPERTY_MESSAGE_CLUSTER), - // msg.getProperty(DeFiBusConstant.PROPERTY_MESSAGE_BROKER), - // msg.getQueueId(), msg.getQueueOffset()); - } - eventMeshConsumer.updateOffset(topic, subscriptionItem.getMode(), Arrays.asList(event), context); + if (Objects.nonNull(eventMeshConsumer) && Objects.nonNull(context) && Objects.nonNull(event)) { + MESSAGE_LOGGER.info("messageAcked|group={}|topic={}|bizSeq={}|uniqId={}|msgRandomNo={}|queueId={}|queueOffset={}", + consumerGroup, topic, bizSeqNo, uniqueId, msgRandomNo, event.getExtension(Constants.PROPERTY_MESSAGE_QUEUE_ID), + event.getExtension(Constants.PROPERTY_MESSAGE_QUEUE_OFFSET)); + eventMeshConsumer.updateOffset(topic, subscriptionItem.getMode(), Collections.singletonList(event), context); } } @@ -211,7 +221,7 @@ public String getUniqueId() { return uniqueId; } - public void setUniqueId(String uniqueId) { + public void setUniqueId(final String uniqueId) { this.uniqueId = uniqueId; } @@ -219,23 +229,32 @@ public int getTtl() { return ttl; } - public void setTtl(int ttl) { + public void setTtl(final int ttl) { this.ttl = ttl; } @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("handleMsgContext={") - .append("consumerGroup=").append(consumerGroup) - .append(",topic=").append(topic) - .append(",subscriptionItem=").append(subscriptionItem) - .append(",consumeTopicConfig=").append(consumeTopicConfig) - .append(",bizSeqNo=").append(bizSeqNo) - .append(",uniqueId=").append(uniqueId) - .append(",ttl=").append(ttl) - .append(",createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); - return sb.toString(); + return new StringBuilder() + .append("handleMsgContext={") + .append("consumerGroup=") + .append(consumerGroup) + .append(",topic=") + .append(topic) + .append(",subscriptionItem=") + .append(subscriptionItem) + .append(",consumeTopicConfig=") + .append(consumeTopicConfig) + .append(",bizSeqNo=") + .append(bizSeqNo) + .append(",uniqueId=") + .append(uniqueId) + .append(",ttl=") + .append(ttl) + .append(",createTime=") + .append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)) + .append('}') + .toString(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HttpClientGroupMapping.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HttpClientGroupMapping.java new file mode 100644 index 0000000000..004c9ee3b9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/consumer/HttpClientGroupMapping.java @@ -0,0 +1,433 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.consumer; + +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.http.header.client.SubscribeRequestHeader; +import org.apache.eventmesh.common.protocol.http.header.client.UnSubscribeRequestHeader; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupMetadata; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicMetadata; +import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public final class HttpClientGroupMapping { + + /** + * key: group + */ + private final transient Map localConsumerGroupMapping = + new ConcurrentHashMap<>(); + + /** + * key: group@topic + */ + private final transient Map> localClientInfoMapping = + new ConcurrentHashMap<>(); + + private final transient Set localTopicSet = new HashSet(16); + + private static final transient ReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock(); + + private HttpClientGroupMapping() { + + } + + private static class Singleton { + + private static final HttpClientGroupMapping INSTANCE = new HttpClientGroupMapping(); + } + + public static HttpClientGroupMapping getInstance() { + return Singleton.INSTANCE; + } + + public Set getLocalTopicSet() { + return localTopicSet; + } + + public Map> getLocalClientInfoMapping() { + return localClientInfoMapping; + } + + public ConsumerGroupConf getConsumerGroupConfByGroup(final String consumerGroup) { + return localConsumerGroupMapping.get(consumerGroup); + } + + public boolean addSubscription(final String consumerGroup, final String url, final String clientIdc, + final List subscriptionList) { + Objects.requireNonNull(url, "url can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(clientIdc, "clientIdc can not be null"); + Objects.requireNonNull(subscriptionList, "subscriptionList can not be null"); + + boolean isChange = false; + try { + READ_WRITE_LOCK.writeLock().lock(); + for (final SubscriptionItem subTopic : subscriptionList) { + isChange = isChange || addSubscriptionByTopic(consumerGroup, url, clientIdc, subTopic); + } + } finally { + READ_WRITE_LOCK.writeLock().unlock(); + } + return isChange; + } + + public boolean removeSubscription(final String consumerGroup, final String unSubscribeUrl, final String clientIdc, + final List unSubTopicList) { + Objects.requireNonNull(unSubTopicList, "unSubTopicList can not be null"); + + boolean isChange = false; + try { + READ_WRITE_LOCK.writeLock().lock(); + for (final String unSubTopic : unSubTopicList) { + isChange = isChange || removeSubscriptionByTopic(consumerGroup, unSubscribeUrl, clientIdc, unSubTopic); + } + } finally { + READ_WRITE_LOCK.writeLock().unlock(); + } + return isChange; + } + + public List querySubscription() { + + try { + READ_WRITE_LOCK.readLock().lock(); + + if (MapUtils.isEmpty(localConsumerGroupMapping)) { + return Collections.emptyList(); + } + final List consumerGroupTopicConfList = new ArrayList<>(); + + for (final ConsumerGroupConf consumerGroupConf : localConsumerGroupMapping.values()) { + if (MapUtils.isEmpty(consumerGroupConf.getConsumerGroupTopicConf())) { + continue; + } + consumerGroupTopicConfList.addAll(consumerGroupConf.getConsumerGroupTopicConf().values()); + } + return consumerGroupTopicConfList; + } finally { + READ_WRITE_LOCK.readLock().unlock(); + } + } + + public Map prepareMetaData() { + final Map metadata = new HashMap<>(1 << 4); + + try { + READ_WRITE_LOCK.readLock().lock(); + + for (final Map.Entry consumerGroupMap : localConsumerGroupMapping.entrySet()) { + final String consumerGroupKey = consumerGroupMap.getKey(); + final ConsumerGroupConf consumerGroupConf = consumerGroupMap.getValue(); + final ConsumerGroupMetadata consumerGroupMetadata = new ConsumerGroupMetadata(); + + consumerGroupMetadata.setConsumerGroup(consumerGroupKey); + + final Map consumerGroupTopicMetadataMap = + new HashMap<>(1 << 4); + for (final Map.Entry consumerGroupTopicConfEntry : consumerGroupConf.getConsumerGroupTopicConf() + .entrySet()) { + final ConsumerGroupTopicConf consumerGroupTopicConf = consumerGroupTopicConfEntry.getValue(); + final ConsumerGroupTopicMetadata consumerGroupTopicMetadata = new ConsumerGroupTopicMetadata(); + consumerGroupTopicMetadata.setConsumerGroup(consumerGroupTopicConf.getConsumerGroup()); + consumerGroupTopicMetadata.setTopic(consumerGroupTopicConf.getTopic()); + consumerGroupTopicMetadata.setUrls(consumerGroupTopicConf.getUrls()); + consumerGroupTopicMetadataMap.put(consumerGroupTopicConfEntry.getKey(), consumerGroupTopicMetadata); + } + consumerGroupMetadata.setConsumerGroupTopicMetadataMap(consumerGroupTopicMetadataMap); + metadata.put(consumerGroupKey, JsonUtils.toJSONString(consumerGroupMetadata)); + } + } finally { + READ_WRITE_LOCK.readLock().unlock(); + } + + metadata.put("topicSet", JsonUtils.toJSONString(localTopicSet)); + return metadata; + } + + public boolean addSubscriptionForRequestCode(final SubscribeRequestHeader subscribeRequestHeader, + final String consumerGroup, + final String url, + final List subscriptionList) { + Objects.requireNonNull(url, "url can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(subscribeRequestHeader, "subscribeRequestHeader can not be null"); + Objects.requireNonNull(subscriptionList, "subscriptionList can not be null"); + + boolean isChange = false; + try { + READ_WRITE_LOCK.writeLock().lock(); + + registerClientForSub(subscribeRequestHeader, consumerGroup, subscriptionList, url); + for (final SubscriptionItem subTopic : subscriptionList) { + isChange = isChange + || addSubscriptionByTopic(consumerGroup, url, subscribeRequestHeader.getIdc(), subTopic); + } + } finally { + READ_WRITE_LOCK.writeLock().unlock(); + } + return isChange; + } + + private boolean addSubscriptionByTopic(final String consumerGroup, final String url, final String clientIdc, + final SubscriptionItem subTopic) { + Objects.requireNonNull(url, "url can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(clientIdc, "clientIdc can not be null"); + Objects.requireNonNull(subTopic, "subTopic can not be null"); + + boolean isChange = false; + + ConsumerGroupConf consumerGroupConf = localConsumerGroupMapping.get(consumerGroup); + if (consumerGroupConf == null) { + // new subscription + consumerGroupConf = new ConsumerGroupConf(consumerGroup); + final ConsumerGroupTopicConf consumeTopicConfig = new ConsumerGroupTopicConf(); + consumeTopicConfig.setConsumerGroup(consumerGroup); + consumeTopicConfig.setTopic(subTopic.getTopic()); + consumeTopicConfig.setSubscriptionItem(subTopic); + consumeTopicConfig.setUrls(new HashSet<>(Collections.singletonList(url))); + final Map> idcUrls = new HashMap<>(); + final List urls = new ArrayList(); + urls.add(url); + idcUrls.put(clientIdc, urls); + consumeTopicConfig.setIdcUrls(idcUrls); + consumerGroupConf.getConsumerGroupTopicConf().put(subTopic.getTopic(), consumeTopicConfig); + localConsumerGroupMapping.put(consumerGroup, consumerGroupConf); + isChange = true; + } else { + // already subscribed + final Map map = + consumerGroupConf.getConsumerGroupTopicConf(); + if (!map.containsKey(subTopic.getTopic())) { + // If there are multiple topics, append it + final ConsumerGroupTopicConf newTopicConf = new ConsumerGroupTopicConf(); + newTopicConf.setConsumerGroup(consumerGroup); + newTopicConf.setTopic(subTopic.getTopic()); + newTopicConf.setSubscriptionItem(subTopic); + newTopicConf.setUrls(new HashSet<>(Collections.singletonList(url))); + final Map> idcUrls = new HashMap<>(); + final List urls = new ArrayList(); + urls.add(url); + idcUrls.put(clientIdc, urls); + newTopicConf.setIdcUrls(idcUrls); + map.put(subTopic.getTopic(), newTopicConf); + isChange = true; + } else { + final ConsumerGroupTopicConf currentTopicConf = map.get(subTopic.getTopic()); + if (!currentTopicConf.getUrls().add(url)) { + isChange = true; + log.info("add subscribe success, group:{}, url:{} , topic:{}", consumerGroup, url, subTopic.getTopic()); + } else { + log.warn("The group has subscribed, group:{}, url:{} , topic:{}", consumerGroup, url, subTopic.getTopic()); + } + + if (!currentTopicConf.getIdcUrls().containsKey(clientIdc)) { + final List urls = new ArrayList(); + urls.add(url); + currentTopicConf.getIdcUrls().put(clientIdc, urls); + isChange = true; + log.info("add url to idcUrlMap success, group:{}, url:{}, topic:{}, clientIdc:{}", + consumerGroup, url, subTopic.getTopic(), clientIdc); + } else { + final Set tmpSet = new HashSet<>(currentTopicConf.getIdcUrls().get(clientIdc)); + if (!tmpSet.contains(url)) { + currentTopicConf.getIdcUrls().get(clientIdc).add(url); + isChange = true; + log.info("add url to idcUrlMap success, group:{}, url:{}, topic:{}, clientIdc:{}", + consumerGroup, url, subTopic.getTopic(), clientIdc); + } else { + log.warn("The idcUrlMap has contains url, group:{}, url:{} , topic:{}, clientIdc:{}", + consumerGroup, url, subTopic.getTopic(), clientIdc); + } + } + } + } + return isChange; + } + + private boolean removeSubscriptionByTopic(final String consumerGroup, final String unSubscribeUrl, + final String clientIdc, final String unSubTopic) { + Objects.requireNonNull(unSubscribeUrl, "unSubscribeUrl can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(clientIdc, "clientIdc can not be null"); + Objects.requireNonNull(unSubTopic, "unSubTopic can not be null"); + + boolean isChange = false; + + final ConsumerGroupConf consumerGroupConf = localConsumerGroupMapping.get(consumerGroup); + if (consumerGroupConf == null) { + log.warn("unsubscribe fail, the current mesh does not have group subscriptionInfo, group:{}, url:{}", consumerGroup, unSubscribeUrl); + return false; + } + + final ConsumerGroupTopicConf consumerGroupTopicConf = consumerGroupConf.getConsumerGroupTopicConf().get(unSubTopic); + if (consumerGroupTopicConf == null) { + log.warn("unsubscribe fail, the current mesh does not have group-topic subscriptionInfo, group:{}, topic:{}, url:{}", + consumerGroup, unSubTopic, unSubscribeUrl); + return false; + } + + if (consumerGroupTopicConf.getUrls().remove(unSubscribeUrl)) { + isChange = true; + log.info("remove url success, group:{}, topic:{}, url:{}", consumerGroup, unSubTopic, unSubscribeUrl); + } else { + log.warn("remove url fail, not exist subscrition of this url, group:{}, topic:{}, url:{}", consumerGroup, unSubTopic, unSubscribeUrl); + } + + if (consumerGroupTopicConf.getIdcUrls().containsKey(clientIdc)) { + if (consumerGroupTopicConf.getIdcUrls().get(clientIdc).remove(unSubscribeUrl)) { + isChange = true; + log.info("remove url from idcUrlMap success, group:{}, topic:{}, url:{}, clientIdc:{}", + consumerGroup, unSubTopic, unSubscribeUrl, clientIdc); + } else { + log.warn("remove url from idcUrlMap fail, not exist subscriber of this url, group:{}, topic:{}, url:{}, clientIdc:{}", + consumerGroup, unSubTopic, unSubscribeUrl, clientIdc); + } + } else { + log.warn("remove url from idcUrlMap fail,not exist subscrition of this idc , group:{}, topic:{}, url:{}, clientIdc:{}", + consumerGroup, unSubTopic, unSubscribeUrl, clientIdc); + } + + if (isChange && CollectionUtils.isEmpty(consumerGroupTopicConf.getUrls())) { + consumerGroupConf.getConsumerGroupTopicConf().remove(unSubTopic); + log.info("group unsubscribe topic success,group:{}, topic:{}", consumerGroup, unSubTopic); + } + + if (isChange && MapUtils.isEmpty(consumerGroupConf.getConsumerGroupTopicConf())) { + localConsumerGroupMapping.remove(consumerGroup); + log.info("group unsubscribe success,group:{}", consumerGroup); + } + return isChange; + } + + private void registerClientForSub(final SubscribeRequestHeader subscribeRequestHeader, final String consumerGroup, + final List subscriptionItems, final String url) { + Objects.requireNonNull(subscribeRequestHeader, "subscribeRequestHeader can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(subscriptionItems, "subscriptionItems can not be null"); + Objects.requireNonNull(url, "url can not be null"); + + for (final SubscriptionItem item : subscriptionItems) { + final Client client = new Client(); + client.setEnv(subscribeRequestHeader.getEnv()); + client.setIdc(subscribeRequestHeader.getIdc()); + client.setSys(subscribeRequestHeader.getSys()); + client.setIp(subscribeRequestHeader.getIp()); + client.setPid(subscribeRequestHeader.getPid()); + client.setConsumerGroup(consumerGroup); + client.setTopic(item.getTopic()); + client.setUrl(url); + client.setLastUpTime(new Date()); + final String groupTopicKey = client.getConsumerGroup() + "@" + client.getTopic(); + List localClients = localClientInfoMapping.computeIfAbsent( + groupTopicKey, key -> Collections.unmodifiableList(new ArrayList() { + + private static final long serialVersionUID = -529919988844134656L; + { + add(client); + } + })); + localClients.stream().filter(o -> StringUtils.equals(o.getUrl(), client.getUrl())).findFirst() + .ifPresent(o -> o.setLastUpTime(client.getLastUpTime())); + } + } + + public boolean removeSubscriptionForRequestCode(final UnSubscribeRequestHeader unSubscribeRequestHeader, + final String consumerGroup, + final String unSubscribeUrl, + final List unSubTopicList) { + Objects.requireNonNull(unSubTopicList, "unSubTopicList can not be null"); + Objects.requireNonNull(unSubscribeRequestHeader, "unSubscribeRequestHeader can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(unSubscribeUrl, "unSubscribeUrl can not be null"); + + boolean isChange = false; + try { + READ_WRITE_LOCK.writeLock().lock(); + + registerClientForUnsub(unSubscribeRequestHeader, consumerGroup, unSubTopicList, unSubscribeUrl); + for (final String unSubTopic : unSubTopicList) { + isChange = isChange + || removeSubscriptionByTopic(consumerGroup, + unSubscribeUrl, + unSubscribeRequestHeader.getIdc(), + unSubTopic); + } + } finally { + READ_WRITE_LOCK.writeLock().unlock(); + } + return isChange; + } + + private void registerClientForUnsub(final UnSubscribeRequestHeader unSubscribeRequestHeader, + final String consumerGroup, + final List topicList, + final String url) { + Objects.requireNonNull(topicList, "topicList can not be null"); + Objects.requireNonNull(unSubscribeRequestHeader, "unSubscribeRequestHeader can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(url, "url can not be null"); + + for (final String topic : topicList) { + final Client client = new Client(); + client.setEnv(unSubscribeRequestHeader.getEnv()); + client.setIdc(unSubscribeRequestHeader.getIdc()); + client.setSys(unSubscribeRequestHeader.getSys()); + client.setIp(unSubscribeRequestHeader.getIp()); + client.setPid(unSubscribeRequestHeader.getPid()); + client.setConsumerGroup(consumerGroup); + client.setTopic(topic); + client.setUrl(url); + client.setLastUpTime(new Date()); + final String groupTopicKey = client.getConsumerGroup() + "@" + client.getTopic(); + List localClients = localClientInfoMapping.computeIfAbsent( + groupTopicKey, key -> Collections.unmodifiableList(new ArrayList() { + + private static final long serialVersionUID = -529919988844134656L; + { + add(client); + } + })); + localClients.stream().filter(o -> StringUtils.equals(o.getUrl(), client.getUrl())).findFirst() + .ifPresent(o -> o.setLastUpTime(client.getLastUpTime())); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AbstractHttpRequestProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AbstractHttpRequestProcessor.java new file mode 100644 index 0000000000..81a4747aab --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AbstractHttpRequestProcessor.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.processor; + +import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; + +public abstract class AbstractHttpRequestProcessor implements HttpRequestProcessor { + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminMetricsProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminMetricsProcessor.java index b1e0688bd9..9a8b369341 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminMetricsProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminMetricsProcessor.java @@ -18,31 +18,27 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor; import org.apache.eventmesh.common.protocol.http.HttpCommand; -import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.boot.EventMeshAdminServer; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.Executor; import io.netty.channel.ChannelHandlerContext; -public class AdminMetricsProcessor implements HttpRequestProcessor { +import lombok.RequiredArgsConstructor; - private EventMeshHTTPServer eventMeshHTTPServer; - public AdminMetricsProcessor(EventMeshHTTPServer eventMeshHTTPServer) { - this.eventMeshHTTPServer = eventMeshHTTPServer; - } +@RequiredArgsConstructor +public class AdminMetricsProcessor extends AbstractHttpRequestProcessor { - public Logger logger = LoggerFactory.getLogger(this.getClass()); + private final EventMeshAdminServer eventMeshAdminServer; @Override public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshAdminServer.getAdminMetricsExecutor(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminShutdownProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminShutdownProcessor.java index d1881ad983..4688ee106f 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminShutdownProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AdminShutdownProcessor.java @@ -24,41 +24,42 @@ import org.apache.eventmesh.runtime.boot.EventMeshServer; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; import org.apache.eventmesh.runtime.util.RemotingHelper; +import java.util.concurrent.Executor; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.netty.channel.ChannelHandlerContext; -public class AdminShutdownProcessor implements HttpRequestProcessor { +import lombok.RequiredArgsConstructor; - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); +@RequiredArgsConstructor +public class AdminShutdownProcessor extends AbstractHttpRequestProcessor { - private EventMeshServer eventMeshServer; + public final Logger cmdLogger = LoggerFactory.getLogger(EventMeshConstants.CMD); - public AdminShutdownProcessor(EventMeshServer eventMeshServer) { - this.eventMeshServer = eventMeshServer; - } + private final EventMeshServer eventMeshServer; @Override public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { - HttpCommand responseEventMeshCommand; + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), + EventMeshConstants.PROTOCOL_HTTP, remoteAddr, IPUtils.getLocalAddress()); eventMeshServer.shutdown(); - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse(EventMeshRetCode.SUCCESS); + HttpCommand responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse(EventMeshRetCode.SUCCESS); asyncContext.onComplete(responseEventMeshCommand); } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return (Runnable runnable) -> { + runnable.run(); + }; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AsyncHttpProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AsyncHttpProcessor.java index 250415d14b..d641efb537 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AsyncHttpProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/AsyncHttpProcessor.java @@ -25,11 +25,12 @@ /** * async http processor */ + public interface AsyncHttpProcessor extends HttpProcessor { - public default HttpResponse handler(HttpRequest httpRequest) { + default HttpResponse handler(HttpRequest httpRequest) { return null; } - public void handler(HandlerSpecific handlerSpecific, HttpRequest httpRequest) throws Exception; + void handler(HandlerSpecific handlerSpecific, HttpRequest httpRequest) throws Exception; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageProcessor.java index 13c0605f7c..7b86661246 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageProcessor.java @@ -20,12 +20,12 @@ import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchRequestBody; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchResponseBody; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.RequestCode; @@ -36,22 +36,23 @@ import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.metrics.http.HttpMetrics; import org.apache.eventmesh.runtime.util.RemotingHelper; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -62,49 +63,47 @@ import io.cloudevents.core.builder.CloudEventBuilder; import io.netty.channel.ChannelHandlerContext; -public class BatchSendMessageProcessor implements HttpRequestProcessor { +import com.google.common.base.Stopwatch; - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); +public class BatchSendMessageProcessor extends AbstractHttpRequestProcessor { - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger CMD_LOGGER = LoggerFactory.getLogger(EventMeshConstants.CMD); - private EventMeshHTTPServer eventMeshHTTPServer; + private static final Logger ACL_LOGGER = LoggerFactory.getLogger(EventMeshConstants.ACL); - public BatchSendMessageProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + private static final Logger BATCH_MSG_LOGGER = LoggerFactory.getLogger(EventMeshConstants.BATCH_MSG); + + private final EventMeshHTTPServer eventMeshHTTPServer; + + private final Acl acl; + + public BatchSendMessageProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } - public Logger batchMessageLogger = LoggerFactory.getLogger("batchMessage"); - @Override public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { - HttpCommand responseEventMeshCommand; + String localAddress = IPUtils.getLocalAddress(); + HttpCommand request = asyncContext.getRequest(); + CMD_LOGGER.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get(Integer.valueOf(request.getRequestCode())), + EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), localAddress); - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get( - Integer.valueOf(asyncContext.getRequest().getRequestCode())), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + SendMessageBatchRequestHeader sendMessageBatchRequestHeader = (SendMessageBatchRequestHeader) request.getHeader(); - SendMessageBatchRequestHeader sendMessageBatchRequestHeader = - (SendMessageBatchRequestHeader) asyncContext.getRequest().getHeader(); - - SendMessageBatchResponseHeader sendMessageBatchResponseHeader = - SendMessageBatchResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); + EventMeshHTTPConfiguration httpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + SendMessageBatchResponseHeader sendMessageBatchResponseHeader = SendMessageBatchResponseHeader.buildHeader( + Integer.valueOf(request.getRequestCode()), httpConfiguration.getEventMeshCluster(), localAddress, httpConfiguration.getEventMeshEnv(), + httpConfiguration.getEventMeshIDC()); String protocolType = sendMessageBatchRequestHeader.getProtocolType(); ProtocolAdaptor httpCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - List eventList = httpCommandProtocolAdaptor.toBatchCloudEvent(asyncContext.getRequest()); + List eventList = httpCommandProtocolAdaptor.toBatchCloudEvent(request); if (CollectionUtils.isEmpty(eventList)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SendMessageBatchResponseBody.class); return; } @@ -112,91 +111,60 @@ public void processRequest(ChannelHandlerContext ctx, AsyncContext String producerGroup = ""; int eventSize = eventList.size(); - if (eventSize > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventBatchSize) { - batchMessageLogger.error("Event batch size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventBatchSize); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - "Event batch size exceeds the limit: " + eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventBatchSize)); - asyncContext.onComplete(responseEventMeshCommand); + if (eventSize > httpConfiguration.getEventMeshEventBatchSize()) { + BATCH_MSG_LOGGER.error("Event batch size exceeds the limit: {}", httpConfiguration.getEventMeshEventBatchSize()); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, + "Event batch size exceeds the limit: " + httpConfiguration.getEventMeshEventBatchSize(), SendMessageBatchResponseBody.class); return; } for (CloudEvent event : eventList) { - //validate event - if (StringUtils.isBlank(event.getId()) - || event.getSource() == null - || event.getSpecVersion() == null - || StringUtils.isBlank(event.getType()) - || StringUtils.isBlank(event.getSubject())) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + // validate event + if (!ObjectUtils.allNotNull(event.getSource(), event.getSpecVersion()) + || StringUtils.isAnyBlank(event.getId(), event.getType(), event.getSubject())) { + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageBatchResponseBody.class); return; } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { - batchMessageLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - "Event size exceeds the limit: " + eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize)); - asyncContext.onComplete(responseEventMeshCommand); + String content = event.getData() == null ? "" : new String(event.getData().toBytes(), Constants.DEFAULT_CHARSET); + if (content.length() > httpConfiguration.getEventMeshEventSize()) { + BATCH_MSG_LOGGER.error("Event size exceeds the limit: {}", httpConfiguration.getEventMeshEventSize()); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, + "Event size exceeds the limit: " + httpConfiguration.getEventMeshEventSize(), SendMessageBatchResponseBody.class); return; } - String idc = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.IDC)).toString(); - String pid = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.PID)).toString(); - String sys = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS)).toString(); - - //validate event-extension - if (StringUtils.isBlank(idc) - || StringUtils.isBlank(pid) - || !StringUtils.isNumeric(pid) - || StringUtils.isBlank(sys)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + String idc = getExtension(event, ProtocolKey.ClientInstanceKey.IDC.getKey()); + String pid = getExtension(event, ProtocolKey.ClientInstanceKey.PID.getKey()); + String sys = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); + + // validate event-extension + if (StringUtils.isAnyBlank(idc, pid, sys) || !StringUtils.isNumeric(pid)) { + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageBatchResponseBody.class); return; } - - batchId = Objects.requireNonNull(event.getExtension(SendMessageBatchRequestBody.BATCHID)).toString(); - producerGroup = Objects.requireNonNull(event.getExtension(SendMessageBatchRequestBody.PRODUCERGROUP)).toString(); - String topic = event.getSubject(); - eventSize = Integer.parseInt(Objects.requireNonNull(event.getExtension(SendMessageBatchRequestBody.SIZE)).toString()); + batchId = getExtension(event, SendMessageBatchRequestBody.BATCHID); + producerGroup = getExtension(event, SendMessageBatchRequestBody.PRODUCERGROUP); + eventSize = Integer.parseInt(getExtension(event, SendMessageBatchRequestBody.SIZE)); CloudEventData eventData = event.getData(); - if (eventData != null || StringUtils.isBlank(batchId) - || StringUtils.isBlank(producerGroup) - || eventSize != eventList.size()) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + if (eventData == null || StringUtils.isAnyBlank(batchId, producerGroup) || eventSize != eventList.size()) { + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SendMessageBatchResponseBody.class); return; } } + HttpMetrics summaryMetrics = eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics(); if (!eventMeshHTTPServer.getBatchRateLimiter() - .tryAcquire(eventSize, EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR.getErrMsg())); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendBatchMsgDiscard(eventSize); - asyncContext.onComplete(responseEventMeshCommand); + .tryAcquire(eventSize, EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + summaryMetrics.recordSendBatchMsgDiscard(eventSize); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR, null, SendMessageBatchResponseBody.class); return; } @@ -204,56 +172,47 @@ public void processRequest(ChannelHandlerContext ctx, AsyncContext batchEventMeshProducer.getMqProducerWrapper().getMeshMQProducer().setExtFields(); - if (!batchEventMeshProducer.getStarted().get()) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_BATCH_PRODUCER_STOPED_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_BATCH_PRODUCER_STOPED_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + if (!batchEventMeshProducer.isStarted()) { + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_BATCH_PRODUCER_STOPED_ERR, null, SendMessageBatchResponseBody.class); return; } - final long batchStartTime = System.currentTimeMillis(); - + final Stopwatch stopwatch = Stopwatch.createStarted(); String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - int requestCode = Integer.parseInt(asyncContext.getRequest().getRequestCode()); + int requestCode = Integer.parseInt(request.getRequestCode()); - Map> topicBatchMessageMappings = new ConcurrentHashMap>(); + Map> topicBatchMessageMappings = new ConcurrentHashMap<>(); for (CloudEvent cloudEvent : eventList) { - if (StringUtils.isBlank(cloudEvent.getSubject()) - || cloudEvent.getData() == null) { + if (StringUtils.isBlank(cloudEvent.getSubject()) || cloudEvent.getData() == null) { continue; } - String user = Objects.requireNonNull(cloudEvent.getExtension(ProtocolKey.ClientInstanceKey.USERNAME)).toString(); - String pass = Objects.requireNonNull(cloudEvent.getExtension(ProtocolKey.ClientInstanceKey.PASSWD)).toString(); - String subsystem = Objects.requireNonNull(cloudEvent.getExtension(ProtocolKey.ClientInstanceKey.SYS)).toString(); + String user = getExtension(cloudEvent, ProtocolKey.ClientInstanceKey.USERNAME.getKey()); + String pass = getExtension(cloudEvent, ProtocolKey.ClientInstanceKey.PASSWD.getKey()); + String subsystem = getExtension(cloudEvent, ProtocolKey.ClientInstanceKey.SYS.getKey()); - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { + // do acl check + if (httpConfiguration.isEventMeshServerSecurityEnable()) { try { - Acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, cloudEvent.getSubject(), requestCode); + this.acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, cloudEvent.getSubject(), requestCode); } catch (Exception e) { - //String errorMsg = String.format("CLIENT HAS NO PERMISSION,send failed, topic:%s, subsys:%s, realIp:%s", topic, subsys, realIp); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_ACL_ERR.getRetCode(), e.getMessage())); - asyncContext.onComplete(responseEventMeshCommand); - aclLogger.warn("CLIENT HAS NO PERMISSION,BatchSendMessageProcessor send failed", e); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_ACL_ERR, e.getMessage(), SendMessageBatchResponseBody.class); + ACL_LOGGER.warn("CLIENT HAS NO PERMISSION,BatchSendMessageProcessor send failed", e); return; } } try { - String ttl = Objects.requireNonNull(cloudEvent.getExtension(SendMessageRequestBody.TTL)).toString(); + String ttl = getExtension(cloudEvent, SendMessageRequestBody.TTL); if (StringUtils.isBlank(ttl) || !StringUtils.isNumeric(ttl)) { cloudEvent = CloudEventBuilder.from(cloudEvent) - .withExtension(SendMessageRequestBody.TTL, String.valueOf(EventMeshConstants.DEFAULT_MSG_TTL_MILLS)) - .withExtension("msgtype", "persistent") - .build(); + .withExtension(SendMessageRequestBody.TTL, String.valueOf(EventMeshConstants.DEFAULT_MSG_TTL_MILLS)) + .withExtension("msgtype", "persistent") + .build(); } if (topicBatchMessageMappings.containsKey(cloudEvent.getSubject())) { @@ -264,65 +223,47 @@ public void processRequest(ChannelHandlerContext ctx, AsyncContext topicBatchMessageMappings.put(cloudEvent.getSubject(), tmp); } - if (batchMessageLogger.isDebugEnabled()) { - batchMessageLogger.debug("msg2MQMsg suc, event:{}", cloudEvent.getData()); - } + BATCH_MSG_LOGGER.debug("msg2MQMsg suc, event:{}", cloudEvent.getData()); } catch (Exception e) { - batchMessageLogger.error("msg2MQMsg err, event:{}", cloudEvent.getData(), e); + BATCH_MSG_LOGGER.error("msg2MQMsg err, event:{}", cloudEvent.getData(), e); } } if (CollectionUtils.isEmpty(eventList)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SendMessageBatchResponseBody.class); return; } long delta = eventSize; - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendBatchMsg(delta); + summaryMetrics.recordSendBatchMsg(delta); - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerBatchMsgBatchEnabled) { + if (httpConfiguration.isEventMeshServerBatchMsgBatchEnabled()) { for (List eventlist : topicBatchMessageMappings.values()) { // TODO: Implementation in API. Consider whether to put it in the plug-in. CloudEvent event = null; - //Message omsMsg = new Message(); - //try { - // msgBatch = msgBatch.generateFromList(batchMsgs); - // for (Message message : msgBatch.getMessages()) { - // // TODO: Detect the maximum length of messages for different producers. - // Validators.checkMessage(message, batchEventMeshProducer.getMqProducerWrapper().getDefaultMQProducer()); - // MessageClientIDSetter.setUniqID(message); - // } - // msgBatch.setBody(msgBatch.encode()); - //} catch (Exception e) { - // continue; - //} - - final SendMessageContext sendMessageContext = new SendMessageContext(batchId, event, batchEventMeshProducer, - eventMeshHTTPServer); - sendMessageContext.setEventList(eventlist); + // TODO: Detect the maximum length of messages for different producers. + final SendMessageContext sendMessageContext = new SendMessageContext(batchId, event, batchEventMeshProducer, eventMeshHTTPServer); batchEventMeshProducer.send(sendMessageContext, new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { } @Override public void onException(OnExceptionContext context) { - batchMessageLogger.warn("", context.getException()); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + BATCH_MSG_LOGGER.warn("", context.getException()); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); } }); } } else { for (CloudEvent event : eventList) { - final SendMessageContext sendMessageContext = new SendMessageContext(batchId, event, batchEventMeshProducer, - eventMeshHTTPServer); + final SendMessageContext sendMessageContext = new SendMessageContext(batchId, event, batchEventMeshProducer, eventMeshHTTPServer); batchEventMeshProducer.send(sendMessageContext, new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { @@ -330,30 +271,26 @@ public void onSuccess(SendResult sendResult) { @Override public void onException(OnExceptionContext context) { - batchMessageLogger.warn("", context.getException()); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + BATCH_MSG_LOGGER.warn("", context.getException()); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); } }); } } - long batchEndTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordBatchSendMsgCost(batchEndTime - batchStartTime); - batchMessageLogger.debug("batchMessage|eventMesh2mq|REQ|ASYNC|batchId={}|send2MQCost={}ms|msgNum={}|topics={}", - batchId, batchEndTime - batchStartTime, eventSize, topicBatchMessageMappings.keySet()); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchResponseHeader, - SendMessageBatchResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), - EventMeshRetCode.SUCCESS.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS); + summaryMetrics.recordBatchSendMsgCost(elapsed); + BATCH_MSG_LOGGER.debug("batchMessage|eventMesh2mq|REQ|ASYNC|batchId={}|send2MQCost={}ms|msgNum={}|topics={}", + batchId, elapsed, eventSize, topicBatchMessageMappings.keySet()); + completeResponse(request, asyncContext, sendMessageBatchResponseHeader, EventMeshRetCode.SUCCESS, null, + SendMessageBatchResponseBody.class); return; } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getBatchMsgExecutor(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageV2Processor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageV2Processor.java index 2b23d786b6..e36e51dd76 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageV2Processor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/BatchSendMessageV2Processor.java @@ -20,34 +20,35 @@ import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchV2RequestBody; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageBatchV2ResponseBody; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.common.protocol.http.header.message.SendMessageBatchV2RequestHeader; import org.apache.eventmesh.common.protocol.http.header.message.SendMessageBatchV2ResponseHeader; -import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.metrics.http.HttpMetrics; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -57,218 +58,170 @@ import io.cloudevents.core.builder.CloudEventBuilder; import io.netty.channel.ChannelHandlerContext; -public class BatchSendMessageV2Processor implements HttpRequestProcessor { +public class BatchSendMessageV2Processor extends AbstractHttpRequestProcessor { - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + private static final Logger CMD_LOGGER = LoggerFactory.getLogger(EventMeshConstants.CMD); - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger ACL_LOGGER = LoggerFactory.getLogger(EventMeshConstants.ACL); - private EventMeshHTTPServer eventMeshHTTPServer; + private static final Logger BATCH_MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.BATCH_MSG); + + private final EventMeshHTTPServer eventMeshHTTPServer; + + private final Acl acl; public BatchSendMessageV2Processor(EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } - public Logger batchMessageLogger = LoggerFactory.getLogger("batchMessage"); - @Override public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) - throws Exception { - - HttpCommand responseEventMeshCommand; + throws Exception { final HttpCommand request = asyncContext.getRequest(); final Integer requestCode = Integer.valueOf(request.getRequestCode()); - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - RequestCode.get(requestCode), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + CMD_LOGGER.info("cmd={}|{}|client2eventMesh|from={}|to={}", + RequestCode.get(requestCode), + EventMeshConstants.PROTOCOL_HTTP, + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), + RemotingHelper.parseChannelRemoteAddr(ctx.channel())); SendMessageBatchV2RequestHeader sendMessageBatchV2RequestHeader = - (SendMessageBatchV2RequestHeader) asyncContext.getRequest().getHeader(); + (SendMessageBatchV2RequestHeader) request.getHeader(); String protocolType = sendMessageBatchV2RequestHeader.getProtocolType(); ProtocolAdaptor httpCommandProtocolAdaptor = - ProtocolPluginFactory.getProtocolAdaptor(protocolType); - CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(asyncContext.getRequest()); + ProtocolPluginFactory.getProtocolAdaptor(protocolType); + CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(request); + EventMeshHTTPConfiguration httpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); SendMessageBatchV2ResponseHeader sendMessageBatchV2ResponseHeader = - SendMessageBatchV2ResponseHeader.buildHeader( - requestCode, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC - ); + SendMessageBatchV2ResponseHeader.buildHeader( + requestCode, + httpConfiguration.getEventMeshCluster(), + httpConfiguration.getEventMeshEnv(), + httpConfiguration.getEventMeshIDC()); // todo: use validate processor to check - //validate event - if (StringUtils.isBlank(event.getId()) - || event.getSource() == null - || event.getSpecVersion() == null - || StringUtils.isBlank(event.getType()) - || StringUtils.isBlank(event.getSubject())) { - responseEventMeshCommand = request.createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + // validate event + if (!ObjectUtils.allNotNull(event.getSource(), event.getSpecVersion()) + || StringUtils.isAnyBlank(event.getId(), event.getType(), event.getSubject())) { + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageBatchV2ResponseBody.class); return; } - String idc = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.IDC)) - .toString(); - String pid = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.PID)) - .toString(); - String sys = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS)) - .toString(); - - //validate event-extension - if (StringUtils.isBlank(idc) - || StringUtils.isBlank(pid) - || !StringUtils.isNumeric(pid) - || StringUtils.isBlank(sys)) { - responseEventMeshCommand = request.createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + String idc = getExtension(event, ProtocolKey.ClientInstanceKey.IDC.getKey()); + String pid = getExtension(event, ProtocolKey.ClientInstanceKey.PID.getKey()); + String sys = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); + + // validate event-extension + if (StringUtils.isAnyBlank(idc, pid, sys) + || !StringUtils.isNumeric(pid)) { + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageBatchV2ResponseBody.class); return; } - String bizNo = - Objects.requireNonNull(event.getExtension(SendMessageBatchV2RequestBody.BIZSEQNO)) - .toString(); - String producerGroup = - Objects.requireNonNull(event.getExtension(SendMessageBatchV2RequestBody.PRODUCERGROUP)) - .toString(); + String bizNo = getExtension(event, SendMessageBatchV2RequestBody.BIZSEQNO); + String producerGroup = getExtension(event, SendMessageBatchV2RequestBody.PRODUCERGROUP); String topic = event.getSubject(); - if (StringUtils.isBlank(bizNo) - || StringUtils.isBlank(topic) - || StringUtils.isBlank(producerGroup) - || event.getData() == null) { - responseEventMeshCommand = request.createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + if (StringUtils.isAnyBlank(bizNo, topic, producerGroup) + || event.getData() == null) { + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SendMessageBatchV2ResponseBody.class); return; } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { - batchMessageLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - "Event size exceeds the limit: " + eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize)); - asyncContext.onComplete(responseEventMeshCommand); + String content = new String(Objects.requireNonNull(event.getData()).toBytes(), Constants.DEFAULT_CHARSET); + if (content.length() > httpConfiguration.getEventMeshEventSize()) { + BATCH_MESSAGE_LOGGER.error("Event size exceeds the limit: {}", httpConfiguration.getEventMeshEventSize()); + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, + "Event size exceeds the limit: " + httpConfiguration.getEventMeshEventSize(), + SendMessageBatchV2ResponseBody.class); return; } - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { + // do acl check + if (httpConfiguration.isEventMeshServerSecurityEnable()) { String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = event.getExtension(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = event.getExtension(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - String subsystem = event.getExtension(ProtocolKey.ClientInstanceKey.SYS).toString(); + String user = getExtension(event, ProtocolKey.ClientInstanceKey.USERNAME.getKey()); + String pass = getExtension(event, ProtocolKey.ClientInstanceKey.PASSWD.getKey()); + String subsystem = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); try { - Acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, topic, requestCode); + this.acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, topic, requestCode); } catch (Exception e) { - //String errorMsg = String.format("CLIENT HAS NO PERMISSION,send failed, topic:%s, subsys:%s, realIp:%s", topic, subsys, realIp); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_ACL_ERR.getRetCode(), - e.getMessage())); - asyncContext.onComplete(responseEventMeshCommand); - aclLogger - .warn("CLIENT HAS NO PERMISSION,BatchSendMessageV2Processor send failed", e); + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_ACL_ERR, e.getMessage(), SendMessageBatchV2ResponseBody.class); + ACL_LOGGER.warn("CLIENT HAS NO PERMISSION,BatchSendMessageV2Processor send failed", e); return; } } + HttpMetrics summaryMetrics = eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics(); if (!eventMeshHTTPServer.getBatchRateLimiter() - .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, - TimeUnit.MILLISECONDS)) { - responseEventMeshCommand = request.createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR.getErrMsg())); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendBatchMsgDiscard(1); - asyncContext.onComplete(responseEventMeshCommand); + .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + summaryMetrics.recordSendBatchMsgDiscard(1); + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_BATCH_SPEED_OVER_LIMIT_ERR, null, SendMessageBatchV2ResponseBody.class); return; } EventMeshProducer batchEventMeshProducer = - eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); + eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); batchEventMeshProducer.getMqProducerWrapper().getMeshMQProducer().setExtFields(); - if (!batchEventMeshProducer.getStarted().get()) { - responseEventMeshCommand = request.createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_BATCH_PRODUCER_STOPED_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_BATCH_PRODUCER_STOPED_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + if (!batchEventMeshProducer.isStarted()) { + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.EVENTMESH_BATCH_PRODUCER_STOPED_ERR, null, SendMessageBatchV2ResponseBody.class); return; } long batchStartTime = System.currentTimeMillis(); - String ttl = String.valueOf(EventMeshConstants.DEFAULT_MSG_TTL_MILLS); + String defaultTTL = String.valueOf(EventMeshConstants.DEFAULT_MSG_TTL_MILLS); // todo: use hashmap to avoid copy - if (StringUtils.isBlank(event.getExtension(SendMessageRequestBody.TTL).toString()) - && !StringUtils.isNumeric(event.getExtension(SendMessageRequestBody.TTL).toString())) { - event = CloudEventBuilder.from(event).withExtension(SendMessageRequestBody.TTL, ttl) - .build(); + String ttlValue = getExtension(event, SendMessageRequestBody.TTL); + if (StringUtils.isBlank(ttlValue) && !StringUtils.isNumeric(ttlValue)) { + event = CloudEventBuilder.from(event).withExtension(SendMessageRequestBody.TTL, defaultTTL) + .build(); } - try { event = CloudEventBuilder.from(event) - .withExtension("msgtype", "persistent") - .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, - String.valueOf(System.currentTimeMillis())) - .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, - String.valueOf(System.currentTimeMillis())) - .build(); - if (batchMessageLogger.isDebugEnabled()) { - batchMessageLogger.debug("msg2MQMsg suc, topic:{}, msg:{}", topic, event.getData()); - } + .withExtension("msgtype", "persistent") + .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, + String.valueOf(System.currentTimeMillis())) + .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, + String.valueOf(System.currentTimeMillis())) + .build(); + BATCH_MESSAGE_LOGGER.debug("msg2MQMsg suc, topic:{}, msg:{}", topic, event.getData()); } catch (Exception e) { - batchMessageLogger.error("msg2MQMsg err, topic:{}, msg:{}", topic, event.getData(), e); - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() - + - EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(responseEventMeshCommand); + BATCH_MESSAGE_LOGGER.error("msg2MQMsg err, topic:{}, msg:{}", topic, event.getData(), e); + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR, + EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() + + + EventMeshUtil.stackTrace(e, 2), + SendMessageBatchV2ResponseBody.class); return; } - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendBatchMsg(1); + summaryMetrics.recordSendBatchMsg(1); final SendMessageContext sendMessageContext = - new SendMessageContext(bizNo, event, batchEventMeshProducer, eventMeshHTTPServer); + new SendMessageContext(bizNo, event, batchEventMeshProducer, eventMeshHTTPServer); try { batchEventMeshProducer.send(sendMessageContext, new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { long batchEndTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordBatchSendMsgCost(batchEndTime - batchStartTime); - batchMessageLogger.debug( + summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + BATCH_MESSAGE_LOGGER.debug( "batchMessageV2|eventMesh2mq|REQ|ASYNC|bizSeqNo={}|send2MQCost={}ms|topic={}", bizNo, batchEndTime - batchStartTime, topic); } @@ -276,42 +229,34 @@ public void onSuccess(SendResult sendResult) { @Override public void onException(OnExceptionContext context) { long batchEndTime = System.currentTimeMillis(); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordBatchSendMsgCost(batchEndTime - batchStartTime); - batchMessageLogger.error( + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); + summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + BATCH_MESSAGE_LOGGER.error( "batchMessageV2|eventMesh2mq|REQ|ASYNC|bizSeqNo={}|send2MQCost={}ms|topic={}", bizNo, batchEndTime - batchStartTime, topic, context.getException()); } }); } catch (Exception e) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_SEND_BATCHLOG_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_SEND_BATCHLOG_MSG_ERR.getErrMsg() - + - EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(responseEventMeshCommand); + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, EventMeshRetCode.EVENTMESH_SEND_BATCHLOG_MSG_ERR, + EventMeshRetCode.EVENTMESH_SEND_BATCHLOG_MSG_ERR.getErrMsg() + + + EventMeshUtil.stackTrace(e, 2), + SendMessageBatchV2ResponseBody.class); long batchEndTime = System.currentTimeMillis(); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordBatchSendMsgCost(batchEndTime - batchStartTime); - batchMessageLogger.error( + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); + summaryMetrics.recordBatchSendMsgCost(batchEndTime - batchStartTime); + BATCH_MESSAGE_LOGGER.error( "batchMessageV2|eventMesh2mq|REQ|ASYNC|bizSeqNo={}|send2MQCost={}ms|topic={}", bizNo, batchEndTime - batchStartTime, topic, e); } - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageBatchV2ResponseHeader, - SendMessageBatchV2ResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), - EventMeshRetCode.SUCCESS.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); - + completeResponse(request, asyncContext, sendMessageBatchV2ResponseHeader, + EventMeshRetCode.SUCCESS, null, SendMessageBatchV2ResponseBody.class); } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getBatchMsgExecutor(); } } - diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/CreateTopicProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/CreateTopicProcessor.java new file mode 100644 index 0000000000..13892591e6 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/CreateTopicProcessor.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.processor; + +import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.RequestURI; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.common.EventMeshTrace; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; +import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.HttpClientGroupMapping; +import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.RemotingHelper; + +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; + +import com.fasterxml.jackson.core.type.TypeReference; + +@EventMeshTrace +public class CreateTopicProcessor implements AsyncHttpProcessor { + + private static final Logger HTTP_LOGGER = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); + + private final transient EventMeshHTTPServer eventMeshHTTPServer; + + public CreateTopicProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + this.eventMeshHTTPServer = eventMeshHTTPServer; + } + + @Override + public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) + throws Exception { + final AsyncContext asyncContext = handlerSpecific.getAsyncContext(); + final ChannelHandlerContext ctx = handlerSpecific.getCtx(); + final HttpEventWrapper requestWrapper = asyncContext.getRequest(); + + HTTP_LOGGER.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), + EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + + // user request header + Map userRequestHeaderMap = requestWrapper.getHeaderMap(); + String requestIp = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), requestIp); + + Map responseHeaderMap = new HashMap<>(); + responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); + responseHeaderMap + .put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); + + // validate body + byte[] requestBody = requestWrapper.getBody(); + + Map requestBodyMap = JsonUtils.parseTypeReferenceObject(new String(requestBody), + new TypeReference>() { + }); + + HttpEventWrapper responseWrapper; + + if (requestBodyMap.get("topic") == null || StringUtils.isBlank(requestBodyMap.get("topic").toString())) { + Map responseBodyMap = new HashMap<>(); + responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode()); + responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + "topic is null"); + HTTP_LOGGER.warn("create topic fail, topic is null"); + responseWrapper = requestWrapper.createHttpResponse(responseHeaderMap, responseBodyMap); + responseWrapper.setHttpResponseStatus(HttpResponseStatus.BAD_REQUEST); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, + responseBodyMap, null); + return; + } + + String topic = requestBodyMap.get("topic").toString(); + + long startTime = System.currentTimeMillis(); + try { + // pub topic in local cache + String[] topicArr = topic.split(";"); + for (String item : topicArr) { + item = StringUtils.deleteWhitespace(item); + if (!HttpClientGroupMapping.getInstance().getLocalTopicSet().contains(item)) { + HttpClientGroupMapping.getInstance().getLocalTopicSet().add(item); + HTTP_LOGGER.info("create topic success, topic:{}", item); + } + } + + final CompleteHandler handler = httpEventWrapper -> { + try { + HTTP_LOGGER.debug("{}", httpEventWrapper); + eventMeshHTTPServer.sendResponse(ctx, httpEventWrapper.httpResponse()); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPReqResTimeCost( + System.currentTimeMillis() - requestWrapper.getReqTime()); + } catch (Exception ex) { + // ignore + HTTP_LOGGER.warn("create topic, sendResponse fail,", ex); + } + }; + + responseWrapper = requestWrapper.createHttpResponse(EventMeshRetCode.SUCCESS); + asyncContext.onComplete(responseWrapper, handler); + + } catch (Exception e) { + Map responseBodyMap = new HashMap<>(); + responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getRetCode()); + responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2)); + responseWrapper = asyncContext.getRequest().createHttpResponse( + responseHeaderMap, responseBodyMap); + responseWrapper.setHttpResponseStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_RUNTIME_ERR, responseHeaderMap, + responseBodyMap, null); + long endTime = System.currentTimeMillis(); + HTTP_LOGGER.warn( + "create topic fail, eventMesh2client|cost={}ms|topic={}", endTime - startTime, topic, e); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgFailed(); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgCost(endTime - startTime); + } + } + + @Override + public String[] paths() { + return new String[] {RequestURI.CREATE_TOPIC.getRequestURI()}; + } + + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/DeleteTopicProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/DeleteTopicProcessor.java new file mode 100644 index 0000000000..c156cc704d --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/DeleteTopicProcessor.java @@ -0,0 +1,184 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.processor; + +import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.RequestURI; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.common.EventMeshTrace; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; +import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.HttpClientGroupMapping; +import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.RemotingHelper; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; + +import com.fasterxml.jackson.core.type.TypeReference; + +@EventMeshTrace +public class DeleteTopicProcessor implements AsyncHttpProcessor { + + private static final Logger HTTP_LOGGER = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); + + private final transient EventMeshHTTPServer eventMeshHTTPServer; + + public DeleteTopicProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + this.eventMeshHTTPServer = eventMeshHTTPServer; + } + + @Override + public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) + throws Exception { + final AsyncContext asyncContext = handlerSpecific.getAsyncContext(); + final ChannelHandlerContext ctx = handlerSpecific.getCtx(); + final HttpEventWrapper requestWrapper = asyncContext.getRequest(); + + HTTP_LOGGER.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), + EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + + // user request header + Map userRequestHeaderMap = requestWrapper.getHeaderMap(); + String requestIp = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), requestIp); + + Map responseHeaderMap = new HashMap<>(); + responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); + responseHeaderMap + .put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); + + // validate body + byte[] requestBody = requestWrapper.getBody(); + + Map requestBodyMap = JsonUtils.parseTypeReferenceObject(new String(requestBody), + new TypeReference>() { + }); + + HttpEventWrapper responseWrapper; + + if (requestBodyMap.get("topic") == null || StringUtils.isBlank(requestBodyMap.get("topic").toString())) { + Map responseBodyMap = new HashMap<>(); + responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode()); + responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + "topic is null"); + HTTP_LOGGER.warn("delete topic fail, topic is null"); + responseWrapper = requestWrapper.createHttpResponse(responseHeaderMap, responseBodyMap); + responseWrapper.setHttpResponseStatus(HttpResponseStatus.BAD_REQUEST); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, + responseBodyMap, null); + return; + } + + String topic = requestBodyMap.get("topic").toString(); + + long startTime = System.currentTimeMillis(); + try { + // pub topic in local cache + String[] topicArr = topic.split(";"); + + // validate topic is exist in eventmesh + List faildTopic = new ArrayList<>(); + for (String deleteTopic : topicArr) { + if (!HttpClientGroupMapping.getInstance().getLocalTopicSet().contains(deleteTopic)) { + faildTopic.add(deleteTopic); + } + } + if (!faildTopic.isEmpty()) { + + Map responseBodyMap = new HashMap<>(); + StringBuilder sb = new StringBuilder(); + String topics = String.join(", ", faildTopic); + sb.append(topics).append(" do not exist in eventmesh"); + HTTP_LOGGER.warn("delete topic fail, {}", sb); + responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_OPERATE_FAIL.getRetCode()); + responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_OPERATE_FAIL.getErrMsg() + sb); + responseWrapper = requestWrapper.createHttpResponse(responseHeaderMap, responseBodyMap); + responseWrapper.setHttpResponseStatus(HttpResponseStatus.BAD_REQUEST); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_OPERATE_FAIL, responseHeaderMap, + responseBodyMap, null); + return; + } + for (String item : topicArr) { + boolean flag = HttpClientGroupMapping.getInstance().getLocalTopicSet().remove(StringUtils.deleteWhitespace(item)); + if (flag) { + HTTP_LOGGER.info("remove topic success, topic:{}", item); + } + } + + final CompleteHandler handler = httpEventWrapper -> { + try { + HTTP_LOGGER.debug("{}", httpEventWrapper); + eventMeshHTTPServer.sendResponse(ctx, httpEventWrapper.httpResponse()); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPReqResTimeCost( + System.currentTimeMillis() - requestWrapper.getReqTime()); + } catch (Exception ex) { + // ignore + HTTP_LOGGER.warn("delete topic, sendResponse fail,", ex); + } + }; + + responseWrapper = requestWrapper.createHttpResponse(EventMeshRetCode.SUCCESS); + asyncContext.onComplete(responseWrapper, handler); + + } catch (Exception e) { + Map responseBodyMap = new HashMap<>(); + responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getRetCode()); + responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2)); + responseWrapper = asyncContext.getRequest().createHttpResponse( + responseHeaderMap, responseBodyMap); + responseWrapper.setHttpResponseStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_RUNTIME_ERR, responseHeaderMap, + responseBodyMap, null); + long endTime = System.currentTimeMillis(); + HTTP_LOGGER.warn( + "delete topic fail, eventMesh2client|cost={}ms|topic={}", endTime - startTime, topic, e); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgFailed(); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgCost(endTime - startTime); + } + } + + @Override + public String[] paths() { + return new String[] {RequestURI.DELETE_TOPIC.getRequestURI()}; + } + + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HandlerService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HandlerService.java index 12377241b4..c2e20ba6a2 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HandlerService.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HandlerService.java @@ -17,14 +17,17 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.enums.ConnectionType; import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.boot.HTTPTrace; import org.apache.eventmesh.runtime.boot.HTTPTrace.TraceOperation; import org.apache.eventmesh.runtime.common.EventMeshTrace; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.metrics.http.HTTPMetricsServer; +import org.apache.eventmesh.runtime.metrics.http.EventMeshHttpMetricsManager; import org.apache.eventmesh.runtime.util.HttpResponseUtils; import org.apache.eventmesh.runtime.util.RemotingHelper; @@ -37,7 +40,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import org.slf4j.Logger; @@ -61,49 +66,54 @@ import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class HandlerService { - private Logger httpServerLogger = LoggerFactory.getLogger(this.getClass()); + private static final Logger HTTP_LOGGER = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); - private Logger httpLogger = LoggerFactory.getLogger("http"); - - private Map httpProcessorMap = new ConcurrentHashMap<>(); + private final Map httpProcessorMap = new ConcurrentHashMap<>(); @Setter - private HTTPMetricsServer metrics; + private EventMeshHttpMetricsManager metrics; @Setter private HTTPTrace httpTrace; public DefaultHttpDataFactory defaultHttpDataFactory = new DefaultHttpDataFactory(false); - public void init() { - httpServerLogger.info("HandlerService start "); + log.info("HandlerService start "); } - public void register(HttpProcessor httpProcessor, ThreadPoolExecutor threadPoolExecutor) { + public void register(HttpProcessor httpProcessor, Executor threadPoolExecutor) { for (String path : httpProcessor.paths()) { this.register(path, httpProcessor, threadPoolExecutor); } } - public void register(String path, HttpProcessor httpProcessor, ThreadPoolExecutor threadPoolExecutor) { + public void register(HttpProcessor httpProcessor) { + for (String path : httpProcessor.paths()) { + this.register(path, httpProcessor, httpProcessor.executor()); + } + } + + public void register(String path, HttpProcessor httpProcessor, Executor threadPoolExecutor) { if (httpProcessorMap.containsKey(path)) { throw new RuntimeException(String.format("HandlerService path %s repeat, repeat processor is %s ", - path, httpProcessor.getClass().getSimpleName())); + path, httpProcessor.getClass().getSimpleName())); } ProcessorWrapper processorWrapper = new ProcessorWrapper(); - processorWrapper.threadPoolExecutor = threadPoolExecutor; + processorWrapper.executor = threadPoolExecutor; if (httpProcessor instanceof AsyncHttpProcessor) { processorWrapper.async = (AsyncHttpProcessor) httpProcessor; } processorWrapper.httpProcessor = httpProcessor; processorWrapper.traceEnabled = httpProcessor.getClass().getAnnotation(EventMeshTrace.class).isEnable(); httpProcessorMap.put(path, processorWrapper); - httpServerLogger.info("path is {} processor name is {}", path, httpProcessor.getClass().getSimpleName()); + log.info("path is {} processor name is {}", path, httpProcessor.getClass().getSimpleName()); } public boolean isProcessorWrapper(HttpRequest httpRequest) { @@ -137,27 +147,47 @@ public void handler(ChannelHandlerContext ctx, HttpRequest httpRequest, ThreadPo handlerSpecific.ctx = ctx; handlerSpecific.traceOperation = traceOperation; handlerSpecific.asyncContext = new AsyncContext<>(new HttpEventWrapper(), null, asyncContextCompleteHandler); - processorWrapper.threadPoolExecutor.execute(handlerSpecific); + processorWrapper.executor.execute(handlerSpecific); } catch (Exception e) { - httpServerLogger.error(e.getMessage(), e); + log.error(e.getMessage(), e); this.sendResponse(ctx, httpRequest, HttpResponseUtils.createInternalServerError()); } } private void sendResponse(ChannelHandlerContext ctx, HttpRequest request, HttpResponse response) { - this.sendResponse(ctx, request, response, true); + this.sendPersistentResponse(ctx, request, response, true); + } + + /** + * persistent connection + */ + private void sendPersistentResponse(ChannelHandlerContext ctx, HttpRequest httpRequest, HttpResponse response, boolean isClose) { + ReferenceCountUtil.release(httpRequest); + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { + if (!f.isSuccess()) { + HTTP_LOGGER.warn("send response to [{}] fail, will close this channel", + RemotingHelper.parseChannelRemoteAddr(f.channel())); + if (isClose) { + f.channel().close(); + } + } + }); + }); } - private void sendResponse(ChannelHandlerContext ctx, HttpRequest httpRequest, HttpResponse response, boolean isClose) { + /** + * short-lived connection + */ + private void sendShortResponse(ChannelHandlerContext ctx, HttpRequest httpRequest, HttpResponse response) { ReferenceCountUtil.release(httpRequest); - ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { - if (!f.isSuccess()) { - httpLogger.warn("send response to [{}] fail, will close this channel", + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { + if (!f.isSuccess()) { + HTTP_LOGGER.warn("send response to [{}] with short-lived connection fail, will close this channel", RemotingHelper.parseChannelRemoteAddr(f.channel())); - if (isClose) { - f.channel().close(); } - } + }).addListener(ChannelFutureListener.CLOSE); }); } @@ -167,13 +197,13 @@ private HttpEventWrapper parseHttpRequest(HttpRequest httpRequest) throws IOExce httpEventWrapper.setHttpVersion(httpRequest.protocolVersion().protocolName()); httpEventWrapper.setRequestURI(httpRequest.uri()); - //parse http header + // parse http header for (String key : httpRequest.headers().names()) { httpEventWrapper.getHeaderMap().put(key, httpRequest.headers().get(key)); } final long bodyDecodeStart = System.currentTimeMillis(); - //parse http body + // parse http body FullHttpRequest fullHttpRequest = (FullHttpRequest) httpRequest; final Map bodyMap = new HashMap<>(); if (HttpMethod.GET == fullHttpRequest.method()) { @@ -186,8 +216,12 @@ private HttpEventWrapper parseHttpRequest(HttpRequest httpRequest) throws IOExce if (length > 0) { byte[] body = new byte[length]; fullHttpRequest.content().readBytes(body); - JsonUtils.deserialize(new String(body), new TypeReference>() { - }).forEach(bodyMap::put); + Optional + .ofNullable(JsonUtils.parseTypeReferenceObject( + new String(body, Constants.DEFAULT_CHARSET), + new TypeReference>() { + })) + .ifPresent(bodyMap::putAll); } } else { HttpPostRequestDecoder decoder = @@ -205,10 +239,13 @@ private HttpEventWrapper parseHttpRequest(HttpRequest httpRequest) throws IOExce throw new RuntimeException("UnSupported Method " + fullHttpRequest.method()); } - byte[] requestBody = JsonUtils.serialize(bodyMap).getBytes(StandardCharsets.UTF_8); + byte[] requestBody = Optional.ofNullable(JsonUtils.toJSONString(bodyMap)) + .map(s -> s.getBytes(StandardCharsets.UTF_8)) + .orElse(new byte[0]); + httpEventWrapper.setBody(requestBody); - metrics.getSummaryMetrics().recordDecodeTimeCost(System.currentTimeMillis() - bodyDecodeStart); + metrics.getHttpMetrics().recordDecodeTimeCost(System.currentTimeMillis() - bodyDecodeStart); return httpEventWrapper; } @@ -235,7 +272,6 @@ class HandlerSpecific implements Runnable { private CloudEvent ce; - public void run() { String processorKey = "/"; for (String eventProcessorKey : httpProcessorMap.keySet()) { @@ -246,7 +282,6 @@ public void run() { } ProcessorWrapper processorWrapper = HandlerService.this.httpProcessorMap.get(processorKey); try { - this.preHandler(); if (processorWrapper.httpProcessor instanceof AsyncHttpProcessor) { // set actual async request HttpEventWrapper httpEventWrapper = parseHttpRequest(request); @@ -256,7 +291,11 @@ public void run() { } response = processorWrapper.httpProcessor.handler(request); - this.postHandler(); + if (processorWrapper.httpProcessor instanceof ShortHttpProcessor) { + this.postHandlerWithTimeCostRecord(ConnectionType.SHORT_LIVED); + return; + } + this.postHandlerWithTimeCostRecord(ConnectionType.PERSISTENT); } catch (Throwable e) { exception = e; // todo: according exception to generate response @@ -265,45 +304,38 @@ public void run() { } } - private void postHandler() { - metrics.getSummaryMetrics().recordHTTPRequest(); - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", request); - } + private void postHandlerWithTimeCostRecord(ConnectionType type) { + metrics.getHttpMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - requestTime); + HTTP_LOGGER.debug("{}", response); + postHandler(type); + } + + private void postHandler(ConnectionType type) { + metrics.getHttpMetrics().recordHTTPRequest(); + HTTP_LOGGER.debug("{}", request); if (Objects.isNull(response)) { this.response = HttpResponseUtils.createSuccess(); } this.traceOperation.endTrace(ce); - HandlerService.this.sendResponse(ctx, this.request, this.response); - } - - private void preHandler() { - metrics.getSummaryMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - requestTime); - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", response); + if (type == ConnectionType.PERSISTENT) { + HandlerService.this.sendResponse(ctx, this.request, this.response); + } else if (type == ConnectionType.SHORT_LIVED) { + sendShortResponse(ctx, this.request, this.response); } } + private void error() { - httpServerLogger.error(this.exception.getMessage(), this.exception); + log.error(this.exception.getMessage(), this.exception); this.traceOperation.exceptionTrace(this.exception, this.traceMap); - metrics.getSummaryMetrics().recordHTTPDiscard(); - metrics.getSummaryMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - requestTime); + metrics.getHttpMetrics().recordHTTPDiscard(); + metrics.getHttpMetrics().recordHTTPReqResTimeCost(System.currentTimeMillis() - requestTime); HandlerService.this.sendResponse(ctx, this.request, this.response); } - - public void setResponseJsonBody(String body) { - this.sendResponse(HttpResponseUtils.setResponseJsonBody(body, ctx)); - } - - public void setResponseTextBody(String body) { - this.sendResponse(HttpResponseUtils.setResponseTextBody(body, ctx)); - } - public void sendResponse(HttpResponse response) { this.response = response; - this.postHandler(); + this.postHandler(ConnectionType.PERSISTENT); } public void sendResponse(Map responseHeaderMap, Map responseBodyMap) { @@ -311,7 +343,7 @@ public void sendResponse(Map responseHeaderMap, Map responseHeaderMap, Map responseHeaderMap, Map responseBodyMap, - Map traceMap) { + Map traceMap) { this.traceMap = traceMap; try { - responseBodyMap.put("retCode", retCode.getRetCode()); - responseBodyMap.put("retMsg", retCode.getErrMsg()); + responseBodyMap.put(EventMeshConstants.RET_CODE, retCode.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, retCode.getErrMsg()); HttpEventWrapper responseWrapper = asyncContext.getRequest().createHttpResponse(responseHeaderMap, responseBodyMap); asyncContext.onComplete(responseWrapper); this.exception = new RuntimeException(retCode.getErrMsg()); @@ -345,15 +377,14 @@ public void sendErrorResponse(EventMeshRetCode retCode, Map resp * @param count */ public void recordSendBatchMsgFailed(int count) { - metrics.getSummaryMetrics().recordSendBatchMsgFailed(1); + metrics.getHttpMetrics().recordSendBatchMsgFailed(1); } } - private static class ProcessorWrapper { - private ThreadPoolExecutor threadPoolExecutor; + private Executor executor; private HttpProcessor httpProcessor; diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HeartBeatProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HeartBeatProcessor.java index cd0b8c463b..add93edcab 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HeartBeatProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HeartBeatProcessor.java @@ -20,7 +20,6 @@ import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.client.HeartbeatRequestBody; import org.apache.eventmesh.common.protocol.http.body.client.HeartbeatResponseBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.common.protocol.http.header.client.HeartbeatRequestHeader; @@ -28,11 +27,11 @@ import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; @@ -43,185 +42,161 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.Executor; import io.netty.channel.ChannelHandlerContext; -public class HeartBeatProcessor implements HttpRequestProcessor { +import lombok.extern.slf4j.Slf4j; - public Logger httpLogger = LoggerFactory.getLogger("http"); +@Slf4j +public class HeartBeatProcessor extends AbstractHttpRequestProcessor { - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private final transient EventMeshHTTPServer eventMeshHTTPServer; - private EventMeshHTTPServer eventMeshHTTPServer; + private final Acl acl; - public HeartBeatProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public HeartBeatProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } @Override - public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { + public void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) throws Exception { HttpCommand responseEventMeshCommand; - httpLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); - HeartbeatRequestHeader heartbeatRequestHeader = (HeartbeatRequestHeader) asyncContext.getRequest().getHeader(); - HeartbeatRequestBody heartbeatRequestBody = (HeartbeatRequestBody) asyncContext.getRequest().getBody(); - - HeartbeatResponseHeader heartbeatResponseHeader = - HeartbeatResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - - //validate header - if (StringUtils.isBlank(heartbeatRequestHeader.getIdc()) - || StringUtils.isBlank(heartbeatRequestHeader.getPid()) - || !StringUtils.isNumeric(heartbeatRequestHeader.getPid()) - || StringUtils.isBlank(heartbeatRequestHeader.getSys())) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - heartbeatResponseHeader, - HeartbeatResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + final String localAddress = IPUtils.getLocalAddress(); + HttpCommand request = asyncContext.getRequest(); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get(Integer.valueOf(request.getRequestCode())), + EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), localAddress); + final HeartbeatRequestHeader heartbeatRequestHeader = (HeartbeatRequestHeader) request.getHeader(); + final HeartbeatRequestBody heartbeatRequestBody = (HeartbeatRequestBody) request.getBody(); + EventMeshHTTPConfiguration httpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + final HeartbeatResponseHeader heartbeatResponseHeader = + HeartbeatResponseHeader.buildHeader(Integer.valueOf(request.getRequestCode()), + httpConfiguration.getEventMeshCluster(), + localAddress, httpConfiguration.getEventMeshEnv(), + httpConfiguration.getEventMeshIDC()); + + // validate header + + if (StringUtils.isAnyBlank( + heartbeatRequestHeader.getIdc(), heartbeatRequestHeader.getPid(), heartbeatRequestHeader.getSys()) + || !StringUtils.isNumeric(heartbeatRequestHeader.getPid())) { + completeResponse(request, asyncContext, heartbeatResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, HeartbeatResponseBody.class); return; } - //validate body - if (StringUtils.isBlank(heartbeatRequestBody.getClientType()) - || StringUtils.isBlank(heartbeatRequestBody.getConsumerGroup()) - || CollectionUtils.isEmpty(heartbeatRequestBody.getHeartbeatEntities())) { - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - heartbeatResponseHeader, - HeartbeatResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + // validate body + if (StringUtils.isAnyBlank(heartbeatRequestBody.getClientType(), heartbeatRequestBody.getConsumerGroup()) + || CollectionUtils.isEmpty(heartbeatRequestBody.getHeartbeatEntities())) { + completeResponse(request, asyncContext, heartbeatResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, HeartbeatResponseBody.class); return; } - ConcurrentHashMap> tmp = new ConcurrentHashMap<>(); - String env = heartbeatRequestHeader.getEnv(); - String idc = heartbeatRequestHeader.getIdc(); - String sys = heartbeatRequestHeader.getSys(); - String ip = heartbeatRequestHeader.getIp(); - String pid = heartbeatRequestHeader.getPid(); - String consumerGroup = heartbeatRequestBody.getConsumerGroup(); - List heartbeatEntities = heartbeatRequestBody.getHeartbeatEntities(); - for (HeartbeatRequestBody.HeartbeatEntity heartbeatEntity : heartbeatEntities) { - - Client client = new Client(); - client.env = env; - client.idc = idc; - client.sys = sys; - client.ip = ip; - client.pid = pid; - client.consumerGroup = consumerGroup; - client.topic = heartbeatEntity.topic; - client.url = heartbeatEntity.url; - - client.lastUpTime = new Date(); - - if (StringUtils.isBlank(client.topic)) { + final ConcurrentHashMap> tmpMap = new ConcurrentHashMap<>(); + final List heartbeatEntities = heartbeatRequestBody.getHeartbeatEntities(); + + for (final HeartbeatRequestBody.HeartbeatEntity heartbeatEntity : heartbeatEntities) { + final Client client = new Client(); + client.setEnv(heartbeatRequestHeader.getEnv()); + client.setIdc(heartbeatRequestHeader.getIdc()); + client.setSys(heartbeatRequestHeader.getSys()); + client.setIp(heartbeatRequestHeader.getIp()); + client.setPid(heartbeatRequestHeader.getPid()); + client.setConsumerGroup(heartbeatRequestBody.getConsumerGroup()); + client.setTopic(heartbeatEntity.getTopic()); + client.setUrl(heartbeatEntity.getUrl()); + client.setLastUpTime(new Date()); + + if (StringUtils.isAnyBlank(client.getTopic(), client.getUrl())) { continue; } - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = heartbeatRequestHeader.getUsername(); - String pass = heartbeatRequestHeader.getPasswd(); - int requestCode = Integer.parseInt(heartbeatRequestHeader.getCode()); + // do acl check + if (eventMeshHTTPServer.getEventMeshHttpConfiguration().isEventMeshServerSecurityEnable()) { try { - Acl.doAclCheckInHttpHeartbeat(remoteAddr, user, pass, sys, client.topic, requestCode); + this.acl.doAclCheckInHttpHeartbeat( + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), + heartbeatRequestHeader.getUsername(), + heartbeatRequestHeader.getPasswd(), + heartbeatRequestHeader.getSys(), + client.getTopic(), + Integer.parseInt(heartbeatRequestHeader.getCode())); } catch (Exception e) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - heartbeatResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_ACL_ERR.getRetCode(), e.getMessage())); - asyncContext.onComplete(responseEventMeshCommand); - aclLogger.warn("CLIENT HAS NO PERMISSION,HeartBeatProcessor subscribe failed", e); + completeResponse(request, asyncContext, heartbeatResponseHeader, + EventMeshRetCode.EVENTMESH_ACL_ERR, e.getMessage(), HeartbeatResponseBody.class); + log.warn("CLIENT HAS NO PERMISSION,HeartBeatProcessor subscribe failed", e); return; } } - if (StringUtils.isBlank(client.url)) { - continue; - } + final String groupTopicKey = client.getConsumerGroup() + "@" + client.getTopic(); + List clients = tmpMap.computeIfAbsent(groupTopicKey, k -> new ArrayList<>()); - String groupTopicKey = client.consumerGroup + "@" + client.topic; + clients.add(client); - if (tmp.containsKey(groupTopicKey)) { - tmp.get(groupTopicKey).add(client); - } else { - List clients = new ArrayList<>(); - clients.add(client); - tmp.put(groupTopicKey, clients); - } } - synchronized (eventMeshHTTPServer.localClientInfoMapping) { - for (Map.Entry> groupTopicClientMapping : tmp.entrySet()) { - List localClientList = - eventMeshHTTPServer.localClientInfoMapping.get(groupTopicClientMapping.getKey()); + + ConcurrentHashMap> clientInfoMap = + eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping(); + synchronized (clientInfoMap) { + for (final Map.Entry> groupTopicClientMapping : tmpMap.entrySet()) { + final List localClientList = clientInfoMap.get(groupTopicClientMapping.getKey()); if (CollectionUtils.isEmpty(localClientList)) { - eventMeshHTTPServer.localClientInfoMapping - .put(groupTopicClientMapping.getKey(), groupTopicClientMapping.getValue()); + clientInfoMap.put(groupTopicClientMapping.getKey(), groupTopicClientMapping.getValue()); } else { - List tmpClientList = groupTopicClientMapping.getValue(); + final List tmpClientList = groupTopicClientMapping.getValue(); supplyClientInfoList(tmpClientList, localClientList); - eventMeshHTTPServer.localClientInfoMapping.put(groupTopicClientMapping.getKey(), localClientList); + clientInfoMap.put(groupTopicClientMapping.getKey(), localClientList); } } } - long startTime = System.currentTimeMillis(); + final long startTime = System.currentTimeMillis(); try { - - final CompleteHandler handler = new CompleteHandler() { - @Override - public void onResponse(HttpCommand httpCommand) { - try { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", httpCommand); - } - eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPReqResTimeCost( - System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); - } catch (Exception ex) { - //ignore - } + final CompleteHandler handler = httpCommand -> { + try { + log.debug("{}", httpCommand); + eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPReqResTimeCost( + System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + } catch (Exception ex) { + // ignore } }; - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse(EventMeshRetCode.SUCCESS); + responseEventMeshCommand = request.createHttpCommandResponse(EventMeshRetCode.SUCCESS); asyncContext.onComplete(responseEventMeshCommand, handler); } catch (Exception e) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - heartbeatResponseHeader, - HeartbeatResponseBody.buildBody(EventMeshRetCode.EVENTMESH_HEARTBEAT_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_HEARTBEAT_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(err); - long endTime = System.currentTimeMillis(); - httpLogger.error("message|eventMesh2mq|REQ|ASYNC|heartBeatMessageCost={}ms", - endTime - startTime, e); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); + completeResponse(request, asyncContext, heartbeatResponseHeader, + EventMeshRetCode.EVENTMESH_HEARTBEAT_ERR, + EventMeshRetCode.EVENTMESH_HEARTBEAT_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2), + HeartbeatResponseBody.class); + final long elapsedTime = System.currentTimeMillis() - startTime; + log.error("message|eventMesh2mq|REQ|ASYNC|heartBeatMessageCost={}ms", elapsedTime, e); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgFailed(); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgCost(elapsedTime); } } - private void supplyClientInfoList(List tmpClientList, List localClientList) { - for (Client tmpClient : tmpClientList) { + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); + } + + private void supplyClientInfoList(final List tmpClientList, final List localClientList) { + Objects.requireNonNull(tmpClientList, "tmpClientList can not be null"); + Objects.requireNonNull(localClientList, "localClientList can not be null"); + + for (final Client tmpClient : tmpClientList) { boolean isContains = false; - for (Client localClient : localClientList) { - if (StringUtils.equals(localClient.url, tmpClient.url)) { + for (final Client localClient : localClientList) { + if (StringUtils.equals(localClient.getUrl(), tmpClient.getUrl())) { isContains = true; - localClient.lastUpTime = tmpClient.lastUpTime; + localClient.setLastUpTime(tmpClient.getLastUpTime()); break; } } @@ -230,10 +205,4 @@ private void supplyClientInfoList(List tmpClientList, List local } } } - - @Override - public boolean rejectRequest() { - return false; - } - } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HttpProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HttpProcessor.java index 34b0d330c7..64fd431b74 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HttpProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/HttpProcessor.java @@ -17,6 +17,8 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor; +import java.util.concurrent.Executor; + import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; @@ -25,7 +27,14 @@ */ public interface HttpProcessor { - public String[] paths(); + String[] paths(); + + HttpResponse handler(HttpRequest httpRequest); - public HttpResponse handler(HttpRequest httpRequest); + /** + * @return {@link Executor} + */ + default Executor executor() { + return null; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalSubscribeEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalSubscribeEventProcessor.java index 4c1810f282..3a74c72c2c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalSubscribeEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalSubscribeEventProcessor.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; @@ -28,126 +29,97 @@ import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; import org.apache.eventmesh.runtime.common.EventMeshTrace; import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; -import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; +import org.apache.eventmesh.runtime.core.consumer.ClientInfo; +import org.apache.eventmesh.runtime.core.consumer.SubscriptionManager; import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.AbstractEventProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.WebhookUtil; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Executor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.Channel; import io.netty.handler.codec.http.HttpRequest; import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; -@EventMeshTrace(isEnable = false) -public class LocalSubscribeEventProcessor extends AbstractEventProcessor implements AsyncHttpProcessor { - - public Logger httpLogger = LoggerFactory.getLogger("http"); +@EventMeshTrace +@Slf4j +public class LocalSubscribeEventProcessor extends AbstractEventProcessor { - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private final Acl acl; - public LocalSubscribeEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public LocalSubscribeEventProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { super(eventMeshHTTPServer); + this.acl = eventMeshHTTPServer.getAcl(); } @Override - public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) throws Exception { - - AsyncContext asyncContext = handlerSpecific.getAsyncContext(); - - ChannelHandlerContext ctx = handlerSpecific.getCtx(); + public void handler(final HandlerService.HandlerSpecific handlerSpecific, final HttpRequest httpRequest) + throws Exception { - HttpEventWrapper requestWrapper = asyncContext.getRequest(); - - HttpEventWrapper responseWrapper; - - httpLogger.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), - EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress() - ); + final Channel channel = handlerSpecific.getCtx().channel(); + final HttpEventWrapper requestWrapper = handlerSpecific.getAsyncContext().getRequest(); + String localAddress = IPUtils.getLocalAddress(); + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(channel); + log.info("uri={}|{}|client2eventMesh|from={}|to={}", + requestWrapper.getRequestURI(), EventMeshConstants.PROTOCOL_HTTP, remoteAddr, localAddress); // user request header - Map userRequestHeaderMap = requestWrapper.getHeaderMap(); - String requestIp = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, requestIp); - + requestWrapper.getHeaderMap().put(ProtocolKey.ClientInstanceKey.IP.getKey(), remoteAddr); // build sys header requestWrapper.buildSysHeaderForClient(); - Map responseHeaderMap = new HashMap<>(); - responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, - IPUtils.getLocalAddress()); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - Map sysHeaderMap = requestWrapper.getSysHeaderMap(); - - Map responseBodyMap = new HashMap<>(); - - //validate header - if (StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || !StringUtils.isNumeric(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString())) { + final Map responseHeaderMap = builderResponseHeaderMap(requestWrapper); + final Map sysHeaderMap = requestWrapper.getSysHeaderMap(); + final Map responseBodyMap = new HashMap<>(); + // validate header + if (validateSysHeader(sysHeaderMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, responseHeaderMap, responseBodyMap, null); return; } - //validate body - byte[] requestBody = requestWrapper.getBody(); - - Map requestBodyMap = JsonUtils.deserialize(new String(requestBody), new TypeReference>() { - }); + // validate body + final Map requestBodyMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + new String(requestWrapper.getBody(), Constants.DEFAULT_CHARSET), + new TypeReference>() { + })).orElseGet(HashMap::new); - if (requestBodyMap.get("url") == null || requestBodyMap.get("topic") == null || requestBodyMap.get("consumerGroup") == null) { + if (validatedRequestBodyMap(requestBodyMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, null); return; } - String url = requestBodyMap.get("url").toString(); - String consumerGroup = requestBodyMap.get("consumerGroup").toString(); - String topic = JsonUtils.serialize(requestBodyMap.get("topic")); + final String url = requestBodyMap.get("url").toString(); + final String consumerGroup = requestBodyMap.get("consumerGroup").toString(); + final String topic = JsonUtils.toJSONString(requestBodyMap.get("topic")); // SubscriptionItem - List subscriptionList = JsonUtils.deserialize(topic, new TypeReference>() { - }); - - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - String subsystem = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString(); - for (SubscriptionItem item : subscriptionList) { + final List subscriptionList = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + topic, + new TypeReference>() { + })).orElseGet(Collections::emptyList); + + // do acl check + if (eventMeshHTTPServer.getEventMeshHttpConfiguration().isEventMeshServerSecurityEnable()) { + for (final SubscriptionItem item : subscriptionList) { try { - Acl.doAclCheckInHttpReceive(remoteAddr, user, pass, subsystem, item.getTopic(), + String user = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.USERNAME.getKey()).toString(); + String pass = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PASSWD.getKey()).toString(); + String subsystem = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS.getKey()).toString(); + this.acl.doAclCheckInHttpReceive(remoteAddr, user, pass, subsystem, item.getTopic(), requestWrapper.getRequestURI()); } catch (Exception e) { - aclLogger.warn("CLIENT HAS NO PERMISSION,SubscribeProcessor subscribe failed", e); + log.warn("CLIENT HAS NO PERMISSION,SubscribeProcessor subscribe failed", e); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_ACL_ERR, responseHeaderMap, responseBodyMap, null); return; @@ -157,124 +129,47 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest // validate URL try { - if (!IPUtils.isValidDomainOrIp(url, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIpv4BlackList, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIpv6BlackList)) { - httpLogger.error("subscriber url {} is not valid", url); + if (!IPUtils.isValidDomainOrIp(url, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIpv4BlackList(), + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIpv6BlackList())) { + log.error("subscriber url {} is not valid", url); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, null); return; } } catch (Exception e) { - httpLogger.error("subscriber url {} is not valid, error {}", url, e.getMessage()); - handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, - responseBodyMap, null); - return; - } + log.error("subscriber url {} is not valid", url, e); - // obtain webhook delivery agreement for Abuse Protection - boolean isWebhookAllowed = WebhookUtil.obtainDeliveryAgreement(eventMeshHTTPServer.httpClientPool.getClient(), - url, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshWebhookOrigin); - - if (!isWebhookAllowed) { - httpLogger.error("subscriber url {} is not allowed by the target system", url); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, null); return; } - synchronized (eventMeshHTTPServer.localClientInfoMapping) { - - registerClient(requestWrapper, consumerGroup, subscriptionList, url); - - for (SubscriptionItem subTopic : subscriptionList) { - List groupTopicClients = eventMeshHTTPServer.localClientInfoMapping - .get(consumerGroup + "@" + subTopic.getTopic()); - - if (CollectionUtils.isEmpty(groupTopicClients)) { - httpLogger.error("group {} topic {} clients is empty", consumerGroup, subTopic); - } - - Map> idcUrls = new HashMap<>(); - for (Client client : groupTopicClients) { - if (idcUrls.containsKey(client.idc)) { - idcUrls.get(client.idc).add(StringUtils.deleteWhitespace(client.url)); - } else { - List urls = new ArrayList<>(); - urls.add(client.url); - idcUrls.put(client.idc, urls); - } - } - ConsumerGroupConf consumerGroupConf = - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup); - if (consumerGroupConf == null) { - // new subscription - consumerGroupConf = new ConsumerGroupConf(consumerGroup); - ConsumerGroupTopicConf consumeTopicConfig = new ConsumerGroupTopicConf(); - consumeTopicConfig.setConsumerGroup(consumerGroup); - consumeTopicConfig.setTopic(subTopic.getTopic()); - consumeTopicConfig.setSubscriptionItem(subTopic); - consumeTopicConfig.setUrls(new HashSet<>(Arrays.asList(url))); - - consumeTopicConfig.setIdcUrls(idcUrls); - - Map map = new HashMap<>(); - map.put(subTopic.getTopic(), consumeTopicConfig); - consumerGroupConf.setConsumerGroupTopicConf(map); - } else { - // already subscribed - Map map = - consumerGroupConf.getConsumerGroupTopicConf(); - if (!map.containsKey(subTopic.getTopic())) { - //If there are multiple topics, append it - ConsumerGroupTopicConf newTopicConf = new ConsumerGroupTopicConf(); - newTopicConf.setConsumerGroup(consumerGroup); - newTopicConf.setTopic(subTopic.getTopic()); - newTopicConf.setSubscriptionItem(subTopic); - newTopicConf.setUrls(new HashSet<>(Arrays.asList(url))); - newTopicConf.setIdcUrls(idcUrls); - map.put(subTopic.getTopic(), newTopicConf); - } - for (String key : map.keySet()) { - if (StringUtils.equals(subTopic.getTopic(), key)) { - ConsumerGroupTopicConf latestTopicConf = new ConsumerGroupTopicConf(); - latestTopicConf.setConsumerGroup(consumerGroup); - latestTopicConf.setTopic(subTopic.getTopic()); - latestTopicConf.setSubscriptionItem(subTopic); - latestTopicConf.setUrls(new HashSet<>(Arrays.asList(url))); - - ConsumerGroupTopicConf currentTopicConf = map.get(key); - latestTopicConf.getUrls().addAll(currentTopicConf.getUrls()); - latestTopicConf.setIdcUrls(idcUrls); - - map.put(key, latestTopicConf); - } - } - } - eventMeshHTTPServer.localConsumerGroupMapping.put(consumerGroup, consumerGroupConf); - } + synchronized (eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping()) { + ClientInfo clientInfo = getClientInfo(requestWrapper); + SubscriptionManager subscriptionManager = eventMeshHTTPServer.getSubscriptionManager(); + subscriptionManager.registerClient(clientInfo, consumerGroup, subscriptionList, url); + subscriptionManager.updateSubscription(clientInfo, consumerGroup, url, subscriptionList); - long startTime = System.currentTimeMillis(); + final long startTime = System.currentTimeMillis(); try { // subscription relationship change notification eventMeshHTTPServer.getConsumerManager().notifyConsumerManager(consumerGroup, - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup)); - - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg()); + eventMeshHTTPServer.getSubscriptionManager().getLocalConsumerGroupMapping().get(consumerGroup)); + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg()); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); } catch (Exception e) { - long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}" - + "|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(subscriptionList), url, e); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|url={}", + System.currentTimeMillis() - startTime, JsonUtils.toJSONString(subscriptionList), url, e); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_SUBSCRIBE_ERR, responseHeaderMap, responseBodyMap, null); } // Update service metadata - updateMetadata(); + eventMeshHTTPServer.getSubscriptionManager().updateMetaData(); } } @@ -284,43 +179,19 @@ public String[] paths() { return new String[] {RequestURI.SUBSCRIBE_LOCAL.getRequestURI()}; } - private void registerClient(HttpEventWrapper requestWrapper, String consumerGroup, - List subscriptionItems, String url) { - Map requestHeaderMap = requestWrapper.getSysHeaderMap(); - for (SubscriptionItem item : subscriptionItems) { - Client client = new Client(); - client.env = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.ENV).toString(); - client.idc = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString(); - client.sys = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString(); - client.ip = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IP).toString(); - client.pid = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString(); - client.consumerGroup = consumerGroup; - client.topic = item.getTopic(); - client.url = url; - client.lastUpTime = new Date(); - - String groupTopicKey = client.consumerGroup + "@" + client.topic; - - if (eventMeshHTTPServer.localClientInfoMapping.containsKey(groupTopicKey)) { - List localClients = - eventMeshHTTPServer.localClientInfoMapping.get(groupTopicKey); - boolean isContains = false; - for (Client localClient : localClients) { - if (StringUtils.equals(localClient.url, client.url)) { - isContains = true; - localClient.lastUpTime = client.lastUpTime; - break; - } - } - if (!isContains) { - localClients.add(client); - } - } else { - List clients = new ArrayList<>(); - clients.add(client); - eventMeshHTTPServer.localClientInfoMapping.put(groupTopicKey, clients); - } - } + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); } + private ClientInfo getClientInfo(final HttpEventWrapper requestWrapper) { + final Map requestHeaderMap = requestWrapper.getSysHeaderMap(); + ClientInfo clientInfo = new ClientInfo(); + clientInfo.setEnv(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.ENV.getKey()).toString()); + clientInfo.setIdc(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC.getKey()).toString()); + clientInfo.setSys(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS.getKey()).toString()); + clientInfo.setIp(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IP.getKey()).toString()); + clientInfo.setPid(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.PID.getKey()).toString()); + return clientInfo; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalUnSubscribeEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalUnSubscribeEventProcessor.java index 3f9c858d64..72ad78b685 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalUnSubscribeEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/LocalUnSubscribeEventProcessor.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; @@ -33,222 +34,197 @@ import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.Executor; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpRequest; import com.fasterxml.jackson.core.type.TypeReference; +import com.google.common.collect.Maps; -@EventMeshTrace(isEnable = false) -public class LocalUnSubscribeEventProcessor extends AbstractEventProcessor implements AsyncHttpProcessor { +import lombok.extern.slf4j.Slf4j; - public Logger httpLogger = LoggerFactory.getLogger("http"); +@Slf4j +@EventMeshTrace(isEnable = false) +public class LocalUnSubscribeEventProcessor extends AbstractEventProcessor { - public LocalUnSubscribeEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public LocalUnSubscribeEventProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { super(eventMeshHTTPServer); } @Override - public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) throws Exception { + public void handler(final HandlerService.HandlerSpecific handlerSpecific, final HttpRequest httpRequest) throws Exception { - AsyncContext asyncContext = handlerSpecific.getAsyncContext(); + final AsyncContext asyncContext = handlerSpecific.getAsyncContext(); - ChannelHandlerContext ctx = handlerSpecific.getCtx(); + final ChannelHandlerContext ctx = handlerSpecific.getCtx(); - HttpEventWrapper requestWrapper = asyncContext.getRequest(); + final HttpEventWrapper requestWrapper = asyncContext.getRequest(); - HttpEventWrapper responseWrapper; + String localAddress = IPUtils.getLocalAddress(); + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - httpLogger.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + log.info("uri={}|{}|client2eventMesh|from={}|to={}", + requestWrapper.getRequestURI(), EventMeshConstants.PROTOCOL_HTTP, remoteAddr, localAddress); // user request header - Map userRequestHeaderMap = requestWrapper.getHeaderMap(); - String requestIp = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, requestIp); + requestWrapper.getHeaderMap().put(ProtocolKey.ClientInstanceKey.IP.getKey(), remoteAddr); // build sys header requestWrapper.buildSysHeaderForClient(); - Map responseHeaderMap = new HashMap<>(); - responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, - IPUtils.getLocalAddress()); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - Map sysHeaderMap = requestWrapper.getSysHeaderMap(); - - Map responseBodyMap = new HashMap<>(); - - //validate header - if (StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || !StringUtils.isNumeric(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString())) { + final Map responseHeaderMap = builderResponseHeaderMap(requestWrapper); + final Map sysHeaderMap = requestWrapper.getSysHeaderMap(); + final Map responseBodyMap = new HashMap<>(); + // validate header + if (validateSysHeader(sysHeaderMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, responseHeaderMap, responseBodyMap, null); return; } - //validate body - byte[] requestBody = requestWrapper.getBody(); + // validate body + final byte[] requestBody = requestWrapper.getBody(); - Map requestBodyMap = JsonUtils.deserialize(new String(requestBody), new TypeReference>() { - }); + final Map requestBodyMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + new String(requestBody, Constants.DEFAULT_CHARSET), + new TypeReference>() { + })).orElseGet(Maps::newHashMap); - if (requestBodyMap.get("url") == null || requestBodyMap.get("topic") == null || requestBodyMap.get("consumerGroup") == null) { + if (validatedRequestBodyMap(requestBodyMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, null); return; } - String unSubscribeUrl = requestBodyMap.get("url").toString(); - String consumerGroup = requestBodyMap.get("consumerGroup").toString(); - String topic = JsonUtils.serialize(requestBodyMap.get("topic")); + final String unSubscribeUrl = requestBodyMap.get(EventMeshConstants.URL).toString(); + final String consumerGroup = requestBodyMap.get(EventMeshConstants.CONSUMER_GROUP).toString(); // unSubscriptionItem - List unSubTopicList = JsonUtils.deserialize(topic, new TypeReference>() { - }); + final List unSubTopicList = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + JsonUtils.toJSONString(requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC)), + new TypeReference>() { + })).orElseGet(Collections::emptyList); - String env = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.ENV).toString(); - String idc = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString(); - String sys = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString(); - String ip = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IP).toString(); - String pid = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString(); + final String pid = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID.getKey()).toString(); - synchronized (eventMeshHTTPServer.localClientInfoMapping) { + synchronized (eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping()) { boolean isChange = true; registerClient(requestWrapper, consumerGroup, unSubTopicList, unSubscribeUrl); - for (String unSubTopic : unSubTopicList) { - List groupTopicClients = eventMeshHTTPServer.localClientInfoMapping + for (final String unSubTopic : unSubTopicList) { + final List groupTopicClients = eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping() .get(consumerGroup + "@" + unSubTopic); - Iterator clientIterator = groupTopicClients.iterator(); + final Iterator clientIterator = groupTopicClients.iterator(); while (clientIterator.hasNext()) { - Client client = clientIterator.next(); - if (StringUtils.equals(client.pid, pid) - && StringUtils.equals(client.url, unSubscribeUrl)) { - httpLogger.warn("client {} start unsubscribe", JsonUtils.serialize(client)); + final Client client = clientIterator.next(); + if (StringUtils.equals(client.getPid(), pid) + && StringUtils.equals(client.getUrl(), unSubscribeUrl)) { + log.warn("client {} start unsubscribe", JsonUtils.toJSONString(client)); clientIterator.remove(); } } - if (groupTopicClients.size() > 0) { - //change url - Map> idcUrls = new HashMap<>(); - Set clientUrls = new HashSet<>(); - for (Client client : groupTopicClients) { + + if (CollectionUtils.isNotEmpty(groupTopicClients)) { + // change url + final Map> idcUrls = new HashMap<>(); + final Set clientUrls = new HashSet<>(); + for (final Client client : groupTopicClients) { // remove subscribed url - if (!StringUtils.equals(unSubscribeUrl, client.url)) { - clientUrls.add(client.url); - if (idcUrls.containsKey(client.idc)) { - idcUrls.get(client.idc) - .add(StringUtils.deleteWhitespace(client.url)); - } else { - List urls = new ArrayList<>(); - urls.add(client.url); - idcUrls.put(client.idc, urls); - } + if (!StringUtils.equals(unSubscribeUrl, client.getUrl())) { + clientUrls.add(client.getUrl()); + + List urls = idcUrls.computeIfAbsent(client.getIdc(), list -> new ArrayList<>()); + urls.add(StringUtils.deleteWhitespace(client.getUrl())); } } - synchronized (eventMeshHTTPServer.localConsumerGroupMapping) { - ConsumerGroupConf consumerGroupConf = - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup); - Map map = + + synchronized (eventMeshHTTPServer.getSubscriptionManager().getLocalConsumerGroupMapping()) { + final ConsumerGroupConf consumerGroupConf = + eventMeshHTTPServer.getSubscriptionManager().getLocalConsumerGroupMapping().get(consumerGroup); + final Map map = consumerGroupConf.getConsumerGroupTopicConf(); - for (String topicKey : map.keySet()) { + for (final Map.Entry entry : map.entrySet()) { // only modify the topic to subscribe - if (StringUtils.equals(unSubTopic, topicKey)) { - ConsumerGroupTopicConf latestTopicConf = - new ConsumerGroupTopicConf(); + if (StringUtils.equals(unSubTopic, entry.getKey())) { + final ConsumerGroupTopicConf latestTopicConf = new ConsumerGroupTopicConf(); latestTopicConf.setConsumerGroup(consumerGroup); latestTopicConf.setTopic(unSubTopic); - latestTopicConf - .setSubscriptionItem(map.get(topicKey).getSubscriptionItem()); + latestTopicConf.setSubscriptionItem(entry.getValue().getSubscriptionItem()); latestTopicConf.setUrls(clientUrls); - latestTopicConf.setIdcUrls(idcUrls); - map.put(unSubTopic, latestTopicConf); } } - eventMeshHTTPServer.localConsumerGroupMapping - .put(consumerGroup, consumerGroupConf); + eventMeshHTTPServer.getSubscriptionManager().getLocalConsumerGroupMapping().put(consumerGroup, consumerGroupConf); } } else { isChange = false; break; } } - long startTime = System.currentTimeMillis(); + final long startTime = System.currentTimeMillis(); if (isChange) { try { eventMeshHTTPServer.getConsumerManager().notifyConsumerManager(consumerGroup, - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup)); + eventMeshHTTPServer.getSubscriptionManager().getLocalConsumerGroupMapping().get(consumerGroup)); - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg()); + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg()); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); } catch (Exception e) { - long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms" - + "|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(unSubTopicList), unSubscribeUrl, e); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms" + + "|topic={}|url={}", System.currentTimeMillis() - startTime, JsonUtils.toJSONString(unSubTopicList), unSubscribeUrl, e); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR, responseHeaderMap, responseBodyMap, null); } } else { - //remove + // remove try { eventMeshHTTPServer.getConsumerManager() .notifyConsumerManager(consumerGroup, null); - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg()); + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg()); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); // clean ClientInfo - eventMeshHTTPServer.localClientInfoMapping.keySet() + eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping().keySet() .removeIf(s -> StringUtils.contains(s, consumerGroup)); // clean ConsumerGroupInfo - eventMeshHTTPServer.localConsumerGroupMapping.keySet() + eventMeshHTTPServer.getSubscriptionManager().getLocalConsumerGroupMapping().keySet() .removeIf(s -> StringUtils.equals(consumerGroup, s)); } catch (Exception e) { - long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms" - + "|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(unSubTopicList), unSubscribeUrl, e); + + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms" + + "|topic={}|url={}", System.currentTimeMillis() - startTime, JsonUtils.toJSONString(unSubTopicList), unSubscribeUrl, e); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR, responseHeaderMap, responseBodyMap, null); } } // Update service metadata - updateMetadata(); + eventMeshHTTPServer.getSubscriptionManager().updateMetaData(); } } @@ -257,43 +233,47 @@ public String[] paths() { return new String[] {RequestURI.UNSUBSCRIBE_LOCAL.getRequestURI()}; } + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); + } - private void registerClient(HttpEventWrapper requestWrapper, - String consumerGroup, - List topicList, String url) { - Map requestHeaderMap = requestWrapper.getSysHeaderMap(); - for (String topic : topicList) { - Client client = new Client(); - client.env = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.ENV).toString(); - client.idc = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString(); - client.sys = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString(); - client.ip = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IP).toString(); - client.pid = requestHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString(); - client.consumerGroup = consumerGroup; - client.topic = topic; - client.url = url; - client.lastUpTime = new Date(); - - String groupTopicKey = client.consumerGroup + "@" + client.topic; - if (eventMeshHTTPServer.localClientInfoMapping.containsKey(groupTopicKey)) { - List localClients = - eventMeshHTTPServer.localClientInfoMapping.get(groupTopicKey); - boolean isContains = false; - for (Client localClient : localClients) { - if (StringUtils.equals(localClient.url, client.url)) { - isContains = true; - localClient.lastUpTime = client.lastUpTime; - break; - } - } - if (!isContains) { - localClients.add(client); + private void registerClient(final HttpEventWrapper requestWrapper, final String consumerGroup, final List topicList, final String url) { + Objects.requireNonNull(requestWrapper, "requestWrapper can not be null"); + Objects.requireNonNull(consumerGroup, "consumerGroup can not be null"); + Objects.requireNonNull(topicList, "topicList can not be null"); + Objects.requireNonNull(url, "url can not be null"); + + final Map requestHeaderMap = requestWrapper.getSysHeaderMap(); + for (final String topic : topicList) { + final Client client = new Client(); + client.setEnv(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.ENV.getKey()).toString()); + client.setIdc(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC.getKey()).toString()); + client.setSys(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS.getKey()).toString()); + client.setIp(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.IP.getKey()).toString()); + client.setPid(requestHeaderMap.get(ProtocolKey.ClientInstanceKey.PID.getKey()).toString()); + client.setConsumerGroup(consumerGroup); + client.setTopic(topic); + client.setUrl(url); + client.setLastUpTime(new Date()); + + final String groupTopicKey = client.getConsumerGroup() + "@" + client.getTopic(); + + List localClients = + eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping().computeIfAbsent(groupTopicKey, list -> new ArrayList<>()); + + boolean isContains = false; + for (final Client localClient : localClients) { + if (StringUtils.equals(localClient.getUrl(), client.getUrl())) { + isContains = true; + localClient.setLastUpTime(client.getLastUpTime()); + break; } - } else { - List clients = new ArrayList<>(); - clients.add(client); - eventMeshHTTPServer.localClientInfoMapping.put(groupTopicKey, clients); } + if (!isContains) { + localClients.add(client); + } + } } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/QuerySubscriptionProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/QuerySubscriptionProcessor.java new file mode 100644 index 0000000000..3093dc9107 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/QuerySubscriptionProcessor.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.processor; + +import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.RequestURI; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.common.EventMeshTrace; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; +import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.HttpClientGroupMapping; +import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.RemotingHelper; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; + +@EventMeshTrace +public class QuerySubscriptionProcessor implements AsyncHttpProcessor { + + private static final Logger HTTP_LOGGER = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); + + private final transient EventMeshHTTPServer eventMeshHTTPServer; + + public QuerySubscriptionProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + this.eventMeshHTTPServer = eventMeshHTTPServer; + } + + @Override + public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) + throws Exception { + final AsyncContext asyncContext = handlerSpecific.getAsyncContext(); + final ChannelHandlerContext ctx = handlerSpecific.getCtx(); + final HttpEventWrapper requestWrapper = asyncContext.getRequest(); + + HttpEventWrapper responseWrapper; + + HTTP_LOGGER.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), + EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + + Map responseHeaderMap = new HashMap<>(); + responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); + responseHeaderMap + .put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); + + long startTime = System.currentTimeMillis(); + try { + // pub topic in local cache + + final CompleteHandler handler = httpEventWrapper -> { + try { + HTTP_LOGGER.debug("{}", httpEventWrapper); + eventMeshHTTPServer.sendResponse(ctx, httpEventWrapper.httpResponse()); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPReqResTimeCost( + System.currentTimeMillis() - requestWrapper.getReqTime()); + } catch (Exception ex) { + HTTP_LOGGER.warn("query subscription, sendResponse fail", ex); + } + }; + + Map responseBodyMap = new HashMap<>(); + + responseBodyMap.put("subsrciption", HttpClientGroupMapping.getInstance().querySubscription()); + responseBodyMap.put("localTopicSet", HttpClientGroupMapping.getInstance().getLocalTopicSet()); + + responseWrapper = requestWrapper.createHttpResponse(responseHeaderMap, responseBodyMap); + asyncContext.onComplete(responseWrapper, handler); + } catch (Exception e) { + Map responseBodyMap = new HashMap<>(); + responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getRetCode()); + responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_RUNTIME_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2)); + responseWrapper = asyncContext.getRequest().createHttpResponse( + responseHeaderMap, responseBodyMap); + responseWrapper.setHttpResponseStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_RUNTIME_ERR, responseHeaderMap, + responseBodyMap, null); + long endTime = System.currentTimeMillis(); + HTTP_LOGGER.warn("query subscription fail,eventMesh2client|cost={}ms", endTime - startTime, e); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgFailed(); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgCost(endTime - startTime); + } + } + + @Override + public String[] paths() { + return new String[] {RequestURI.SUBSCRIPTION_QUERY.getRequestURI()}; + } + + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteSubscribeEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteSubscribeEventProcessor.java index f1a9d9c330..821b5d3001 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteSubscribeEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteSubscribeEventProcessor.java @@ -25,31 +25,25 @@ import org.apache.eventmesh.common.protocol.http.common.RequestURI; import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; import org.apache.eventmesh.runtime.common.EventMeshTrace; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.AbstractEventProcessor; import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.WebhookUtil; -import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; -import java.io.IOException; -import java.nio.charset.Charset; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Executor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,18 +52,20 @@ import io.netty.handler.codec.http.HttpRequest; import com.fasterxml.jackson.core.type.TypeReference; -import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; -@EventMeshTrace(isEnable = false) -public class RemoteSubscribeEventProcessor extends AbstractEventProcessor implements AsyncHttpProcessor { +@EventMeshTrace +public class RemoteSubscribeEventProcessor extends AbstractEventProcessor { - public Logger httpLogger = LoggerFactory.getLogger("http"); + private static final Logger httpLogger = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger aclLogger = LoggerFactory.getLogger(EventMeshConstants.ACL); + private final Acl acl; public RemoteSubscribeEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { super(eventMeshHTTPServer); + this.acl = eventMeshHTTPServer.getAcl(); } @Override @@ -80,165 +76,102 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest ChannelHandlerContext ctx = handlerSpecific.getCtx(); HttpEventWrapper requestWrapper = asyncContext.getRequest(); - - HttpEventWrapper responseWrapper; - + String localAddress = IPUtils.getLocalAddress(); + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); httpLogger.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), - EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress() - ); + EventMeshConstants.PROTOCOL_HTTP, remoteAddr, localAddress); // user request header Map userRequestHeaderMap = requestWrapper.getHeaderMap(); - String requestIp = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, requestIp); + userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), remoteAddr); // build sys header requestWrapper.buildSysHeaderForClient(); - Map responseHeaderMap = new HashMap<>(); - responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); - responseHeaderMap - .put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); + Map responseHeaderMap = builderResponseHeaderMap(requestWrapper); Map sysHeaderMap = requestWrapper.getSysHeaderMap(); Map responseBodyMap = new HashMap<>(); - //validate header - if (StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || !StringUtils.isNumeric(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString())) { - + // validate header + if (validateSysHeader(sysHeaderMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, responseHeaderMap, responseBodyMap, null); return; } - - //validate body + // validate body byte[] requestBody = requestWrapper.getBody(); - Map requestBodyMap = JsonUtils.deserialize(new String(requestBody), new TypeReference>() { - }); - + Map requestBodyMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + new String(requestBody, Constants.DEFAULT_CHARSET), + new TypeReference>() { + })).orElseGet(Maps::newHashMap); - if (requestBodyMap.get("url") == null || requestBodyMap.get("topic") == null || requestBodyMap.get("consumerGroup") == null) { + if (validatedRequestBodyMap(requestBodyMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, null); return; } - String url = requestBodyMap.get("url").toString(); - String consumerGroup = requestBodyMap.get("consumerGroup").toString(); - String topic = JsonUtils.serialize(requestBodyMap.get("topic")); - + // String url = requestBodyMap.get(EventMeshConstants.URL).toString(); + String topic = JsonUtils.toJSONString(requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC)); // SubscriptionItem - List subscriptionList = JsonUtils.deserialize(topic, new TypeReference>() { - }); - - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - String subsystem = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString(); + List subscriptionList = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + topic, + new TypeReference>() { + })).orElseGet(Collections::emptyList); + + // do acl check + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + if (eventMeshHttpConfiguration.isEventMeshServerSecurityEnable()) { + String user = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.USERNAME.getKey()).toString(); + String pass = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PASSWD.getKey()).toString(); + String subsystem = sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS.getKey()).toString(); for (SubscriptionItem item : subscriptionList) { try { - Acl.doAclCheckInHttpReceive(remoteAddr, user, pass, subsystem, item.getTopic(), - requestWrapper.getRequestURI()); + this.acl.doAclCheckInHttpReceive(remoteAddr, user, pass, subsystem, item.getTopic(), requestWrapper.getRequestURI()); } catch (Exception e) { aclLogger.warn("CLIENT HAS NO PERMISSION,SubscribeProcessor subscribe failed", e); - handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_ACL_ERR, responseHeaderMap, - responseBodyMap, null); - + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_ACL_ERR, responseHeaderMap, responseBodyMap, null); return; } } } - // validate URL - try { - if (!IPUtils.isValidDomainOrIp(url, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIpv4BlackList, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIpv6BlackList)) { - httpLogger.error("subscriber url {} is not valid", url); - handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, - responseBodyMap, null); - return; - } - } catch (Exception e) { - httpLogger.error("subscriber url {} is not valid, error {}", url, e.getMessage()); - handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, - responseBodyMap, null); - return; - } - - // obtain webhook delivery agreement for Abuse Protection - boolean isWebhookAllowed = WebhookUtil.obtainDeliveryAgreement(eventMeshHTTPServer.httpClientPool.getClient(), - url, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshWebhookOrigin); - - if (!isWebhookAllowed) { - httpLogger.error("subscriber url {} is not allowed by the target system", url); - handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, - responseBodyMap, null); - return; - } - long startTime = System.currentTimeMillis(); try { - // request to remote - - String env = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv; - String idc = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC; - String cluster = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster; - String sysId = eventMeshHTTPServer.getEventMeshHttpConfiguration().sysID; - String meshGroup = env + "-" + idc + "-" + cluster + "-" + sysId; - - Map remoteHeaderMap = new HashMap<>(); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.ENV, env); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.IDC, idc); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, IPUtils.getLocalAddress()); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PID, String.valueOf(ThreadUtils.getPID())); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.SYS, sysId); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.USERNAME, "eventmesh"); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PASSWD, "pass"); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PRODUCERGROUP, meshGroup); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.CONSUMERGROUP, meshGroup); - // local subscription url - String localUrl = "http://" + IPUtils.getLocalAddress() + ":" - + eventMeshHTTPServer.getEventMeshHttpConfiguration().httpServerPort + String localUrl = "http://" + localAddress + ":" + + eventMeshHttpConfiguration.getHttpServerPort() + RequestURI.PUBLISH_BRIDGE.getRequestURI(); - Map remoteBodyMap = new HashMap<>(); - remoteBodyMap.put("url", localUrl); - remoteBodyMap.put("consumerGroup", meshGroup); - remoteBodyMap.put("topic", requestBodyMap.get("topic")); + remoteBodyMap.put(EventMeshConstants.URL, localUrl); + remoteBodyMap.put(EventMeshConstants.CONSUMER_GROUP, eventMeshHttpConfiguration.getMeshGroup()); + remoteBodyMap.put(EventMeshConstants.MANAGE_TOPIC, requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC)); String targetMesh = requestBodyMap.get("remoteMesh") == null ? "" : requestBodyMap.get("remoteMesh").toString(); // Get mesh address from registry - String meshAddress = getTargetMesh(consumerGroup, subscriptionList); + String meshAddress = getTargetMesh(eventMeshHttpConfiguration.getMeshGroup(), subscriptionList); if (StringUtils.isNotBlank(meshAddress)) { targetMesh = meshAddress; } + CloseableHttpClient closeableHttpClient = eventMeshHTTPServer.getHttpClientPool().getClient(); + String remoteResult = post(closeableHttpClient, targetMesh, builderRemoteHeaderMap(localAddress), remoteBodyMap, + response -> EntityUtils.toString(response.getEntity(), Constants.DEFAULT_CHARSET)); - CloseableHttpClient closeableHttpClient = eventMeshHTTPServer.httpClientPool.getClient(); + Map remoteResultMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + remoteResult, + new TypeReference>() { + })).orElseGet(Maps::newHashMap); - String remoteResult = post(closeableHttpClient, targetMesh, remoteHeaderMap, remoteBodyMap, - response -> EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET))); - - Map remoteResultMap = JsonUtils.deserialize(remoteResult, new TypeReference>() { - }); - - if (String.valueOf(EventMeshRetCode.SUCCESS.getRetCode()).equals(remoteResultMap.get("retCode"))) { - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg()); + if (String.valueOf(EventMeshRetCode.SUCCESS.getRetCode()).equals(remoteResultMap.get(EventMeshConstants.RET_CODE))) { + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg()); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); } else { @@ -248,10 +181,8 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest } catch (Exception e) { long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}" - + "|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(subscriptionList), url, e); + httpLogger.error("subscribe Remote|cost={}ms|topic={}", endTime - startTime, + JsonUtils.toJSONString(subscriptionList), e); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_SUBSCRIBE_ERR, responseHeaderMap, responseBodyMap, null); } @@ -262,40 +193,9 @@ public String[] paths() { return new String[] {RequestURI.SUBSCRIBE_REMOTE.getRequestURI()}; } - public static String post(CloseableHttpClient client, String uri, - Map requestHeader, Map requestBody, - ResponseHandler responseHandler) throws IOException { - Preconditions.checkState(client != null, "client can't be null"); - Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); - Preconditions.checkState(requestHeader != null, "requestParam can't be null"); - Preconditions.checkState(responseHandler != null, "responseHandler can't be null"); - - HttpPost httpPost = new HttpPost(uri); - - httpPost.addHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); - - //header - if (MapUtils.isNotEmpty(requestHeader)) { - for (Map.Entry entry : requestHeader.entrySet()) { - httpPost.addHeader(entry.getKey(), entry.getValue()); - } - } - - //body - if (MapUtils.isNotEmpty(requestBody)) { - String jsonStr = JsonUtils.serialize(requestBody); - httpPost.setEntity(new StringEntity(jsonStr, ContentType.APPLICATION_JSON)); - } - - //ttl - RequestConfig.Builder configBuilder = RequestConfig.custom(); - configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))) - .setConnectTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))) - .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))); - - httpPost.setConfig(configBuilder.build()); - - return client.execute(httpPost, responseHandler); + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteUnSubscribeEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteUnSubscribeEventProcessor.java index 9c3d9ff7c6..fbd1af445d 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteUnSubscribeEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/RemoteUnSubscribeEventProcessor.java @@ -25,29 +25,25 @@ import org.apache.eventmesh.common.protocol.http.common.RequestURI; import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; import org.apache.eventmesh.runtime.common.EventMeshTrace; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.AbstractEventProcessor; import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; -import java.io.IOException; -import java.nio.charset.Charset; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Executor; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -57,14 +53,14 @@ import io.netty.handler.codec.http.HttpRequest; import com.fasterxml.jackson.core.type.TypeReference; -import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; -@EventMeshTrace(isEnable = false) -public class RemoteUnSubscribeEventProcessor extends AbstractEventProcessor implements AsyncHttpProcessor { +@EventMeshTrace +public class RemoteUnSubscribeEventProcessor extends AbstractEventProcessor { - public Logger httpLogger = LoggerFactory.getLogger("http"); + private static final Logger httpLogger = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger aclLogger = LoggerFactory.getLogger(EventMeshConstants.ACL); public RemoteUnSubscribeEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { super(eventMeshHTTPServer); @@ -79,95 +75,76 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest HttpEventWrapper requestWrapper = asyncContext.getRequest(); - HttpEventWrapper responseWrapper; - + String localAddress = IPUtils.getLocalAddress(); + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); httpLogger.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), - EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress() - ); + EventMeshConstants.PROTOCOL_HTTP, remoteAddr, localAddress); // user request header Map userRequestHeaderMap = requestWrapper.getHeaderMap(); - String requestIp = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, requestIp); + userRequestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), remoteAddr); // build sys header requestWrapper.buildSysHeaderForClient(); - Map responseHeaderMap = new HashMap<>(); - responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); - responseHeaderMap - .put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); + Map responseHeaderMap = builderResponseHeaderMap(requestWrapper); Map sysHeaderMap = requestWrapper.getSysHeaderMap(); Map responseBodyMap = new HashMap<>(); - //validate header - if (StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || !StringUtils.isNumeric(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID).toString()) - || StringUtils.isBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS).toString())) { + // validate header + if (validateSysHeader(sysHeaderMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, responseHeaderMap, responseBodyMap, null); return; } - - //validate body + // validate body byte[] requestBody = requestWrapper.getBody(); - Map requestBodyMap = JsonUtils.deserialize(new String(requestBody), new TypeReference>() { - }); - + Map requestBodyMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + new String(requestBody, Constants.DEFAULT_CHARSET), + new TypeReference>() { + })).orElseGet(Maps::newHashMap); - if (requestBodyMap.get("url") == null || requestBodyMap.get("topic") == null || requestBodyMap.get("consumerGroup") == null) { + if (validatedRequestBodyMap(requestBodyMap)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, null); return; } - String unSubscribeUrl = requestBodyMap.get("url").toString(); - String consumerGroup = requestBodyMap.get("consumerGroup").toString(); - String topic = requestBodyMap.get("topic").toString(); + String topic = JsonUtils.toJSONString(requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC).toString()); long startTime = System.currentTimeMillis(); try { // request to remote - - String env = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv; - String idc = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC; - String cluster = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster; - String sysId = eventMeshHTTPServer.getEventMeshHttpConfiguration().sysID; - String meshGroup = env + "-" + idc + "-" + cluster + "-" + sysId; - - Map remoteHeaderMap = new HashMap<>(); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.ENV, env); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.IDC, idc); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, IPUtils.getLocalAddress()); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PID, String.valueOf(ThreadUtils.getPID())); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.SYS, sysId); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.USERNAME, "eventmesh"); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PASSWD, "pass"); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PRODUCERGROUP, meshGroup); - remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.CONSUMERGROUP, meshGroup); + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + String env = eventMeshHttpConfiguration.getEventMeshEnv(); + String idc = eventMeshHttpConfiguration.getEventMeshIDC(); + String cluster = eventMeshHttpConfiguration.getEventMeshCluster(); + String sysId = eventMeshHttpConfiguration.getSysID(); + String meshGroup = String.join("-", env, idc, cluster, sysId); // local unSubscription url - String unsubscribeUrl = "http://" + IPUtils.getLocalAddress() + ":" - + eventMeshHTTPServer.getEventMeshHttpConfiguration().httpServerPort + String unsubscribeUrl = "http://" + localAddress + ":" + + eventMeshHttpConfiguration.getHttpServerPort() + RequestURI.PUBLISH_BRIDGE.getRequestURI(); Map remoteBodyMap = new HashMap<>(); - remoteBodyMap.put("url", unsubscribeUrl); - remoteBodyMap.put("consumerGroup", meshGroup); - remoteBodyMap.put("topic", requestBodyMap.get("topic")); - - List unSubTopicList = JsonUtils.deserialize(topic, new TypeReference>() { - }); - - String targetMesh = requestBodyMap.get("remoteMesh").toString(); + remoteBodyMap.put(EventMeshConstants.URL, unsubscribeUrl); + remoteBodyMap.put(EventMeshConstants.CONSUMER_GROUP, meshGroup); + remoteBodyMap.put(EventMeshConstants.MANAGE_TOPIC, requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC)); + + List unSubTopicList = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + JsonUtils.toJSONString(requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC)), + new TypeReference>() { + })).orElseGet(Collections::emptyList); + + String targetMesh = ""; + if (!Objects.isNull(requestBodyMap.get("remoteMesh"))) { + targetMesh = requestBodyMap.get("remoteMesh").toString(); + } List subscriptionList = unSubTopicList.stream().map(s -> { SubscriptionItem subscriptionItem = new SubscriptionItem(); @@ -175,39 +152,35 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return subscriptionItem; }).collect(Collectors.toList()); // Get mesh address from registry - String meshAddress = getTargetMesh(consumerGroup, subscriptionList); + String meshAddress = getTargetMesh(meshGroup, subscriptionList); if (StringUtils.isNotBlank(meshAddress)) { targetMesh = meshAddress; } - CloseableHttpClient closeableHttpClient = eventMeshHTTPServer.httpClientPool.getClient(); - - String remoteResult = post(closeableHttpClient, targetMesh, remoteHeaderMap, remoteBodyMap, - response -> EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET))); + CloseableHttpClient closeableHttpClient = eventMeshHTTPServer.getHttpClientPool().getClient(); - Map remoteResultMap = JsonUtils.deserialize(remoteResult, new TypeReference>() { - }); + String remoteResult = post(closeableHttpClient, targetMesh, builderRemoteHeaderMap(localAddress), remoteBodyMap, + response -> EntityUtils.toString(response.getEntity(), Constants.DEFAULT_CHARSET)); - if (String.valueOf(EventMeshRetCode.SUCCESS.getRetCode()).equals(remoteResultMap.get("retCode"))) { - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg()); + Map remoteResultMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + remoteResult, + new TypeReference>() { + })).orElseGet(Maps::newHashMap); + if (String.valueOf(EventMeshRetCode.SUCCESS.getRetCode()).equals(remoteResultMap.get(EventMeshConstants.RET_CODE))) { + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg()); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); } else { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR, responseHeaderMap, responseBodyMap, null); } - } catch (Exception e) { long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}" - + "|bizSeqNo={}|uniqueId={}", endTime - startTime, - topic, unSubscribeUrl, e); + httpLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}", endTime - startTime, topic, e); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR, responseHeaderMap, responseBodyMap, null); } - } @Override @@ -215,40 +188,9 @@ public String[] paths() { return new String[] {RequestURI.UNSUBSCRIBE_REMOTE.getRequestURI()}; } - public static String post(CloseableHttpClient client, String uri, - Map requestHeader, Map requestBody, - ResponseHandler responseHandler) throws IOException { - Preconditions.checkState(client != null, "client can't be null"); - Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); - Preconditions.checkState(requestHeader != null, "requestParam can't be null"); - Preconditions.checkState(responseHandler != null, "responseHandler can't be null"); - - HttpPost httpPost = new HttpPost(uri); - - httpPost.addHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); - - //header - if (MapUtils.isNotEmpty(requestHeader)) { - for (Map.Entry entry : requestHeader.entrySet()) { - httpPost.addHeader(entry.getKey(), entry.getValue()); - } - } - - //body - if (MapUtils.isNotEmpty(requestBody)) { - String jsonStr = JsonUtils.serialize(requestBody); - httpPost.setEntity(new StringEntity(jsonStr, ContentType.APPLICATION_JSON)); - } - - //ttl - RequestConfig.Builder configBuilder = RequestConfig.custom(); - configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))) - .setConnectTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))) - .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))); - - httpPost.setConfig(configBuilder.build()); - - return client.execute(httpPost, responseHandler); + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ReplyMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ReplyMessageProcessor.java index aadb17e456..55051573c2 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ReplyMessageProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ReplyMessageProcessor.java @@ -25,7 +25,6 @@ import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.message.ReplyMessageResponseBody; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.RequestCode; @@ -35,19 +34,20 @@ import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.metrics.http.HttpMetrics; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; -import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -57,15 +57,15 @@ import io.cloudevents.core.builder.CloudEventBuilder; import io.netty.channel.ChannelHandlerContext; -public class ReplyMessageProcessor implements HttpRequestProcessor { +public class ReplyMessageProcessor extends AbstractHttpRequestProcessor { - public Logger messageLogger = LoggerFactory.getLogger("message"); + public static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + public final Logger cmdLogger = LoggerFactory.getLogger(EventMeshConstants.CMD); - public Logger httpLogger = LoggerFactory.getLogger("http"); + public final Logger httpLogger = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); - private EventMeshHTTPServer eventMeshHTTPServer; + private final EventMeshHTTPServer eventMeshHTTPServer; public ReplyMessageProcessor(EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; @@ -73,220 +73,182 @@ public ReplyMessageProcessor(EventMeshHTTPServer eventMeshHTTPServer) { @Override public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { - HttpCommand responseEventMeshCommand; + String localAddress = IPUtils.getLocalAddress(); + HttpCommand request = asyncContext.getRequest(); + final String channelRemoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get(Integer.valueOf(request.getRequestCode())), + EventMeshConstants.PROTOCOL_HTTP, + channelRemoteAddr, localAddress); - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); - - ReplyMessageRequestHeader replyMessageRequestHeader = (ReplyMessageRequestHeader) asyncContext.getRequest().getHeader(); - //ReplyMessageRequestBody replyMessageRequestBody = (ReplyMessageRequestBody) asyncContext.getRequest().getBody(); + ReplyMessageRequestHeader replyMessageRequestHeader = (ReplyMessageRequestHeader) request.getHeader(); String protocolType = replyMessageRequestHeader.getProtocolType(); ProtocolAdaptor httpCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(asyncContext.getRequest()); - + CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(request); + EventMeshHTTPConfiguration httpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); ReplyMessageResponseHeader replyMessageResponseHeader = - ReplyMessageResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - //validate event - if (event == null - || StringUtils.isBlank(event.getId()) - || event.getSource() == null - || event.getSpecVersion() == null - || StringUtils.isBlank(event.getType()) - || StringUtils.isBlank(event.getSubject())) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + ReplyMessageResponseHeader.buildHeader(Integer.valueOf(request.getRequestCode()), + httpConfiguration.getEventMeshCluster(), + localAddress, httpConfiguration.getEventMeshEnv(), + httpConfiguration.getEventMeshIDC()); + + // validate event + if (!ObjectUtils.allNotNull(event, event.getSource(), event.getSpecVersion()) + || StringUtils.isAnyBlank(event.getId(), event.getType(), event.getSubject())) { + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, ReplyMessageResponseBody.class); return; } - String idc = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.IDC)).toString(); - String pid = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.PID)).toString(); - String sys = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS)).toString(); - - //validate HEADER - if (StringUtils.isBlank(idc) - || StringUtils.isBlank(pid) - || !StringUtils.isNumeric(pid) - || StringUtils.isBlank(sys)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + String idc = getExtension(event, ProtocolKey.ClientInstanceKey.IDC.getKey()); + String pid = getExtension(event, ProtocolKey.ClientInstanceKey.PID.getKey()); + String sys = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); + + // validate HEADER + if (StringUtils.isAnyBlank(idc, pid, sys) + || !StringUtils.isNumeric(pid)) { + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, ReplyMessageResponseBody.class); return; } - String bizNo = Objects.requireNonNull(event.getExtension(SendMessageRequestBody.BIZSEQNO)).toString(); - String uniqueId = Objects.requireNonNull(event.getExtension(SendMessageRequestBody.UNIQUEID)).toString(); - String producerGroup = Objects.requireNonNull(event.getExtension(SendMessageRequestBody.PRODUCERGROUP)).toString(); - - //validate body - if (StringUtils.isBlank(bizNo) - || StringUtils.isBlank(uniqueId) - || StringUtils.isBlank(producerGroup) - || event.getData() == null) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + String bizNo = getExtension(event, SendMessageRequestBody.BIZSEQNO); + String uniqueId = getExtension(event, SendMessageRequestBody.UNIQUEID); + String producerGroup = getExtension(event, SendMessageRequestBody.PRODUCERGROUP); + + // validate body + if (StringUtils.isAnyBlank(bizNo, uniqueId, producerGroup) + || event.getData() == null) { + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, ReplyMessageResponseBody.class); return; } // control flow rate limit + HttpMetrics summaryMetrics = eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics(); if (!eventMeshHTTPServer.getMsgRateLimiter() - .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getErrMsg())); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPDiscard(); - asyncContext.onComplete(responseEventMeshCommand); + .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + summaryMetrics.recordHTTPDiscard(); + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR, null, ReplyMessageResponseBody.class); return; } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { + String content = event.getData() == null ? "" : new String(event.getData().toBytes(), Constants.DEFAULT_CHARSET); + if (content.length() > httpConfiguration.getEventMeshEventSize()) { httpLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - "Event size exceeds the limit: " + eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize)); - asyncContext.onComplete(responseEventMeshCommand); + httpConfiguration.getEventMeshEventSize()); + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, + "Event size exceeds the limit: " + httpConfiguration.getEventMeshEventSize(), + ReplyMessageResponseBody.class); return; } EventMeshProducer eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); - if (!eventMeshProducer.getStarted().get()) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + if (!eventMeshProducer.isStarted()) { + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR, null, ReplyMessageResponseBody.class); return; } long startTime = System.currentTimeMillis(); - String replyTopic = EventMeshConstants.RR_REPLY_TOPIC; - String origTopic = event.getSubject(); - - final String replyMQCluster = event.getExtension(EventMeshConstants.PROPERTY_MESSAGE_CLUSTER).toString(); - if (!org.apache.commons.lang3.StringUtils.isEmpty(replyMQCluster)) { + final String replyMQCluster = getExtension(event, EventMeshConstants.PROPERTY_MESSAGE_CLUSTER); + if (!StringUtils.isEmpty(replyMQCluster)) { replyTopic = replyMQCluster + "-" + replyTopic; } else { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR, null, ReplyMessageResponseBody.class); return; } try { // body - //omsMsg.setBody(replyMessageRequestBody.getContent().getBytes(EventMeshConstants.DEFAULT_CHARSET)); event = CloudEventBuilder.from(event) - .withSubject(replyTopic) - .withExtension("msgtype", "persistent") - .withExtension(Constants.PROPERTY_MESSAGE_TIMEOUT, String.valueOf(EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS)) - .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) - .build(); - - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, replyTopic); - } + .withSubject(replyTopic) + .withExtension(EventMeshConstants.MSG_TYPE, EventMeshConstants.PERSISTENT) + .withExtension(Constants.PROPERTY_MESSAGE_TIMEOUT, String.valueOf(EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS)) + .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) + .build(); + + MESSAGE_LOGGER.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, replyTopic); } catch (Exception e) { - messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, replyTopic, e); - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(responseEventMeshCommand); + MESSAGE_LOGGER.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, replyTopic, e); + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR, + EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2), + ReplyMessageResponseBody.class); return; } final SendMessageContext sendMessageContext = new SendMessageContext(bizNo, event, eventMeshProducer, eventMeshHTTPServer); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordReplyMsg(); - + summaryMetrics.recordReplyMsg(); CompleteHandler handler = httpCommand -> { try { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", httpCommand); - } + httpLogger.debug("{}", httpCommand); eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPReqResTimeCost( - System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + summaryMetrics.recordHTTPReqResTimeCost( + System.currentTimeMillis() - request.getReqTime()); } catch (Exception ex) { - //ignore + // ignore } }; - try { CloudEvent clone = CloudEventBuilder.from(sendMessageContext.getEvent()) .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .build(); sendMessageContext.setEvent(clone); eventMeshProducer.reply(sendMessageContext, new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { - HttpCommand succ = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), EventMeshRetCode.SUCCESS.getErrMsg())); + HttpCommand succ = request.createHttpCommandResponse( + replyMessageResponseHeader, + ReplyMessageResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), EventMeshRetCode.SUCCESS.getErrMsg())); asyncContext.onComplete(succ, handler); long endTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordReplyMsgCost(endTime - startTime); - messageLogger.info("message|eventMesh2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", + summaryMetrics.recordReplyMsgCost(endTime - startTime); + MESSAGE_LOGGER.info("message|eventMesh2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, replyMQCluster + "-" + EventMeshConstants.RR_REPLY_TOPIC, origTopic, bizNo, uniqueId); } @Override public void onException(OnExceptionContext context) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + HttpCommand err = request.createHttpCommandResponse( replyMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getRetCode(), + ReplyMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getRetCode(), EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(context.getException(), 2))); asyncContext.onComplete(err, handler); long endTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordReplyMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordReplyMsgCost(endTime - startTime); - messageLogger.error("message|eventMesh2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", + summaryMetrics.recordReplyMsgFailed(); + summaryMetrics.recordReplyMsgCost(endTime - startTime); + MESSAGE_LOGGER.error("message|eventMesh2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, replyMQCluster + "-" + EventMeshConstants.RR_REPLY_TOPIC, origTopic, bizNo, uniqueId, context.getException()); } }); } catch (Exception ex) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - replyMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(ex, 2))); - asyncContext.onComplete(err); + completeResponse(request, asyncContext, replyMessageResponseHeader, + EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR, + EventMeshRetCode.EVENTMESH_REPLY_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(ex, 2), + ReplyMessageResponseBody.class); long endTime = System.currentTimeMillis(); - messageLogger.error("message|eventMesh2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", + MESSAGE_LOGGER.error("message|eventMesh2mq|RSP|SYNC|reply2MQCost={}|topic={}|origTopic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, replyTopic, origTopic, bizNo, uniqueId, ex); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordReplyMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordReplyMsgCost(endTime - startTime); + summaryMetrics.recordReplyMsgFailed(); + summaryMetrics.recordReplyMsgCost(endTime - startTime); } } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getReplyMsgExecutor(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncEventProcessor.java index 51076199ec..0e41d827ab 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncEventProcessor.java @@ -19,7 +19,9 @@ import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.AclException; import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; @@ -27,7 +29,10 @@ import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.RequestURI; import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.function.filter.pattern.Pattern; +import org.apache.eventmesh.function.transformer.Transformer; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.acl.Acl; @@ -35,8 +40,8 @@ import org.apache.eventmesh.runtime.common.EventMeshTrace; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; @@ -46,50 +51,47 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpRequest; +import lombok.extern.slf4j.Slf4j; + +@Slf4j @EventMeshTrace(isEnable = true) public class SendAsyncEventProcessor implements AsyncHttpProcessor { - public Logger messageLogger = LoggerFactory.getLogger("message"); - - public Logger httpLogger = LoggerFactory.getLogger("http"); + private final transient EventMeshHTTPServer eventMeshHTTPServer; - public Logger aclLogger = LoggerFactory.getLogger("acl"); - - private EventMeshHTTPServer eventMeshHTTPServer; + private final Acl acl; public SendAsyncEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } @Override - public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) throws Exception { - - AsyncContext asyncContext = handlerSpecific.getAsyncContext(); - - ChannelHandlerContext ctx = handlerSpecific.getCtx(); + public void handler(final HandlerService.HandlerSpecific handlerSpecific, final HttpRequest httpRequest) throws Exception { - HttpEventWrapper requestWrapper = asyncContext.getRequest(); + final AsyncContext asyncContext = handlerSpecific.getAsyncContext(); + final ChannelHandlerContext ctx = handlerSpecific.getCtx(); + final HttpEventWrapper requestWrapper = asyncContext.getRequest(); - HttpEventWrapper responseWrapper; + final String localAddress = IPUtils.getLocalAddress(); - httpLogger.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), - EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + log.info("uri={}|{}|client2eventMesh|from={}|to={}", + requestWrapper.getRequestURI(), EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), localAddress); // user request header - Map requestHeaderMap = requestWrapper.getHeaderMap(); - String source = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - requestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, source); + final Map requestHeaderMap = requestWrapper.getHeaderMap(); + final String source = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + requestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), source); // build sys header requestWrapper.buildSysHeaderForClient(); @@ -98,41 +100,43 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest requestHeaderMap.putIfAbsent("source", source); requestWrapper.buildSysHeaderForCE(); - String bizNo = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.BIZSEQNO, RandomStringUtils.generateNum(30)).toString(); - String uniqueId = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.UNIQUEID, RandomStringUtils.generateNum(30)).toString(); - String ttl = requestHeaderMap.getOrDefault(Constants.EVENTMESH_MESSAGE_CONST_TTL, 4 * 1000).toString(); + final String bizNo = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey(), + RandomStringUtils.generateNum(32)).toString(); + final String uniqueId = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey(), + RandomStringUtils.generateNum(32)).toString(); + final String ttl = requestHeaderMap.getOrDefault(Constants.EVENTMESH_MESSAGE_CONST_TTL, + 14400000).toString(); - - requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.BIZSEQNO, bizNo); - requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.UNIQUEID, uniqueId); + requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey(), bizNo); + requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey(), uniqueId); requestWrapper.getSysHeaderMap().putIfAbsent(Constants.EVENTMESH_MESSAGE_CONST_TTL, ttl); - Map responseHeaderMap = new HashMap<>(); + final Map responseHeaderMap = new HashMap<>(); responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster); + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster()); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, - IPUtils.getLocalAddress()); + localAddress); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv()); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); - Map responseBodyMap = new HashMap<>(); + final Map responseBodyMap = new HashMap<>(); - String protocolType = requestHeaderMap.getOrDefault(ProtocolKey.PROTOCOL_TYPE, "http").toString(); + final String protocolType = requestHeaderMap.getOrDefault(ProtocolKey.PROTOCOL_TYPE, + "http").toString(); - ProtocolAdaptor httpProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + final ProtocolAdaptor httpProtocolAdaptor = + ProtocolPluginFactory.getProtocolAdaptor(protocolType); CloudEvent event = httpProtocolAdaptor.toCloudEvent(requestWrapper); - //validate event + // validate event if (event == null - || StringUtils.isBlank(event.getId()) || event.getSource() == null || event.getSpecVersion() == null - || StringUtils.isBlank(event.getType()) - || StringUtils.isBlank(event.getSubject())) { + || StringUtils.isAnyBlank(event.getId(), event.getType(), event.getSubject())) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); @@ -140,49 +144,51 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return; } - String idc = event.getExtension(ProtocolKey.ClientInstanceKey.IDC).toString(); - String pid = event.getExtension(ProtocolKey.ClientInstanceKey.PID).toString(); - String sys = event.getExtension(ProtocolKey.ClientInstanceKey.SYS).toString(); + final String idc = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.IDC.getKey())).toString(); + final String pid = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.PID.getKey())).toString(); + final String sys = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS.getKey())).toString(); + + // validate event-extension - //validate event-extension - if (StringUtils.isBlank(idc) - || StringUtils.isBlank(pid) - || !StringUtils.isNumeric(pid) - || StringUtils.isBlank(sys)) { + if (StringUtils.isAnyBlank(idc, pid, sys) + || !StringUtils.isNumeric(pid)) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; } + final String producerGroup = Objects.requireNonNull( + event.getExtension(ProtocolKey.ClientInstanceKey.PRODUCERGROUP.getKey())).toString(); + final String topic = event.getSubject(); - String producerGroup = event.getExtension(ProtocolKey.ClientInstanceKey.PRODUCERGROUP).toString(); - String topic = event.getSubject(); + Pattern filterPattern = eventMeshHTTPServer.getFilterEngine().getFilterPattern(producerGroup + "-" + topic); + Transformer transformer = eventMeshHTTPServer.getTransformerEngine().getTransformer(producerGroup + "-" + topic); - //validate body - if (StringUtils.isBlank(bizNo) - || StringUtils.isBlank(uniqueId) - || StringUtils.isBlank(producerGroup) - || StringUtils.isBlank(topic) + // validate body + if (StringUtils.isAnyBlank(bizNo, uniqueId, producerGroup, topic) || event.getData() == null) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; } - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = event.getExtension(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = event.getExtension(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - String subsystem = event.getExtension(ProtocolKey.ClientInstanceKey.SYS).toString(); - String requestURI = requestWrapper.getRequestURI(); + final String token = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.TOKEN.getKey())).toString(); + // do acl check + if (eventMeshHTTPServer.getEventMeshHttpConfiguration().isEventMeshServerSecurityEnable()) { + final String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + final String requestURI = requestWrapper.getRequestURI(); + String subsystem = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS.getKey())).toString(); try { - Acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, topic, requestURI); + EventMeshServicePubTopicInfo eventMeshServicePubTopicInfo = eventMeshHTTPServer.getEventMeshServer() + .getProducerTopicManager().getEventMeshServicePubTopicInfo(producerGroup); + if (eventMeshServicePubTopicInfo == null) { + throw new AclException("no group register"); + } + this.acl.doAclCheckInHttpSend(remoteAddr, token, subsystem, topic, requestURI, eventMeshServicePubTopicInfo); } catch (Exception e) { - //String errorMsg = String.format("CLIENT HAS NO PERMISSION,send failed, topic:%s, subsys:%s, realIp:%s", topic, subsys, realIp); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_ACL_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); - aclLogger.warn("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); + log.warn("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); return; } } @@ -195,18 +201,22 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return; } - EventMeshProducer eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); + final EventMeshProducer eventMeshProducer; + if (StringUtils.isNotBlank(token)) { + eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup, token); + } else { + eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); + } - if (!eventMeshProducer.getStarted().get()) { + if (!eventMeshProducer.isStarted()) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { - httpLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); + final String content = new String(Objects.requireNonNull(event.getData()).toBytes(), StandardCharsets.UTF_8); + if (Objects.requireNonNull(content).length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEventSize()) { + log.error("Event size exceeds the limit: {}", eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEventSize()); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_SIZE_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; @@ -214,67 +224,84 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest try { event = CloudEventBuilder.from(event) - .withExtension("msgtype", "persistent") + .withExtension(EventMeshConstants.MSG_TYPE, EventMeshConstants.PERSISTENT) .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .build(); - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); - } + log.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); } catch (Exception e) { - messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); + log.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; } - final SendMessageContext sendMessageContext = new SendMessageContext(bizNo, event, eventMeshProducer, - eventMeshHTTPServer); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsg(); - - long startTime = System.currentTimeMillis(); + final SendMessageContext sendMessageContext = new SendMessageContext(bizNo, event, eventMeshProducer, eventMeshHTTPServer); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsg(); + final long startTime = System.currentTimeMillis(); + boolean isFiltered = true; try { event = CloudEventBuilder.from(sendMessageContext.getEvent()) .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .build(); handlerSpecific.getTraceOperation().createClientTraceOperation(EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event), EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_CLIENT_SPAN, false); + if (filterPattern != null) { + isFiltered = filterPattern.filter(JsonUtils.toJSONString(event)); + } - eventMeshProducer.send(sendMessageContext, new SendCallback() { - - @Override - public void onSuccess(SendResult sendResult) { - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg() + sendResult.toString()); + // apply transformer + if (isFiltered && transformer != null) { + String data = transformer.transform(JsonUtils.toJSONString(event)); + event = CloudEventBuilder.from(event).withData(Objects.requireNonNull(JsonUtils.toJSONString(data)) + .getBytes(StandardCharsets.UTF_8)).build(); + sendMessageContext.setEvent(event); + } - messageLogger.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - System.currentTimeMillis() - startTime, topic, bizNo, uniqueId); - handlerSpecific.getTraceOperation().endLatestTrace(sendMessageContext.getEvent()); - handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); - } + if (isFiltered) { + eventMeshProducer.send(sendMessageContext, new SendCallback() { + + @Override + public void onSuccess(final SendResult sendResult) { + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg() + sendResult); + + log.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + System.currentTimeMillis() - startTime, topic, bizNo, uniqueId); + handlerSpecific.getTraceOperation().endLatestTrace(sendMessageContext.getEvent()); + handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); + } + + @Override + public void onException(final OnExceptionContext context) { + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg() + + EventMeshUtil.stackTrace(context.getException(), 2)); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); + handlerSpecific.getTraceOperation().exceptionLatestTrace(context.getException(), + EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), sendMessageContext.getEvent())); + + handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + System.currentTimeMillis() - startTime, topic, bizNo, uniqueId, context.getException()); + } + }); + } else { + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}|apply filter failed", + System.currentTimeMillis() - startTime, topic, bizNo, uniqueId); + handlerSpecific.getTraceOperation().endLatestTrace(sendMessageContext.getEvent()); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_FILTER_MSG_ERR, responseHeaderMap, responseBodyMap, + EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); + } - @Override - public void onException(OnExceptionContext context) { - responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg() - + EventMeshUtil.stackTrace(context.getException(), 2)); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); - handlerSpecific.getTraceOperation().exceptionLatestTrace(context.getException(), - EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), sendMessageContext.getEvent())); - - handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); - messageLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - System.currentTimeMillis() - startTime, topic, bizNo, uniqueId, context.getException()); - } - }); } catch (Exception ex) { - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR, responseHeaderMap, responseBodyMap, null); - long endTime = System.currentTimeMillis(); - messageLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + final long endTime = System.currentTimeMillis(); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, topic, bizNo, uniqueId, ex); } } @@ -283,4 +310,9 @@ public void onException(OnExceptionContext context) { public String[] paths() { return new String[] {RequestURI.PUBLISH.getRequestURI()}; } + + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getSendMsgExecutor(); + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncMessageProcessor.java index f2e01c04ff..f4dcc65a97 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncMessageProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncMessageProcessor.java @@ -20,6 +20,7 @@ import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; @@ -34,21 +35,23 @@ import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; -import org.apache.eventmesh.runtime.trace.TraceUtils; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.metrics.http.HttpMetrics; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.TraceUtils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -59,269 +62,206 @@ import io.netty.channel.ChannelHandlerContext; import io.opentelemetry.api.trace.Span; -public class SendAsyncMessageProcessor implements HttpRequestProcessor { +public class SendAsyncMessageProcessor extends AbstractHttpRequestProcessor { - public Logger messageLogger = LoggerFactory.getLogger("message"); + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - public Logger httpLogger = LoggerFactory.getLogger("http"); + private static final Logger HTTP_LOGGER = LoggerFactory.getLogger(EventMeshConstants.PROTOCOL_HTTP); - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + private static final Logger CMD_LOGGER = LoggerFactory.getLogger(EventMeshConstants.CMD); - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private static final Logger ACL_LOGGER = LoggerFactory.getLogger(EventMeshConstants.ACL); - private EventMeshHTTPServer eventMeshHTTPServer; + private final EventMeshHTTPServer eventMeshHTTPServer; - public SendAsyncMessageProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + private final Acl acl; + + public SendAsyncMessageProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } @Override public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) throws Exception { HttpCommand responseEventMeshCommand; - - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get( - Integer.valueOf(asyncContext.getRequest().getRequestCode())), + String localAddress = IPUtils.getLocalAddress(); + HttpCommand request = asyncContext.getRequest(); + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + CMD_LOGGER.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get( + Integer.valueOf(request.getRequestCode())), EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + remoteAddr, localAddress); - SendMessageRequestHeader sendMessageRequestHeader = (SendMessageRequestHeader) asyncContext.getRequest().getHeader(); + SendMessageRequestHeader sendMessageRequestHeader = (SendMessageRequestHeader) request.getHeader(); + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); SendMessageResponseHeader sendMessageResponseHeader = - SendMessageResponseHeader.buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); + SendMessageResponseHeader.buildHeader(Integer.valueOf(request.getRequestCode()), + eventMeshHttpConfiguration.getEventMeshCluster(), + localAddress, eventMeshHttpConfiguration.getEventMeshEnv(), + eventMeshHttpConfiguration.getEventMeshIDC()); String protocolType = sendMessageRequestHeader.getProtocolType(); - String protocolVersin = sendMessageRequestHeader.getProtocolVersion(); - ProtocolAdaptor httpCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); - CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(asyncContext.getRequest()); + String protocolVersion = sendMessageRequestHeader.getProtocolVersion(); + ProtocolAdaptor httpCommandProtocolAdaptor = + ProtocolPluginFactory.getProtocolAdaptor(protocolType); + CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(request); - Span span = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), + Span span = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, true); - //validate event - if (event == null - || StringUtils.isBlank(event.getId()) - || event.getSource() == null - || event.getSpecVersion() == null - || StringUtils.isBlank(event.getType()) - || StringUtils.isBlank(event.getSubject())) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg(), null); + // validate event + if (!ObjectUtils.allNotNull(event, event.getSource(), event.getSpecVersion()) + || StringUtils.isAnyBlank(event.getId(), event.getType(), event.getSubject())) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR); return; } - String idc = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.IDC)).toString(); - String pid = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.PID)).toString(); - String sys = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS)).toString(); - - //validate event-extension - if (StringUtils.isBlank(idc) - || StringUtils.isBlank(pid) - || !StringUtils.isNumeric(pid) - || StringUtils.isBlank(sys)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg(), null); + String idc = getExtension(event, ProtocolKey.ClientInstanceKey.IDC.getKey()); + String pid = getExtension(event, ProtocolKey.ClientInstanceKey.PID.getKey()); + String sys = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); + + // validate event-extension + if (StringUtils.isAnyBlank(idc, pid, sys) + || !StringUtils.isNumeric(pid)) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR); return; } - String bizNo = Objects.requireNonNull(event.getExtension(SendMessageRequestBody.BIZSEQNO)).toString(); - String uniqueId = Objects.requireNonNull(event.getExtension(SendMessageRequestBody.UNIQUEID)).toString(); - String producerGroup = Objects.requireNonNull(event.getExtension(SendMessageRequestBody.PRODUCERGROUP)).toString(); + String bizNo = getExtension(event, SendMessageRequestBody.BIZSEQNO); + String uniqueId = getExtension(event, SendMessageRequestBody.UNIQUEID); + String producerGroup = getExtension(event, SendMessageRequestBody.PRODUCERGROUP); String topic = event.getSubject(); - //validate body - if (StringUtils.isBlank(bizNo) - || StringUtils.isBlank(uniqueId) - || StringUtils.isBlank(producerGroup) - || StringUtils.isBlank(topic) + // validate body + if (StringUtils.isAnyBlank(bizNo, uniqueId, producerGroup, topic) || event.getData() == null) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg(), null); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR); return; } - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = event.getExtension(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = event.getExtension(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - String subsystem = event.getExtension(ProtocolKey.ClientInstanceKey.SYS).toString(); - int requestCode = Integer.parseInt(asyncContext.getRequest().getRequestCode()); + // do acl check + if (eventMeshHttpConfiguration.isEventMeshServerSecurityEnable()) { + String user = getExtension(event, ProtocolKey.ClientInstanceKey.USERNAME.getKey()); + String pass = getExtension(event, ProtocolKey.ClientInstanceKey.PASSWD.getKey()); + String subsystem = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); + int requestCode = Integer.parseInt(request.getRequestCode()); try { - Acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, topic, requestCode); + this.acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, topic, requestCode); } catch (Exception e) { - //String errorMsg = String.format("CLIENT HAS NO PERMISSION,send failed, topic:%s, subsys:%s, realIp:%s", topic, subsys, realIp); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_ACL_ERR.getRetCode(), e.getMessage())); - asyncContext.onComplete(responseEventMeshCommand); - aclLogger.warn("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_ACL_ERR.getErrMsg(), null); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_ACL_ERR, e.getMessage(), SendMessageResponseBody.class); + ACL_LOGGER.warn("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); + + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_ACL_ERR); return; } } + final HttpMetrics summaryMetrics = eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics(); // control flow rate limit if (!eventMeshHTTPServer.getMsgRateLimiter() .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getErrMsg())); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPDiscard(); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getErrMsg(), null); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR, null, SendMessageResponseBody.class); + summaryMetrics.recordHTTPDiscard(); + + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR); return; } EventMeshProducer eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); - if (!eventMeshProducer.getStarted().get()) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getErrMsg(), null); + if (!eventMeshProducer.isStarted()) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR, null, SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR); return; } String ttl = String.valueOf(EventMeshConstants.DEFAULT_MSG_TTL_MILLS); - if (StringUtils.isBlank(event.getExtension(SendMessageRequestBody.TTL).toString()) - && !StringUtils.isNumeric(event.getExtension(SendMessageRequestBody.TTL).toString())) { + String ttlExt = getExtension(event, SendMessageRequestBody.TTL); + if (StringUtils.isBlank(ttlExt) && !StringUtils.isNumeric(ttlExt)) { event = CloudEventBuilder.from(event).withExtension(SendMessageRequestBody.TTL, ttl).build(); } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { - httpLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_SIZE_ERR.getRetCode(), - "Event size exceeds the limit: " + eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize)); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_SIZE_ERR.getErrMsg(), null); + String content = event.getData() == null ? "" : new String(Objects.requireNonNull(event.getData()).toBytes(), Constants.DEFAULT_CHARSET); + if (content.length() > eventMeshHttpConfiguration.getEventMeshEventSize()) { + HTTP_LOGGER.error("Event size exceeds the limit: {}", + eventMeshHttpConfiguration.getEventMeshEventSize()); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_SIZE_ERR, + "Event size exceeds the limit: " + eventMeshHttpConfiguration.getEventMeshEventSize(), + SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_SIZE_ERR); return; } try { event = CloudEventBuilder.from(event) - .withExtension("msgtype", "persistent") - .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, asyncContext.getRequest().reqTime) - .withExtension(EventMeshConstants.REQ_SEND_EVENTMESH_IP, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerIp) + .withExtension(EventMeshConstants.MSG_TYPE, EventMeshConstants.PERSISTENT) + .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, request.reqTime) + .withExtension(EventMeshConstants.REQ_SEND_EVENTMESH_IP, eventMeshHttpConfiguration.getEventMeshServerIp()) .build(); - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); - } + MESSAGE_LOGGER.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); } catch (Exception e) { - messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(responseEventMeshCommand); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg(), null); + MESSAGE_LOGGER.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR, + EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2), + SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR); return; } final SendMessageContext sendMessageContext = new SendMessageContext(bizNo, event, eventMeshProducer, eventMeshHTTPServer); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsg(); + summaryMetrics.recordSendMsg(); long startTime = System.currentTimeMillis(); - final CompleteHandler handler = new CompleteHandler() { - @Override - public void onResponse(HttpCommand httpCommand) { - try { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", httpCommand); - } - eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + final CompleteHandler handler = httpCommand -> { + try { + HTTP_LOGGER.debug("{}", httpCommand); + eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPReqResTimeCost( - System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); - } catch (Exception ex) { - //ignore - } + summaryMetrics.recordHTTPReqResTimeCost( + System.currentTimeMillis() - request.getReqTime()); + } catch (Exception ex) { + // ignore } }; - try { event = CloudEventBuilder.from(sendMessageContext.getEvent()) .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .build(); sendMessageContext.setEvent(event); - Span clientSpan = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), + Span clientSpan = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_CLIENT_SPAN, false); try { eventMeshProducer.send(sendMessageContext, new SendCallback() { @Override public void onSuccess(SendResult sendResult) { - HttpCommand succ = asyncContext.getRequest().createHttpCommandResponse( + HttpCommand succ = request.createHttpCommandResponse( sendMessageResponseHeader, SendMessageResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), - EventMeshRetCode.SUCCESS.getErrMsg() + sendResult.toString())); + EventMeshRetCode.SUCCESS.getErrMsg() + sendResult)); asyncContext.onComplete(succ, handler); long endTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); - messageLogger.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + summaryMetrics.recordSendMsgCost(endTime - startTime); + MESSAGE_LOGGER.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, topic, bizNo, uniqueId); TraceUtils.finishSpan(span, sendMessageContext.getEvent()); @@ -329,22 +269,22 @@ public void onSuccess(SendResult sendResult) { @Override public void onException(OnExceptionContext context) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( + HttpCommand err = request.createHttpCommandResponse( sendMessageResponseHeader, SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode(), EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(context.getException(), 2))); asyncContext.onComplete(err, handler); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); long endTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); - messageLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + summaryMetrics.recordSendMsgFailed(); + summaryMetrics.recordSendMsgCost(endTime - startTime); + MESSAGE_LOGGER.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, topic, bizNo, uniqueId, context.getException()); TraceUtils.finishSpanWithException(span, - EventMeshUtil.getCloudEventExtensionMap(protocolVersin, sendMessageContext.getEvent()), + EventMeshUtil.getCloudEventExtensionMap(protocolVersion, sendMessageContext.getEvent()), EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg(), context.getException()); } }); @@ -352,34 +292,29 @@ public void onException(OnExceptionContext context) { TraceUtils.finishSpan(clientSpan, event); } - } catch (Exception ex) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg() - + EventMeshUtil.stackTrace(ex, 2))); - asyncContext.onComplete(err); - - Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); - TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersin, event), - EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg(), null); - - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR, null, SendMessageResponseBody.class); + spanWithException(event, protocolVersion, EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR); + + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); long endTime = System.currentTimeMillis(); - messageLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + MESSAGE_LOGGER.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, topic, bizNo, uniqueId, ex); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); + summaryMetrics.recordSendMsgFailed(); + summaryMetrics.recordSendMsgCost(endTime - startTime); } - - return; } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getSendMsgExecutor(); } + private void spanWithException(CloudEvent event, String protocolVersion, EventMeshRetCode retCode) { + Span excepSpan = TraceUtils.prepareServerSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, false); + TraceUtils.finishSpanWithException(excepSpan, EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), + retCode.getErrMsg(), null); + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncRemoteEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncRemoteEventProcessor.java index 9d1eb94a68..fb4f21a82d 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncRemoteEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendAsyncRemoteEventProcessor.java @@ -36,8 +36,8 @@ import org.apache.eventmesh.runtime.common.EventMeshTrace; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; @@ -48,11 +48,11 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; @@ -60,50 +60,58 @@ import io.netty.handler.codec.http.HttpRequest; import com.fasterxml.jackson.core.type.TypeReference; +import com.google.common.collect.Maps; + +import lombok.extern.slf4j.Slf4j; +@Slf4j @EventMeshTrace(isEnable = true) public class SendAsyncRemoteEventProcessor implements AsyncHttpProcessor { - public Logger messageLogger = LoggerFactory.getLogger("message"); - - public Logger httpLogger = LoggerFactory.getLogger("http"); + private final transient EventMeshHTTPServer eventMeshHTTPServer; - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private final Acl acl; - private EventMeshHTTPServer eventMeshHTTPServer; - - public SendAsyncRemoteEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public SendAsyncRemoteEventProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } @Override - public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest httpRequest) throws Exception { - - AsyncContext asyncContext = handlerSpecific.getAsyncContext(); + public void handler(final HandlerService.HandlerSpecific handlerSpecific, final HttpRequest httpRequest) throws Exception { - ChannelHandlerContext ctx = handlerSpecific.getCtx(); + final AsyncContext asyncContext = handlerSpecific.getAsyncContext(); - HttpEventWrapper requestWrapper = asyncContext.getRequest(); + final ChannelHandlerContext ctx = handlerSpecific.getCtx(); - HttpEventWrapper responseWrapper; + final HttpEventWrapper requestWrapper = asyncContext.getRequest(); - httpLogger.info("uri={}|{}|client2eventMesh|from={}|to={}", requestWrapper.getRequestURI(), - EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); + final String localAddress = IPUtils.getLocalAddress(); + log.info("uri={}|{}|client2eventMesh|from={}|to={}", + requestWrapper.getRequestURI(), EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), localAddress); // user request header - Map requestHeaderMap = requestWrapper.getHeaderMap(); - String source = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - - String env = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv; - String idc = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC; - String cluster = eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster; - String sysId = eventMeshHTTPServer.getEventMeshHttpConfiguration().sysID; - String meshGroup = env + "-" + idc + "-" + cluster + "-" + sysId; - requestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP, source); - requestHeaderMap.put(ProtocolKey.ClientInstanceKey.ENV, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); - requestHeaderMap.put(ProtocolKey.ClientInstanceKey.IDC, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - requestHeaderMap.put(ProtocolKey.ClientInstanceKey.SYS, eventMeshHTTPServer.getEventMeshHttpConfiguration().sysID); - requestHeaderMap.put(ProtocolKey.ClientInstanceKey.PRODUCERGROUP, meshGroup); + final Map requestHeaderMap = requestWrapper.getHeaderMap(); + final String source = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + + final String env = eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv(); + final String meshGroup = new StringBuilder() + .append(env) + .append('-') + .append(eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()) + .append('-') + .append(eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster()) + .append('-') + .append(eventMeshHTTPServer.getEventMeshHttpConfiguration().getSysID()) + .toString(); + requestHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), source); + requestHeaderMap.put(ProtocolKey.ClientInstanceKey.ENV.getKey(), + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv()); + requestHeaderMap.put(ProtocolKey.ClientInstanceKey.IDC.getKey(), + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); + requestHeaderMap.put(ProtocolKey.ClientInstanceKey.SYS.getKey(), + eventMeshHTTPServer.getEventMeshHttpConfiguration().getSysID()); + requestHeaderMap.put(ProtocolKey.ClientInstanceKey.PRODUCERGROUP.getKey(), meshGroup); // build sys header requestWrapper.buildSysHeaderForClient(); @@ -113,49 +121,52 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest requestWrapper.buildSysHeaderForCE(); // process remote event body - Map bodyMap = JsonUtils.deserialize(new String(requestWrapper.getBody()), new TypeReference>() { - }); + final Map bodyMap = Optional.ofNullable(JsonUtils.parseTypeReferenceObject( + new String(requestWrapper.getBody(), Constants.DEFAULT_CHARSET), + new TypeReference>() { + } - byte[] convertedBody = bodyMap.get("content").toString().getBytes(StandardCharsets.UTF_8); - requestWrapper.setBody(convertedBody); + )).orElseGet(Maps::newHashMap); - String bizNo = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.BIZSEQNO, RandomStringUtils.generateNum(30)).toString(); - String uniqueId = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.UNIQUEID, RandomStringUtils.generateNum(30)).toString(); - String ttl = requestHeaderMap.getOrDefault(Constants.EVENTMESH_MESSAGE_CONST_TTL, 4 * 1000).toString(); + requestWrapper.setBody(bodyMap.get("content").toString().getBytes(StandardCharsets.UTF_8)); + final String bizNo = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey(), + RandomStringUtils.generateNum(30)).toString(); + final String uniqueId = requestHeaderMap.getOrDefault(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey(), + RandomStringUtils.generateNum(30)).toString(); + final String ttl = requestHeaderMap.getOrDefault(Constants.EVENTMESH_MESSAGE_CONST_TTL, + 4 * 1000).toString(); - requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.BIZSEQNO, bizNo); - requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.UNIQUEID, uniqueId); + requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey(), bizNo); + requestWrapper.getSysHeaderMap().putIfAbsent(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey(), uniqueId); requestWrapper.getSysHeaderMap().putIfAbsent(Constants.EVENTMESH_MESSAGE_CONST_TTL, ttl); - Map responseHeaderMap = new HashMap<>(); + final Map responseHeaderMap = new HashMap<>(); responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster); - responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshCluster()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, localAddress); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv); + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEnv()); responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - Map responseBodyMap = new HashMap<>(); + eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshIDC()); - Map sysHeaderMap = requestWrapper.getSysHeaderMap(); - Iterator> it = requestHeaderMap.entrySet().iterator(); + final Map responseBodyMap = new HashMap<>(); + final Map sysHeaderMap = requestWrapper.getSysHeaderMap(); + final Iterator> it = requestHeaderMap.entrySet().iterator(); while (it.hasNext()) { - String key = it.next().getKey(); + final String key = it.next().getKey(); if (sysHeaderMap.containsKey(key)) { it.remove(); } } - String protocolType = requestHeaderMap.getOrDefault(ProtocolKey.PROTOCOL_TYPE, "http").toString(); + final String protocolType = requestHeaderMap.getOrDefault(ProtocolKey.PROTOCOL_TYPE, "http").toString(); - ProtocolAdaptor httpProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + final ProtocolAdaptor httpProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); CloudEvent event = httpProtocolAdaptor.toCloudEvent(requestWrapper); - - //validate event + // validate event if (event == null || StringUtils.isBlank(event.getId()) || event.getSource() == null @@ -169,12 +180,11 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return; } - idc = event.getExtension(ProtocolKey.ClientInstanceKey.IDC).toString(); - String pid = event.getExtension(ProtocolKey.ClientInstanceKey.PID).toString(); - String sys = event.getExtension(ProtocolKey.ClientInstanceKey.SYS).toString(); + final String pid = getExtension(event, ProtocolKey.ClientInstanceKey.PID.getKey()); + final String sys = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); - //validate event-extension - if (StringUtils.isBlank(idc) + // validate event-extension + if (StringUtils.isBlank(getExtension(event, ProtocolKey.ClientInstanceKey.IDC.getKey())) || StringUtils.isBlank(pid) || !StringUtils.isNumeric(pid) || StringUtils.isBlank(sys)) { @@ -183,11 +193,10 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return; } + final String producerGroup = getExtension(event, ProtocolKey.ClientInstanceKey.PRODUCERGROUP.getKey()); + final String topic = event.getSubject(); - String producerGroup = event.getExtension(ProtocolKey.ClientInstanceKey.PRODUCERGROUP).toString(); - String topic = event.getSubject(); - - //validate body + // validate body if (StringUtils.isBlank(bizNo) || StringUtils.isBlank(uniqueId) || StringUtils.isBlank(producerGroup) @@ -198,20 +207,20 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return; } - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = event.getExtension(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = event.getExtension(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - String subsystem = event.getExtension(ProtocolKey.ClientInstanceKey.SYS).toString(); - String requestURI = requestWrapper.getRequestURI(); + // do acl check + if (eventMeshHTTPServer.getEventMeshHttpConfiguration().isEventMeshServerSecurityEnable()) { try { - Acl.doAclCheckInHttpSend(remoteAddr, user, pass, subsystem, topic, requestURI); + this.acl.doAclCheckInHttpSend(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), + getExtension(event, ProtocolKey.ClientInstanceKey.USERNAME.getKey()), + getExtension(event, ProtocolKey.ClientInstanceKey.PASSWD.getKey()), + getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()), + topic, + requestWrapper.getRequestURI()); } catch (Exception e) { - //String errorMsg = String.format("CLIENT HAS NO PERMISSION,send failed, topic:%s, subsys:%s, realIp:%s", topic, subsys, realIp); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_ACL_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); - aclLogger.warn("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); + + log.error("CLIENT HAS NO PERMISSION,SendAsyncMessageProcessor send failed", e); return; } } @@ -224,18 +233,17 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest return; } - EventMeshProducer eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); + final EventMeshProducer eventMeshProducer = eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); - if (!eventMeshProducer.getStarted().get()) { + if (!eventMeshProducer.isStarted()) { handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { - httpLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); + final String content = event.getData() == null ? "" : new String(event.getData().toBytes(), StandardCharsets.UTF_8); + if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEventSize()) { + log.error("Event size exceeds the limit: {}", eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshEventSize()); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_SIZE_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; @@ -243,26 +251,23 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest try { event = CloudEventBuilder.from(event) - .withExtension("msgtype", "persistent") + .withExtension(EventMeshConstants.MSG_TYPE, EventMeshConstants.PERSISTENT) .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .build(); - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); - } + log.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); } catch (Exception e) { - messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); + log.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR, responseHeaderMap, responseBodyMap, EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), event)); return; } - final SendMessageContext sendMessageContext = new SendMessageContext(bizNo, event, eventMeshProducer, - eventMeshHTTPServer); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsg(); + final SendMessageContext sendMessageContext = new SendMessageContext(bizNo, event, eventMeshProducer, eventMeshHTTPServer); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsg(); - long startTime = System.currentTimeMillis(); + final long startTime = System.currentTimeMillis(); try { event = CloudEventBuilder.from(sendMessageContext.getEvent()) @@ -274,43 +279,55 @@ public void handler(HandlerService.HandlerSpecific handlerSpecific, HttpRequest eventMeshProducer.send(sendMessageContext, new SendCallback() { @Override - public void onSuccess(SendResult sendResult) { - responseBodyMap.put("retCode", EventMeshRetCode.SUCCESS.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.SUCCESS.getErrMsg() + sendResult.toString()); + public void onSuccess(final SendResult sendResult) { + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.SUCCESS.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.SUCCESS.getErrMsg() + sendResult); - messageLogger.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + log.info("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", System.currentTimeMillis() - startTime, topic, bizNo, uniqueId); handlerSpecific.getTraceOperation().endLatestTrace(sendMessageContext.getEvent()); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); } @Override - public void onException(OnExceptionContext context) { - responseBodyMap.put("retCode", EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode()); - responseBodyMap.put("retMsg", EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg() + public void onException(final OnExceptionContext context) { + responseBodyMap.put(EventMeshConstants.RET_CODE, EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode()); + responseBodyMap.put(EventMeshConstants.RET_MSG, EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(context.getException(), 2)); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); handlerSpecific.getTraceOperation().exceptionLatestTrace(context.getException(), EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), sendMessageContext.getEvent())); handlerSpecific.sendResponse(responseHeaderMap, responseBodyMap); - messageLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", System.currentTimeMillis() - startTime, topic, bizNo, uniqueId, context.getException()); } }); } catch (Exception ex) { - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); - handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR, responseHeaderMap, responseBodyMap, null); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); + handlerSpecific.sendErrorResponse(EventMeshRetCode.EVENTMESH_SEND_ASYNC_MSG_ERR, responseHeaderMap, + responseBodyMap, null); - long endTime = System.currentTimeMillis(); - messageLogger.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", - endTime - startTime, topic, bizNo, uniqueId, ex); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + System.currentTimeMillis() - startTime, topic, bizNo, uniqueId, ex); } } + private String getExtension(final CloudEvent event, final String protocolKey) { + return Optional.ofNullable(event.getExtension(protocolKey)) + .map(Objects::toString) + .orElseGet(() -> ""); + } + @Override public String[] paths() { return new String[] {RequestURI.PUBLISH_BRIDGE.getRequestURI()}; } + @Override + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getRemoteMsgExecutor(); + } + } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendSyncMessageProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendSyncMessageProcessor.java index 529d3ce94e..0f5a97dc43 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendSyncMessageProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SendSyncMessageProcessor.java @@ -18,6 +18,7 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor; import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; @@ -25,6 +26,7 @@ import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.protocol.http.header.message.SendMessageRequestHeader; import org.apache.eventmesh.common.protocol.http.header.message.SendMessageResponseHeader; import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; @@ -32,310 +34,251 @@ import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; -import org.apache.eventmesh.runtime.core.protocol.http.producer.EventMeshProducer; -import org.apache.eventmesh.runtime.core.protocol.http.producer.SendMessageContext; +import org.apache.eventmesh.runtime.core.protocol.producer.EventMeshProducer; +import org.apache.eventmesh.runtime.core.protocol.producer.SendMessageContext; +import org.apache.eventmesh.runtime.metrics.http.HttpMetrics; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import java.nio.charset.StandardCharsets; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.netty.channel.ChannelHandlerContext; -public class SendSyncMessageProcessor implements HttpRequestProcessor { - - public Logger messageLogger = LoggerFactory.getLogger("message"); - - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); +import lombok.extern.slf4j.Slf4j; - public Logger httpLogger = LoggerFactory.getLogger("http"); +@Slf4j +public class SendSyncMessageProcessor extends AbstractHttpRequestProcessor { - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private transient EventMeshHTTPServer eventMeshHTTPServer; - private EventMeshHTTPServer eventMeshHTTPServer; + private final Acl acl; - public SendSyncMessageProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public SendSyncMessageProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } @Override - public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) - throws Exception { - - HttpCommand responseEventMeshCommand; - - cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); - - ProtocolAdaptor httpCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor("cloudevents"); - CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(asyncContext.getRequest()); - - SendMessageResponseHeader sendMessageResponseHeader = - SendMessageResponseHeader - .buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - //validate event - if (event == null - || StringUtils.isBlank(event.getId()) - || event.getSource() == null - || event.getSpecVersion() == null - || StringUtils.isBlank(event.getType()) - || StringUtils.isBlank(event.getSubject())) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + public void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) + throws Exception { + + HttpCommand request = asyncContext.getRequest(); + final String localAddress = IPUtils.getLocalAddress(); + final String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", + RequestCode.get(Integer.valueOf(request.getRequestCode())), EventMeshConstants.PROTOCOL_HTTP, remoteAddr, localAddress); + + SendMessageRequestHeader sendMessageRequestHeader = (SendMessageRequestHeader) request.getHeader(); + + String protocolType = sendMessageRequestHeader.getProtocolType(); + + final ProtocolAdaptor httpCommandProtocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + + final CloudEvent event = httpCommandProtocolAdaptor.toCloudEvent(asyncContext.getRequest()); + + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + final SendMessageResponseHeader sendMessageResponseHeader = + SendMessageResponseHeader + .buildHeader(Integer.valueOf(request.getRequestCode()), + eventMeshHttpConfiguration.getEventMeshCluster(), + localAddress, + eventMeshHttpConfiguration.getEventMeshEnv(), + eventMeshHttpConfiguration.getEventMeshIDC()); + + // validate event + if (!ObjectUtils.allNotNull(event, event.getSource(), event.getSpecVersion()) + || StringUtils.isAnyBlank(event.getId(), event.getType(), event.getSubject())) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageResponseBody.class); return; } - String idc = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.IDC)) - .toString(); - String pid = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.PID)) - .toString(); - String sys = Objects.requireNonNull(event.getExtension(ProtocolKey.ClientInstanceKey.SYS)) - .toString(); - - //validate event-extension - if (StringUtils.isBlank(idc) - || StringUtils.isBlank(pid) - || !StringUtils.isNumeric(pid) - || StringUtils.isBlank(sys)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + final String idc = getExtension(event, ProtocolKey.ClientInstanceKey.IDC.getKey()); + final String pid = getExtension(event, ProtocolKey.ClientInstanceKey.PID.getKey()); + final String sys = getExtension(event, ProtocolKey.ClientInstanceKey.SYS.getKey()); + + // validate event-extension + if (StringUtils.isAnyBlank(idc, pid, sys) || !StringUtils.isNumeric(pid)) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SendMessageResponseBody.class); return; } - String bizNo = - Objects.requireNonNull(event.getExtension(SendMessageRequestBody.BIZSEQNO)).toString(); - String uniqueId = - Objects.requireNonNull(event.getExtension(SendMessageRequestBody.UNIQUEID)).toString(); - String producerGroup = - Objects.requireNonNull(event.getExtension(SendMessageRequestBody.PRODUCERGROUP)) - .toString(); - String topic = event.getSubject(); - String ttl = - Objects.requireNonNull(event.getExtension(SendMessageRequestBody.TTL)).toString(); - - //validate body - if (StringUtils.isBlank(bizNo) - || StringUtils.isBlank(uniqueId) - || StringUtils.isBlank(producerGroup) - || StringUtils.isBlank(topic) - || event.getData() == null - || StringUtils.isBlank(ttl)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + final String bizNo = getExtension(event, SendMessageRequestBody.BIZSEQNO); + final String uniqueId = getExtension(event, SendMessageRequestBody.UNIQUEID); + final String producerGroup = getExtension(event, SendMessageRequestBody.PRODUCERGROUP); + final String topic = event.getSubject(); + final String ttl = getExtension(event, SendMessageRequestBody.TTL); + + // validate body + if (StringUtils.isAnyBlank(bizNo, uniqueId, producerGroup, topic, ttl) || event.getData() == null) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SendMessageResponseBody.class); return; } - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = event.getExtension(ProtocolKey.ClientInstanceKey.USERNAME).toString(); - String pass = event.getExtension(ProtocolKey.ClientInstanceKey.PASSWD).toString(); - int requestCode = Integer.parseInt(asyncContext.getRequest().getRequestCode()); + // do acl check + if (eventMeshHttpConfiguration.isEventMeshServerSecurityEnable()) { + final String user = getExtension(event, ProtocolKey.ClientInstanceKey.USERNAME.getKey()); + final String pass = getExtension(event, ProtocolKey.ClientInstanceKey.PASSWD.getKey()); + final int requestCode = Integer.parseInt(request.getRequestCode()); try { - Acl.doAclCheckInHttpSend(remoteAddr, user, pass, sys, topic, requestCode); + this.acl.doAclCheckInHttpSend(remoteAddr, user, pass, sys, topic, requestCode); } catch (Exception e) { - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_ACL_ERR.getRetCode(), - e.getMessage())); - asyncContext.onComplete(responseEventMeshCommand); - aclLogger.warn("CLIENT HAS NO PERMISSION,SendSyncMessageProcessor send failed", e); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_ACL_ERR, e.getMessage(), SendMessageResponseBody.class); + log.warn("CLIENT HAS NO PERMISSION,SendSyncMessageProcessor send failed", e); return; } } + final HttpMetrics summaryMetrics = eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics(); // control flow rate limit if (!eventMeshHTTPServer.getMsgRateLimiter() - .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, - TimeUnit.MILLISECONDS)) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR.getErrMsg())); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPDiscard(); - asyncContext.onComplete(responseEventMeshCommand); + .tryAcquire(EventMeshConstants.DEFAULT_FASTFAIL_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS)) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_HTTP_MES_SEND_OVER_LIMIT_ERR, null, SendMessageResponseBody.class); + summaryMetrics.recordHTTPDiscard(); return; } - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize) { - httpLogger.error("Event size exceeds the limit: {}", - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize); - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - "Event size exceeds the limit: " + eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEventSize)); - asyncContext.onComplete(responseEventMeshCommand); + final String content = new String(Objects.requireNonNull(event.getData()).toBytes(), Constants.DEFAULT_CHARSET); + int eventMeshEventSize = eventMeshHttpConfiguration.getEventMeshEventSize(); + if (content.length() > eventMeshEventSize) { + log.error("Event size exceeds the limit: {}", eventMeshEventSize); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, + "Event size exceeds the limit: " + eventMeshEventSize, + SendMessageResponseBody.class); return; } - EventMeshProducer eventMeshProducer = - eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); + final EventMeshProducer eventMeshProducer = + eventMeshHTTPServer.getProducerManager().getEventMeshProducer(producerGroup); - if (!eventMeshProducer.getStarted().get()) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + if (!eventMeshProducer.isStarted()) { + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_GROUP_PRODUCER_STOPED_ERR, null, SendMessageResponseBody.class); return; } + CloudEvent newEvent; try { - event = CloudEventBuilder.from(event) - .withExtension("msgtype", "persistent") - .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) - .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) - .build(); - - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); - } + newEvent = CloudEventBuilder.from(event) + .withExtension(EventMeshConstants.MSG_TYPE, EventMeshConstants.PERSISTENT) + .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) + .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, String.valueOf(System.currentTimeMillis())) + .build(); + + log.debug("msg2MQMsg suc, bizSeqNo={}, topic={}", bizNo, topic); } catch (Exception e) { - messageLogger.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR.getErrMsg() - + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(responseEventMeshCommand); + log.error("msg2MQMsg err, bizSeqNo={}, topic={}", bizNo, topic, e); + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_PACKAGE_MSG_ERR, null, SendMessageResponseBody.class); return; } final SendMessageContext sendMessageContext = - new SendMessageContext(bizNo, event, eventMeshProducer, - eventMeshHTTPServer); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsg(); - - long startTime = System.currentTimeMillis(); - - final CompleteHandler handler = new CompleteHandler() { - @Override - public void onResponse(HttpCommand httpCommand) { - try { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", httpCommand); - } - eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPReqResTimeCost( - System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); - } catch (Exception ex) { - // ignore - } + new SendMessageContext(bizNo, newEvent, eventMeshProducer, eventMeshHTTPServer); + summaryMetrics.recordSendMsg(); + + final long startTime = System.currentTimeMillis(); + + final CompleteHandler handler = httpCommand -> { + try { + log.debug("{}", httpCommand); + eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPReqResTimeCost( + System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); + } catch (Exception ex) { + log.error("onResponse error", ex); + // ignore } }; - try { eventMeshProducer.request(sendMessageContext, new RequestReplyCallback() { + @Override - public void onSuccess(CloudEvent event) { - messageLogger.info("message|mq2eventMesh|RSP|SYNC|rrCost={}ms|topic={}" - + "|bizSeqNo={}|uniqueId={}", System.currentTimeMillis() - startTime, - topic, bizNo, uniqueId); + public void onSuccess(final CloudEvent event) { + + log.info("message|mq2eventMesh|RSP|SYNC|rrCost={}ms|topic={}" + + "|bizSeqNo={}|uniqueId={}", System.currentTimeMillis() - startTime, topic, bizNo, uniqueId); try { - event = CloudEventBuilder.from(event) - .withExtension(EventMeshConstants.RSP_EVENTMESH2C_TIMESTAMP, - String.valueOf(System.currentTimeMillis())) - .withExtension(EventMeshConstants.RSP_MQ2EVENTMESH_TIMESTAMP, - String.valueOf(System.currentTimeMillis())) - .build(); - final String rtnMsg = new String(event.getData().toBytes(), - EventMeshConstants.DEFAULT_CHARSET); - - HttpCommand succ = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), - JsonUtils.serialize(SendMessageResponseBody.ReplyMessage.builder() - .topic(topic) - .body(rtnMsg) - .properties(EventMeshUtil.getEventProp(event)) - .build()))); + final CloudEvent newEvent = CloudEventBuilder.from(event) + .withExtension(EventMeshConstants.RSP_EVENTMESH2C_TIMESTAMP, + String.valueOf(System.currentTimeMillis())) + .withExtension(EventMeshConstants.RSP_MQ2EVENTMESH_TIMESTAMP, + String.valueOf(System.currentTimeMillis())) + .build(); + + final String rtnMsg = new String(Objects.requireNonNull(newEvent.getData()).toBytes(), + Constants.DEFAULT_CHARSET); + + final HttpCommand succ = request.createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody(EventMeshRetCode.SUCCESS.getRetCode(), + JsonUtils.toJSONString(SendMessageResponseBody.ReplyMessage.builder() + .topic(topic) + .body(rtnMsg) + .properties(EventMeshUtil.getEventProp(newEvent)) + .build()))); asyncContext.onComplete(succ, handler); } catch (Exception ex) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody.buildBody( - EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getErrMsg() - + EventMeshUtil.stackTrace(ex, 2))); + final HttpCommand err = request.createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody.buildBody( + EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getRetCode(), + EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getErrMsg() + + EventMeshUtil.stackTrace(ex, 2))); asyncContext.onComplete(err, handler); - messageLogger.warn("message|mq2eventMesh|RSP", ex); + + log.warn("message|mq2eventMesh|RSP", ex); } } @Override - public void onException(Throwable e) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getErrMsg() - + EventMeshUtil.stackTrace(e, 2))); + public void onException(final Throwable e) { + final HttpCommand err = request.createHttpCommandResponse( + sendMessageResponseHeader, + SendMessageResponseBody + .buildBody(EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getRetCode(), + EventMeshRetCode.EVENTMESH_WAITING_RR_MSG_ERR.getErrMsg() + + EventMeshUtil.stackTrace(e, 2))); asyncContext.onComplete(err, handler); - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); - messageLogger.error( - "message|mq2eventMesh|RSP|SYNC|rrCost={}ms|topic={}" - + "|bizSeqNo={}|uniqueId={}", System.currentTimeMillis() - startTime, - topic, bizNo, uniqueId, e); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); + + log.error("message|mq2eventMesh|RSP|SYNC|rrCost={}ms|topic={}" + + "|bizSeqNo={}|uniqueId={}", System.currentTimeMillis() - startTime, topic, bizNo, uniqueId, e); + } }, Integer.parseInt(ttl)); } catch (Exception ex) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - sendMessageResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_SEND_SYNC_MSG_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_SEND_SYNC_MSG_ERR.getErrMsg() - + EventMeshUtil.stackTrace(ex, 2))); - asyncContext.onComplete(err); - - eventMeshHTTPServer.getHttpRetryer().pushRetry(sendMessageContext.delay(10000)); - long endTime = System.currentTimeMillis(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); - messageLogger.error( - "message|eventMesh2mq|REQ|SYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + completeResponse(request, asyncContext, sendMessageResponseHeader, + EventMeshRetCode.EVENTMESH_SEND_SYNC_MSG_ERR, + EventMeshRetCode.EVENTMESH_SEND_SYNC_MSG_ERR.getErrMsg() + EventMeshUtil.stackTrace(ex, 2), + SendMessageResponseBody.class); + eventMeshHTTPServer.getHttpRetryer().newTimeout(sendMessageContext, 10, TimeUnit.SECONDS); + final long endTime = System.currentTimeMillis(); + summaryMetrics.recordSendMsgFailed(); + summaryMetrics.recordSendMsgCost(endTime - startTime); + + log.error("message|eventMesh2mq|REQ|SYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, topic, bizNo, uniqueId, ex); } @@ -343,7 +286,7 @@ public void onException(Throwable e) { } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getSendMsgExecutor(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ShortHttpProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ShortHttpProcessor.java new file mode 100644 index 0000000000..76ec80c66a --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/ShortHttpProcessor.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.processor; + +/** + * short-lived HTTP processor + */ + +public interface ShortHttpProcessor extends HttpProcessor { + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SubscribeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SubscribeProcessor.java index fa521f8716..272feb7db4 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SubscribeProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/SubscribeProcessor.java @@ -21,7 +21,6 @@ import org.apache.eventmesh.common.protocol.http.HttpCommand; import org.apache.eventmesh.common.protocol.http.body.client.SubscribeRequestBody; import org.apache.eventmesh.common.protocol.http.body.client.SubscribeResponseBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; import org.apache.eventmesh.common.protocol.http.common.RequestCode; import org.apache.eventmesh.common.protocol.http.header.client.SubscribeRequestHeader; @@ -30,320 +29,175 @@ import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.acl.Acl; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; +import org.apache.eventmesh.runtime.core.consumer.ClientInfo; +import org.apache.eventmesh.runtime.core.consumer.SubscriptionManager; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.WebhookUtil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.Executor; import io.netty.channel.ChannelHandlerContext; -public class SubscribeProcessor implements HttpRequestProcessor { +import lombok.extern.slf4j.Slf4j; - public Logger httpLogger = LoggerFactory.getLogger("http"); +@Slf4j +public class SubscribeProcessor extends AbstractHttpRequestProcessor { - public Logger aclLogger = LoggerFactory.getLogger("acl"); + private final transient EventMeshHTTPServer eventMeshHTTPServer; - private EventMeshHTTPServer eventMeshHTTPServer; + private final Acl acl; - public SubscribeProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public SubscribeProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; + this.acl = eventMeshHTTPServer.getAcl(); } @Override - public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) - throws Exception { + public void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) + throws Exception { HttpCommand responseEventMeshCommand; final HttpCommand request = asyncContext.getRequest(); - final Integer requestCode = Integer.valueOf(asyncContext.getRequest().getRequestCode()); - - httpLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - RequestCode.get(requestCode), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress() - ); - SubscribeRequestHeader subscribeRequestHeader = (SubscribeRequestHeader) request.getHeader(); - SubscribeRequestBody subscribeRequestBody = (SubscribeRequestBody) request.getBody(); - - SubscribeResponseHeader subscribeResponseHeader = - SubscribeResponseHeader - .buildHeader(requestCode, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - //validate header - if (StringUtils.isBlank(subscribeRequestHeader.getIdc()) - || StringUtils.isBlank(subscribeRequestHeader.getPid()) - || !StringUtils.isNumeric(subscribeRequestHeader.getPid()) - || StringUtils.isBlank(subscribeRequestHeader.getSys())) { - responseEventMeshCommand = request.createHttpCommandResponse( - subscribeResponseHeader, - SubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + final Integer requestCode = Integer.valueOf(request.getRequestCode()); + final String localAddress = IPUtils.getLocalAddress(); + final String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", + RequestCode.get(requestCode), EventMeshConstants.PROTOCOL_HTTP, remoteAddr, localAddress); + + final SubscribeRequestHeader subscribeRequestHeader = (SubscribeRequestHeader) request.getHeader(); + final SubscribeRequestBody subscribeRequestBody = (SubscribeRequestBody) request.getBody(); + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + final SubscribeResponseHeader subscribeResponseHeader = + SubscribeResponseHeader + .buildHeader(requestCode, + eventMeshHttpConfiguration.getEventMeshCluster(), + localAddress, + eventMeshHttpConfiguration.getEventMeshEnv(), + eventMeshHttpConfiguration.getEventMeshIDC()); + + // validate header + if (StringUtils.isAnyBlank(subscribeRequestHeader.getIdc(), + subscribeRequestHeader.getPid(), subscribeRequestHeader.getSys()) + || !StringUtils.isNumeric(subscribeRequestHeader.getPid())) { + completeResponse(request, asyncContext, subscribeResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, SubscribeResponseBody.class); return; } - //validate body - if (StringUtils.isBlank(subscribeRequestBody.getUrl()) - || CollectionUtils.isEmpty(subscribeRequestBody.getTopics()) - || StringUtils.isBlank(subscribeRequestBody.getConsumerGroup())) { - - responseEventMeshCommand = request.createHttpCommandResponse( - subscribeResponseHeader, - SubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + // validate body + if (StringUtils.isAnyBlank(subscribeRequestBody.getUrl(), subscribeRequestBody.getConsumerGroup()) + || CollectionUtils.isEmpty(subscribeRequestBody.getTopics())) { + completeResponse(request, asyncContext, subscribeResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, SubscribeResponseBody.class); return; } - List subTopicList = subscribeRequestBody.getTopics(); + final List subTopicList = subscribeRequestBody.getTopics(); - //do acl check - if (eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - String user = subscribeRequestHeader.getUsername(); - String pass = subscribeRequestHeader.getPasswd(); - String subsystem = subscribeRequestHeader.getSys(); - for (SubscriptionItem item : subTopicList) { + // do acl check + if (eventMeshHttpConfiguration.isEventMeshServerSecurityEnable()) { + for (final SubscriptionItem item : subTopicList) { try { - Acl.doAclCheckInHttpReceive(remoteAddr, user, pass, subsystem, item.getTopic(), - requestCode); + this.acl.doAclCheckInHttpReceive(remoteAddr, + subscribeRequestHeader.getUsername(), + subscribeRequestHeader.getPasswd(), + subscribeRequestHeader.getSys(), item.getTopic(), + requestCode); } catch (Exception e) { - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - subscribeResponseHeader, - SendMessageResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_ACL_ERR.getRetCode(), - e.getMessage())); - asyncContext.onComplete(responseEventMeshCommand); - aclLogger - .warn("CLIENT HAS NO PERMISSION,SubscribeProcessor subscribe failed", e); + completeResponse(request, asyncContext, subscribeResponseHeader, + EventMeshRetCode.EVENTMESH_ACL_ERR, e.getMessage(), SubscribeResponseBody.class); + log.warn("CLIENT HAS NO PERMISSION,SubscribeProcessor subscribe failed", e); return; } } } - String url = subscribeRequestBody.getUrl(); - String consumerGroup = subscribeRequestBody.getConsumerGroup(); + final String url = subscribeRequestBody.getUrl(); + final String consumerGroup = subscribeRequestBody.getConsumerGroup(); // validate URL try { - if (!IPUtils.isValidDomainOrIp(url, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIpv4BlackList, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIpv6BlackList)) { - httpLogger.error("subscriber url {} is not valid", url); - responseEventMeshCommand = request.createHttpCommandResponse( - subscribeResponseHeader, - SubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + " invalid URL: " + url)); - asyncContext.onComplete(responseEventMeshCommand); + if (!IPUtils.isValidDomainOrIp(url, eventMeshHttpConfiguration.getEventMeshIpv4BlackList(), + eventMeshHttpConfiguration.getEventMeshIpv6BlackList())) { + log.error("subscriber url {} is not valid", url); + completeResponse(request, asyncContext, subscribeResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + " invalid URL: " + url, + SubscribeResponseBody.class); return; } } catch (Exception e) { - httpLogger.error("subscriber url {} is not valid, error {}", url, e.getMessage()); - responseEventMeshCommand = request.createHttpCommandResponse( - subscribeResponseHeader, - SubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + " invalid URL: " + url)); - asyncContext.onComplete(responseEventMeshCommand); - return; - } - - // obtain webhook delivery agreement for Abuse Protection - boolean isWebhookAllowed = WebhookUtil.obtainDeliveryAgreement(eventMeshHTTPServer.httpClientPool.getClient(), - url, eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshWebhookOrigin); - - if (!isWebhookAllowed) { - httpLogger.error("subscriber url {} is not allowed by the target system", url); - responseEventMeshCommand = request.createHttpCommandResponse( - subscribeResponseHeader, - SubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + " unauthorized webhook URL: " + url)); - asyncContext.onComplete(responseEventMeshCommand); + log.error("subscriber url:{} is invalid.", url, e); + completeResponse(request, asyncContext, subscribeResponseHeader, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, + EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg() + " invalid URL: " + url, + SubscribeResponseBody.class); return; } - synchronized (eventMeshHTTPServer.localClientInfoMapping) { - - registerClient(subscribeRequestHeader, consumerGroup, subTopicList, url); - - for (SubscriptionItem subTopic : subTopicList) { - List groupTopicClients = eventMeshHTTPServer.localClientInfoMapping - .get(consumerGroup + "@" + subTopic.getTopic()); - - if (CollectionUtils.isEmpty(groupTopicClients)) { - httpLogger.error("group {} topic {} clients is empty", consumerGroup, subTopic); - } - - Map> idcUrls = new HashMap<>(); - for (Client client : groupTopicClients) { - if (idcUrls.containsKey(client.idc)) { - idcUrls.get(client.idc).add(StringUtils.deleteWhitespace(client.url)); - } else { - List urls = new ArrayList<>(); - urls.add(client.url); - idcUrls.put(client.idc, urls); - } - } - ConsumerGroupConf consumerGroupConf = - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup); - if (consumerGroupConf == null) { - // new subscription - consumerGroupConf = new ConsumerGroupConf(consumerGroup); - ConsumerGroupTopicConf consumeTopicConfig = new ConsumerGroupTopicConf(); - consumeTopicConfig.setConsumerGroup(consumerGroup); - consumeTopicConfig.setTopic(subTopic.getTopic()); - consumeTopicConfig.setSubscriptionItem(subTopic); - consumeTopicConfig.setUrls(new HashSet<>(Arrays.asList(url))); - - consumeTopicConfig.setIdcUrls(idcUrls); + SubscriptionManager subscriptionManager = eventMeshHTTPServer.getSubscriptionManager(); + synchronized (subscriptionManager.getLocalClientInfoMapping()) { + ClientInfo clientInfo = getClientInfo(subscribeRequestHeader); + subscriptionManager.registerClient(clientInfo, consumerGroup, subTopicList, url); + subscriptionManager.updateSubscription(clientInfo, consumerGroup, url, subTopicList); - Map map = new HashMap<>(); - map.put(subTopic.getTopic(), consumeTopicConfig); - consumerGroupConf.setConsumerGroupTopicConf(map); - } else { - // already subscribed - Map map = - consumerGroupConf.getConsumerGroupTopicConf(); - if (!map.containsKey(subTopic.getTopic())) { - //If there are multiple topics, append it - ConsumerGroupTopicConf newTopicConf = new ConsumerGroupTopicConf(); - newTopicConf.setConsumerGroup(consumerGroup); - newTopicConf.setTopic(subTopic.getTopic()); - newTopicConf.setSubscriptionItem(subTopic); - newTopicConf.setUrls(new HashSet<>(Arrays.asList(url))); - newTopicConf.setIdcUrls(idcUrls); - map.put(subTopic.getTopic(), newTopicConf); - } - for (String key : map.keySet()) { - if (StringUtils.equals(subTopic.getTopic(), key)) { - ConsumerGroupTopicConf latestTopicConf = new ConsumerGroupTopicConf(); - latestTopicConf.setConsumerGroup(consumerGroup); - latestTopicConf.setTopic(subTopic.getTopic()); - latestTopicConf.setSubscriptionItem(subTopic); - latestTopicConf.setUrls(new HashSet<>(Arrays.asList(url))); - - ConsumerGroupTopicConf currentTopicConf = map.get(key); - latestTopicConf.getUrls().addAll(currentTopicConf.getUrls()); - latestTopicConf.setIdcUrls(idcUrls); - - map.put(key, latestTopicConf); - } - } - } - eventMeshHTTPServer.localConsumerGroupMapping.put(consumerGroup, consumerGroupConf); - } - - long startTime = System.currentTimeMillis(); + final long startTime = System.currentTimeMillis(); try { // subscription relationship change notification eventMeshHTTPServer.getConsumerManager().notifyConsumerManager(consumerGroup, - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup)); + subscriptionManager.getLocalConsumerGroupMapping().get(consumerGroup)); - final CompleteHandler handler = new CompleteHandler() { - @Override - public void onResponse(HttpCommand httpCommand) { - try { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", httpCommand); - } - eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPReqResTimeCost( - System.currentTimeMillis() - request.getReqTime()); - } catch (Exception ex) { - // ignore - } + final CompleteHandler handler = httpCommand -> { + try { + log.debug("{}", httpCommand); + eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPReqResTimeCost( + System.currentTimeMillis() - request.getReqTime()); + } catch (Exception ex) { + log.error("onResponse error", ex); } }; responseEventMeshCommand = request.createHttpCommandResponse(EventMeshRetCode.SUCCESS); asyncContext.onComplete(responseEventMeshCommand, handler); } catch (Exception e) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - subscribeResponseHeader, - SubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_SUBSCRIBE_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_SUBSCRIBE_ERR.getErrMsg() - + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(err); - long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}" - + "|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(subscribeRequestBody.getTopics()), - subscribeRequestBody.getUrl(), e); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); + completeResponse(request, asyncContext, subscribeResponseHeader, + EventMeshRetCode.EVENTMESH_SUBSCRIBE_ERR, + EventMeshRetCode.EVENTMESH_SUBSCRIBE_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2), + SubscribeResponseBody.class); + final long endTime = System.currentTimeMillis(); + + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|bizSeqNo={}|uniqueId={}", + endTime - startTime, JsonUtils.toJSONString(subscribeRequestBody.getTopics()), subscribeRequestBody.getUrl(), e); + + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgFailed(); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordSendMsgCost(endTime - startTime); } + eventMeshHTTPServer.getSubscriptionManager().updateMetaData(); } } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); } - private void registerClient(SubscribeRequestHeader subscribeRequestHeader, String consumerGroup, - List subscriptionItems, String url) { - for (SubscriptionItem item : subscriptionItems) { - Client client = new Client(); - client.env = subscribeRequestHeader.getEnv(); - client.idc = subscribeRequestHeader.getIdc(); - client.sys = subscribeRequestHeader.getSys(); - client.ip = subscribeRequestHeader.getIp(); - client.pid = subscribeRequestHeader.getPid(); - client.consumerGroup = consumerGroup; - client.topic = item.getTopic(); - client.url = url; - client.lastUpTime = new Date(); - - String groupTopicKey = client.consumerGroup + "@" + client.topic; - - if (eventMeshHTTPServer.localClientInfoMapping.containsKey(groupTopicKey)) { - List localClients = - eventMeshHTTPServer.localClientInfoMapping.get(groupTopicKey); - boolean isContains = false; - for (Client localClient : localClients) { - if (StringUtils.equals(localClient.url, client.url)) { - isContains = true; - localClient.lastUpTime = client.lastUpTime; - break; - } - } - if (!isContains) { - localClients.add(client); - } - } else { - List clients = new ArrayList<>(); - clients.add(client); - eventMeshHTTPServer.localClientInfoMapping.put(groupTopicKey, clients); - } - } + private ClientInfo getClientInfo(final SubscribeRequestHeader subscribeRequestHeader) { + ClientInfo clientInfo = new ClientInfo(); + clientInfo.setEnv(subscribeRequestHeader.getEnv()); + clientInfo.setIdc(subscribeRequestHeader.getIdc()); + clientInfo.setSys(subscribeRequestHeader.getSys()); + clientInfo.setIp(subscribeRequestHeader.getIp()); + clientInfo.setPid(subscribeRequestHeader.getPid()); + return clientInfo; } + } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/UnSubscribeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/UnSubscribeProcessor.java index 43eeb3835e..431fa65a49 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/UnSubscribeProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/UnSubscribeProcessor.java @@ -27,13 +27,15 @@ import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.consumer.SubscriptionManager; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; import org.apache.eventmesh.runtime.core.protocol.http.async.CompleteHandler; import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.Client; -import org.apache.eventmesh.runtime.core.protocol.http.processor.inf.HttpRequestProcessor; +import org.apache.eventmesh.runtime.metrics.http.HttpMetrics; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; @@ -48,252 +50,198 @@ import java.util.List; import java.util.Map; import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import io.netty.channel.ChannelHandlerContext; -public class UnSubscribeProcessor implements HttpRequestProcessor { +import lombok.extern.slf4j.Slf4j; - public Logger httpLogger = LoggerFactory.getLogger("http"); +@Slf4j +public class UnSubscribeProcessor extends AbstractHttpRequestProcessor { - private EventMeshHTTPServer eventMeshHTTPServer; + private final transient EventMeshHTTPServer eventMeshHTTPServer; - public UnSubscribeProcessor(EventMeshHTTPServer eventMeshHTTPServer) { + public UnSubscribeProcessor(final EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; } @Override - public void processRequest(ChannelHandlerContext ctx, AsyncContext asyncContext) - throws Exception { + public void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) throws Exception { HttpCommand responseEventMeshCommand; - httpLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}", - RequestCode.get(Integer.valueOf(asyncContext.getRequest().getRequestCode())), - EventMeshConstants.PROTOCOL_HTTP, - RemotingHelper.parseChannelRemoteAddr(ctx.channel()), IPUtils.getLocalAddress()); - UnSubscribeRequestHeader unSubscribeRequestHeader = - (UnSubscribeRequestHeader) asyncContext.getRequest().getHeader(); - UnSubscribeRequestBody unSubscribeRequestBody = - (UnSubscribeRequestBody) asyncContext.getRequest().getBody(); - - UnSubscribeResponseHeader unSubscribeResponseHeader = - UnSubscribeResponseHeader - .buildHeader(Integer.valueOf(asyncContext.getRequest().getRequestCode()), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshCluster, - IPUtils.getLocalAddress(), - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshEnv, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshIDC); - - //validate header - if (StringUtils.isBlank(unSubscribeRequestHeader.getIdc()) - || StringUtils.isBlank(unSubscribeRequestHeader.getPid()) - || !StringUtils.isNumeric(unSubscribeRequestHeader.getPid()) - || StringUtils.isBlank(unSubscribeRequestHeader.getSys())) { - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - unSubscribeResponseHeader, - UnSubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + final HttpCommand request = asyncContext.getRequest(); + final String localAddress = IPUtils.getLocalAddress(); + + log.info("cmd={}|{}|client2eventMesh|from={}|to={}", RequestCode.get(Integer.valueOf(request.getRequestCode())), + + EventMeshConstants.PROTOCOL_HTTP, RemotingHelper.parseChannelRemoteAddr(ctx.channel()), localAddress); + + final UnSubscribeRequestHeader unSubscribeRequestHeader = (UnSubscribeRequestHeader) request.getHeader(); + final UnSubscribeRequestBody unSubscribeRequestBody = (UnSubscribeRequestBody) request.getBody(); + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + final UnSubscribeResponseHeader unSubscribeResponseHeader = UnSubscribeResponseHeader.buildHeader(Integer.valueOf(request.getRequestCode()), + eventMeshHttpConfiguration.getEventMeshCluster(), localAddress, eventMeshHttpConfiguration.getEventMeshEnv(), + eventMeshHttpConfiguration.getEventMeshIDC()); + + // validate header + if (StringUtils.isAnyBlank(unSubscribeRequestHeader.getIdc(), unSubscribeRequestHeader.getPid(), unSubscribeRequestHeader.getSys()) + || !StringUtils.isNumeric(unSubscribeRequestHeader.getPid())) { + completeResponse(request, asyncContext, unSubscribeResponseHeader, EventMeshRetCode.EVENTMESH_PROTOCOL_HEADER_ERR, null, + UnSubscribeResponseBody.class); return; } - //validate body - if (StringUtils.isBlank(unSubscribeRequestBody.getUrl()) - || CollectionUtils.isEmpty(unSubscribeRequestBody.getTopics()) - || StringUtils.isBlank(unSubscribeRequestBody.getConsumerGroup())) { - - responseEventMeshCommand = asyncContext.getRequest().createHttpCommandResponse( - unSubscribeResponseHeader, - UnSubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR.getErrMsg())); - asyncContext.onComplete(responseEventMeshCommand); + // validate body + if (StringUtils.isAnyBlank(unSubscribeRequestBody.getUrl(), unSubscribeRequestBody.getConsumerGroup()) || CollectionUtils.isEmpty( + unSubscribeRequestBody.getTopics())) { + completeResponse(request, asyncContext, unSubscribeResponseHeader, EventMeshRetCode.EVENTMESH_PROTOCOL_BODY_ERR, null, + UnSubscribeResponseBody.class); return; } - String env = unSubscribeRequestHeader.getEnv(); - String idc = unSubscribeRequestHeader.getIdc(); - String sys = unSubscribeRequestHeader.getSys(); - String ip = unSubscribeRequestHeader.getIp(); - String pid = unSubscribeRequestHeader.getPid(); - String consumerGroup = unSubscribeRequestBody.getConsumerGroup(); - String unSubscribeUrl = unSubscribeRequestBody.getUrl(); - List unSubTopicList = unSubscribeRequestBody.getTopics(); - - final CompleteHandler handler = new CompleteHandler() { - @Override - public void onResponse(HttpCommand httpCommand) { - try { - if (httpLogger.isDebugEnabled()) { - httpLogger.debug("{}", httpCommand); - } - eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPReqResTimeCost( - System.currentTimeMillis() - asyncContext.getRequest().getReqTime()); - } catch (Exception ex) { - // ignore - } + + final String pid = unSubscribeRequestHeader.getPid(); + final String consumerGroup = unSubscribeRequestBody.getConsumerGroup(); + final String unSubscribeUrl = unSubscribeRequestBody.getUrl(); + final List unSubTopicList = unSubscribeRequestBody.getTopics(); + final HttpMetrics summaryMetrics = eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics(); + final CompleteHandler handler = httpCommand -> { + try { + log.debug("{}", httpCommand); + eventMeshHTTPServer.sendResponse(ctx, httpCommand.httpResponse()); + summaryMetrics.recordHTTPReqResTimeCost(System.currentTimeMillis() - request.getReqTime()); + } catch (Exception ex) { + // ignore } }; - synchronized (eventMeshHTTPServer.localClientInfoMapping) { + SubscriptionManager subscriptionManager = eventMeshHTTPServer.getSubscriptionManager(); + ConcurrentHashMap localConsumerGroupMap = subscriptionManager.getLocalConsumerGroupMapping(); + synchronized (subscriptionManager.getLocalClientInfoMapping()) { boolean isChange = true; registerClient(unSubscribeRequestHeader, consumerGroup, unSubTopicList, unSubscribeUrl); - for (String unSubTopic : unSubTopicList) { - List groupTopicClients = eventMeshHTTPServer.localClientInfoMapping - .get(consumerGroup + "@" + unSubTopic); - Iterator clientIterator = groupTopicClients.iterator(); + for (final String unSubTopic : unSubTopicList) { + final List groupTopicClients = subscriptionManager.getLocalClientInfoMapping().get(consumerGroup + "@" + unSubTopic); + + final Iterator clientIterator = groupTopicClients.iterator(); while (clientIterator.hasNext()) { - Client client = clientIterator.next(); - if (StringUtils.equals(client.pid, pid) - && StringUtils.equals(client.url, unSubscribeUrl)) { - httpLogger.warn("client {} start unsubscribe", JsonUtils.serialize(client)); + final Client client = clientIterator.next(); + + if (StringUtils.equals(client.getPid(), pid) + && StringUtils.equals(client.getUrl(), unSubscribeUrl)) { + log.warn("client {} start unsubscribe", JsonUtils.toJSONString(client)); + clientIterator.remove(); } } - if (groupTopicClients.size() > 0) { - //change url - Map> idcUrls = new HashMap<>(); - Set clientUrls = new HashSet<>(); - for (Client client : groupTopicClients) { + if (CollectionUtils.isNotEmpty(groupTopicClients)) { + // change url + final Map> idcUrls = new HashMap<>(); + final Set clientUrls = new HashSet<>(); + for (final Client client : groupTopicClients) { // remove subscribed url - if (!StringUtils.equals(unSubscribeUrl, client.url)) { - clientUrls.add(client.url); - if (idcUrls.containsKey(client.idc)) { - idcUrls.get(client.idc) - .add(StringUtils.deleteWhitespace(client.url)); - } else { - List urls = new ArrayList<>(); - urls.add(client.url); - idcUrls.put(client.idc, urls); - } + if (!StringUtils.equals(unSubscribeUrl, client.getUrl())) { + clientUrls.add(client.getUrl()); + idcUrls.computeIfAbsent(client.getIdc(), k -> new ArrayList<>()); } } - synchronized (eventMeshHTTPServer.localConsumerGroupMapping) { - ConsumerGroupConf consumerGroupConf = - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup); - Map map = - consumerGroupConf.getConsumerGroupTopicConf(); - for (String topicKey : map.keySet()) { + + synchronized (localConsumerGroupMap) { + final ConsumerGroupConf consumerGroupConf = localConsumerGroupMap.get(consumerGroup); + + final Map map = consumerGroupConf.getConsumerGroupTopicConf(); + for (final Map.Entry topicConf : map.entrySet()) { // only modify the topic to subscribe - if (StringUtils.equals(unSubTopic, topicKey)) { - ConsumerGroupTopicConf latestTopicConf = - new ConsumerGroupTopicConf(); + if (StringUtils.equals(unSubTopic, topicConf.getKey())) { + final ConsumerGroupTopicConf latestTopicConf = new ConsumerGroupTopicConf(); latestTopicConf.setConsumerGroup(consumerGroup); latestTopicConf.setTopic(unSubTopic); - latestTopicConf - .setSubscriptionItem(map.get(topicKey).getSubscriptionItem()); + latestTopicConf.setSubscriptionItem(topicConf.getValue().getSubscriptionItem()); latestTopicConf.setUrls(clientUrls); - latestTopicConf.setIdcUrls(idcUrls); - map.put(unSubTopic, latestTopicConf); } } - eventMeshHTTPServer.localConsumerGroupMapping - .put(consumerGroup, consumerGroupConf); + localConsumerGroupMap.put(consumerGroup, consumerGroupConf); } } else { isChange = false; break; } } - long startTime = System.currentTimeMillis(); + + final long startTime = System.currentTimeMillis(); if (isChange) { try { - eventMeshHTTPServer.getConsumerManager().notifyConsumerManager(consumerGroup, - eventMeshHTTPServer.localConsumerGroupMapping.get(consumerGroup)); + eventMeshHTTPServer.getConsumerManager().notifyConsumerManager(consumerGroup, localConsumerGroupMap.get(consumerGroup)); - responseEventMeshCommand = - asyncContext.getRequest().createHttpCommandResponse(EventMeshRetCode.SUCCESS); + responseEventMeshCommand = request.createHttpCommandResponse(EventMeshRetCode.SUCCESS); asyncContext.onComplete(responseEventMeshCommand, handler); } catch (Exception e) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - unSubscribeResponseHeader, - UnSubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR.getErrMsg() - + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(err); - long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms" - + "|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(unSubscribeRequestBody.getTopics()), - unSubscribeRequestBody.getUrl(), e); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics() - .recordSendMsgCost(endTime - startTime); + completeResponse(request, asyncContext, unSubscribeResponseHeader, EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR, + EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2), UnSubscribeResponseBody.class); + final long endTime = System.currentTimeMillis(); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|url={}", endTime - startTime, + JsonUtils.toJSONString(unSubscribeRequestBody.getTopics()), unSubscribeRequestBody.getUrl(), e); + summaryMetrics.recordSendMsgFailed(); + summaryMetrics.recordSendMsgCost(endTime - startTime); } } else { - //remove + // remove try { - eventMeshHTTPServer.getConsumerManager() - .notifyConsumerManager(consumerGroup, null); - responseEventMeshCommand = - asyncContext.getRequest().createHttpCommandResponse(EventMeshRetCode.SUCCESS); + eventMeshHTTPServer.getConsumerManager().notifyConsumerManager(consumerGroup, null); + responseEventMeshCommand = request.createHttpCommandResponse(EventMeshRetCode.SUCCESS); asyncContext.onComplete(responseEventMeshCommand, handler); // clean ClientInfo - eventMeshHTTPServer.localClientInfoMapping.keySet() - .removeIf(s -> StringUtils.contains(s, consumerGroup)); + subscriptionManager.getLocalClientInfoMapping().keySet().removeIf(s -> StringUtils.contains(s, consumerGroup)); // clean ConsumerGroupInfo - eventMeshHTTPServer.localConsumerGroupMapping.keySet() - .removeIf(s -> StringUtils.equals(consumerGroup, s)); + localConsumerGroupMap.keySet().removeIf(s -> StringUtils.equals(consumerGroup, s)); } catch (Exception e) { - HttpCommand err = asyncContext.getRequest().createHttpCommandResponse( - unSubscribeResponseHeader, - UnSubscribeResponseBody - .buildBody(EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR.getRetCode(), - EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR.getErrMsg() - + EventMeshUtil.stackTrace(e, 2))); - asyncContext.onComplete(err); - long endTime = System.currentTimeMillis(); - httpLogger.error( - "message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms" - + "|topic={}|bizSeqNo={}|uniqueId={}", endTime - startTime, - JsonUtils.serialize(unSubscribeRequestBody.getTopics()), - unSubscribeRequestBody.getUrl(), e); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgFailed(); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendMsgCost(endTime - startTime); + completeResponse(request, asyncContext, unSubscribeResponseHeader, EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR, + EventMeshRetCode.EVENTMESH_UNSUBSCRIBE_ERR.getErrMsg() + EventMeshUtil.stackTrace(e, 2), UnSubscribeResponseBody.class); + final long endTime = System.currentTimeMillis(); + log.error("message|eventMesh2mq|REQ|ASYNC|send2MQCost={}ms|topic={}|url={}", endTime - startTime, + JsonUtils.toJSONString(unSubscribeRequestBody.getTopics()), unSubscribeRequestBody.getUrl(), e); + summaryMetrics.recordSendMsgFailed(); + summaryMetrics.recordSendMsgCost(endTime - startTime); } } + eventMeshHTTPServer.getSubscriptionManager().updateMetaData(); } } @Override - public boolean rejectRequest() { - return false; + public Executor executor() { + return eventMeshHTTPServer.getHttpThreadPoolGroup().getClientManageExecutor(); } - private void registerClient(UnSubscribeRequestHeader unSubscribeRequestHeader, - String consumerGroup, - List topicList, String url) { - for (String topic : topicList) { - Client client = new Client(); - client.env = unSubscribeRequestHeader.getEnv(); - client.idc = unSubscribeRequestHeader.getIdc(); - client.sys = unSubscribeRequestHeader.getSys(); - client.ip = unSubscribeRequestHeader.getIp(); - client.pid = unSubscribeRequestHeader.getPid(); - client.consumerGroup = consumerGroup; - client.topic = topic; - client.url = url; - client.lastUpTime = new Date(); - - String groupTopicKey = client.consumerGroup + "@" + client.topic; - if (eventMeshHTTPServer.localClientInfoMapping.containsKey(groupTopicKey)) { - List localClients = - eventMeshHTTPServer.localClientInfoMapping.get(groupTopicKey); + + private void registerClient(final UnSubscribeRequestHeader unSubscribeRequestHeader, final String consumerGroup, + final List topicList, final String url) { + for (final String topic : topicList) { + final Client client = new Client(); + client.setEnv(unSubscribeRequestHeader.getEnv()); + client.setIdc(unSubscribeRequestHeader.getIdc()); + client.setSys(unSubscribeRequestHeader.getSys()); + client.setIp(unSubscribeRequestHeader.getIp()); + client.setPid(unSubscribeRequestHeader.getPid()); + client.setConsumerGroup(consumerGroup); + client.setTopic(topic); + client.setUrl(url); + client.setLastUpTime(new Date()); + + final String groupTopicKey = client.getConsumerGroup() + "@" + client.getTopic(); + ConcurrentHashMap> localClientInfoMap = eventMeshHTTPServer.getSubscriptionManager().getLocalClientInfoMapping(); + if (localClientInfoMap.containsKey(groupTopicKey)) { + final List localClients = localClientInfoMap.get(groupTopicKey); boolean isContains = false; - for (Client localClient : localClients) { - if (StringUtils.equals(localClient.url, client.url)) { + for (final Client localClient : localClients) { + if (StringUtils.equals(localClient.getUrl(), client.getUrl())) { isContains = true; - localClient.lastUpTime = client.lastUpTime; + localClient.setLastUpTime(client.getLastUpTime()); break; } } @@ -301,9 +249,9 @@ private void registerClient(UnSubscribeRequestHeader unSubscribeRequestHeader, localClients.add(client); } } else { - List clients = new ArrayList<>(); + final List clients = new ArrayList<>(); clients.add(client); - eventMeshHTTPServer.localClientInfoMapping.put(groupTopicKey, clients); + localClientInfoMap.put(groupTopicKey, clients); } } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/WebHookProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/WebHookProcessor.java deleted file mode 100644 index 2bc878fa79..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/WebHookProcessor.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.http.processor; - -import org.apache.eventmesh.runtime.common.EventMeshTrace; -import org.apache.eventmesh.runtime.util.HttpResponseUtils; -import org.apache.eventmesh.webhook.receive.WebHookController; - -import java.util.HashMap; -import java.util.Map; - -import io.netty.handler.codec.http.DefaultFullHttpRequest; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; - -import lombok.Setter; - -@EventMeshTrace(isEnable = true) -public class WebHookProcessor implements HttpProcessor { - - @Setter - private WebHookController webHookController; - - @Override - public String[] paths() { - return new String[]{"/webhook"}; - } - - @Override - public HttpResponse handler(HttpRequest httpRequest) { - try { - Map header = new HashMap<>(); - for (Map.Entry entry : httpRequest.headers().entries()) { - header.put(entry.getKey().toLowerCase(), entry.getValue()); - } - byte[] bytes = ((DefaultFullHttpRequest) httpRequest).content().array(); - webHookController.execute(httpRequest.uri(), header, bytes); - return HttpResponseUtils.createSuccess(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/AbstractEventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/AbstractEventProcessor.java index 2fe7f25bad..02d6933f10 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/AbstractEventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/AbstractEventProcessor.java @@ -17,108 +17,94 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor.inf; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; +import static org.apache.eventmesh.common.Constants.HTTP; +import static org.apache.eventmesh.runtime.constants.EventMeshConstants.CONTENT_TYPE; + +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.config.CommonConfiguration; import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.common.protocol.http.HttpEventWrapper; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.utils.AssertUtils; +import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.registry.nacos.constant.NacosConstant; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.meta.nacos.constant.NacosConstant; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupConf; +import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupMetadata; -import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicConf; import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicMetadata; -import org.apache.eventmesh.runtime.registry.Registry; +import org.apache.eventmesh.runtime.core.protocol.http.processor.AsyncHttpProcessor; +import org.apache.eventmesh.runtime.meta.MetaStorage; +import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; - +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; + +import com.google.common.collect.Maps; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** * EventProcessor */ -public class AbstractEventProcessor { +@Slf4j +public abstract class AbstractEventProcessor implements AsyncHttpProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger("AbstractEventProcessor"); - - protected EventMeshHTTPServer eventMeshHTTPServer; + protected transient EventMeshHTTPServer eventMeshHTTPServer; public AbstractEventProcessor(EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; } - /** - * Add a topic with subscribers to the service's metadata. - */ - protected void updateMetadata() { - if (!eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerRegistryEnable) { - return; - } - try { - Map metadata = new HashMap<>(1 << 4); - for (Map.Entry consumerGroupMap : eventMeshHTTPServer.localConsumerGroupMapping.entrySet()) { - String consumerGroupKey = consumerGroupMap.getKey(); - ConsumerGroupConf consumerGroupConf = consumerGroupMap.getValue(); - - ConsumerGroupMetadata consumerGroupMetadata = new ConsumerGroupMetadata(); - consumerGroupMetadata.setConsumerGroup(consumerGroupKey); - - Map consumerGroupTopicMetadataMap = new HashMap<>(1 << 4); - for (Map.Entry consumerGroupTopicConfEntry : consumerGroupConf.getConsumerGroupTopicConf() - .entrySet()) { - final String topic = consumerGroupTopicConfEntry.getKey(); - ConsumerGroupTopicConf consumerGroupTopicConf = consumerGroupTopicConfEntry.getValue(); - ConsumerGroupTopicMetadata consumerGroupTopicMetadata = new ConsumerGroupTopicMetadata(); - consumerGroupTopicMetadata.setConsumerGroup(consumerGroupTopicConf.getConsumerGroup()); - consumerGroupTopicMetadata.setTopic(consumerGroupTopicConf.getTopic()); - consumerGroupTopicMetadata.setUrls(consumerGroupTopicConf.getUrls()); - - consumerGroupTopicMetadataMap.put(topic, consumerGroupTopicMetadata); - } - consumerGroupMetadata.setConsumerGroupTopicMetadataMap(consumerGroupTopicMetadataMap); - metadata.put(consumerGroupKey, JsonUtils.serialize(consumerGroupMetadata)); - } - Registry registry = eventMeshHTTPServer.getRegistry(); - registry.registerMetadata(metadata); - } catch (Exception e) { - LOGGER.error("[LocalSubscribeEventProcessor] update eventmesh metadata error", e); - } - } - - protected String getTargetMesh(String consumerGroup, List subscriptionList) throws Exception { // Currently only supports http CommonConfiguration httpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); - if (!httpConfiguration.eventMeshServerRegistryEnable) { + if (!httpConfiguration.isEventMeshServerMetaStorageEnable()) { return ""; } String targetMesh = ""; - Registry registry = eventMeshHTTPServer.getRegistry(); - List allEventMeshInfo = registry.findAllEventMeshInfo(); + MetaStorage metaStorage = eventMeshHTTPServer.getMetaStorage(); + List allEventMeshInfo = metaStorage.findAllEventMeshInfo(); String httpServiceName = - ConfigurationContextUtil.HTTP + "-" + NacosConstant.GROUP + "@@" + httpConfiguration.eventMeshName + "-" + ConfigurationContextUtil.HTTP; + HTTP + "-" + NacosConstant.GROUP + "@@" + httpConfiguration.getEventMeshName() + + "-" + HTTP; for (EventMeshDataInfo eventMeshDataInfo : allEventMeshInfo) { if (!eventMeshDataInfo.getEventMeshName().equals(httpServiceName)) { continue; } - if (httpConfiguration.eventMeshCluster.equals(eventMeshDataInfo.getEventMeshClusterName())) { + + if (httpConfiguration.getEventMeshCluster().equals(eventMeshDataInfo.getEventMeshClusterName())) { continue; } + Map metadata = eventMeshDataInfo.getMetadata(); String topicMetadataJson = metadata.get(consumerGroup); if (StringUtils.isBlank(topicMetadataJson)) { continue; } - ConsumerGroupMetadata consumerGroupMetadata = JsonUtils.deserialize(topicMetadataJson, ConsumerGroupMetadata.class); - Map consumerGroupTopicMetadataMap = consumerGroupMetadata.getConsumerGroupTopicMetadataMap(); + ConsumerGroupMetadata consumerGroupMetadata = + JsonUtils.parseObject(topicMetadataJson, ConsumerGroupMetadata.class); + Map consumerGroupTopicMetadataMap = + Optional.ofNullable(consumerGroupMetadata) + .map(ConsumerGroupMetadata::getConsumerGroupTopicMetadataMap) + .orElseGet(Maps::newConcurrentMap); for (SubscriptionItem subscriptionItem : subscriptionList) { if (consumerGroupTopicMetadataMap.containsKey(subscriptionItem.getTopic())) { @@ -130,4 +116,118 @@ protected String getTargetMesh(String consumerGroup, List subs } return targetMesh; } + + /** + * builder response header map + * + * @param requestWrapper requestWrapper + * @return Map + */ + protected Map builderResponseHeaderMap(HttpEventWrapper requestWrapper) { + Map responseHeaderMap = new HashMap<>(); + EventMeshHTTPConfiguration eventMeshHttpConfiguration = eventMeshHTTPServer.getEventMeshHttpConfiguration(); + responseHeaderMap.put(ProtocolKey.REQUEST_URI, requestWrapper.getRequestURI()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, + eventMeshHttpConfiguration.getEventMeshCluster()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, + IPUtils.getLocalAddress()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, + eventMeshHttpConfiguration.getEventMeshEnv()); + responseHeaderMap.put(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, + eventMeshHttpConfiguration.getEventMeshIDC()); + return responseHeaderMap; + } + + /** + * validation sysHeaderMap is null + * + * @param sysHeaderMap sysHeaderMap + * @return Returns true if any is empty + */ + protected boolean validateSysHeader(Map sysHeaderMap) { + return StringUtils.isAnyBlank(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.IDC.getKey()).toString(), + sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID.getKey()).toString(), + sysHeaderMap.get(ProtocolKey.ClientInstanceKey.SYS.getKey()).toString()) + || !StringUtils.isNumeric(sysHeaderMap.get(ProtocolKey.ClientInstanceKey.PID.getKey()).toString()); + } + + /** + * validation requestBodyMap key url topic consumerGroup is any null + * + * @param requestBodyMap requestBodyMap + * @return any null then true + */ + protected boolean validatedRequestBodyMap(Map requestBodyMap) { + return requestBodyMap.get(EventMeshConstants.MANAGE_TOPIC) == null; + + } + + /** + * builder RemoteHeaderMap + * + * @param localAddress + * @return + */ + protected Map builderRemoteHeaderMap(String localAddress) { + EventMeshHTTPConfiguration eventMeshHttpConfiguration = this.eventMeshHTTPServer.getEventMeshHttpConfiguration(); + String meshGroup = eventMeshHttpConfiguration.getMeshGroup(); + + Map remoteHeaderMap = new HashMap<>(); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.ENV.getKey(), eventMeshHttpConfiguration.getEventMeshEnv()); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.IDC.getKey(), eventMeshHttpConfiguration.getEventMeshIDC()); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.IP.getKey(), localAddress); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PID.getKey(), String.valueOf(ThreadUtils.getPID())); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.SYS.getKey(), eventMeshHttpConfiguration.getSysID()); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), EventMeshConstants.USER_NAME); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), EventMeshConstants.PASSWD); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.PRODUCERGROUP.getKey(), meshGroup); + remoteHeaderMap.put(ProtocolKey.ClientInstanceKey.CONSUMERGROUP.getKey(), meshGroup); + return remoteHeaderMap; + } + + /** + * http post + * + * @param client client + * @param uri uri + * @param requestHeader requestHeader + * @param requestBody requestBody + * @param responseHandler responseHandler + * @return string + * @throws IOException + */ + public static String post(CloseableHttpClient client, String uri, + Map requestHeader, Map requestBody, + ResponseHandler responseHandler) throws IOException { + AssertUtils.notNull(client, "client can't be null"); + AssertUtils.notBlank(uri, "uri can't be null"); + AssertUtils.notNull(requestHeader, "requestParam can't be null"); + AssertUtils.notNull(responseHandler, "responseHandler can't be null"); + + HttpPost httpPost = new HttpPost(uri); + + httpPost.addHeader(CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); + + // header + if (MapUtils.isNotEmpty(requestHeader)) { + requestHeader.forEach(httpPost::addHeader); + } + + // body + if (MapUtils.isNotEmpty(requestBody)) { + String jsonStr = Optional.ofNullable(JsonUtils.toJSONString(requestBody)).orElse(""); + httpPost.setEntity(new StringEntity(jsonStr, ContentType.APPLICATION_JSON)); + } + + // ttl + RequestConfig.Builder configBuilder = RequestConfig.custom(); + configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))) + .setConnectTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))) + .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(Constants.DEFAULT_HTTP_TIME_OUT))); + + httpPost.setConfig(configBuilder.build()); + + return client.execute(httpPost, responseHandler); + } + } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/Client.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/Client.java index 119c1dea2e..ced93b99e1 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/Client.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/Client.java @@ -1,20 +1,18 @@ /* - * Licensed to 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. Apache Software Foundation (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 + * 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. + * 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. */ package org.apache.eventmesh.runtime.core.protocol.http.processor.inf; @@ -23,43 +21,156 @@ public class Client { - public String env; + private String env; - public String idc; + private String idc; - public String consumerGroup; + private String consumerGroup; - public String topic; + private String topic; - public String url; + private String url; - public String sys; + private String sys; - public String ip; + private String ip; - public String pid; + private String pid; - public String hostname; + private String hostname; - public String apiVersion; + private Date lastUpTime; - public Date lastUpTime; + public void setEnv(String env) { + this.env = env; + } + + public void setIdc(String idc) { + this.idc = idc; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public void setUrl(String url) { + this.url = url; + } + + public void setSys(String sys) { + this.sys = sys; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public void setLastUpTime(Date lastUpTime) { + this.lastUpTime = lastUpTime; + } + + private String apiVersion; + + public String getEnv() { + return env; + } + + public String getIdc() { + return idc; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public String getTopic() { + return topic; + } + + public String getUrl() { + return url; + } + + public String getSys() { + return sys; + } + + public String getIp() { + return ip; + } + + public String getPid() { + return pid; + } + + public String getHostname() { + return hostname; + } + + public String getApiVersion() { + return apiVersion; + } + + public Date getLastUpTime() { + return lastUpTime; + } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("endPoint={env=").append(env) - .append(",idc=").append(idc) - .append(",consumerGroup=").append(consumerGroup) - .append(",topic=").append(topic) - .append(",url=").append(url) - .append(",sys=").append(sys) - .append(",ip=").append(ip) - .append(",pid=").append(pid) - .append(",hostname=").append(hostname) - .append(",apiVersion=").append(apiVersion) - .append(",registerTime=").append("}"); + .append(",idc=").append(idc) + .append(",consumerGroup=").append(consumerGroup) + .append(",topic=").append(topic) + .append(",url=").append(url) + .append(",sys=").append(sys) + .append(",ip=").append(ip) + .append(",pid=").append(pid) + .append(",hostname=").append(hostname) + .append(",apiVersion=").append(apiVersion) + .append(",registerTime=").append("}"); return sb.toString(); } -} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Client client = (Client) o; + return java.util.Objects.equals(env, client.env) + && java.util.Objects.equals(idc, client.idc) + && java.util.Objects.equals(consumerGroup, client.consumerGroup) + && java.util.Objects.equals(topic, client.topic) + && java.util.Objects.equals(url, client.url) + && java.util.Objects.equals(sys, client.sys) + && java.util.Objects.equals(ip, client.ip) + && java.util.Objects.equals(pid, client.pid) + && java.util.Objects.equals(hostname, client.hostname) + && java.util.Objects.equals(apiVersion, client.apiVersion); + } + + @Override + public int hashCode() { + return java.util.Objects.hash(env, idc, consumerGroup, topic, url, sys, ip, pid, hostname, apiVersion); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/EventProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/EventProcessor.java index ea9be37c36..b917d8c4a9 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/EventProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/EventProcessor.java @@ -28,7 +28,7 @@ public interface EventProcessor { void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) - throws Exception; + throws Exception; boolean rejectRequest(); diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/HttpRequestProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/HttpRequestProcessor.java index 41354f44c3..35231ef8b7 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/HttpRequestProcessor.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/processor/inf/HttpRequestProcessor.java @@ -18,8 +18,21 @@ package org.apache.eventmesh.runtime.core.protocol.http.processor.inf; import org.apache.eventmesh.common.protocol.http.HttpCommand; +import org.apache.eventmesh.common.protocol.http.body.Body; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.header.Header; import org.apache.eventmesh.runtime.core.protocol.http.async.AsyncContext; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Method; +import java.util.Objects; +import java.util.concurrent.Executor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; import io.netty.channel.ChannelHandlerContext; /** @@ -27,9 +40,37 @@ */ public interface HttpRequestProcessor { + Logger log = LoggerFactory.getLogger(HttpRequestProcessor.class); + void processRequest(final ChannelHandlerContext ctx, final AsyncContext asyncContext) - throws Exception; + throws Exception; + + default boolean rejectRequest() { + return false; + } + + default void completeResponse(HttpCommand req, AsyncContext asyncContext, + T respHeader, EventMeshRetCode emCode, + String msg, Class clazz) { + try { + Method method = clazz.getMethod("buildBody", Integer.class, String.class); + Object o = method.invoke(null, emCode.getRetCode(), + StringUtils.isNotBlank(msg) ? msg : emCode.getErrMsg()); + HttpCommand response = req.createHttpCommandResponse(respHeader, (Body) o); + asyncContext.onComplete(response); + } catch (Exception e) { + log.error("response failed", e); + } + } + + default String getExtension(CloudEvent event, String protocolKey) { + Object extension = event.getExtension(protocolKey); + return Objects.isNull(extension) ? "" : extension.toString(); + } - boolean rejectRequest(); + /** + * @return {@link Executor} + */ + Executor executor(); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/EventMeshProducer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/EventMeshProducer.java deleted file mode 100644 index ff488d3fbc..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/EventMeshProducer.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.http.producer; - -import org.apache.eventmesh.api.RequestReplyCallback; -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; -import org.apache.eventmesh.runtime.core.consumergroup.ProducerGroupConf; -import org.apache.eventmesh.runtime.core.plugin.MQProducerWrapper; -import org.apache.eventmesh.runtime.util.EventMeshUtil; - -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventMeshProducer { - - protected AtomicBoolean started = new AtomicBoolean(Boolean.FALSE); - - protected AtomicBoolean inited = new AtomicBoolean(Boolean.FALSE); - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - public AtomicBoolean getInited() { - return inited; - } - - public AtomicBoolean getStarted() { - return started; - } - - protected ProducerGroupConf producerGroupConfig; - - protected EventMeshHTTPConfiguration eventMeshHttpConfiguration; - - public void send(SendMessageContext sendMsgContext, SendCallback sendCallback) throws Exception { - mqProducerWrapper.send(sendMsgContext.getEvent(), sendCallback); - } - - public void request(SendMessageContext sendMsgContext, RequestReplyCallback rrCallback, long timeout) - throws Exception { - mqProducerWrapper.request(sendMsgContext.getEvent(), rrCallback, timeout); - } - - public boolean reply(final SendMessageContext sendMsgContext, final SendCallback sendCallback) throws Exception { - mqProducerWrapper.reply(sendMsgContext.getEvent(), sendCallback); - return true; - } - - protected MQProducerWrapper mqProducerWrapper; - - public MQProducerWrapper getMqProducerWrapper() { - return mqProducerWrapper; - } - - public synchronized void init(EventMeshHTTPConfiguration eventMeshHttpConfiguration, - ProducerGroupConf producerGroupConfig) throws Exception { - this.producerGroupConfig = producerGroupConfig; - this.eventMeshHttpConfiguration = eventMeshHttpConfiguration; - - Properties keyValue = new Properties(); - keyValue.put("producerGroup", producerGroupConfig.getGroupName()); - keyValue.put("instanceName", EventMeshUtil.buildMeshClientID(producerGroupConfig.getGroupName(), - eventMeshHttpConfiguration.eventMeshCluster)); - - //TODO for defibus - keyValue.put("eventMeshIDC", eventMeshHttpConfiguration.eventMeshIDC); - mqProducerWrapper = new MQProducerWrapper(eventMeshHttpConfiguration.eventMeshConnectorPluginType); - mqProducerWrapper.init(keyValue); - inited.compareAndSet(false, true); - logger.info("EventMeshProducer [{}] inited.............", producerGroupConfig.getGroupName()); - } - - - public synchronized void start() throws Exception { - if (started.get()) { - return; - } - - mqProducerWrapper.start(); - started.compareAndSet(false, true); - logger.info("EventMeshProducer [{}] started.............", producerGroupConfig.getGroupName()); - } - - public synchronized void shutdown() throws Exception { - if (!inited.get()) { - return; - } - - if (!started.get()) { - return; - } - mqProducerWrapper.shutdown(); - inited.compareAndSet(true, false); - started.compareAndSet(true, false); - logger.info("EventMeshProducer [{}] shutdown.............", producerGroupConfig.getGroupName()); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("eventMeshProducer={") - .append("inited=").append(inited.get()).append(",") - .append("started=").append(started.get()).append(",") - .append("producerGroupConfig=").append(producerGroupConfig).append("}"); - return sb.toString(); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/ProducerManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/ProducerManager.java deleted file mode 100644 index ebf65b4e50..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/ProducerManager.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.http.producer; - -import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; -import org.apache.eventmesh.runtime.core.consumergroup.ProducerGroupConf; - -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ProducerManager { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private EventMeshHTTPServer eventMeshHTTPServer; - - private ConcurrentHashMap producerTable = new ConcurrentHashMap(); - - public ProducerManager(EventMeshHTTPServer eventMeshHTTPServer) { - this.eventMeshHTTPServer = eventMeshHTTPServer; - } - - public void init() throws Exception { - logger.info("producerManager inited......"); - } - - public void start() throws Exception { - logger.info("producerManager started......"); - } - - public EventMeshProducer getEventMeshProducer(String producerGroup) throws Exception { - EventMeshProducer eventMeshProducer = null; - if (!producerTable.containsKey(producerGroup)) { - synchronized (producerTable) { - if (!producerTable.containsKey(producerGroup)) { - ProducerGroupConf producerGroupConfig = new ProducerGroupConf(producerGroup); - eventMeshProducer = createEventMeshProducer(producerGroupConfig); - eventMeshProducer.start(); - } - } - } - - eventMeshProducer = producerTable.get(producerGroup); - - if (!eventMeshProducer.getStarted().get()) { - eventMeshProducer.start(); - } - - return eventMeshProducer; - } - - public synchronized EventMeshProducer createEventMeshProducer(ProducerGroupConf producerGroupConfig) throws Exception { - if (producerTable.containsKey(producerGroupConfig.getGroupName())) { - return producerTable.get(producerGroupConfig.getGroupName()); - } - EventMeshProducer eventMeshProducer = new EventMeshProducer(); - eventMeshProducer.init(eventMeshHTTPServer.getEventMeshHttpConfiguration(), producerGroupConfig); - producerTable.put(producerGroupConfig.getGroupName(), eventMeshProducer); - return eventMeshProducer; - } - - public void shutdown() { - for (EventMeshProducer eventMeshProducer : producerTable.values()) { - try { - eventMeshProducer.shutdown(); - } catch (Exception ex) { - logger.error("shutdown eventMeshProducer[{}] err", eventMeshProducer, ex); - } - } - logger.info("producerManager shutdown......"); - } - - public EventMeshHTTPServer getEventMeshHTTPServer() { - return eventMeshHTTPServer; - } - - public ConcurrentHashMap getProducerTable() { - return producerTable; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/ProducerTopicManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/ProducerTopicManager.java new file mode 100644 index 0000000000..6201c21a33 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/ProducerTopicManager.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.http.producer; + +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.runtime.boot.EventMeshServer; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ProducerTopicManager { + + private final EventMeshServer eventMeshServer; + + private transient ScheduledFuture scheduledTask; + + protected static ScheduledExecutorService scheduler; + + private final ConcurrentHashMap eventMeshServicePubTopicInfoMap = new ConcurrentHashMap<>(64); + + public ProducerTopicManager(EventMeshServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + } + + public void init() { + scheduler = ThreadPoolFactory.createScheduledExecutor(Runtime.getRuntime().availableProcessors(), + new EventMeshThreadFactory("Producer-Topic-Manager", true)); + log.info("ProducerTopicManager inited......"); + } + + public void start() { + + if (scheduledTask == null) { + synchronized (ProducerTopicManager.class) { + scheduledTask = scheduler.scheduleAtFixedRate(() -> { + try { + if (!eventMeshServer.getConfiguration().isEventMeshServerMetaStorageEnable()) { + return; + } + List pubTopicInfoList = eventMeshServer.getMetaStorage().findEventMeshServicePubTopicInfos(); + Optional.ofNullable(pubTopicInfoList) + .ifPresent(lt -> lt.forEach(item -> eventMeshServicePubTopicInfoMap.put(item.getService(), item))); + } catch (Exception e) { + log.error("ProducerTopicManager update eventMesh pub topic info error. ", e); + } + + }, 5, 20, TimeUnit.SECONDS); + } + } + log.info("ProducerTopicManager started......"); + } + + public void shutdown() { + if (scheduledTask != null) { + scheduledTask.cancel(false); + } + log.info("ProducerTopicManager shutdown......"); + } + + public ConcurrentHashMap getEventMeshServicePubTopicInfoMap() { + return eventMeshServicePubTopicInfoMap; + } + + public EventMeshServicePubTopicInfo getEventMeshServicePubTopicInfo(String producerGroup) { + return eventMeshServicePubTopicInfoMap.get(producerGroup); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/SendMessageContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/SendMessageContext.java deleted file mode 100644 index 054e283c50..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/producer/SendMessageContext.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.http.producer; - -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; -import org.apache.eventmesh.runtime.core.protocol.http.retry.RetryContext; - -import org.apache.commons.lang3.time.DateFormatUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class SendMessageContext extends RetryContext { - - public static Logger logger = LoggerFactory.getLogger("retry"); - - private CloudEvent event; - - private String bizSeqNo; - - private EventMeshProducer eventMeshProducer; - - private long createTime = System.currentTimeMillis(); - - private Map props; - - public EventMeshHTTPServer eventMeshHTTPServer; - - private List eventList; - - public SendMessageContext(String bizSeqNo, CloudEvent event, EventMeshProducer eventMeshProducer, EventMeshHTTPServer eventMeshHTTPServer) { - this.bizSeqNo = bizSeqNo; - this.event = event; - this.eventMeshProducer = eventMeshProducer; - this.eventMeshHTTPServer = eventMeshHTTPServer; - } - - public void addProp(String key, String val) { - if (props == null) { - props = new HashMap<>(); - } - props.put(key, val); - } - - public String getProp(String key) { - return props.get(key); - } - - public String getBizSeqNo() { - return bizSeqNo; - } - - public void setBizSeqNo(String bizSeqNo) { - this.bizSeqNo = bizSeqNo; - } - - public CloudEvent getEvent() { - return event; - } - - public void setEvent(CloudEvent event) { - this.event = event; - } - - public EventMeshProducer getEventMeshProducer() { - return eventMeshProducer; - } - - public void setEventMeshProducer(EventMeshProducer eventMeshProducer) { - this.eventMeshProducer = eventMeshProducer; - } - - public long getCreateTime() { - return createTime; - } - - public void setCreateTime(long createTime) { - this.createTime = createTime; - } - - public List getEventList() { - return eventList; - } - - public void setEventList(List eventList) { - this.eventList = eventList; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("sendMessageContext={") - .append("bizSeqNo=").append(bizSeqNo) - .append(",retryTimes=").append(retryTimes) - .append(",producer=").append(eventMeshProducer != null ? eventMeshProducer.producerGroupConfig.getGroupName() : null) - .append(",executeTime=").append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT)) - .append(",createTime=").append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); - return sb.toString(); - } - - @Override - public boolean retry() throws Exception { - if (eventMeshProducer == null) { - return false; - } - - if (retryTimes > 0) { //retry once - return false; - } - - retryTimes++; - eventMeshProducer.send(this, new SendCallback() { - - @Override - public void onSuccess(SendResult sendResult) { - } - - @Override - public void onException(OnExceptionContext context) { - logger.warn("", context.getException()); - eventMeshHTTPServer.metrics.getSummaryMetrics().recordSendBatchMsgFailed(1); - } - - }); - - return true; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AbstractHTTPPushRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AbstractHTTPPushRequest.java index 1f7c3a5f61..562c6ba014 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AbstractHTTPPushRequest.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AbstractHTTPPushRequest.java @@ -20,44 +20,49 @@ import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.RetryContext; import org.apache.eventmesh.runtime.core.protocol.http.consumer.HandleMsgContext; import org.apache.eventmesh.runtime.core.protocol.http.retry.HttpRetryer; -import org.apache.eventmesh.runtime.core.protocol.http.retry.RetryContext; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.RandomUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import com.google.common.collect.Lists; public abstract class AbstractHTTPPushRequest extends RetryContext { - public EventMeshHTTPServer eventMeshHTTPServer; + public final EventMeshHTTPServer eventMeshHTTPServer; - public long createTime = System.currentTimeMillis(); + public final long createTime = System.currentTimeMillis(); public long lastPushTime = System.currentTimeMillis(); - public Map> urls; + /** + * key: IDC + */ + public final Map> urls; - public List totalUrls; + public final List totalUrls; public volatile int startIdx; - public EventMeshHTTPConfiguration eventMeshHttpConfiguration; + public final EventMeshHTTPConfiguration eventMeshHttpConfiguration; - public HttpRetryer retryer; + public final HttpRetryer retryer; - public int ttl; + public final int ttl; - public HandleMsgContext handleMsgContext; + public final HandleMsgContext handleMsgContext; - private AtomicBoolean complete = new AtomicBoolean(Boolean.FALSE); + private final AtomicBoolean complete = new AtomicBoolean(Boolean.FALSE); public AbstractHTTPPushRequest(HandleMsgContext handleMsgContext) { this.eventMeshHTTPServer = handleMsgContext.getEventMeshHTTPServer(); @@ -67,17 +72,17 @@ public AbstractHTTPPushRequest(HandleMsgContext handleMsgContext) { this.eventMeshHttpConfiguration = handleMsgContext.getEventMeshHTTPServer().getEventMeshHttpConfiguration(); this.retryer = handleMsgContext.getEventMeshHTTPServer().getHttpRetryer(); this.ttl = handleMsgContext.getTtl(); - this.startIdx = RandomUtils.nextInt(0, totalUrls.size()); + this.startIdx = ThreadLocalRandom.current().nextInt(0, totalUrls.size()); + super.commonConfiguration = eventMeshHttpConfiguration; } public void tryHTTPRequest() { } - public void delayRetry(long delayTime) { + public void delayRetry(long delayTime, TimeUnit timeUnit) { if (retryTimes < EventMeshConstants.DEFAULT_PUSH_RETRY_TIMES && delayTime > 0) { retryTimes++; - delay(delayTime); - retryer.pushRetry(this); + retryer.newTimeout(this, delayTime, timeUnit); } else { complete.compareAndSet(Boolean.FALSE, Boolean.TRUE); } @@ -86,8 +91,7 @@ public void delayRetry(long delayTime) { public void delayRetry() { if (retryTimes < EventMeshConstants.DEFAULT_PUSH_RETRY_TIMES) { retryTimes++; - delay(retryTimes * EventMeshConstants.DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS); - retryer.pushRetry(this); + retryer.newTimeout(this, EventMeshConstants.DEFAULT_PUSH_RETRY_TIME_DISTANCE_IN_MILLSECONDS, TimeUnit.MILLISECONDS); } else { complete.compareAndSet(Boolean.FALSE, Boolean.TRUE); } @@ -95,7 +99,7 @@ public void delayRetry() { public String getUrl() { List localIDCUrl = MapUtils.getObject(urls, - eventMeshHttpConfiguration.eventMeshIDC, null); + eventMeshHttpConfiguration.getEventMeshIDC(), null); if (CollectionUtils.isNotEmpty(localIDCUrl)) { return localIDCUrl.get((startIdx + retryTimes) % localIDCUrl.size()); } @@ -125,4 +129,10 @@ public void timeout() { delayRetry(); } } -} \ No newline at end of file + + @Override + protected ProducerManager getProducerManager() { + return eventMeshHTTPServer.getProducerManager(); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AsyncHTTPPushRequest.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AsyncHTTPPushRequest.java index 5abc9932d1..ad136fad73 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AsyncHTTPPushRequest.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/AsyncHTTPPushRequest.java @@ -18,7 +18,6 @@ package org.apache.eventmesh.runtime.core.protocol.http.push; import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.exception.JsonException; import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.SubscriptionType; import org.apache.eventmesh.common.protocol.http.HttpCommand; @@ -31,12 +30,13 @@ import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.function.filter.pattern.Pattern; +import org.apache.eventmesh.function.transformer.Transformer; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.http.consumer.HandleMsgContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; -import org.apache.eventmesh.runtime.util.WebhookUtil; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; @@ -45,7 +45,6 @@ import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; -import org.apache.http.client.ResponseHandler; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicNameValuePair; @@ -61,6 +60,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,16 +73,18 @@ public class AsyncHTTPPushRequest extends AbstractHTTPPushRequest { - public Logger messageLogger = LoggerFactory.getLogger("message"); + public static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - public Logger cmdLogger = LoggerFactory.getLogger("cmd"); + public static final Logger CMD_LOGGER = LoggerFactory.getLogger(EventMeshConstants.CMD); + + public static final Logger LOGGER = LoggerFactory.getLogger("AsyncHTTPPushRequest"); - public Logger logger = LoggerFactory.getLogger(this.getClass()); public String currPushUrl; - private Map> waitingRequests; + + private final Map> waitingRequests; public AsyncHTTPPushRequest(HandleMsgContext handleMsgContext, - Map> waitingRequests) { + Map> waitingRequests) { super(handleMsgContext); this.waitingRequests = waitingRequests; } @@ -93,30 +95,31 @@ public void tryHTTPRequest() { currPushUrl = getUrl(); if (StringUtils.isBlank(currPushUrl)) { + LOGGER.warn("tryHTTPRequest fail, getUrl is null, group:{}, topic:{}, bizSeqNo={}, uniqueId={}", this.handleMsgContext.getConsumerGroup(), + this.handleMsgContext.getTopic(), this.handleMsgContext.getBizSeqNo(), this.handleMsgContext.getUniqueId()); return; } HttpPost builder = new HttpPost(currPushUrl); String requestCode = ""; - - if (SubscriptionType.SYNC.equals(handleMsgContext.getSubscriptionItem().getType())) { + if (SubscriptionType.SYNC == handleMsgContext.getSubscriptionItem().getType()) { requestCode = String.valueOf(RequestCode.HTTP_PUSH_CLIENT_SYNC.getRequestCode()); } else { requestCode = String.valueOf(RequestCode.HTTP_PUSH_CLIENT_ASYNC.getRequestCode()); } - + String localAddress = IPUtils.getLocalAddress(); builder.addHeader(ProtocolKey.REQUEST_CODE, requestCode); builder.addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA); builder.addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()); builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHCLUSTER, handleMsgContext.getEventMeshHTTPServer() - .getEventMeshHttpConfiguration().eventMeshCluster); - builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, IPUtils.getLocalAddress()); + .getEventMeshHttpConfiguration().getEventMeshCluster()); + builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIP, localAddress); builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHENV, - handleMsgContext.getEventMeshHTTPServer().getEventMeshHttpConfiguration().eventMeshEnv); + handleMsgContext.getEventMeshHTTPServer().getEventMeshHttpConfiguration().getEventMeshEnv()); builder.addHeader(ProtocolKey.EventMeshInstanceKey.EVENTMESHIDC, - handleMsgContext.getEventMeshHTTPServer().getEventMeshHttpConfiguration().eventMeshIDC); + handleMsgContext.getEventMeshHTTPServer().getEventMeshHttpConfiguration().getEventMeshIDC()); CloudEvent event = CloudEventBuilder.from(handleMsgContext.getEvent()) .withExtension(EventMeshConstants.REQ_EVENTMESH2C_TIMESTAMP, @@ -124,7 +127,33 @@ public void tryHTTPRequest() { .withExtension(EventMeshConstants.RSP_URL, currPushUrl) .withExtension(EventMeshConstants.RSP_GROUP, handleMsgContext.getConsumerGroup()) .build(); + + Pattern filterPattern = eventMeshHTTPServer.getFilterEngine() + .getFilterPattern(handleMsgContext.getConsumerGroup() + "-" + handleMsgContext.getTopic()); + if (filterPattern != null) { + if (!filterPattern.filter(JsonUtils.toJSONString(event))) { + LOGGER.error("apply filter failed, group:{}, topic:{}, bizSeqNo={}, uniqueId={}", + this.handleMsgContext.getConsumerGroup(), + this.handleMsgContext.getTopic(), this.handleMsgContext.getBizSeqNo(), this.handleMsgContext.getUniqueId()); + return; + } + } + Transformer transformer = eventMeshHTTPServer.getTransformerEngine() + .getTransformer(handleMsgContext.getConsumerGroup() + "-" + handleMsgContext.getTopic()); + if (transformer != null) { + try { + String data = transformer.transform(JsonUtils.toJSONString(event)); + event = CloudEventBuilder.from(event).withData(Objects.requireNonNull(JsonUtils.toJSONString(data)) + .getBytes(StandardCharsets.UTF_8)).build(); + } catch (Exception exception) { + LOGGER.warn("apply transformer to cloudevents error, group:{}, topic:{}, bizSeqNo={}, uniqueId={}", + this.handleMsgContext.getConsumerGroup(), + this.handleMsgContext.getTopic(), this.handleMsgContext.getBizSeqNo(), this.handleMsgContext.getUniqueId(), exception); + return; + } + } handleMsgContext.setEvent(event); + super.setEvent(event); String content = ""; try { @@ -138,16 +167,18 @@ public void tryHTTPRequest() { content = ((HttpCommand) protocolTransportObject).getBody().toMap().get("content").toString(); } else { HttpEventWrapper httpEventWrapper = (HttpEventWrapper) protocolTransportObject; - Map sysHeaderMap = httpEventWrapper.getSysHeaderMap(); - content = new String(httpEventWrapper.getBody(), StandardCharsets.UTF_8); - for (String header : sysHeaderMap.keySet()) { - if (!builder.containsHeader(header)) { - builder.addHeader(header, sysHeaderMap.get(header).toString()); + content = new String(httpEventWrapper.getBody(), Constants.DEFAULT_CHARSET); + httpEventWrapper.getSysHeaderMap().forEach((k, v) -> { + if (!builder.containsHeader(k)) { + builder.addHeader(k, v.toString()); } - } + }); } } catch (Exception ex) { + LOGGER.warn("cloudevent to HttpEventWrapper occur except, group:{}, topic:{}, bizSeqNo={}, uniqueId={}", + this.handleMsgContext.getConsumerGroup(), + this.handleMsgContext.getTopic(), this.handleMsgContext.getBizSeqNo(), this.handleMsgContext.getUniqueId(), ex); return; } @@ -173,100 +204,79 @@ public void tryHTTPRequest() { body.add(new BasicNameValuePair(PushMessageRequestBody.TOPIC, handleMsgContext.getTopic())); body.add(new BasicNameValuePair(PushMessageRequestBody.EXTFIELDS, - JsonUtils.serialize(EventMeshUtil.getEventProp(handleMsgContext.getEvent())))); + JsonUtils.toJSONString(EventMeshUtil.getEventProp(handleMsgContext.getEvent())))); - HttpEntity httpEntity = new UrlEncodedFormEntity(body, StandardCharsets.UTF_8); + HttpEntity httpEntity = new UrlEncodedFormEntity(body, Constants.DEFAULT_CHARSET); builder.setEntity(httpEntity); - // for CloudEvents Webhook spec - String urlAuthType = handleMsgContext.getConsumerGroupConfig().getConsumerGroupTopicConf() - .get(handleMsgContext.getTopic()).getHttpAuthTypeMap().get(currPushUrl); - - WebhookUtil.setWebhookHeaders(builder, httpEntity.getContentType().getValue(), eventMeshHttpConfiguration.eventMeshWebhookOrigin, - urlAuthType); - - eventMeshHTTPServer.metrics.getSummaryMetrics().recordPushMsg(); + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordPushMsg(); this.lastPushTime = System.currentTimeMillis(); addToWaitingMap(this); - cmdLogger.info("cmd={}|eventMesh2client|from={}|to={}", requestCode, - IPUtils.getLocalAddress(), currPushUrl); + CMD_LOGGER.info("cmd={}|eventMesh2client|from={}|to={}", requestCode, localAddress, currPushUrl); try { - eventMeshHTTPServer.httpClientPool.getClient().execute(builder, new ResponseHandler() { - @Override - public Object handleResponse(HttpResponse response) { - removeWaitingMap(AsyncHTTPPushRequest.this); - long cost = System.currentTimeMillis() - lastPushTime; - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHTTPPushTimeCost(cost); - - if (processResponseStatus(response.getStatusLine().getStatusCode(), response)) { - // this is successful response, process response payload - String res = ""; - try { - res = EntityUtils.toString(response.getEntity(), - Charset.forName(EventMeshConstants.DEFAULT_CHARSET)); - } catch (IOException e) { - handleMsgContext.finish(); - return new Object(); - } - ClientRetCode result = processResponseContent(res); - messageLogger.info( - "message|eventMesh2client|{}|url={}|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", - result, currPushUrl, handleMsgContext.getTopic(), - handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), cost); - if (result == ClientRetCode.OK || result == ClientRetCode.REMOTE_OK) { + eventMeshHTTPServer.getHttpClientPool().getClient().execute(builder, response -> { + removeWaitingMap(AsyncHTTPPushRequest.this); + long cost = System.currentTimeMillis() - lastPushTime; + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHTTPPushTimeCost(cost); + + if (processResponseStatus(response.getStatusLine().getStatusCode(), response)) { + // this is successful response, process response payload + String res; + try { + res = EntityUtils.toString(response.getEntity(), Charset.forName(EventMeshConstants.DEFAULT_CHARSET)); + } catch (IOException e) { + LOGGER.warn("handleResponse exception", e); + handleMsgContext.finish(); + return new Object(); + } + ClientRetCode result = processResponseContent(res); + MESSAGE_LOGGER.info("message|eventMesh2client|{}|url={}|topic={}|bizSeqNo={}|uniqueId={}|cost={}", + result, currPushUrl, handleMsgContext.getTopic(), + handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), cost); + switch (result) { + case OK: + case REMOTE_OK: + case FAIL: complete(); if (isComplete()) { handleMsgContext.finish(); } - } else if (result == ClientRetCode.RETRY) { + break; + case RETRY: + case NOLISTEN: delayRetry(); if (isComplete()) { handleMsgContext.finish(); } - } else if (result == ClientRetCode.NOLISTEN) { - delayRetry(); - if (isComplete()) { - handleMsgContext.finish(); - } - } else if (result == ClientRetCode.FAIL) { - complete(); - if (isComplete()) { - handleMsgContext.finish(); - } - } - } else { - eventMeshHTTPServer.metrics.getSummaryMetrics().recordHttpPushMsgFailed(); - messageLogger.info( - "message|eventMesh2client|exception|url={}|topic={}|bizSeqNo={}" - + "|uniqueId={}|cost={}", currPushUrl, handleMsgContext.getTopic(), - handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), cost); - - if (isComplete()) { - handleMsgContext.finish(); - } + break; + default: // do nothing + } + } else { + eventMeshHTTPServer.getEventMeshHttpMetricsManager().getHttpMetrics().recordHttpPushMsgFailed(); + MESSAGE_LOGGER.info("message|eventMesh2client|exception|url={}|topic={}|bizSeqNo={}|uniqueId={}|cost={}", + currPushUrl, handleMsgContext.getTopic(), handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), cost); + + if (isComplete()) { + handleMsgContext.finish(); } - return new Object(); } + return new Object(); }); - if (messageLogger.isDebugEnabled()) { - messageLogger.debug("message|eventMesh2client|url={}|topic={}|event={}", currPushUrl, - handleMsgContext.getTopic(), - handleMsgContext.getEvent()); + if (MESSAGE_LOGGER.isDebugEnabled()) { + MESSAGE_LOGGER.debug("message|eventMesh2client|url={}|topic={}|event={}", + currPushUrl, handleMsgContext.getTopic(), handleMsgContext.getEvent()); } else { - messageLogger - .info("message|eventMesh2client|url={}|topic={}|bizSeqNo={}|uniqueId={}", - currPushUrl, handleMsgContext.getTopic(), - handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId()); + MESSAGE_LOGGER.info("message|eventMesh2client|url={}|topic={}|bizSeqNo={}|uniqueId={}", + currPushUrl, handleMsgContext.getTopic(), handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId()); } } catch (IOException e) { - messageLogger.error("push2client err", e); + MESSAGE_LOGGER.error("push2client err", e); removeWaitingMap(this); delayRetry(); if (isComplete()) { @@ -284,11 +294,11 @@ public String toString() { .append(",retryTimes=").append(retryTimes) .append(",uniqueId=").append(handleMsgContext.getUniqueId()) .append(",executeTime=") - .append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT)) + .append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)) .append(",lastPushTime=") - .append(DateFormatUtils.format(lastPushTime, Constants.DATE_FORMAT)) + .append(DateFormatUtils.format(lastPushTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)) .append(",createTime=") - .append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT)).append("}"); + .append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); return sb.toString(); } @@ -304,7 +314,7 @@ boolean processResponseStatus(int httpStatus, HttpResponse httpResponse) { // retry after the time specified by the header Optional
optHeader = Arrays.stream(httpResponse.getHeaders("Retry-After")).findAny(); if (optHeader.isPresent() && StringUtils.isNumeric(optHeader.get().getValue())) { - delayRetry(Long.parseLong(optHeader.get().getValue())); + delayRetry(Long.parseLong(optHeader.get().getValue()), TimeUnit.MILLISECONDS); } return false; } else if (httpStatus == HttpStatus.SC_GONE || httpStatus == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE) { @@ -317,6 +327,11 @@ boolean processResponseStatus(int httpStatus, HttpResponse httpResponse) { return false; } + @Override + protected HandleMsgContext getHandleMessageContext() { + return handleMsgContext; + } + ClientRetCode processResponseContent(String content) { if (StringUtils.isBlank(content)) { return ClientRetCode.FAIL; @@ -324,25 +339,21 @@ ClientRetCode processResponseContent(String content) { try { Map ret = - JsonUtils.deserialize(content, new TypeReference>() { + JsonUtils.parseTypeReferenceObject(content, new TypeReference>() { }); - Integer retCode = (Integer) ret.get("retCode"); + Integer retCode = (Integer) Objects.requireNonNull(ret).get(ProtocolKey.RETCODE); if (retCode != null && ClientRetCode.contains(retCode)) { return ClientRetCode.get(retCode); } return ClientRetCode.FAIL; } catch (NumberFormatException e) { - messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", currPushUrl, - handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); - return ClientRetCode.FAIL; - } catch (JsonException e) { - messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", currPushUrl, - handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); + MESSAGE_LOGGER.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", + currPushUrl, handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); return ClientRetCode.FAIL; - } catch (Throwable t) { - messageLogger.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", currPushUrl, - handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); + } catch (Exception e) { + MESSAGE_LOGGER.warn("url:{}, bizSeqno:{}, uniqueId:{}, httpResponse:{}", + currPushUrl, handleMsgContext.getBizSeqNo(), handleMsgContext.getUniqueId(), content); return ClientRetCode.FAIL; } } @@ -364,8 +375,7 @@ private void removeWaitingMap(AsyncHTTPPushRequest request) { } @Override - public boolean retry() { + public void doRun() { tryHTTPRequest(); - return true; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPClientPool.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPClientPool.java index b54ec70f77..393b01d7f8 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPClientPool.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPClientPool.java @@ -18,11 +18,12 @@ package org.apache.eventmesh.runtime.core.protocol.http.push; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.RandomUtils; +import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.client.CloseableHttpClient; @@ -33,6 +34,7 @@ import org.apache.http.ssl.SSLContexts; import org.apache.http.ssl.TrustStrategy; +import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -41,78 +43,99 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class HTTPClientPool { - public Logger logger = LoggerFactory.getLogger(this.getClass()); + private final transient List clients = Collections.synchronizedList(new ArrayList<>()); - private List clients = Collections.synchronizedList(new ArrayList<>()); + private final int core; - private int core = 1; + private static final int DEFAULT_MAX_TOTAL = 200; + private static final int DEFAULT_IDLETIME_SECONDS = 30; - public HTTPClientPool(int core) { - this.core = core; + private static final int CONNECT_TIMEOUT = 5000; + private static final int SOCKET_TIMEOUT = 5000; + + private transient PoolingHttpClientConnectionManager connectionManager; + + public HTTPClientPool(final int core) { + this.core = core <= 0 ? 1 : core; } public CloseableHttpClient getClient() { if (CollectionUtils.size(clients) < core) { - CloseableHttpClient client = getHttpClient(200, 30, null); + final CloseableHttpClient client = getHttpClient(DEFAULT_MAX_TOTAL, DEFAULT_IDLETIME_SECONDS, null); clients.add(client); return client; } - return clients.get(RandomUtils.nextInt(core, 2 * core) % core); + + return clients.get(ThreadLocalRandom.current().nextInt(core, 2 * core) % core); } - public void shutdown() throws Exception { - Iterator itr = clients.iterator(); - while (itr.hasNext()) { - CloseableHttpClient client = itr.next(); - client.close(); - itr.remove(); + public void shutdown() throws IOException { + synchronized (clients) { + final Iterator itr = clients.iterator(); + while (itr.hasNext()) { + try (CloseableHttpClient client = itr.next()) { + itr.remove(); + } + } + } + + if (this.connectionManager == null) { + this.connectionManager.close(); } } - @SuppressWarnings("deprecation") - public CloseableHttpClient getHttpClient(int maxTotal, int idleTimeInSeconds, SSLContext sslContext) { + // @SuppressWarnings("deprecation") + public CloseableHttpClient getHttpClient(final int maxTotal, final int idleTimeInSeconds, final SSLContext sslContext) { + + SSLContext innerSSLContext = sslContext; try { - if (sslContext == null) { - sslContext = SSLContexts.custom().loadTrustMaterial(new TheTrustStrategy()).build(); - } + innerSSLContext = innerSSLContext == null ? SSLContexts.custom().loadTrustMaterial(new TheTrustStrategy()).build() : innerSSLContext; + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { - logger.error("Get sslContext error: {}", e.getMessage()); + log.error("Get sslContext error", e); return HttpClients.createDefault(); } - HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; - - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); - Registry socketFactoryRegistry - = RegistryBuilder.create() + if (connectionManager == null) { + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(innerSSLContext, NoopHostnameVerifier.INSTANCE); + final Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) - .register("https", sslsf).build(); - PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + .register("https", sslsf) + .build(); + connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + connectionManager.setDefaultMaxPerRoute(maxTotal); + connectionManager.setMaxTotal(maxTotal); + } + + RequestConfig config = RequestConfig.custom() + .setConnectTimeout(CONNECT_TIMEOUT) + .setConnectionRequestTimeout(CONNECT_TIMEOUT) + .setSocketTimeout(SOCKET_TIMEOUT).build(); - connectionManager.setDefaultMaxPerRoute(maxTotal); - connectionManager.setMaxTotal(maxTotal); return HttpClients.custom() - .setConnectionManager(connectionManager) - .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) - .evictIdleConnections(idleTimeInSeconds, TimeUnit.SECONDS) - .setConnectionReuseStrategy(new DefaultConnectionReuseStrategy()) - .setRetryHandler(new DefaultHttpRequestRetryHandler()) - .build(); + .setDefaultRequestConfig(config) + .setConnectionManager(connectionManager) + .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) + .evictIdleConnections(idleTimeInSeconds, TimeUnit.SECONDS) + .setConnectionReuseStrategy(new DefaultConnectionReuseStrategy()) + .setRetryHandler(new DefaultHttpRequestRetryHandler()) + .build(); } - public static class TheTrustStrategy implements TrustStrategy { + private static class TheTrustStrategy implements TrustStrategy { + @Override - public boolean isTrusted(X509Certificate[] arg0, String arg1) { + public boolean isTrusted(final X509Certificate[] chain, final String authType) { return true; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPMessageHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPMessageHandler.java index 166ddca928..68ad9c5963 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPMessageHandler.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/HTTPMessageHandler.java @@ -17,12 +17,11 @@ package org.apache.eventmesh.runtime.core.protocol.http.push; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.ThreadPoolFactory; import org.apache.eventmesh.runtime.core.protocol.http.consumer.EventMeshConsumer; import org.apache.eventmesh.runtime.core.protocol.http.consumer.HandleMsgContext; -import org.apache.eventmesh.runtime.trace.TraceUtils; import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.TraceUtils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; import org.apache.commons.collections4.MapUtils; @@ -35,50 +34,48 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.opentelemetry.api.trace.Span; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class HTTPMessageHandler implements MessageHandler { - public Logger logger = LoggerFactory.getLogger(this.getClass()); + private final transient EventMeshConsumer eventMeshConsumer; - private EventMeshConsumer eventMeshConsumer; + private static final ScheduledExecutorService SCHEDULER = + ThreadPoolFactory.createSingleScheduledExecutor("eventMesh-pushMsgTimeout"); - private static final ScheduledExecutorService SCHEDULER = ThreadPoolFactory.createSingleScheduledExecutor("eventMesh-pushMsgTimeout-"); + private static final Integer CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD = 10000; - private ThreadPoolExecutor pushExecutor; + protected static final Map> waitingRequests = Maps.newConcurrentMap(); - private static final Integer CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD = 10000; + private final transient ThreadPoolExecutor pushExecutor; private void checkTimeout() { - waitingRequests.entrySet().stream().forEach(entry -> { - for (AbstractHTTPPushRequest request : entry.getValue()) { - request.timeout(); - waitingRequests.get(request.handleMsgContext.getConsumerGroup()).remove(request); - } - }); - } + waitingRequests.forEach((key, value) -> value.forEach(r -> { + r.timeout(); + waitingRequests.get(r.handleMsgContext.getConsumerGroup()).remove(r); + })); - public static Map> waitingRequests = Maps.newConcurrentMap(); + } public HTTPMessageHandler(EventMeshConsumer eventMeshConsumer) { this.eventMeshConsumer = eventMeshConsumer; - this.pushExecutor = eventMeshConsumer.getEventMeshHTTPServer().pushMsgExecutor; + this.pushExecutor = eventMeshConsumer.getEventMeshHTTPServer().getHttpThreadPoolGroup().getPushMsgExecutor(); waitingRequests.put(this.eventMeshConsumer.getConsumerGroupConf().getConsumerGroup(), Sets.newConcurrentHashSet()); SCHEDULER.scheduleAtFixedRate(this::checkTimeout, 0, 1000, TimeUnit.MILLISECONDS); } @Override public boolean handle(final HandleMsgContext handleMsgContext) { - Set waitingRequests4Group = MapUtils.getObject(waitingRequests, - handleMsgContext.getConsumerGroup(), Sets.newConcurrentHashSet()); - if (waitingRequests4Group.size() > CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD) { - logger.warn("waitingRequests is too many, so reject, this message will be send back to MQ, consumerGroup:{}, threshold:{}", + if (MapUtils.getObject(waitingRequests, handleMsgContext.getConsumerGroup(), Sets.newConcurrentHashSet()) + .size() > CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD) { + log.warn("waitingRequests is too many, so reject, this message will be send back to MQ, " + + "consumerGroup:{}, threshold:{}", handleMsgContext.getConsumerGroup(), CONSUMER_GROUP_WAITING_REQUEST_THRESHOLD); return false; } @@ -87,12 +84,12 @@ public boolean handle(final HandleMsgContext handleMsgContext) { pushExecutor.submit(() -> { String protocolVersion = Objects.requireNonNull(handleMsgContext.getEvent().getSpecVersion()).toString(); - Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, handleMsgContext.getEvent()), + Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, + handleMsgContext.getEvent()), EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_CLIENT_SPAN, false); try { - AsyncHTTPPushRequest asyncPushRequest = new AsyncHTTPPushRequest(handleMsgContext, waitingRequests); - asyncPushRequest.tryHTTPRequest(); + new AsyncHTTPPushRequest(handleMsgContext, waitingRequests).tryHTTPRequest(); } finally { TraceUtils.finishSpan(span, handleMsgContext.getEvent()); } @@ -100,8 +97,8 @@ public boolean handle(final HandleMsgContext handleMsgContext) { }); return true; } catch (RejectedExecutionException e) { - logger.warn("pushMsgThreadPoolQueue is full, so reject, current task size {}", - handleMsgContext.getEventMeshHTTPServer().getPushMsgExecutor().getQueue().size(), e); + log.warn("pushMsgThreadPoolQueue is full, so reject, current task size {}", + handleMsgContext.getEventMeshHTTPServer().getHttpThreadPoolGroup().getPushMsgExecutor().getQueue().size(), e); return false; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/MessageHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/MessageHandler.java index bf29c0e5ed..46b918b9b0 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/MessageHandler.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/push/MessageHandler.java @@ -23,5 +23,6 @@ * MessageHandler */ public interface MessageHandler { + boolean handle(HandleMsgContext handleMsgContext); -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/DelayRetryable.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/DelayRetryable.java deleted file mode 100644 index f79a6c2005..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/DelayRetryable.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.http.retry; - -import java.util.concurrent.Delayed; - -/** - * DelayRetryable - */ -public interface DelayRetryable extends Delayed { - boolean retry() throws Exception; -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/HttpRetryer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/HttpRetryer.java index 6448db3fe4..f081cc1595 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/HttpRetryer.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/HttpRetryer.java @@ -17,106 +17,17 @@ package org.apache.eventmesh.runtime.core.protocol.http.retry; +import org.apache.eventmesh.retry.api.AbstractRetryer; import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; +import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +@Slf4j +public class HttpRetryer extends AbstractRetryer { -public class HttpRetryer { - - private Logger retryLogger = LoggerFactory.getLogger("retry"); - - private Logger logger = LoggerFactory.getLogger(this.getClass()); - - private EventMeshHTTPServer eventMeshHTTPServer; + private final EventMeshHTTPServer eventMeshHTTPServer; public HttpRetryer(EventMeshHTTPServer eventMeshHTTPServer) { this.eventMeshHTTPServer = eventMeshHTTPServer; } - - private DelayQueue failed = new DelayQueue<>(); - - private ThreadPoolExecutor pool; - - private Thread dispatcher; - - public void pushRetry(DelayRetryable delayRetryable) { - if (failed.size() >= eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerRetryBlockQSize) { - retryLogger.error("[RETRY-QUEUE] is full!"); - return; - } - failed.offer(delayRetryable); - } - - public void init() { - pool = new ThreadPoolExecutor(eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerRetryThreadNum, - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerRetryThreadNum, - 60000, - TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>( - eventMeshHTTPServer.getEventMeshHttpConfiguration().eventMeshServerRetryBlockQSize), - new ThreadFactory() { - private AtomicInteger count = new AtomicInteger(); - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "http-retry-" + count.incrementAndGet()); - thread.setPriority(Thread.NORM_PRIORITY); - thread.setDaemon(true); - return thread; - } - }, - new ThreadPoolExecutor.AbortPolicy()); - - dispatcher = new Thread(() -> { - try { - DelayRetryable retryObj; - while (!Thread.currentThread().isInterrupted() && (retryObj = failed.take()) != null) { - final DelayRetryable delayRetryable = retryObj; - pool.execute(() -> { - try { - delayRetryable.retry(); - if (retryLogger.isDebugEnabled()) { - retryLogger.debug("retryObj : {}", delayRetryable); - } - } catch (Exception e) { - retryLogger.error("http-retry-dispatcher error!", e); - } - }); - } - } catch (Exception e) { - retryLogger.error("http-retry-dispatcher error!", e); - } - }, "http-retry-dispatcher"); - dispatcher.setDaemon(true); - logger.info("HttpRetryer inited......"); - } - - public int size() { - return failed.size(); - } - - /** - * Get failed queue, this method is just used for metrics. - */ - public DelayQueue getFailedQueue() { - return failed; - } - - public void shutdown() { - dispatcher.interrupt(); - pool.shutdown(); - logger.info("HttpRetryer shutdown......"); - } - - public void start() throws Exception { - dispatcher.start(); - logger.info("HttpRetryer started......"); - } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/RetryContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/RetryContext.java deleted file mode 100644 index 7841cca1e4..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/http/retry/RetryContext.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.http.retry; - -import java.util.concurrent.Delayed; -import java.util.concurrent.TimeUnit; - -public abstract class RetryContext implements DelayRetryable { - - public int retryTimes = 0; - - public long executeTime = System.currentTimeMillis(); - - public RetryContext delay(long delay) { - this.executeTime = System.currentTimeMillis() + delay; - return this; - } - - @Override - public int compareTo(Delayed delayed) { - RetryContext obj = (RetryContext) delayed; - if (this.executeTime > obj.executeTime) { - return 1; - } else if (this.executeTime == obj.executeTime) { - return 0; - } else { - return -1; - } - } - - @Override - public long getDelay(TimeUnit unit) { - return unit.convert(this.executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/EventMeshProducer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/EventMeshProducer.java new file mode 100644 index 0000000000..749695d4c7 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/EventMeshProducer.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.runtime.common.ServiceState; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.consumergroup.ProducerGroupConf; +import org.apache.eventmesh.runtime.core.plugin.MQProducerWrapper; +import org.apache.eventmesh.runtime.util.EventMeshUtil; + +import java.util.Properties; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshProducer { + + private ProducerGroupConf producerGroupConfig; + + private MQProducerWrapper mqProducerWrapper; + + private ServiceState serviceState; + + public void send(SendMessageContext sendMsgContext, SendCallback sendCallback) + throws Exception { + mqProducerWrapper.send(sendMsgContext.getEvent(), sendCallback); + } + + public void request(SendMessageContext sendMsgContext, RequestReplyCallback rrCallback, long timeout) + throws Exception { + mqProducerWrapper.request(sendMsgContext.getEvent(), rrCallback, timeout); + } + + public void reply(SendMessageContext sendMessageContext, SendCallback sendCallback) throws Exception { + mqProducerWrapper.reply(sendMessageContext.getEvent(), sendCallback); + } + + public synchronized void init(CommonConfiguration configuration, + ProducerGroupConf producerGroupConfig) throws Exception { + if (ServiceState.INITED == serviceState) { + return; + } + this.producerGroupConfig = producerGroupConfig; + + Properties keyValue = new Properties(); + keyValue.put(EventMeshConstants.PRODUCER_GROUP, producerGroupConfig.getGroupName()); + keyValue.put(EventMeshConstants.INSTANCE_NAME, EventMeshUtil.buildMeshClientID( + producerGroupConfig.getGroupName(), configuration.getEventMeshCluster())); + + keyValue.put(EventMeshConstants.EVENT_MESH_IDC, configuration.getEventMeshIDC()); + mqProducerWrapper = new MQProducerWrapper( + configuration.getEventMeshStoragePluginType()); + mqProducerWrapper.init(keyValue); + serviceState = ServiceState.INITED; + log.info("EventMeshProducer [{}] inited...........", producerGroupConfig.getGroupName()); + } + + public synchronized void start() throws Exception { + if (serviceState == null || ServiceState.RUNNING == serviceState) { + return; + } + + mqProducerWrapper.start(); + serviceState = ServiceState.RUNNING; + log.info("EventMeshProducer [{}] started..........", producerGroupConfig.getGroupName()); + } + + public synchronized void shutdown() throws Exception { + if (serviceState == null || ServiceState.STOPPED == serviceState) { + return; + } + + mqProducerWrapper.shutdown(); + serviceState = ServiceState.STOPPED; + log.info("EventMeshProducer [{}] shutdown.........", producerGroupConfig.getGroupName()); + } + + public ServiceState getStatus() { + return this.serviceState; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("eventMeshProducer={").append("status=").append(serviceState.name()).append(",").append("producerGroupConfig=") + .append(producerGroupConfig).append("}"); + return sb.toString(); + } + + public MQProducerWrapper getMqProducerWrapper() { + return mqProducerWrapper; + } + + public boolean isStarted() { + return serviceState == ServiceState.RUNNING; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/ProducerManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/ProducerManager.java new file mode 100644 index 0000000000..251790f89a --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/ProducerManager.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.producer; + +import org.apache.eventmesh.runtime.boot.AbstractRemotingServer; +import org.apache.eventmesh.runtime.core.consumergroup.ProducerGroupConf; + +import java.util.concurrent.ConcurrentHashMap; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ProducerManager { + + private final AbstractRemotingServer eventMeshServer; + + /** + * key: group name + */ + private final ConcurrentHashMap producerTable = new ConcurrentHashMap<>(); + + public ProducerManager(AbstractRemotingServer eventMeshServer) { + this.eventMeshServer = eventMeshServer; + } + + public void init() throws Exception { + log.info("producerManager inited......"); + } + + public void start() throws Exception { + log.info("producerManager started......"); + } + + public EventMeshProducer getEventMeshProducer(String producerGroup) throws Exception { + EventMeshProducer eventMeshProducer; + if (!producerTable.containsKey(producerGroup)) { + synchronized (producerTable) { + if (!producerTable.containsKey(producerGroup)) { + ProducerGroupConf producerGroupConfig = new ProducerGroupConf(producerGroup); + eventMeshProducer = createEventMeshProducer(producerGroupConfig); + eventMeshProducer.start(); + } + } + } + + eventMeshProducer = producerTable.get(producerGroup); + + if (!eventMeshProducer.isStarted()) { + eventMeshProducer.start(); + } + + return eventMeshProducer; + } + + public EventMeshProducer getEventMeshProducer(String producerGroup, String token) throws Exception { + EventMeshProducer eventMeshProducer; + if (!producerTable.containsKey(producerGroup)) { + synchronized (producerTable) { + if (!producerTable.containsKey(producerGroup)) { + ProducerGroupConf producerGroupConfig = new ProducerGroupConf(producerGroup, token); + eventMeshProducer = createEventMeshProducer(producerGroupConfig); + eventMeshProducer.start(); + } + } + } + + eventMeshProducer = producerTable.get(producerGroup); + + if (!eventMeshProducer.isStarted()) { + eventMeshProducer.start(); + } + + return eventMeshProducer; + } + + public synchronized EventMeshProducer createEventMeshProducer(ProducerGroupConf producerGroupConfig) throws Exception { + if (producerTable.containsKey(producerGroupConfig.getGroupName())) { + return producerTable.get(producerGroupConfig.getGroupName()); + } + EventMeshProducer eventMeshProducer = new EventMeshProducer(); + eventMeshProducer.init(eventMeshServer.getConfiguration(), producerGroupConfig); + producerTable.put(producerGroupConfig.getGroupName(), eventMeshProducer); + return eventMeshProducer; + } + + public void shutdown() { + for (EventMeshProducer eventMeshProducer : producerTable.values()) { + try { + eventMeshProducer.shutdown(); + } catch (Exception ex) { + log.error("shutdown eventMeshProducer[{}] err", eventMeshProducer, ex); + } + } + log.info("producerManager shutdown......"); + } + + public AbstractRemotingServer getEventMeshServer() { + return eventMeshServer; + } + + public ConcurrentHashMap getProducerTable() { + return producerTable; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/SendMessageContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/SendMessageContext.java new file mode 100644 index 0000000000..0de970f701 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/producer/SendMessageContext.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.producer; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.runtime.boot.AbstractRemotingServer; +import org.apache.eventmesh.runtime.core.protocol.RetryContext; + +import org.apache.commons.lang3.time.DateFormatUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; + +public class SendMessageContext extends RetryContext { + + public static final Logger logger = LoggerFactory.getLogger("retry"); + + private CloudEvent event; + + private String bizSeqNo; + + private EventMeshProducer eventMeshProducer; + + private long createTime = System.currentTimeMillis(); + + public AbstractRemotingServer eventMeshServer; + + public SendMessageContext(String bizSeqNo, CloudEvent event, EventMeshProducer eventMeshProducer, + AbstractRemotingServer eventMeshServer) { + this.bizSeqNo = bizSeqNo; + this.event = event; + this.eventMeshProducer = eventMeshProducer; + this.eventMeshServer = eventMeshServer; + } + + public String getBizSeqNo() { + return bizSeqNo; + } + + public void setBizSeqNo(String bizSeqNo) { + this.bizSeqNo = bizSeqNo; + } + + public CloudEvent getEvent() { + return event; + } + + public void setEvent(CloudEvent event) { + this.event = event; + } + + public EventMeshProducer getEventMeshProducer() { + return eventMeshProducer; + } + + public void setEventMeshProducer(EventMeshProducer eventMeshProducer) { + this.eventMeshProducer = eventMeshProducer; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("sendMessageContext={") + .append("bizSeqNo=").append(bizSeqNo) + .append(",retryTimes=").append(retryTimes) + .append(",producer=") + .append(eventMeshProducer != null ? eventMeshProducer : null) + .append(",executeTime=") + .append(DateFormatUtils.format(executeTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)) + .append(",createTime=") + .append(DateFormatUtils.format(createTime, Constants.DATE_FORMAT_INCLUDE_MILLISECONDS)).append("}"); + return sb.toString(); + } + + public void retry() throws Exception { + if (eventMeshProducer == null) { + logger.error("Exception happends during retry. EventMeshProducer is null."); + return; + } + + if (retryTimes > 0) { // retry once + logger.error("Exception happends during retry. The retryTimes > 0."); + return; + } + + retryTimes++; + eventMeshProducer.send(this, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + } + + @Override + public void onException(OnExceptionContext context) { + logger.warn("", context.getException()); + } + }); + } + + @Override + public void doRun() throws Exception { + retry(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcp2Client.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcp2Client.java index 35f17aad10..c4acc8d81e 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcp2Client.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcp2Client.java @@ -24,142 +24,121 @@ import org.apache.eventmesh.common.protocol.tcp.OPStatus; import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.common.protocol.tcp.RedirectInfo; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.runtime.boot.TCPThreadPoolGroup; import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.SessionState; -import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMonitor; +import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMetricsManager; import org.apache.eventmesh.runtime.util.RemotingHelper; import org.apache.eventmesh.runtime.util.Utils; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -public class EventMeshTcp2Client { +import lombok.extern.slf4j.Slf4j; - private static final Logger logger = LoggerFactory.getLogger(EventMeshTcp2Client.class); +@Slf4j +public class EventMeshTcp2Client { - public static InetSocketAddress serverGoodby2Client(EventMeshTCPServer eventMeshTCPServer, Session session, - ClientSessionGroupMapping mapping) { - logger.info("serverGoodby2Client client[{}]", session.getClient()); + public static InetSocketAddress serverGoodby2Client(TCPThreadPoolGroup tcpThreadPoolGroup, + Session session, + ClientSessionGroupMapping mapping) { + log.info("serverGoodby2Client client[{}]", session.getClient()); try { long startTime = System.currentTimeMillis(); Package msg = new Package(); - msg.setHeader( - new Header(SERVER_GOODBYE_REQUEST, OPStatus.SUCCESS.getCode(), "graceful normal quit from eventmesh", - null)); - - eventMeshTCPServer.getScheduler().submit(new Runnable() { - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - } + msg.setHeader(new Header(SERVER_GOODBYE_REQUEST, OPStatus.SUCCESS.getCode(), + "graceful normal quit from eventmesh", null)); + + tcpThreadPoolGroup.getScheduler().submit(() -> { + long taskExecuteTime = System.currentTimeMillis(); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); }); InetSocketAddress address = (InetSocketAddress) session.getContext().channel().remoteAddress(); - closeSessionIfTimeout(eventMeshTCPServer, session, mapping); + closeSessionIfTimeout(tcpThreadPoolGroup, session, mapping); return address; } catch (Exception e) { - logger.error("exception occur while serverGoodby2Client", e); + log.error("exception occur while serverGoodby2Client", e); return null; } } - public static InetSocketAddress goodBye2Client(EventMeshTCPServer eventMeshTCPServer, - Session session, - String errMsg, - int eventMeshStatus, - ClientSessionGroupMapping mapping) { + public static InetSocketAddress goodBye2Client(TCPThreadPoolGroup tcpThreadPoolGroup, Session session, + String errMsg, int eventMeshStatus, + ClientSessionGroupMapping mapping) { try { long startTime = System.currentTimeMillis(); Package msg = new Package(); msg.setHeader(new Header(SERVER_GOODBYE_REQUEST, eventMeshStatus, errMsg, null)); - eventMeshTCPServer.getScheduler().schedule(new Runnable() { - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - } + tcpThreadPoolGroup.getScheduler().schedule(() -> { + long taskExecuteTime = System.currentTimeMillis(); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); }, 1 * 1000, TimeUnit.MILLISECONDS); - closeSessionIfTimeout(eventMeshTCPServer, session, mapping); + closeSessionIfTimeout(tcpThreadPoolGroup, session, mapping); return session.getRemoteAddress(); } catch (Exception e) { - logger.error("exception occur while goodbye2client", e); + log.error("exception occur while goodbye2client", e); return null; } } - public static void goodBye2Client(ChannelHandlerContext ctx, - String errMsg, - ClientSessionGroupMapping mapping, - EventMeshTcpMonitor eventMeshTcpMonitor) { + public static void goodBye2Client(ChannelHandlerContext ctx, String errMsg, ClientSessionGroupMapping mapping, + EventMeshTcpMetricsManager eventMeshTcpMetricsManager) { long startTime = System.currentTimeMillis(); Package pkg = new Package(new Header(SERVER_GOODBYE_REQUEST, OPStatus.FAIL.getCode(), errMsg, null)); - eventMeshTcpMonitor.getTcpSummaryMetrics().getEventMesh2clientMsgNum().incrementAndGet(); - logger.info("goodBye2Client client[{}]", RemotingHelper.parseChannelRemoteAddr(ctx.channel())); - ctx.writeAndFlush(pkg).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - Utils.logSucceedMessageFlow(pkg, null, startTime, startTime); - try { - mapping.closeSession(ctx); - } catch (Exception e) { - logger.warn("close session failed!", e); - } - } + eventMeshTcpMetricsManager.eventMesh2clientMsgNumIncrement(IPUtils.parseChannelRemoteAddr(ctx.channel())); + log.info("goodBye2Client client[{}]", RemotingHelper.parseChannelRemoteAddr(ctx.channel())); + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(pkg).addListener((ChannelFutureListener) future -> { + Utils.logSucceedMessageFlow(pkg, null, startTime, startTime); + try { + mapping.closeSession(ctx); + } catch (Exception e) { + log.warn("close session failed!", e); } - ); + }); + }); } - public static String redirectClient2NewEventMesh(EventMeshTCPServer eventMeshTCPServer, String newEventMeshIp, - int port, Session session, ClientSessionGroupMapping mapping) { - logger.info("begin to gracefully redirect Client {}, newIPPort[{}]", session.getClient(), - newEventMeshIp + ":" + port); + public static String redirectClient2NewEventMesh(TCPThreadPoolGroup tcpThreadPoolGroup, String newEventMeshIp, + int port, Session session, ClientSessionGroupMapping mapping) { + log.info("begin to gracefully redirect Client {}, newIPPort[{}]", session.getClient(), newEventMeshIp + ":" + + port); try { long startTime = System.currentTimeMillis(); Package pkg = new Package(); pkg.setHeader(new Header(REDIRECT_TO_CLIENT, OPStatus.SUCCESS.getCode(), null, null)); pkg.setBody(new RedirectInfo(newEventMeshIp, port)); - eventMeshTCPServer.getScheduler().schedule(new Runnable() { - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Utils.writeAndFlush(pkg, startTime, taskExecuteTime, session.getContext(), session); - } + tcpThreadPoolGroup.getScheduler().schedule(() -> { + long taskExecuteTime = System.currentTimeMillis(); + Utils.writeAndFlush(pkg, startTime, taskExecuteTime, session.getContext(), session); }, 5 * 1000, TimeUnit.MILLISECONDS); - closeSessionIfTimeout(eventMeshTCPServer, session, mapping); + closeSessionIfTimeout(tcpThreadPoolGroup, session, mapping); return session.getRemoteAddress() + "--->" + newEventMeshIp + ":" + port; } catch (Exception e) { - logger.error("exception occur while redirectClient2NewEventMesh", e); + log.error("exception occur while redirectClient2NewEventMesh", e); return null; } } - public static void closeSessionIfTimeout(EventMeshTCPServer eventMeshTCPServer, Session session, - ClientSessionGroupMapping mapping) { - eventMeshTCPServer.getScheduler().schedule(new Runnable() { - @Override - public void run() { - try { - if (!session.getSessionState().equals(SessionState.CLOSED)) { - mapping.closeSession(session.getContext()); - logger.info("closeSessionIfTimeout success, session[{}]", session.getClient()); - } - } catch (Exception e) { - logger.error("close session failed", e); + public static void closeSessionIfTimeout(TCPThreadPoolGroup tcpThreadPoolGroup, Session session, + ClientSessionGroupMapping mapping) { + tcpThreadPoolGroup.getScheduler().schedule(() -> { + try { + if (session.getSessionState() != SessionState.CLOSED) { + mapping.closeSession(session.getContext()); + log.info("closeSessionIfTimeout success, session[{}]", session.getClient()); } + } catch (Exception e) { + log.error("close session failed", e); } }, 30 * 1000, TimeUnit.MILLISECONDS); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpConnectionHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpConnectionHandler.java deleted file mode 100644 index 685abc6a6b..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpConnectionHandler.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.util.RemotingHelper; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.timeout.IdleState; -import io.netty.handler.timeout.IdleStateEvent; - -public class EventMeshTcpConnectionHandler extends ChannelDuplexHandler { - - public static AtomicInteger connections = new AtomicInteger(0); - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private EventMeshTCPServer eventMeshTCPServer; - - public EventMeshTcpConnectionHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - logger.info("client|tcp|channelRegistered|remoteAddress={}|msg={}", remoteAddress, ""); - super.channelRegistered(ctx); - } - - @Override - public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - logger.info("client|tcp|channelUnregistered|remoteAddress={}|msg={}", remoteAddress, ""); - super.channelUnregistered(ctx); - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - logger.info("client|tcp|channelActive|remoteAddress={}|msg={}", remoteAddress, ""); - - int c = connections.incrementAndGet(); - if (c > eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpClientMaxNum) { - logger.warn("client|tcp|channelActive|remoteAddress={}|msg={}", remoteAddress, "too many client connect " - + - "this eventMesh server"); - ctx.close(); - return; - } - - super.channelActive(ctx); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - connections.decrementAndGet(); - final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - logger.info("client|tcp|channelInactive|remoteAddress={}|msg={}", remoteAddress, ""); - eventMeshTCPServer.getClientSessionGroupMapping().closeSession(ctx); - super.channelInactive(ctx); - } - - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof IdleStateEvent) { - IdleStateEvent event = (IdleStateEvent) evt; - if (event.state().equals(IdleState.ALL_IDLE)) { - final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - logger.info("client|tcp|userEventTriggered|remoteAddress={}|msg={}", remoteAddress, evt.getClass().getName()); - eventMeshTCPServer.getClientSessionGroupMapping().closeSession(ctx); - } - } - - ctx.fireUserEventTriggered(evt); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpExceptionHandler.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpExceptionHandler.java deleted file mode 100644 index d9aace846a..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpExceptionHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client; - -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; - -public class EventMeshTcpExceptionHandler extends ChannelDuplexHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private EventMeshTCPServer eventMeshTCPServer; - - public EventMeshTcpExceptionHandler(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); - UserAgent client = session == null ? null : session.getClient(); - logger.error("exceptionCaught, push goodbye to client|user={},errMsg={}", client, cause.fillInStackTrace()); - String errMsg; - if (cause.toString().contains("value not one of declared Enum instance names")) { - errMsg = "Unknown Command type"; - } else { - errMsg = cause.toString(); - } - - if (session != null) { - EventMeshTcp2Client.goodBye2Client(eventMeshTCPServer, session, errMsg, OPStatus.FAIL.getCode(), - eventMeshTCPServer.getClientSessionGroupMapping()); - } else { - EventMeshTcp2Client.goodBye2Client(ctx, errMsg, eventMeshTCPServer.getClientSessionGroupMapping(), - eventMeshTCPServer.getEventMeshTcpMonitor()); - } - } - -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpMessageDispatcher.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpMessageDispatcher.java deleted file mode 100644 index 0623d282cf..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/EventMeshTcpMessageDispatcher.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client; - -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.SessionState; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.GoodbyeTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.HeartBeatTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.HelloTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.ListenTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.MessageAckTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.MessageTransferTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.RecommendTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.SubscribeTask; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.task.UnSubscribeTask; -import org.apache.eventmesh.runtime.trace.TraceUtils; -import org.apache.eventmesh.runtime.util.EventMeshUtil; -import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; - -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.opentelemetry.api.trace.Span; - -public class EventMeshTcpMessageDispatcher extends SimpleChannelInboundHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final Logger messageLogger = LoggerFactory.getLogger("message"); - private EventMeshTCPServer eventMeshTCPServer; - - public EventMeshTcpMessageDispatcher(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, Package pkg) throws Exception { - long startTime = System.currentTimeMillis(); - validateMsg(pkg); - - eventMeshTCPServer.getEventMeshTcpMonitor().getTcpSummaryMetrics() - .getClient2eventMeshMsgNum().incrementAndGet(); - - Command cmd = pkg.getHeader().getCmd(); - try { - Runnable task; - - if (isNeedTrace(cmd)) { - pkg.getHeader().getProperties() - .put(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, startTime); - pkg.getHeader().getProperties().put(EventMeshConstants.REQ_SEND_EVENTMESH_IP, - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerIp); - Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); - - pkg.getHeader().getProperties().put(EventMeshConstants.REQ_SYS, session.getClient().getSubsystem()); - pkg.getHeader().getProperties().put(EventMeshConstants.REQ_IP, session.getClient().getHost()); - pkg.getHeader().getProperties().put(EventMeshConstants.REQ_IDC, session.getClient().getIdc()); - pkg.getHeader().getProperties().put(EventMeshConstants.REQ_GROUP, session.getClient().getGroup()); - } - - if (cmd.equals(Command.RECOMMEND_REQUEST)) { - messageLogger.info("pkg|c2eventMesh|cmd={}|pkg={}", cmd, pkg); - task = new RecommendTask(pkg, ctx, startTime, eventMeshTCPServer); - eventMeshTCPServer.getTaskHandleExecutorService().submit(task); - return; - } - if (cmd.equals(Command.HELLO_REQUEST)) { - messageLogger.info("pkg|c2eventMesh|cmd={}|pkg={}", cmd, pkg); - task = new HelloTask(pkg, ctx, startTime, eventMeshTCPServer); - eventMeshTCPServer.getTaskHandleExecutorService().submit(task); - return; - } - - if (eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx) == null) { - messageLogger.info("pkg|c2eventMesh|cmd={}|pkg={},no session is found", cmd, pkg); - throw new Exception("no session is found"); - } - - logMessageFlow(ctx, pkg, cmd); - - if (eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx) - .getSessionState() == SessionState.CLOSED) { - throw new Exception( - "this eventMesh tcp session will be closed, may be reboot or version change!"); - } - - dispatch(ctx, pkg, startTime, cmd); - } catch (Exception e) { - logger.error("exception occurred while pkg|cmd={}|pkg={}", cmd, pkg, e); - - if (isNeedTrace(cmd)) { - Span span = TraceUtils.prepareServerSpan(pkg.getHeader().getProperties(), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, startTime, - TimeUnit.MILLISECONDS, false); - TraceUtils.finishSpanWithException(span, pkg.getHeader().getProperties(), - "exception occurred while dispatch pkg", e); - } - - writeToClient(cmd, pkg, ctx, e); - } - } - - private boolean isNeedTrace(Command cmd) { - if (eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerTraceEnable - && cmd != null && (Command.REQUEST_TO_SERVER == cmd - || Command.ASYNC_MESSAGE_TO_SERVER == cmd - || Command.BROADCAST_MESSAGE_TO_SERVER == cmd)) { - return true; - } - return false; - } - - private void writeToClient(Command cmd, Package pkg, ChannelHandlerContext ctx, Exception e) { - try { - Package res = new Package(); - res.setHeader(new Header(getReplyCommand(cmd), OPStatus.FAIL.getCode(), e.toString(), - pkg.getHeader().getSeq())); - ctx.writeAndFlush(res); - } catch (Exception ex) { - logger.warn("writeToClient failed", ex); - } - } - - private Command getReplyCommand(Command cmd) { - switch (cmd) { - case HELLO_REQUEST: - return Command.HELLO_RESPONSE; - case RECOMMEND_REQUEST: - return Command.RECOMMEND_RESPONSE; - case HEARTBEAT_REQUEST: - return Command.HEARTBEAT_RESPONSE; - case SUBSCRIBE_REQUEST: - return Command.SUBSCRIBE_RESPONSE; - case UNSUBSCRIBE_REQUEST: - return Command.UNSUBSCRIBE_RESPONSE; - case LISTEN_REQUEST: - return Command.LISTEN_RESPONSE; - case CLIENT_GOODBYE_REQUEST: - return Command.CLIENT_GOODBYE_RESPONSE; - case REQUEST_TO_SERVER: - return Command.RESPONSE_TO_CLIENT; - case ASYNC_MESSAGE_TO_SERVER: - return Command.ASYNC_MESSAGE_TO_SERVER_ACK; - case BROADCAST_MESSAGE_TO_SERVER: - return Command.BROADCAST_MESSAGE_TO_SERVER_ACK; - default: - return cmd; - } - } - - private void logMessageFlow(ChannelHandlerContext ctx, Package pkg, Command cmd) { - if (pkg.getBody() instanceof EventMeshMessage) { - messageLogger.info("pkg|c2eventMesh|cmd={}|Msg={}|user={}", cmd, - EventMeshUtil.printMqMessage((EventMeshMessage) pkg.getBody()), - eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx).getClient()); - } else { - messageLogger.info("pkg|c2eventMesh|cmd={}|pkg={}|user={}", cmd, pkg, - eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx).getClient()); - } - } - - private void validateMsg(Package pkg) throws Exception { - if (pkg == null) { - throw new Exception("the incoming message is empty."); - } - if (pkg.getHeader() == null) { - logger.error("the incoming message does not have a header|pkg={}", pkg); - throw new Exception("the incoming message does not have a header."); - } - if (pkg.getHeader().getCmd() == null) { - logger.error("the incoming message does not have a command type|pkg={}", pkg); - throw new Exception("the incoming message does not have a command type."); - } - } - - private void dispatch(ChannelHandlerContext ctx, Package pkg, long startTime, Command cmd) - throws Exception { - Runnable task; - switch (cmd) { - case HEARTBEAT_REQUEST: - task = new HeartBeatTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - case CLIENT_GOODBYE_REQUEST: - case SERVER_GOODBYE_RESPONSE: - task = new GoodbyeTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - case SUBSCRIBE_REQUEST: - task = new SubscribeTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - case UNSUBSCRIBE_REQUEST: - task = new UnSubscribeTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - case LISTEN_REQUEST: - task = new ListenTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - case REQUEST_TO_SERVER: - case RESPONSE_TO_SERVER: - case ASYNC_MESSAGE_TO_SERVER: - case BROADCAST_MESSAGE_TO_SERVER: - task = new MessageTransferTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - case RESPONSE_TO_CLIENT_ACK: - case ASYNC_MESSAGE_TO_CLIENT_ACK: - case BROADCAST_MESSAGE_TO_CLIENT_ACK: - case REQUEST_TO_CLIENT_ACK: - task = new MessageAckTask(pkg, ctx, startTime, eventMeshTCPServer); - break; - default: - throw new Exception("unknown cmd"); - } - eventMeshTCPServer.getTaskHandleExecutorService().submit(task); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientGroupWrapper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientGroupWrapper.java index fc85da4d3f..f2ab7fe686 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientGroupWrapper.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientGroupWrapper.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.runtime.core.protocol.tcp.client.group; +import org.apache.eventmesh.api.AsyncConsumeContext; import org.apache.eventmesh.api.EventListener; import org.apache.eventmesh.api.EventMeshAction; import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; @@ -24,7 +25,6 @@ import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.Constants; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.utils.JsonUtils; @@ -36,21 +36,24 @@ import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.dispatch.DownstreamDispatchStrategy; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.EventMeshTcpRetryer; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.TcpRetryer; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.UpStreamMsgContext; -import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMonitor; -import org.apache.eventmesh.runtime.trace.TraceUtils; +import org.apache.eventmesh.runtime.metrics.tcp.EventMeshTcpMetricsManager; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.HttpTinyClient; +import org.apache.eventmesh.runtime.util.TraceUtils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Properties; import java.util.Set; @@ -59,81 +62,83 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Scope; import com.google.common.base.Preconditions; -public class ClientGroupWrapper { +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; - public static Logger logger = LoggerFactory.getLogger(ClientGroupWrapper.class); +@Slf4j +public class ClientGroupWrapper { - private String sysId; + private final String sysId; private String group; private EventMeshTCPConfiguration eventMeshTCPConfiguration; - private EventMeshTCPServer eventMeshTCPServer; + private final EventMeshTCPServer eventMeshTCPServer; - private EventMeshTcpRetryer eventMeshTcpRetryer; + private TcpRetryer tcpRetryer; - private EventMeshTcpMonitor eventMeshTcpMonitor; + private EventMeshTcpMetricsManager eventMeshTcpMetricsManager; private DownstreamDispatchStrategy downstreamDispatchStrategy; private final ReadWriteLock groupLock = new ReentrantReadWriteLock(); - public Set groupConsumerSessions = new HashSet(); + @Getter + private final Set groupConsumerSessions = new HashSet(); + + @Getter + private final Set groupProducerSessions = new HashSet(); - public Set groupProducerSessions = new HashSet(); + @Getter + private final AtomicBoolean started4Persistent = new AtomicBoolean(Boolean.FALSE); - public AtomicBoolean started4Persistent = new AtomicBoolean(Boolean.FALSE); + @Getter + private final AtomicBoolean started4Broadcast = new AtomicBoolean(Boolean.FALSE); - public AtomicBoolean started4Broadcast = new AtomicBoolean(Boolean.FALSE); + @Getter + private final AtomicBoolean inited4Persistent = new AtomicBoolean(Boolean.FALSE); - public AtomicBoolean inited4Persistent = new AtomicBoolean(Boolean.FALSE); + @Getter + private final AtomicBoolean inited4Broadcast = new AtomicBoolean(Boolean.FALSE); - public AtomicBoolean inited4Broadcast = new AtomicBoolean(Boolean.FALSE); + @Getter + private final AtomicBoolean producerStarted = new AtomicBoolean(Boolean.FALSE); private MQConsumerWrapper persistentMsgConsumer; private MQConsumerWrapper broadCastMsgConsumer; - private ConcurrentHashMap> topic2sessionInGroupMapping = - new ConcurrentHashMap>(); + private final ConcurrentHashMap> topic2sessionInGroupMapping = + new ConcurrentHashMap>(); - private ConcurrentHashMap subscriptions = new ConcurrentHashMap<>(); + private final ConcurrentHashMap subscriptions = new ConcurrentHashMap<>(); - public AtomicBoolean producerStarted = new AtomicBoolean(Boolean.FALSE); - - private MQProducerWrapper mqProducerWrapper; + private final MQProducerWrapper mqProducerWrapper; public ClientGroupWrapper(String sysId, String group, - EventMeshTCPServer eventMeshTCPServer, - DownstreamDispatchStrategy downstreamDispatchStrategy) { + EventMeshTCPServer eventMeshTCPServer, + DownstreamDispatchStrategy downstreamDispatchStrategy) { this.sysId = sysId; this.group = group; this.eventMeshTCPServer = eventMeshTCPServer; this.eventMeshTCPConfiguration = eventMeshTCPServer.getEventMeshTCPConfiguration(); - this.eventMeshTcpRetryer = eventMeshTCPServer.getEventMeshTcpRetryer(); - this.eventMeshTcpMonitor = - Preconditions.checkNotNull(eventMeshTCPServer.getEventMeshTcpMonitor()); + this.tcpRetryer = eventMeshTCPServer.getTcpRetryer(); + this.eventMeshTcpMetricsManager = + Preconditions.checkNotNull(eventMeshTCPServer.getEventMeshTcpMetricsManager()); this.downstreamDispatchStrategy = downstreamDispatchStrategy; - this.persistentMsgConsumer = new MQConsumerWrapper( - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshConnectorPluginType); - this.broadCastMsgConsumer = new MQConsumerWrapper( - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshConnectorPluginType); - this.mqProducerWrapper = new MQProducerWrapper( - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshConnectorPluginType); + this.persistentMsgConsumer = new MQConsumerWrapper(eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshStoragePluginType()); + this.broadCastMsgConsumer = new MQConsumerWrapper(eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshStoragePluginType()); + this.mqProducerWrapper = new MQProducerWrapper(eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshStoragePluginType()); } - public ConcurrentHashMap> getTopic2sessionInGroupMapping() { + public ConcurrentHashMap> getTopic2sessionInGroupMapping() { return topic2sessionInGroupMapping; } @@ -143,7 +148,10 @@ public boolean hasSubscription(String topic) { this.groupLock.readLock().lockInterruptibly(); has = topic2sessionInGroupMapping.containsKey(topic); } catch (Exception e) { - logger.error("hasSubscription error! topic[{}]", topic); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("hasSubscription error! topic[{}]", topic); } finally { this.groupLock.readLock().unlock(); } @@ -158,23 +166,23 @@ public boolean send(UpStreamMsgContext upStreamMsgContext, SendCallback sendCall } public void request(UpStreamMsgContext upStreamMsgContext, RequestReplyCallback rrCallback, - long timeout) + long timeout) throws Exception { mqProducerWrapper.request(upStreamMsgContext.getEvent(), rrCallback, timeout); } public boolean reply(UpStreamMsgContext upStreamMsgContext) throws Exception { mqProducerWrapper.reply(upStreamMsgContext.getEvent(), new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { - } @Override public void onException(OnExceptionContext context) { String bizSeqNo = (String) upStreamMsgContext.getEvent() .getExtension(EventMeshConstants.PROPERTY_MESSAGE_KEYS); - logger.error("reply err! topic:{}, bizSeqNo:{}, client:{}", + log.error("reply err! topic:{}, bizSeqNo:{}, client:{}", upStreamMsgContext.getEvent().getSubject(), bizSeqNo, upStreamMsgContext.getSession().getClient(), context.getException()); } @@ -189,13 +197,13 @@ public MQProducerWrapper getMqProducerWrapper() { public boolean addSubscription(SubscriptionItem subscriptionItem, Session session) throws Exception { if (subscriptionItem == null) { - logger.error("addSubscription param error,subscriptionItem is null", session); + log.error("addSubscription param error, subscriptionItem is null, session:{}", session); return false; } String topic = subscriptionItem.getTopic(); if (session == null || !StringUtils.equalsIgnoreCase(group, EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { - logger.error("addSubscription param error,topic:{},session:{}", topic, session); + log.error("addSubscription param error, topic:{}, session:{}", topic, session); return false; } @@ -203,23 +211,24 @@ public boolean addSubscription(SubscriptionItem subscriptionItem, Session sessio try { this.groupLock.writeLock().lockInterruptibly(); if (!topic2sessionInGroupMapping.containsKey(topic)) { - Set sessions = new HashSet(); + Map sessions = new HashMap<>(); topic2sessionInGroupMapping.put(topic, sessions); } - r = topic2sessionInGroupMapping.get(topic).add(session); - if (r) { - logger.info("addSubscription success, group:{} topic:{} client:{}", group, - topic, session.getClient()); + Session s = topic2sessionInGroupMapping.get(topic).putIfAbsent(session.getSessionId(), session); + if (s == null) { + log.info("Cache session success, group:{} topic:{} client:{} sessionId:{}", + group, topic, session.getClient(), session.getSessionId()); } else { - logger - .warn("addSubscription fail, group:{} topic:{} client:{}", group, topic, - session.getClient()); + log.warn("Session already exists in topic2sessionInGroupMapping. group:{} topic:{} client:{} sessionId:{}", + group, topic, session.getClient(), session.getSessionId()); } subscriptions.putIfAbsent(topic, subscriptionItem); } catch (Exception e) { - logger - .error("addSubscription error! topic:{} client:{}", topic, session.getClient(), e); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("addSubscription error! topic:{} client:{}", topic, session.getClient(), e); throw new Exception("addSubscription fail"); } finally { this.groupLock.writeLock().unlock(); @@ -229,14 +238,12 @@ public boolean addSubscription(SubscriptionItem subscriptionItem, Session sessio public boolean removeSubscription(SubscriptionItem subscriptionItem, Session session) { if (subscriptionItem == null) { - logger.error("addSubscription param error,subscriptionItem is null", session); + log.error("addSubscription param error,subscriptionItem is null, session:{}", session); return false; } String topic = subscriptionItem.getTopic(); - if (session == null - || !StringUtils.equalsIgnoreCase(group, - EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { - logger.error("removeSubscription param error,topic:{},session:{}", topic, session); + if (session == null || !StringUtils.equalsIgnoreCase(group, EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { + log.error("removeSubscription param error, topic:{}, session:{}", topic, session); return false; } @@ -244,25 +251,26 @@ public boolean removeSubscription(SubscriptionItem subscriptionItem, Session ses try { this.groupLock.writeLock().lockInterruptibly(); if (topic2sessionInGroupMapping.containsKey(topic)) { - r = topic2sessionInGroupMapping.get(topic).remove(session); - if (r) { - logger.info( - "removeSubscription remove session success, group:{} topic:{} client:{}", + if (topic2sessionInGroupMapping.get(topic).remove(session.getSessionId()) != null) { + log.info("removeSubscription remove session success, group:{} topic:{} client:{}", group, topic, session.getClient()); } else { - logger.warn( - "removeSubscription remove session failed, group:{} topic:{} client:{}", - group, topic, session.getClient()); + log.warn("Not found session in cache, group:{} topic:{} client:{} sessionId:{}", + group, topic, session.getClient(), session.getSessionId()); } } if (CollectionUtils.size(topic2sessionInGroupMapping.get(topic)) == 0) { topic2sessionInGroupMapping.remove(topic); subscriptions.remove(topic); - logger.info("removeSubscription remove topic success, group:{} topic:{}", + + log.info("removeSubscription remove topic success, group:{} topic:{}", group, topic); } } catch (Exception e) { - logger.error("removeSubscription error! topic:{} client:{}", topic, session.getClient(), + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("removeSubscription error! topic:{} client:{}", topic, session.getClient(), e); } finally { this.groupLock.writeLock().unlock(); @@ -276,17 +284,17 @@ public synchronized void startClientGroupProducer() throws Exception { } Properties keyValue = new Properties(); - keyValue.put("producerGroup", group); - keyValue.put("instanceName", EventMeshUtil - .buildMeshTcpClientID(sysId, "PUB", eventMeshTCPConfiguration.eventMeshCluster)); + keyValue.put(EventMeshConstants.PRODUCER_GROUP, group); + keyValue.put(EventMeshConstants.INSTANCE_NAME, EventMeshUtil + .buildMeshTcpClientID(sysId, EventMeshConstants.PURPOSE_PUB_UPPER_CASE, + eventMeshTCPConfiguration.getEventMeshCluster())); - //TODO for defibus - keyValue.put("eventMeshIDC", eventMeshTCPConfiguration.eventMeshIDC); + keyValue.put(EventMeshConstants.EVENT_MESH_IDC, eventMeshTCPConfiguration.getEventMeshIDC()); mqProducerWrapper.init(keyValue); mqProducerWrapper.start(); producerStarted.compareAndSet(false, true); - logger.info("starting producer success, group:{}", group); + log.info("starting producer success, group:{}", group); } public synchronized void shutdownProducer() throws Exception { @@ -295,7 +303,7 @@ public synchronized void shutdownProducer() throws Exception { } mqProducerWrapper.shutdown(); producerStarted.compareAndSet(true, false); - logger.info("shutdown producer success for group:{}", group); + log.info("shutdown producer success for group:{}", group); } public String getGroup() { @@ -307,10 +315,8 @@ public void setGroup(String group) { } public boolean addGroupConsumerSession(Session session) { - if (session == null - || !StringUtils.equalsIgnoreCase(group, - EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { - logger.error("addGroupConsumerSession param error,session:{}", session); + if (session == null || !StringUtils.equalsIgnoreCase(group, EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { + log.error("addGroupConsumerSession param error, session:{}", session); return false; } @@ -319,12 +325,13 @@ public boolean addGroupConsumerSession(Session session) { this.groupLock.writeLock().lockInterruptibly(); r = groupConsumerSessions.add(session); if (r) { - logger.info("addGroupConsumerSession success, group:{} client:{}", group, - session.getClient()); + log.info("addGroupConsumerSession success, group:{} client:{}", group, session.getClient()); } } catch (Exception e) { - logger.error("addGroupConsumerSession error! group:{} client:{}", group, - session.getClient(), e); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("addGroupConsumerSession error! group:{} client:{}", group, session.getClient(), e); } finally { this.groupLock.writeLock().unlock(); } @@ -332,10 +339,8 @@ public boolean addGroupConsumerSession(Session session) { } public boolean addGroupProducerSession(Session session) { - if (session == null - || !StringUtils.equalsIgnoreCase(group, - EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { - logger.error("addGroupProducerSession param error,session:{}", session); + if (session == null || !StringUtils.equalsIgnoreCase(group, EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { + log.error("addGroupProducerSession param error, session:{}", session); return false; } @@ -344,12 +349,14 @@ public boolean addGroupProducerSession(Session session) { this.groupLock.writeLock().lockInterruptibly(); r = groupProducerSessions.add(session); if (r) { - logger.info("addGroupProducerSession success, group:{} client:{}", group, - session.getClient()); + + log.info("addGroupProducerSession success, group:{} client:{}", group, session.getClient()); } } catch (Exception e) { - logger.error("addGroupProducerSession error! group:{} client:{}", group, - session.getClient(), e); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("addGroupProducerSession error! group:{} client:{}", group, session.getClient(), e); } finally { this.groupLock.writeLock().unlock(); } @@ -357,10 +364,8 @@ public boolean addGroupProducerSession(Session session) { } public boolean removeGroupConsumerSession(Session session) { - if (session == null - || !StringUtils.equalsIgnoreCase(group, - EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { - logger.error("removeGroupConsumerSession param error,session:{}", session); + if (session == null || !StringUtils.equalsIgnoreCase(group, EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { + log.error("removeGroupConsumerSession param error, session:{}", session); return false; } @@ -369,12 +374,13 @@ public boolean removeGroupConsumerSession(Session session) { this.groupLock.writeLock().lockInterruptibly(); r = groupConsumerSessions.remove(session); if (r) { - logger.info("removeGroupConsumerSession success, group:{} client:{}", group, - session.getClient()); + log.info("removeGroupConsumerSession success, group:{} client:{}", group, session.getClient()); } } catch (Exception e) { - logger.error("removeGroupConsumerSession error! group:{} client:{}", group, - session.getClient(), e); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("removeGroupConsumerSession error! group:{} client:{}", group, session.getClient(), e); } finally { this.groupLock.writeLock().unlock(); } @@ -382,10 +388,8 @@ public boolean removeGroupConsumerSession(Session session) { } public boolean removeGroupProducerSession(Session session) { - if (session == null - || !StringUtils.equalsIgnoreCase(group, - EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { - logger.error("removeGroupProducerSession param error,session:{}", session); + if (session == null || !StringUtils.equalsIgnoreCase(group, EventMeshUtil.buildClientGroup(session.getClient().getGroup()))) { + log.error("removeGroupProducerSession param error, session:{}", session); return false; } @@ -394,12 +398,14 @@ public boolean removeGroupProducerSession(Session session) { this.groupLock.writeLock().lockInterruptibly(); r = groupProducerSessions.remove(session); if (r) { - logger.info("removeGroupProducerSession success, group:{} client:{}", group, - session.getClient()); + + log.info("removeGroupProducerSession success, group:{} client:{}", group, session.getClient()); } } catch (Exception e) { - logger.error("removeGroupProducerSession error! group:{} client:{}", group, - session.getClient(), e); + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + log.error("removeGroupProducerSession error! group:{} client:{}", group, session.getClient(), e); } finally { this.groupLock.writeLock().unlock(); } @@ -413,15 +419,16 @@ public synchronized void initClientGroupPersistentConsumer() throws Exception { } Properties keyValue = new Properties(); - keyValue.put("isBroadcast", "false"); - keyValue.put("consumerGroup", group); - keyValue.put("eventMeshIDC", eventMeshTCPConfiguration.eventMeshIDC); - keyValue.put("instanceName", EventMeshUtil - .buildMeshTcpClientID(sysId, "SUB", eventMeshTCPConfiguration.eventMeshCluster)); + keyValue.put(EventMeshConstants.IS_BROADCAST, "false"); + keyValue.put(EventMeshConstants.CONSUMER_GROUP, group); + keyValue.put(EventMeshConstants.EVENT_MESH_IDC, eventMeshTCPConfiguration.getEventMeshIDC()); + keyValue.put(EventMeshConstants.INSTANCE_NAME, EventMeshUtil + .buildMeshTcpClientID(sysId, EventMeshConstants.PURPOSE_SUB_UPPER_CASE, + eventMeshTCPConfiguration.getEventMeshCluster())); persistentMsgConsumer.init(keyValue); - EventListener listener = (event, context) -> { + EventListener listener = (CloudEvent event, AsyncConsumeContext context) -> { String protocolVersion = Objects.requireNonNull(event.getSpecVersion()).toString(); @@ -430,13 +437,13 @@ public synchronized void initClientGroupPersistentConsumer() throws Exception { EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_SERVER_SPAN, false); try { - eventMeshTcpMonitor.getTcpSummaryMetrics().getMq2eventMeshMsgNum() - .incrementAndGet(); + eventMeshTcpMetricsManager.mq2eventMeshMsgNumIncrement(); event = CloudEventBuilder.from(event) .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .withExtension(EventMeshConstants.REQ_RECEIVE_EVENTMESH_IP, - eventMeshTCPConfiguration.eventMeshServerIp).build(); + eventMeshTCPConfiguration.getEventMeshServerIp()) + .build(); String topic = event.getSubject(); EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = @@ -459,19 +466,15 @@ public synchronized void initClientGroupPersistentConsumer() throws Exception { EventMeshConstants.EVENTMESH_SEND_BACK_IP); } - logger.error( + log.error( "found no session to downstream msg,groupName:{}, topic:{}, " + "bizSeqNo:{}, sendBackTimes:{}, sendBackFromEventMeshIp:{}", group, topic, bizSeqNo, sendBackTimes, sendBackFromEventMeshIp); - if (sendBackTimes >= eventMeshTCPServer - .getEventMeshTCPConfiguration().eventMeshTcpSendBackMaxTimes) { - logger.error( - "sendBack to broker over max times:{}, groupName:{}, topic:{}, " - + "bizSeqNo:{}", eventMeshTCPServer - .getEventMeshTCPConfiguration() - .eventMeshTcpSendBackMaxTimes, + int eventMeshTcpSendBackMaxTimes = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpSendBackMaxTimes(); + if (Objects.requireNonNull(sendBackTimes) >= eventMeshTcpSendBackMaxTimes) { + log.error("sendBack to broker over max times:{}, groupName:{}, topic:{}, " + "bizSeqNo:{}", eventMeshTcpSendBackMaxTimes, group, topic, bizSeqNo); } else { sendBackTimes++; @@ -479,11 +482,12 @@ public synchronized void initClientGroupPersistentConsumer() throws Exception { .withExtension(EventMeshConstants.EVENTMESH_SEND_BACK_TIMES, sendBackTimes.toString()) .withExtension(EventMeshConstants.EVENTMESH_SEND_BACK_IP, - eventMeshTCPConfiguration.eventMeshServerIp).build(); + eventMeshTCPConfiguration.getEventMeshServerIp()) + .build(); sendMsgBackToBroker(event, bizSeqNo); } } catch (Exception e) { - logger.warn("handle msg exception when no session found", e); + log.warn("handle msg exception when no session found", e); } eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); @@ -495,7 +499,7 @@ public synchronized void initClientGroupPersistentConsumer() throws Exception { new DownStreamMsgContext(event, session, persistentMsgConsumer, eventMeshAsyncConsumeContext.getAbstractContext(), false, subscriptionItem); - //msg put in eventmesh,waiting client ack + // msg put in eventmesh,waiting client ack session.getPusher().unAckMsg(downStreamMsgContext.seq, downStreamMsgContext); session.downstreamMsg(downStreamMsgContext); eventMeshAsyncConsumeContext.commit(EventMeshAction.ManualAck); @@ -506,7 +510,7 @@ public synchronized void initClientGroupPersistentConsumer() throws Exception { persistentMsgConsumer.registerEventListener(listener); inited4Persistent.compareAndSet(false, true); - logger.info("init persistentMsgConsumer success, group:{}", group); + log.info("init persistentMsgConsumer success, group:{}", group); } public synchronized void startClientGroupPersistentConsumer() throws Exception { @@ -515,7 +519,7 @@ public synchronized void startClientGroupPersistentConsumer() throws Exception { } persistentMsgConsumer.start(); started4Persistent.compareAndSet(false, true); - logger.info("starting persistentMsgConsumer success, group:{}", group); + log.info("starting persistentMsgConsumer success, group:{}", group); } public synchronized void initClientGroupBroadcastConsumer() throws Exception { @@ -524,11 +528,12 @@ public synchronized void initClientGroupBroadcastConsumer() throws Exception { } Properties keyValue = new Properties(); - keyValue.put("isBroadcast", "true"); - keyValue.put("consumerGroup", group); - keyValue.put("eventMeshIDC", eventMeshTCPConfiguration.eventMeshIDC); - keyValue.put("instanceName", EventMeshUtil - .buildMeshTcpClientID(sysId, "SUB", eventMeshTCPConfiguration.eventMeshCluster)); + keyValue.put(EventMeshConstants.IS_BROADCAST, "true"); + keyValue.put(EventMeshConstants.CONSUMER_GROUP, group); + keyValue.put(EventMeshConstants.EVENT_MESH_IDC, eventMeshTCPConfiguration.getEventMeshIDC()); + keyValue.put(EventMeshConstants.INSTANCE_NAME, EventMeshUtil + .buildMeshTcpClientID(sysId, EventMeshConstants.PURPOSE_SUB_UPPER_CASE, + eventMeshTCPConfiguration.getEventMeshCluster())); broadCastMsgConsumer.init(keyValue); EventListener listener = (event, context) -> { @@ -539,19 +544,19 @@ public synchronized void initClientGroupBroadcastConsumer() throws Exception { EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_SERVER_SPAN, false); try { - eventMeshTcpMonitor.getTcpSummaryMetrics().getMq2eventMeshMsgNum() - .incrementAndGet(); + eventMeshTcpMetricsManager.mq2eventMeshMsgNumIncrement(); event = CloudEventBuilder.from(event) .withExtension(EventMeshConstants.REQ_MQ2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) .withExtension(EventMeshConstants.REQ_RECEIVE_EVENTMESH_IP, - eventMeshTCPConfiguration.eventMeshServerIp).build(); + eventMeshTCPConfiguration.getEventMeshServerIp()) + .build(); String topic = event.getSubject(); EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = (EventMeshAsyncConsumeContext) context; if (CollectionUtils.isEmpty(groupConsumerSessions)) { - logger.warn("found no session to downstream broadcast msg"); + log.warn("found no session to downstream broadcast msg"); eventMeshAsyncConsumeContext.commit(EventMeshAction.CommitMessage); return; } @@ -568,24 +573,18 @@ public synchronized void initClientGroupBroadcastConsumer() throws Exception { Session session = sessionsItr.next(); if (!session.isAvailable(topic)) { - logger - .warn("downstream broadcast msg,session is not available,client:{}", - session.getClient()); + log.warn("downstream broadcast msg, session is not available, client:{}", session.getClient()); continue; } - downStreamMsgContext.session = session; - - //downstream broadcast msg asynchronously - eventMeshTCPServer.getBroadcastMsgDownstreamExecutorService() - .submit(new Runnable() { - @Override - public void run() { - //msg put in eventmesh,waiting client ack - session.getPusher() - .unAckMsg(downStreamMsgContext.seq, downStreamMsgContext); - session.downstreamMsg(downStreamMsgContext); - } + downStreamMsgContext.setSession(session); + + // downstream broadcast msg asynchronously + eventMeshTCPServer.getTcpThreadPoolGroup().getBroadcastMsgDownstreamExecutorService() + .submit(() -> { + // msg put in eventmesh,waiting client ack + session.getPusher().unAckMsg(downStreamMsgContext.seq, downStreamMsgContext); + session.downstreamMsg(downStreamMsgContext); }); } @@ -597,7 +596,7 @@ public void run() { broadCastMsgConsumer.registerEventListener(listener); inited4Broadcast.compareAndSet(false, true); - logger.info("init broadCastMsgConsumer success, group:{}", group); + log.info("init broadCastMsgConsumer success, group:{}", group); } public synchronized void startClientGroupBroadcastConsumer() throws Exception { @@ -606,11 +605,11 @@ public synchronized void startClientGroupBroadcastConsumer() throws Exception { } broadCastMsgConsumer.start(); started4Broadcast.compareAndSet(false, true); - logger.info("starting broadCastMsgConsumer success, group:{}", group); + log.info("starting broadCastMsgConsumer success, group:{}", group); } public void subscribe(SubscriptionItem subscriptionItem) throws Exception { - if (SubscriptionMode.BROADCASTING.equals(subscriptionItem.getMode())) { + if (SubscriptionMode.BROADCASTING == subscriptionItem.getMode()) { broadCastMsgConsumer.subscribe(subscriptionItem.getTopic()); } else { persistentMsgConsumer.subscribe(subscriptionItem.getTopic()); @@ -618,7 +617,7 @@ public void subscribe(SubscriptionItem subscriptionItem) throws Exception { } public void unsubscribe(SubscriptionItem subscriptionItem) throws Exception { - if (SubscriptionMode.BROADCASTING.equals(subscriptionItem.getMode())) { + if (SubscriptionMode.BROADCASTING == subscriptionItem.getMode()) { broadCastMsgConsumer.unsubscribe(subscriptionItem.getTopic()); } else { persistentMsgConsumer.unsubscribe(subscriptionItem.getTopic()); @@ -628,7 +627,7 @@ public void unsubscribe(SubscriptionItem subscriptionItem) throws Exception { public synchronized void shutdownBroadCastConsumer() throws Exception { if (started4Broadcast.get()) { broadCastMsgConsumer.shutdown(); - logger.info("broadcast consumer group:{} shutdown...", group); + log.info("broadcast consumer group:{} shutdown...", group); } started4Broadcast.compareAndSet(true, false); inited4Broadcast.compareAndSet(true, false); @@ -639,21 +638,13 @@ public synchronized void shutdownPersistentConsumer() throws Exception { if (started4Persistent.get()) { persistentMsgConsumer.shutdown(); - logger.info("persistent consumer group:{} shutdown...", group); + log.info("persistent consumer group:{} shutdown...", group); } started4Persistent.compareAndSet(true, false); inited4Persistent.compareAndSet(true, false); persistentMsgConsumer = null; } - public Set getGroupConsumerSessions() { - return groupConsumerSessions; - } - - public Set getGroupProducerSessions() { - return groupProducerSessions; - } - public EventMeshTCPConfiguration getEventMeshTCPConfiguration() { return eventMeshTCPConfiguration; } @@ -662,20 +653,20 @@ public void setEventMeshTCPConfiguration(EventMeshTCPConfiguration eventMeshTCPC this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; } - public EventMeshTcpRetryer getEventMeshTcpRetryer() { - return eventMeshTcpRetryer; + public TcpRetryer getTcpRetryer() { + return tcpRetryer; } - public void setEventMeshTcpRetryer(EventMeshTcpRetryer eventMeshTcpRetryer) { - this.eventMeshTcpRetryer = eventMeshTcpRetryer; + public void setTcpRetryer(TcpRetryer tcpRetryer) { + this.tcpRetryer = tcpRetryer; } - public EventMeshTcpMonitor getEventMeshTcpMonitor() { - return eventMeshTcpMonitor; + public EventMeshTcpMetricsManager getEventMeshTcpMetricsManager() { + return eventMeshTcpMetricsManager; } - public void setEventMeshTcpMonitor(EventMeshTcpMonitor eventMeshTcpMonitor) { - this.eventMeshTcpMonitor = eventMeshTcpMonitor; + public void setEventMeshTcpMetricsManager(EventMeshTcpMetricsManager eventMeshTcpMetricsManager) { + this.eventMeshTcpMetricsManager = eventMeshTcpMetricsManager; } public DownstreamDispatchStrategy getDownstreamDispatchStrategy() { @@ -698,22 +689,21 @@ private String pushMsgToEventMesh(CloudEvent msg, String ip, int port) throws Ex HttpTinyClient.HttpResult result = null; try { - logger.info("pushMsgToEventMesh,targetUrl:{},msg:{}", targetUrl, - msg); + log.info("pushMsgToEventMesh,targetUrl:{},msg:{}", targetUrl, msg); List paramValues = new ArrayList(); - paramValues.add("msg"); - paramValues.add(JsonUtils.serialize(msg)); - paramValues.add("group"); + paramValues.add(EventMeshConstants.MANAGE_MSG); + paramValues.add(JsonUtils.toJSONString(msg)); + paramValues.add(EventMeshConstants.MANAGE_GROUP); paramValues.add(group); result = HttpTinyClient.httpPost( targetUrl.toString(), null, paramValues, - "UTF-8", + StandardCharsets.UTF_8.name(), 3000); } catch (Exception e) { - logger.error("httpPost " + targetUrl + " is fail,", e); + log.error("httpPost " + targetUrl + " is fail,", e); throw e; } @@ -733,30 +723,29 @@ public MQConsumerWrapper getPersistentMsgConsumer() { private void sendMsgBackToBroker(CloudEvent event, String bizSeqNo) throws Exception { try { String topic = event.getSubject(); - logger.warn("send msg back to broker, bizSeqno:{}, topic:{}", bizSeqNo, topic); + log.warn("send msg back to broker, bizSeqno:{}, topic:{}", bizSeqNo, topic); long startTime = System.currentTimeMillis(); long taskExcuteTime = startTime; send(new UpStreamMsgContext(null, event, null, startTime, taskExcuteTime), new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { - logger.info( - "group:{} consume fail, sendMessageBack success, bizSeqno:{}, " - + "topic:{}", group, bizSeqNo, topic); + log.info("group:{} consume fail, sendMessageBack success, bizSeqno:{}, topic:{}", + group, bizSeqNo, topic); } @Override public void onException(OnExceptionContext context) { - logger.warn( - "group:{} consume fail, sendMessageBack fail, bizSeqno:{}," - + " topic:{}", group, bizSeqNo, topic); + log.warn("group:{} consume fail, sendMessageBack fail, bizSeqno:{}, topic:{}", + group, bizSeqNo, topic); } }); - eventMeshTcpMonitor.getTcpSummaryMetrics().getEventMesh2mqMsgNum().incrementAndGet(); + eventMeshTcpMetricsManager.eventMesh2mqMsgNumIncrement(); } catch (Exception e) { - logger.warn("try send msg back to broker failed"); + log.warn("try send msg back to broker failed"); throw e; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientSessionGroupMapping.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientSessionGroupMapping.java index 8a184d5042..94086b82d3 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientSessionGroupMapping.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/ClientSessionGroupMapping.java @@ -17,12 +17,16 @@ package org.apache.eventmesh.runtime.core.protocol.tcp.client.group; +import org.apache.eventmesh.api.meta.config.EventMeshMetaConfig; import org.apache.eventmesh.common.protocol.SubscriptionItem; import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupMetadata; +import org.apache.eventmesh.runtime.core.consumergroup.ConsumerGroupTopicMetadata; import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.dispatch.DownstreamDispatchStrategy; import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.dispatch.FreePriorityDispatchStrategy; @@ -32,36 +36,45 @@ import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import java.lang.ref.WeakReference; import java.net.InetSocketAddress; import java.util.HashMap; -import java.util.Iterator; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class ClientSessionGroupMapping { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final Logger sessionLogger = LoggerFactory.getLogger("sessionLogger"); + private static final Logger SESSION_LOGGER = LoggerFactory.getLogger("sessionLogger"); - private ConcurrentHashMap sessionTable = new ConcurrentHashMap<>(); + private final ConcurrentHashMap sessionTable = new ConcurrentHashMap<>(); - private ConcurrentHashMap clientGroupMap = - new ConcurrentHashMap(); + /** + * key: subsystem eg . 5109 or 5109-1A0 + */ + private final ConcurrentHashMap clientGroupMap = + new ConcurrentHashMap(); - private ConcurrentHashMap lockMap = - new ConcurrentHashMap(); + /** + * key: subsystem eg . 5109 or 5109-1A0 + */ + private final ConcurrentHashMap lockMap = + new ConcurrentHashMap(); private EventMeshTCPServer eventMeshTCPServer; @@ -82,8 +95,7 @@ public ClientGroupWrapper getClientGroupWrapper(String sysId) { } public Session getSession(ChannelHandlerContext ctx) { - Session session = getSession((InetSocketAddress) ctx.channel().remoteAddress()); - return session; + return getSession((InetSocketAddress) ctx.channel().remoteAddress()); } public Session getSession(InetSocketAddress address) { @@ -94,16 +106,16 @@ public Session createSession(UserAgent user, ChannelHandlerContext ctx) throws E InetSocketAddress addr = (InetSocketAddress) ctx.channel().remoteAddress(); user.setHost(addr.getHostString()); user.setPort(addr.getPort()); - Session session = null; + Session session; if (!sessionTable.containsKey(addr)) { - logger.info("createSession client[{}]", RemotingHelper.parseChannelRemoteAddr(ctx.channel())); + log.info("createSession client[{}]", RemotingHelper.parseChannelRemoteAddr(ctx.channel())); session = new Session(user, ctx, eventMeshTCPServer.getEventMeshTCPConfiguration()); initClientGroupWrapper(user, session); sessionTable.put(addr, session); - sessionLogger.info("session|open|succeed|user={}", user); + SESSION_LOGGER.info("session|open|succeed|user={}", user); } else { session = sessionTable.get(addr); - sessionLogger.error("session|open|failed|user={}|msg={}", user, "session has been created!"); + SESSION_LOGGER.error("session|open|failed|user={}|msg={}", user, "session has been created!"); } return session; } @@ -121,84 +133,84 @@ public synchronized void closeSession(ChannelHandlerContext ctx) throws Exceptio Session session = MapUtils.getObject(sessionTable, addr, null); if (session == null) { final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - logger.info("begin to close channel to remote address[{}]", remoteAddress); - ctx.channel().close().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - logger.info("close the connection to remote address[{}] result: {}", remoteAddress, - future.isSuccess()); - } - }); - sessionLogger.info("session|close|succeed|address={}|msg={}", addr, "no session was found"); + log.info("begin to close channel to remote address[{}]", remoteAddress); + ctx.channel().close().addListener( + (ChannelFutureListener) future -> log.info("close the connection to remote address[{}] result: {}", remoteAddress, + future.isSuccess())); + SESSION_LOGGER.info("session|close|succeed|address={}|msg={}", addr, "no session was found"); return; } closeSession(session); - //remove session from sessionTable + // remove session from sessionTable sessionTable.remove(addr); - sessionLogger.info("session|close|succeed|user={}", session.getClient()); + SESSION_LOGGER.info("session|close|succeed|user={}", session.getClient()); } private void closeSession(Session session) throws Exception { final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(session.getContext().channel()); if (SessionState.CLOSED == session.getSessionState()) { - logger.info("session has been closed, addr:{}", remoteAddress); + log.info("session has been closed, addr:{}", remoteAddress); return; } - //session must be synchronized to avoid SessionState be confound, for example adding subscribe when session closing + // session must be synchronized to avoid SessionState be confound, for example adding subscribe when session closing synchronized (session) { if (SessionState.CLOSED == session.getSessionState()) { - logger.info("session has been closed in sync, addr:{}", remoteAddress); + log.info("session has been closed in sync, addr:{}", remoteAddress); return; } session.setSessionState(SessionState.CLOSED); - if (EventMeshConstants.PURPOSE_SUB.equals(session.getClient().getPurpose())) { - cleanClientGroupWrapperByCloseSub(session); - } else if (EventMeshConstants.PURPOSE_PUB.equals(session.getClient().getPurpose())) { - cleanClientGroupWrapperByClosePub(session); - } else { - logger.error("client purpose config is error:{}", session.getClient().getPurpose()); + final String clientGroup = session.getClient().getGroup(); + if (!lockMap.containsKey(clientGroup)) { + lockMap.putIfAbsent(clientGroup, new Object()); + } + synchronized (lockMap.get(clientGroup)) { + if (EventMeshConstants.PURPOSE_SUB.equals(session.getClient().getPurpose())) { + cleanClientGroupWrapperByCloseSub(session); + } else if (EventMeshConstants.PURPOSE_PUB.equals( + session.getClient().getPurpose())) { + cleanClientGroupWrapperByClosePub(session); + } else { + log.error("client purpose config is error:{}", + session.getClient().getPurpose()); + } } if (session.getContext() != null) { - logger.info("begin to close channel to remote address[{}]", remoteAddress); - session.getContext().channel().close().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - logger.info("close the connection to remote address[{}] result: {}", remoteAddress, - future.isSuccess()); - } - }); + log.info("begin to close channel to remote address[{}]", remoteAddress); + session.getContext().channel().close().addListener( + (ChannelFutureListener) future -> log.info("close the connection to remote address[{}] result: {}", remoteAddress, + future.isSuccess())); } } } private ClientGroupWrapper constructClientGroupWrapper(String sysId, String group, - EventMeshTCPServer eventMeshTCPServer, - DownstreamDispatchStrategy downstreamDispatchStrategy) { + EventMeshTCPServer eventMeshTCPServer, + DownstreamDispatchStrategy downstreamDispatchStrategy) { return new ClientGroupWrapper(sysId, group, eventMeshTCPServer, - downstreamDispatchStrategy); + downstreamDispatchStrategy); } private void initClientGroupWrapper(UserAgent user, Session session) throws Exception { if (!lockMap.containsKey(user.getGroup())) { Object obj = lockMap.putIfAbsent(user.getGroup(), new Object()); if (obj == null) { - logger.info("add lock to map for group:{}", user.getGroup()); + log.info("add lock to map for group:{}", user.getGroup()); } } synchronized (lockMap.get(user.getGroup())) { if (!clientGroupMap.containsKey(user.getGroup())) { ClientGroupWrapper cgw = constructClientGroupWrapper(user.getSubsystem(), user.getGroup(), - eventMeshTCPServer, new FreePriorityDispatchStrategy()); + eventMeshTCPServer, new FreePriorityDispatchStrategy()); clientGroupMap.put(user.getGroup(), cgw); - logger.info("create new ClientGroupWrapper, group:{}", user.getGroup()); + log.info("create new ClientGroupWrapper, group:{}", user.getGroup()); } ClientGroupWrapper cgw = clientGroupMap.get(user.getGroup()); @@ -208,16 +220,16 @@ private void initClientGroupWrapper(UserAgent user, Session session) throws Exce } else if (EventMeshConstants.PURPOSE_SUB.equals(user.getPurpose())) { initClientGroupConsumser(cgw); } else { - logger.error("unknown client purpose:{}", user.getPurpose()); + log.error("unknown client purpose:{}", user.getPurpose()); throw new Exception("client purpose config is error"); } - session.setClientGroupWrapper(new WeakReference(cgw)); + session.setClientGroupWrapper(new WeakReference<>(cgw)); } } private void startClientGroupProducer(ClientGroupWrapper cgw, Session session) throws Exception { - if (!cgw.producerStarted.get()) { + if (!cgw.getProducerStarted().get()) { cgw.startClientGroupProducer(); } boolean flag = cgw.addGroupProducerSession(session); @@ -228,36 +240,37 @@ private void startClientGroupProducer(ClientGroupWrapper cgw, Session session) t } private void initClientGroupConsumser(ClientGroupWrapper cgw) throws Exception { - if (!cgw.producerStarted.get()) { + if (!cgw.getProducerStarted().get()) { cgw.startClientGroupProducer(); } - if (!cgw.inited4Broadcast.get()) { + if (!cgw.getInited4Broadcast().get()) { cgw.initClientGroupBroadcastConsumer(); } - if (!cgw.inited4Persistent.get()) { + if (!cgw.getInited4Persistent().get()) { cgw.initClientGroupPersistentConsumer(); } } private void startClientGroupConsumer(Session session) throws Exception { - if (!lockMap.containsKey(session.getClient().getSubsystem())) { - lockMap.putIfAbsent(session.getClient().getSubsystem(), new Object()); + String subsystem = session.getClient().getSubsystem(); + if (!lockMap.containsKey(subsystem)) { + lockMap.putIfAbsent(subsystem, new Object()); } - synchronized (lockMap.get(session.getClient().getSubsystem())) { - logger.info("readySession session[{}]", session); + synchronized (lockMap.get(subsystem)) { + log.info("readySession session[{}]", session); ClientGroupWrapper cgw = session.getClientGroupWrapper().get(); - boolean flag = cgw.addGroupConsumerSession(session); + boolean flag = cgw != null && cgw.addGroupConsumerSession(session); if (!flag) { throw new Exception("addGroupConsumerSession fail"); } - if (cgw.inited4Persistent.get() && !cgw.started4Persistent.get()) { + if (cgw.getInited4Persistent().get() && !cgw.getStarted4Persistent().get()) { cgw.startClientGroupPersistentConsumer(); } - if (cgw.inited4Broadcast.get() && !cgw.started4Broadcast.get()) { + if (cgw.getInited4Broadcast().get() && !cgw.getStarted4Broadcast().get()) { cgw.startClientGroupBroadcastConsumer(); } session.setSessionState(SessionState.RUNNING); @@ -266,14 +279,16 @@ private void startClientGroupConsumer(Session session) throws Exception { private void cleanClientGroupWrapperByCloseSub(Session session) throws Exception { cleanSubscriptionInSession(session); - session.getClientGroupWrapper().get().removeGroupConsumerSession(session); + ClientGroupWrapper clientGroupWrapper = Objects.requireNonNull(session.getClientGroupWrapper().get()); + clientGroupWrapper.removeGroupConsumerSession(session); handleUnackMsgsInSession(session); - cleanClientGroupWrapperCommon(session); + cleanClientGroupWrapperCommon(clientGroupWrapper); } private void cleanClientGroupWrapperByClosePub(Session session) throws Exception { - session.getClientGroupWrapper().get().removeGroupProducerSession(session); - cleanClientGroupWrapperCommon(session); + ClientGroupWrapper clientGroupWrapper = Objects.requireNonNull(session.getClientGroupWrapper().get()); + clientGroupWrapper.removeGroupProducerSession(session); + cleanClientGroupWrapperCommon(clientGroupWrapper); } /** @@ -282,10 +297,11 @@ private void cleanClientGroupWrapperByClosePub(Session session) throws Exception * @param session */ private void cleanSubscriptionInSession(Session session) throws Exception { - for (SubscriptionItem item : session.getSessionContext().subscribeTopics.values()) { - session.getClientGroupWrapper().get().removeSubscription(item, session); - if (!session.getClientGroupWrapper().get().hasSubscription(item.getTopic())) { - session.getClientGroupWrapper().get().unsubscribe(item); + for (SubscriptionItem item : session.getSessionContext().getSubscribeTopics().values()) { + ClientGroupWrapper clientGroupWrapper = Objects.requireNonNull(session.getClientGroupWrapper().get()); + clientGroupWrapper.removeSubscription(item, session); + if (!clientGroupWrapper.hasSubscription(item.getTopic())) { + clientGroupWrapper.unsubscribe(item); } } } @@ -296,170 +312,152 @@ private void cleanSubscriptionInSession(Session session) throws Exception { * @param session */ private void handleUnackMsgsInSession(Session session) { - ConcurrentHashMap unAckMsg = session.getPusher().getUnAckMsg(); - if (unAckMsg.size() > 0 && session.getClientGroupWrapper().get().getGroupConsumerSessions().size() > 0) { + // key: seq + ConcurrentHashMap unAckMsg = session.getPusher().getUnAckMsg(); + ClientGroupWrapper clientGroupWrapper = Objects.requireNonNull(session.getClientGroupWrapper().get()); + if (unAckMsg.size() > 0 && !clientGroupWrapper.getGroupConsumerSessions().isEmpty()) { for (Map.Entry entry : unAckMsg.entrySet()) { DownStreamMsgContext downStreamMsgContext = entry.getValue(); - if (SubscriptionMode.BROADCASTING.equals(downStreamMsgContext.subscriptionItem.getMode())) { - logger.warn("exist broadcast msg unack when closeSession,seq:{},bizSeq:{},client:{}", - downStreamMsgContext.seq, EventMeshUtil.getMessageBizSeq(downStreamMsgContext.event), - session.getClient()); + if (SubscriptionMode.BROADCASTING == downStreamMsgContext.getSubscriptionItem().getMode()) { + log.warn("exist broadcast msg unack when closeSession,seq:{},bizSeq:{},client:{}", + downStreamMsgContext.seq, EventMeshUtil.getMessageBizSeq(downStreamMsgContext.event), + session.getClient()); continue; } - Session reChooseSession = session.getClientGroupWrapper().get().getDownstreamDispatchStrategy() - .select(session.getClientGroupWrapper().get().getGroup(), - downStreamMsgContext.event.getSubject(), - Objects.requireNonNull(session.getClientGroupWrapper().get()).groupConsumerSessions); + Session reChooseSession = clientGroupWrapper.getDownstreamDispatchStrategy() + .select(clientGroupWrapper.getGroup(), + downStreamMsgContext.event.getSubject(), + clientGroupWrapper.getGroupConsumerSessions()); if (reChooseSession != null) { - downStreamMsgContext.session = reChooseSession; + downStreamMsgContext.setSession(reChooseSession); reChooseSession.getPusher().unAckMsg(downStreamMsgContext.seq, downStreamMsgContext); reChooseSession.downstreamMsg(downStreamMsgContext); - logger.info("rePush msg form unAckMsgs,seq:{},rePushClient:{}", entry.getKey(), - downStreamMsgContext.session.getClient()); + log.info("rePush msg form unAckMsgs,seq:{},rePushClient:{}", entry.getKey(), + downStreamMsgContext.getSession().getClient()); } else { - logger.warn("select session fail in handleUnackMsgsInSession,seq:{},topic:{}", entry.getKey(), - downStreamMsgContext.event.getSubject()); + log.warn("select session fail in handleUnackMsgsInSession,seq:{},topic:{}", entry.getKey(), + downStreamMsgContext.event.getSubject()); } } } } - private void cleanClientGroupWrapperCommon(Session session) throws Exception { - logger.info("GroupConsumerSessions size:{}", - session.getClientGroupWrapper().get().getGroupConsumerSessions().size()); - if (session.getClientGroupWrapper().get().getGroupConsumerSessions().size() == 0) { - shutdownClientGroupConsumer(session); + private void cleanClientGroupWrapperCommon(ClientGroupWrapper clientGroupWrapper) throws Exception { + + if (CollectionUtils.isEmpty(clientGroupWrapper.getGroupConsumerSessions())) { + shutdownClientGroupConsumer(clientGroupWrapper); } - logger.info("GroupProducerSessions size:{}", - session.getClientGroupWrapper().get().getGroupProducerSessions().size()); - if ((session.getClientGroupWrapper().get().getGroupConsumerSessions().size() == 0) - && (session.getClientGroupWrapper().get().getGroupProducerSessions().size() == 0)) { - shutdownClientGroupProducer(session); + log.info("GroupProducerSessions size:{}", + clientGroupWrapper.getGroupProducerSessions().size()); + if ((CollectionUtils.isEmpty(clientGroupWrapper.getGroupConsumerSessions())) + && (CollectionUtils.isEmpty(clientGroupWrapper.getGroupProducerSessions()))) { + shutdownClientGroupProducer(clientGroupWrapper); - clientGroupMap.remove(session.getClientGroupWrapper().get().getGroup()); - lockMap.remove(session.getClientGroupWrapper().get().getGroup()); - logger.info("remove clientGroupWrapper group[{}]", session.getClientGroupWrapper().get().getGroup()); + clientGroupMap.remove(clientGroupWrapper.getGroup()); + lockMap.remove(clientGroupWrapper.getGroup()); + log.info("remove clientGroupWrapper group[{}]", clientGroupWrapper.getGroup()); } } - private void shutdownClientGroupConsumer(Session session) throws Exception { - if (session.getClientGroupWrapper().get().started4Broadcast.get() == Boolean.TRUE) { - session.getClientGroupWrapper().get().shutdownBroadCastConsumer(); + private void shutdownClientGroupConsumer(ClientGroupWrapper clientGroupWrapper) throws Exception { + if (clientGroupWrapper.getStarted4Broadcast().get()) { + clientGroupWrapper.shutdownBroadCastConsumer(); } - if (session.getClientGroupWrapper().get().started4Persistent.get() == Boolean.TRUE) { - session.getClientGroupWrapper().get().shutdownPersistentConsumer(); + if (clientGroupWrapper.getStarted4Persistent().get()) { + clientGroupWrapper.shutdownPersistentConsumer(); } } - - private void shutdownClientGroupProducer(Session session) throws Exception { - if (session.getClientGroupWrapper().get().producerStarted.get() == Boolean.TRUE) { - session.getClientGroupWrapper().get().shutdownProducer(); + private void shutdownClientGroupProducer(ClientGroupWrapper clientGroupWrapper) throws Exception { + if (clientGroupWrapper.getProducerStarted().get()) { + clientGroupWrapper.shutdownProducer(); } } private void initSessionCleaner() { - eventMeshTCPServer.getScheduler().scheduleAtFixedRate( - new Runnable() { - @Override - public void run() { - Iterator sessionIterator = sessionTable.values().iterator(); - while (sessionIterator.hasNext()) { - Session tmp = sessionIterator.next(); - if (System.currentTimeMillis() - tmp.getLastHeartbeatTime() - > eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpSessionExpiredInMills) { - try { - logger.warn("clean expired session,client:{}", tmp.getClient()); - closeSession(tmp.getContext()); - } catch (Exception e) { - logger.error("say goodbye to session error! {}", tmp, e); - } - } + eventMeshTCPServer.getTcpThreadPoolGroup().getScheduler().scheduleAtFixedRate( + () -> { + for (Session tmp : sessionTable.values()) { + long interval = System.currentTimeMillis() - tmp.getLastHeartbeatTime(); + if (interval > eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpSessionExpiredInMills()) { + try { + log.warn("clean expired session,client:{}", tmp.getClient()); + closeSession(tmp.getContext()); + } catch (Exception e) { + log.error("say goodbye to session error! {}", tmp, e); } } - }, 1000, eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpSessionExpiredInMills, - TimeUnit.MILLISECONDS); + } + }, 1000, eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpSessionExpiredInMills(), TimeUnit.MILLISECONDS); } private void initDownStreamMsgContextCleaner() { - eventMeshTCPServer.getScheduler().scheduleAtFixedRate( - new Runnable() { - @Override - public void run() { - - //scan non-broadcast msg - Iterator sessionIterator = sessionTable.values().iterator(); - while (sessionIterator.hasNext()) { - Session tmp = sessionIterator.next(); - for (Map.Entry entry : tmp.getPusher().getUnAckMsg().entrySet()) { - String seqKey = entry.getKey(); - DownStreamMsgContext downStreamMsgContext = entry.getValue(); - if (!downStreamMsgContext.isExpire()) { - continue; - } - downStreamMsgContext.ackMsg(); - tmp.getPusher().getUnAckMsg().remove(seqKey); - logger.warn("remove expire downStreamMsgContext, session:{}, topic:{}, seq:{}", tmp, - downStreamMsgContext.event.getSubject(), seqKey); - } + eventMeshTCPServer.getTcpThreadPoolGroup().getScheduler().scheduleAtFixedRate( + () -> { + + // scan non-broadcast msg + for (Session tmp : sessionTable.values()) { + for (Map.Entry entry : tmp.getPusher().getUnAckMsg().entrySet()) { + String seqKey = entry.getKey(); + DownStreamMsgContext downStreamMsgContext = entry.getValue(); + if (!downStreamMsgContext.isExpire()) { + continue; } + downStreamMsgContext.ackMsg(); + tmp.getPusher().getUnAckMsg().remove(seqKey); + log.warn("remove expire downStreamMsgContext, session:{}, topic:{}, seq:{}", tmp, + downStreamMsgContext.event.getSubject(), seqKey); } - }, 1000, 5 * 1000, TimeUnit.MILLISECONDS); + } + }, 1000, 5 * 1000, TimeUnit.MILLISECONDS); } - public void init() throws Exception { initSessionCleaner(); initDownStreamMsgContextCleaner(); - logger.info("ClientSessionGroupMapping inited......"); + log.info("ClientSessionGroupMapping inited......"); } public void start() throws Exception { - logger.info("ClientSessionGroupMapping started......"); + log.info("ClientSessionGroupMapping started......"); } public void shutdown() throws Exception { - logger.info("begin to close sessions gracefully"); + log.info("begin to close sessions gracefully"); for (ClientGroupWrapper clientGroupWrapper : clientGroupMap.values()) { for (Session subSession : clientGroupWrapper.getGroupConsumerSessions()) { try { - EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer, subSession, this); + EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer.getTcpThreadPoolGroup(), subSession, this); } catch (Exception e) { - logger.error("say goodbye to subSession error! {}", subSession, e); + log.error("say goodbye to subSession error! {}", subSession, e); } } for (Session pubSession : clientGroupWrapper.getGroupProducerSessions()) { try { - EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer, pubSession, this); + EventMeshTcp2Client.serverGoodby2Client(eventMeshTCPServer.getTcpThreadPoolGroup(), pubSession, this); } catch (Exception e) { - logger.error("say goodbye to pubSession error! {}", pubSession, e); + log.error("say goodbye to pubSession error! {}", pubSession, e); } } - try { - Thread.sleep(eventMeshTCPServer.getEventMeshTCPConfiguration().gracefulShutdownSleepIntervalInMills); - } catch (InterruptedException e) { - logger.warn("Thread.sleep occur InterruptedException", e); - } - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - logger.warn("Thread.sleep occur InterruptedException", e); + ThreadUtils.sleep(eventMeshTCPServer.getEventMeshTCPConfiguration().getGracefulShutdownSleepIntervalInMills(), TimeUnit.MILLISECONDS); + } + ThreadUtils.sleep(1, TimeUnit.SECONDS); + sessionTable.values().parallelStream().forEach(itr -> { try { - EventMeshTcp2Client.serverGoodby2Client(this.eventMeshTCPServer, itr, this); + EventMeshTcp2Client.serverGoodby2Client(this.eventMeshTCPServer.getTcpThreadPoolGroup(), itr, this); } catch (Exception e) { - logger.error("say goodbye to session error! {}", itr, e); + log.error("say goodbye to session error! {}", itr, e); } }); - ThreadUtils.randomSleep(50); - logger.info("ClientSessionGroupMapping shutdown......"); + ThreadUtils.randomPause(50); + log.info("ClientSessionGroupMapping shutdown......"); } public ConcurrentHashMap getSessionMap() { @@ -501,4 +499,48 @@ public Map> prepareProxyClientDistributionData() { return result; } + + public void updateMetaData() { + if (!eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerMetaStorageEnable()) { + return; + } + try { + Map metadata = new HashMap<>(1 << 4); + + for (Map.Entry clientGroupWrapperMap : this.clientGroupMap.entrySet()) { + String group = clientGroupWrapperMap.getKey(); + ClientGroupWrapper cgw = clientGroupWrapperMap.getValue(); + ConsumerGroupMetadata consumerGroupMetadata = new ConsumerGroupMetadata(); + consumerGroupMetadata.setConsumerGroup(group); + Map consumerGroupTopicMetadataMap = + new HashMap<>(1 << 4); + Map> topic2sessionInGroupMapping = cgw.getTopic2sessionInGroupMapping(); + for (Map.Entry> topicSessionMap : topic2sessionInGroupMapping.entrySet()) { + String topic = topicSessionMap.getKey(); + Map sessionMap = topicSessionMap.getValue(); + + ConsumerGroupTopicMetadata consumerGroupTopicMetadata = new ConsumerGroupTopicMetadata(); + consumerGroupTopicMetadata.setConsumerGroup(group); + consumerGroupTopicMetadata.setTopic(topic); + Set sessionSet = new HashSet<>(); + for (Map.Entry sessionEntry : sessionMap.entrySet()) { + String sessionId = sessionEntry.getKey(); + Session session = sessionEntry.getValue(); + sessionSet.add(session.toString()); + } + consumerGroupTopicMetadata.setUrls(sessionSet); + consumerGroupTopicMetadataMap.put(topic, consumerGroupTopicMetadata); + } + + consumerGroupMetadata.setConsumerGroupTopicMetadataMap(consumerGroupTopicMetadataMap); + metadata.put(group, JsonUtils.toJSONString(consumerGroupMetadata)); + } + metadata.put(EventMeshMetaConfig.EVENT_MESH_PROTO, "tcp"); + + eventMeshTCPServer.getMetaStorage().updateMetaData(metadata); + + } catch (Exception e) { + log.error("update eventmesh metadata error", e); + } + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java index 9259c51de8..d795285ea2 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/DownstreamDispatchStrategy.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.runtime.core.protocol.tcp.client.group.dispatch; - import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; import java.util.Set; @@ -26,12 +25,13 @@ * DownstreamDispatchStrategy */ public interface DownstreamDispatchStrategy { + /** * select a SESSION * * @param group * @param consumeSessions - * @return + * @return client session */ Session select(String group, String topic, Set consumeSessions); } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java index 623dbb07d9..c466557401 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/group/dispatch/FreePriorityDispatchStrategy.java @@ -27,48 +27,47 @@ import java.util.List; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class FreePriorityDispatchStrategy implements DownstreamDispatchStrategy { - private static final Logger logger = LoggerFactory.getLogger(FreePriorityDispatchStrategy.class); - @Override - public Session select(String group, String topic, Set groupConsumerSessions) { + public Session select(final String group, final String topic, final Set groupConsumerSessions) { if (CollectionUtils.isEmpty(groupConsumerSessions) - || StringUtils.isBlank(topic) - || StringUtils.isBlank(group)) { + || StringUtils.isBlank(topic) + || StringUtils.isBlank(group)) { return null; } - List filtered = new ArrayList(); - List isolatedSessions = new ArrayList<>(); - for (Session session : groupConsumerSessions) { + final List filtered = new ArrayList<>(); + final List isolatedSessions = new ArrayList<>(); + for (final Session session : groupConsumerSessions) { if (!session.isAvailable(topic)) { continue; } + if (session.isIsolated()) { isolatedSessions.add(session); - logger.info("session is not available because session is isolated,isolateTime:{},client:{}", - session.getIsolateTime(), session.getClient()); + log.info("session is not available because session is isolated,isolateTime:{},client:{}", + session.getIsolateTime(), session.getClient()); continue; } + filtered.add(session); } if (CollectionUtils.isEmpty(filtered)) { if (CollectionUtils.isEmpty(isolatedSessions)) { - logger.warn("all sessions can't downstream msg"); + log.warn("all sessions can't downstream msg"); return null; } else { - logger.warn("all sessions are isolated,group:{},topic:{}", group, topic); + log.warn("all sessions are isolated,group:{},topic:{}", group, topic); filtered.addAll(isolatedSessions); } } Collections.shuffle(filtered); - Session session = filtered.get(0); - return session; + return filtered.get(0); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/GoodbyeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/GoodbyeProcessor.java new file mode 100644 index 0000000000..1cb7c04c85 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/GoodbyeProcessor.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import static org.apache.eventmesh.common.protocol.tcp.Command.CLIENT_GOODBYE_RESPONSE; + +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.Utils; + +import java.util.Arrays; + +import io.netty.channel.ChannelHandlerContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GoodbyeProcessor implements TcpProcessor { + + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public GoodbyeProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + long taskExecuteTime = System.currentTimeMillis(); + Package msg = new Package(); + try { + if (pkg.getHeader().getCmd() == Command.SERVER_GOODBYE_RESPONSE) { + log.info("client|address={}| has reject ", session.getContext().channel().remoteAddress()); + } else { + msg.setHeader( + new Header(CLIENT_GOODBYE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), + pkg.getHeader().getSeq())); + } + } catch (Exception e) { + log.error("GoodbyeTask failed|user={}|errMsg={}", session.getClient(), e); + msg.setHeader(new Header(CLIENT_GOODBYE_RESPONSE, OPStatus.FAIL.getCode(), Arrays.toString(e.getStackTrace()), + pkg.getHeader().getSeq())); + } finally { + this.eventMeshTCPServer.getTcpThreadPoolGroup().getScheduler() + .submit(() -> Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session)); + } + EventMeshTcp2Client + .closeSessionIfTimeout(this.eventMeshTCPServer.getTcpThreadPoolGroup(), session, eventMeshTCPServer.getClientSessionGroupMapping()); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/HeartBeatProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/HeartBeatProcessor.java new file mode 100644 index 0000000000..a4677dc1d0 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/HeartBeatProcessor.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import static org.apache.eventmesh.common.protocol.tcp.Command.HEARTBEAT_REQUEST; +import static org.apache.eventmesh.common.protocol.tcp.Command.HEARTBEAT_RESPONSE; + +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.Utils; + +import java.util.Objects; + +import io.netty.channel.ChannelHandlerContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HeartBeatProcessor implements TcpProcessor { + + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public HeartBeatProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + long taskExecuteTime = System.currentTimeMillis(); + Package res = new Package(); + try { + // do acl check in heartbeat + if (eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + this.acl.doAclCheckInTcpHeartbeat(remoteAddr, session.getClient(), HEARTBEAT_REQUEST.getValue()); + } + + if (session != null) { + session.notifyHeartbeat(startTime); + } + res.setHeader(new Header(HEARTBEAT_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), + pkg.getHeader().getSeq())); + } catch (Exception e) { + log.error("HeartBeatTask failed|user={}|errMsg={}", Objects.requireNonNull(session).getClient(), e); + res.setHeader(new Header(HEARTBEAT_RESPONSE, OPStatus.FAIL.getCode(), "exception while " + + "heartbeating", pkg.getHeader().getSeq())); + } finally { + Utils.writeAndFlush(res, startTime, taskExecuteTime, Objects.requireNonNull(session).getContext(), session); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/HelloProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/HelloProcessor.java new file mode 100644 index 0000000000..2827f9f324 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/HelloProcessor.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import static org.apache.eventmesh.common.protocol.tcp.Command.HELLO_RESPONSE; + +import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.common.ServiceState; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.Utils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HelloProcessor implements TcpProcessor { + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); + + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public HelloProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + long taskExecuteTime = System.currentTimeMillis(); + Package res = new Package(); + Session session = null; + UserAgent user = (UserAgent) pkg.getBody(); + try { + + // do acl check in connect + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + String group = user.getGroup(); + String token = user.getToken(); + String subsystem = user.getSubsystem(); + + if (eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerSecurityEnable()) { + EventMeshAppSubTopicInfo eventMeshAppSubTopicInfo = eventMeshTCPServer.getMetaStorage().findEventMeshAppSubTopicInfo(group); + if (eventMeshAppSubTopicInfo == null) { + throw new AclException("no group register"); + } + this.acl.doAclCheckInTcpConnect(remoteAddr, token, subsystem, eventMeshAppSubTopicInfo); + } + + if (eventMeshTCPServer.getEventMeshServer().getServiceState() != ServiceState.RUNNING) { + log.error("server state is not running:{}", eventMeshTCPServer.getEventMeshServer().getServiceState()); + throw new Exception("server state is not running, maybe deploying..."); + } + + validateUserAgent(user); + session = eventMeshTCPServer.getClientSessionGroupMapping().createSession(user, ctx); + res.setHeader(new Header(HELLO_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), + pkg.getHeader().getSeq())); + Utils.writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); + } catch (Throwable e) { + MESSAGE_LOGGER.error("HelloTask failed|address={}", ctx.channel().remoteAddress(), e); + res.setHeader(new Header(HELLO_RESPONSE, OPStatus.FAIL.getCode(), Arrays.toString(e.getStackTrace()), pkg + .getHeader().getSeq())); + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(res).addListener( + (ChannelFutureListener) future -> { + if (!future.isSuccess()) { + Utils.logFailedMessageFlow(future, res, user, startTime, taskExecuteTime); + } else { + Utils.logSucceedMessageFlow(res, user, startTime, taskExecuteTime); + } + log.warn("HelloTask failed,close session,addr:{}", ctx.channel().remoteAddress()); + eventMeshTCPServer.getClientSessionGroupMapping().closeSession(ctx); + }); + }); + } + } + + private void validateUserAgent(UserAgent user) throws Exception { + if (user == null) { + throw new Exception("client info cannot be null"); + } + + if (user.getVersion() == null) { + throw new Exception("client version cannot be null"); + } + + if (!StringUtils.equalsAny(user.getPurpose(), EventMeshConstants.PURPOSE_PUB, EventMeshConstants.PURPOSE_SUB)) { + throw new Exception("client purpose config is error"); + } + + if (StringUtils.isBlank(user.getGroup())) { + throw new Exception("client group cannot be null"); + } + + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/ListenProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/ListenProcessor.java new file mode 100644 index 0000000000..866098a451 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/ListenProcessor.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import static org.apache.eventmesh.common.protocol.tcp.Command.LISTEN_RESPONSE; + +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import io.netty.channel.ChannelHandlerContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ListenProcessor implements TcpProcessor { + + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public ListenProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + long taskExecuteTime = System.currentTimeMillis(); + Header header = new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq()); + session.setListenRequestSeq(pkg.getHeader().getSeq()); + try { + synchronized (session) { + eventMeshTCPServer.getClientSessionGroupMapping().readySession(session); + } + } catch (Exception e) { + log.error("ListenTask failed|user={}|errMsg={}", session.getClient(), e); + Integer status = OPStatus.FAIL.getCode(); + header = new Header(LISTEN_RESPONSE, status, e.toString(), pkg.getHeader().getSeq()); + } finally { + // check to avoid send repeatedly + session.trySendListenResponse(header, startTime, taskExecuteTime); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/MessageAckProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/MessageAckProcessor.java new file mode 100644 index 0000000000..fd25d5bbd9 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/MessageAckProcessor.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelHandlerContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MessageAckProcessor implements TcpProcessor { + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public MessageAckProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + long taskExecuteTime = System.currentTimeMillis(); + String seq = pkg.getHeader().getSeq(); + Command cmd = pkg.getHeader().getCmd(); + + if (seq == null) { + log.error("MessageAckTask failed, seq cannot be null|user={}", session.getClient()); + return; + } + DownStreamMsgContext downStreamMsgContext = session.getPusher().getUnAckMsg().get(seq); + // ack non-broadcast msg + if (downStreamMsgContext != null) { + downStreamMsgContext.ackMsg(); + session.getPusher().getUnAckMsg().remove(seq); + } else { + if (cmd != Command.RESPONSE_TO_CLIENT_ACK) { + log.warn("MessageAckTask, seq:{}, downStreamMsgContext not in downStreamMap,client:{}", + seq, session.getClient()); + } + } + MESSAGE_LOGGER.info("pkg|c2eventMesh|cmd={}|seq=[{}]|user={}|wait={}ms|cost={}ms", cmd, seq, session.getClient(), + taskExecuteTime - startTime, System.currentTimeMillis() - startTime); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/MessageTransferProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/MessageTransferProcessor.java new file mode 100644 index 0000000000..fdb7595c62 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/MessageTransferProcessor.java @@ -0,0 +1,290 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import static org.apache.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER; +import static org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.SessionSender.TRY_PERMIT_TIME_OUT; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.protocol.api.ProtocolAdaptor; +import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.EventMeshTcpSendResult; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.EventMeshTcpSendStatus; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.UpStreamMsgContext; +import org.apache.eventmesh.runtime.trace.AttributeKeys; +import org.apache.eventmesh.runtime.trace.SpanKey; +import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.TraceUtils; +import org.apache.eventmesh.runtime.util.Utils; +import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; + +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MessageTransferProcessor implements TcpProcessor { + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + private Package pkg; + private ChannelHandlerContext ctx; + private Session session; + private long startTime; + + public MessageTransferProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + + this.pkg = pkg; + this.ctx = ctx; + this.session = session; + this.startTime = startTime; + + long taskExecuteTime = System.currentTimeMillis(); + Command cmd = pkg.getHeader().getCmd(); + + try { + if (eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerTraceEnable() + && RESPONSE_TO_SERVER != cmd) { + // attach the span to the server context + Span span = TraceUtils.prepareServerSpan(pkg.getHeader().getProperties(), + EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, + startTime, TimeUnit.MILLISECONDS, true); + Context context = Context.current().with(SpanKey.SERVER_KEY, span); + // put the context in channel + ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).set(context); + } + } catch (Exception ex) { + log.warn("upload trace fail in MessageTransferTask[server-span-start]", ex); + } + + Command replyCmd = getReplyCmd(cmd); + Package msg = new Package(); + + EventMeshTcpSendResult sendStatus; + CloudEvent event = null; + + try { + String protocolType = "eventmeshmessage"; + if (pkg.getHeader().getProperties() != null + && pkg.getHeader().getProperty(Constants.PROTOCOL_TYPE) != null) { + protocolType = (String) pkg.getHeader().getProperty(Constants.PROTOCOL_TYPE); + } + ProtocolAdaptor protocolAdaptor = + ProtocolPluginFactory.getProtocolAdaptor(protocolType); + event = protocolAdaptor.toCloudEvent(pkg); + + if (event == null) { + throw new Exception("event is null"); + } + + String content = new String(Objects.requireNonNull(event.getData()).toBytes(), StandardCharsets.UTF_8); + int eventMeshEventSize = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshEventSize(); + if (content.length() > eventMeshEventSize) { + throw new Exception("event size exceeds the limit: " + eventMeshEventSize); + } + + // do acl check in sending msg + if (eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerSecurityEnable()) { + String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + this.acl.doAclCheckInTcpSend(remoteAddr, session.getClient(), event.getSubject(), cmd.getValue()); + } + + if (!eventMeshTCPServer.getRateLimiter() + .tryAcquire(TRY_PERMIT_TIME_OUT, TimeUnit.MILLISECONDS)) { + + msg.setHeader(new Header(replyCmd, OPStatus.FAIL.getCode(), "Tps overload, global flow control", pkg.getHeader().getSeq())); + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(msg).addListener( + (ChannelFutureListener) future -> Utils.logSucceedMessageFlow(msg, session.getClient(), startTime, taskExecuteTime)); + }); + + TraceUtils.finishSpanWithException(ctx, event, "Tps overload, global flow control", null); + + log.warn("======Tps overload, global flow control, rate:{}! PLEASE CHECK!========", eventMeshTCPServer.getRateLimiter().getRate()); + return; + } + + synchronized (session) { + long sendTime = System.currentTimeMillis(); + event = addTimestamp(event, cmd, sendTime); + + sendStatus = session + .upstreamMsg(pkg.getHeader(), event, + createSendCallback(replyCmd, taskExecuteTime, event), + startTime, taskExecuteTime); + + if (StringUtils.equals(EventMeshTcpSendStatus.SUCCESS.name(), + sendStatus.getSendStatus().name())) { + MESSAGE_LOGGER.info("pkg|eventMesh2mq|cmd={}|Msg={}|user={}|wait={}ms|cost={}ms", + cmd, event, + session.getClient(), taskExecuteTime - startTime, sendTime - startTime); + } else { + throw new Exception(sendStatus.getDetail()); + } + } + } catch (Exception e) { + log.error("MessageTransferTask failed|cmd={}|event={}|user={}", cmd, event, + session.getClient(), + e); + + if (cmd != RESPONSE_TO_SERVER) { + msg.setHeader( + new Header(replyCmd, OPStatus.FAIL.getCode(), e.toString(), + pkg.getHeader() + .getSeq())); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + + if (event != null) { + TraceUtils.finishSpanWithException(ctx, event, "MessageTransferTask failed", e); + } + } + } + } + + private CloudEvent addTimestamp(CloudEvent event, Command cmd, long sendTime) { + if (cmd == RESPONSE_TO_SERVER) { + return buildCloudEventWithTimestamps(event, + EventMeshConstants.RSP_C2EVENTMESH_TIMESTAMP, + EventMeshConstants.RSP_EVENTMESH2MQ_TIMESTAMP, sendTime, + EventMeshConstants.RSP_SEND_EVENTMESH_IP); + } else { + return buildCloudEventWithTimestamps(event, + EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, + EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, sendTime, + EventMeshConstants.REQ_SEND_EVENTMESH_IP); + } + } + + private CloudEvent buildCloudEventWithTimestamps(CloudEvent event, String client2EventMeshTime, + String eventMesh2MqTime, long sendTime, String eventMeshIP) { + return CloudEventBuilder.from(event) + .withExtension(client2EventMeshTime, String.valueOf(startTime)) + .withExtension(eventMesh2MqTime, String.valueOf(sendTime)) + .withExtension(eventMeshIP, eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshServerIp()) + .build(); + } + + private Command getReplyCmd(Command cmd) { + switch (cmd) { + case REQUEST_TO_SERVER: + return Command.RESPONSE_TO_CLIENT; + case ASYNC_MESSAGE_TO_SERVER: + return Command.ASYNC_MESSAGE_TO_SERVER_ACK; + case BROADCAST_MESSAGE_TO_SERVER: + return Command.BROADCAST_MESSAGE_TO_SERVER_ACK; + default: + return cmd; + } + } + + protected SendCallback createSendCallback(Command replyCmd, long taskExecuteTime, + CloudEvent event) { + final long createTime = System.currentTimeMillis(); + Package msg = new Package(); + + return new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + session.getSender().getUpstreamBuff().release(); + MESSAGE_LOGGER.info("upstreamMsg message success|user={}|callback cost={}", + session.getClient(), + System.currentTimeMillis() - createTime); + if (replyCmd == Command.BROADCAST_MESSAGE_TO_SERVER_ACK + || replyCmd == Command.ASYNC_MESSAGE_TO_SERVER_ACK) { + msg.setHeader( + new Header(replyCmd, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), + pkg.getHeader().getSeq())); + msg.setBody(event); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), + session); + + // async request need finish span when callback, rr request will finish span when rrCallback + TraceUtils.finishSpan(ctx, event); + } + } + + @Override + public void onException(OnExceptionContext context) { + session.getSender().getUpstreamBuff().release(); + + // retry + UpStreamMsgContext upStreamMsgContext = new UpStreamMsgContext( + session, event, pkg.getHeader(), startTime, taskExecuteTime); + Objects.requireNonNull( + session.getClientGroupWrapper().get()).getTcpRetryer() + .newTimeout(upStreamMsgContext, 10, TimeUnit.SECONDS); + + session.getSender().getFailMsgCount().incrementAndGet(); + MESSAGE_LOGGER + .error("upstreamMsg mq message error|user={}|callback cost={}, errMsg={}", + session.getClient(), + (System.currentTimeMillis() - createTime), + new Exception(context.getException())); + msg.setHeader( + new Header(replyCmd, OPStatus.FAIL.getCode(), context.getException().toString(), + pkg.getHeader().getSeq())); + msg.setBody(event); + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + + // both rr request and async request need finish span when reqeust fail + if (replyCmd != RESPONSE_TO_SERVER) { + // upload trace + TraceUtils.finishSpanWithException(ctx, event, + "upload trace fail in MessageTransferTask.createSendCallback.onException", + context.getException()); + } + } + }; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/RecommendProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/RecommendProcessor.java new file mode 100644 index 0000000000..a53a7889b5 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/RecommendProcessor.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import static org.apache.eventmesh.common.protocol.tcp.Command.RECOMMEND_RESPONSE; +import static org.apache.eventmesh.runtime.util.Utils.writeAndFlush; + +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendStrategy; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelHandlerContext; + +public class RecommendProcessor implements TcpProcessor { + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); + + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public RecommendProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + long taskExecuteTime = System.currentTimeMillis(); + Package res = new Package(); + try { + if (!eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerMetaStorageEnable()) { + throw new Exception("registry enable config is false, not support"); + } + UserAgent user = (UserAgent) pkg.getBody(); + validateUserAgent(user); + String group = getGroupOfClient(user); + EventMeshRecommendStrategy eventMeshRecommendStrategy = new EventMeshRecommendImpl(eventMeshTCPServer); + String eventMeshRecommendResult = eventMeshRecommendStrategy.calculateRecommendEventMesh(group, user.getPurpose()); + res.setHeader(new Header(RECOMMEND_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), + pkg.getHeader().getSeq())); + res.setBody(eventMeshRecommendResult); + } catch (Exception e) { + MESSAGE_LOGGER.error("RecommendTask failed|address={}|errMsg={}", ctx.channel().remoteAddress(), e); + res.setHeader(new Header(RECOMMEND_RESPONSE, OPStatus.FAIL.getCode(), e.toString(), pkg + .getHeader().getSeq())); + + } finally { + writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); + // session.write2Client(res); + } + } + + private void validateUserAgent(UserAgent user) throws Exception { + if (user == null) { + throw new Exception("client info cannot be null"); + } + + if (user.getVersion() == null) { + throw new Exception("client version cannot be null"); + } + + if (user.getUsername() == null) { + throw new Exception("client wemqUser cannot be null"); + } + + if (user.getPassword() == null) { + throw new Exception("client wemqPasswd cannot be null"); + } + + if (!StringUtils.equalsAny(user.getPurpose(), EventMeshConstants.PURPOSE_PUB, EventMeshConstants.PURPOSE_SUB)) { + throw new Exception("client purpose config is error"); + } + } + + private String getGroupOfClient(UserAgent userAgent) { + if (userAgent == null) { + return null; + } + return userAgent.getGroup(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/SubscribeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/SubscribeProcessor.java new file mode 100644 index 0000000000..4003fa897b --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/SubscribeProcessor.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.Subscription; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.RemotingHelper; +import org.apache.eventmesh.runtime.util.Utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import io.netty.channel.ChannelHandlerContext; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SubscribeProcessor implements TcpProcessor { + + private final Acl acl; + private EventMeshTCPServer eventMeshTCPServer; + + public SubscribeProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + final long taskExecuteTime = System.currentTimeMillis(); + + final Package msg = new Package(); + try { + final Subscription subscriptionInfo = (Subscription) pkg.getBody(); + Objects.requireNonNull(subscriptionInfo, "subscriptionInfo can not be null"); + + final List subscriptionItems = new ArrayList<>(); + final boolean eventMeshServerSecurityEnable = eventMeshTCPServer.getEventMeshTCPConfiguration().isEventMeshServerSecurityEnable(); + final String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); + + String group = session.getClient().getGroup(); + String token = session.getClient().getToken(); + String subsystem = session.getClient().getSubsystem(); + + subscriptionInfo.getTopicList().forEach(item -> { + if (eventMeshServerSecurityEnable) { + try { + EventMeshAppSubTopicInfo eventMeshAppSubTopicInfo = eventMeshTCPServer.getMetaStorage().findEventMeshAppSubTopicInfo(group); + if (eventMeshAppSubTopicInfo == null) { + throw new AclException("no group register"); + } + this.acl.doAclCheckInTcpReceive(remoteAddr, token, subsystem, item.getTopic(), null, eventMeshAppSubTopicInfo); + } catch (Exception e) { + throw new AclException("group:" + session.getClient().getGroup() + " has no auth to sub the topic:" + item.getTopic()); + } + } + + subscriptionItems.add(item); + }); + + synchronized (session) { + session.subscribe(subscriptionItems); + log.info("SubscribeTask succeed|user={}|topics={}", session.getClient(), subscriptionItems); + } + eventMeshTCPServer.getClientSessionGroupMapping().updateMetaData(); + msg.setHeader(new Header(Command.SUBSCRIBE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); + } catch (Exception e) { + log.error("SubscribeTask failed|user={}|errMsg={}", session.getClient(), e); + msg.setHeader(new Header(Command.SUBSCRIBE_RESPONSE, OPStatus.FAIL.getCode(), e.toString(), pkg.getHeader().getSeq())); + } finally { + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/TcpProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/TcpProcessor.java new file mode 100644 index 0000000000..01dff61c43 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/TcpProcessor.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import org.apache.eventmesh.common.protocol.tcp.Package; + +import io.netty.channel.ChannelHandlerContext; + +/** + * TcpProcessor + */ +public interface TcpProcessor { + + void process(final Package pkg, final ChannelHandlerContext ctx, long startTime); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/UnSubscribeProcessor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/UnSubscribeProcessor.java new file mode 100644 index 0000000000..7706264c5c --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/processor/UnSubscribeProcessor.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.processor; + +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.OPStatus; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.runtime.acl.Acl; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.util.Utils; + +import org.apache.commons.collections4.MapUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ChannelHandlerContext; + +public class UnSubscribeProcessor implements TcpProcessor { + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); + + private EventMeshTCPServer eventMeshTCPServer; + private final Acl acl; + + public UnSubscribeProcessor(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.acl = eventMeshTCPServer.getAcl(); + } + + @Override + public void process(final Package pkg, final ChannelHandlerContext ctx, long startTime) { + Session session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); + long taskExecuteTime = System.currentTimeMillis(); + Package msg = new Package(); + try { + synchronized (session) { + ConcurrentHashMap subscribeTopics = session.getSessionContext().getSubscribeTopics(); + if (MapUtils.isNotEmpty(subscribeTopics)) { + List topics = new ArrayList<>(subscribeTopics.values()); + session.unsubscribe(topics); + MESSAGE_LOGGER.info("UnSubscriberTask succeed|user={}|topics={}", session.getClient(), topics); + } + } + msg.setHeader(new Header(Command.UNSUBSCRIBE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader() + .getSeq())); + } catch (Exception e) { + MESSAGE_LOGGER.error("UnSubscribeTask failed|user={}|errMsg={}", session.getClient(), e); + msg.setHeader(new Header(Command.UNSUBSCRIBE_RESPONSE, OPStatus.FAIL.getCode(), "exception while " + + + "unSubscribing", pkg.getHeader().getSeq())); + } finally { + Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); + } + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceImpl.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceImpl.java new file mode 100644 index 0000000000..816c17adab --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceImpl.java @@ -0,0 +1,274 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance; + +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendStrategy; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshRebalanceImpl implements EventMeshRebalanceStrategy { + + private final EventMeshTCPServer eventMeshTCPServer; + + public EventMeshRebalanceImpl(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void doRebalance() throws Exception { + long startTime = System.currentTimeMillis(); + log.info("doRebalance start===========startTime:{}", startTime); + + Set groupSet = eventMeshTCPServer.getClientSessionGroupMapping().getClientGroupMap().keySet(); + if (CollectionUtils.isEmpty(groupSet)) { + log.warn("doRebalance failed,eventmesh has no group, please check eventmeshData"); + return; + } + + final String cluster = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshCluster(); + // get eventmesh of local idc + Map localEventMeshMap = queryLocalEventMeshMap(cluster); + if (MapUtils.isEmpty(localEventMeshMap)) { + return; + } + + for (String group : groupSet) { + doRebalanceByGroup(cluster, group, EventMeshConstants.PURPOSE_SUB, localEventMeshMap); + doRebalanceByGroup(cluster, group, EventMeshConstants.PURPOSE_PUB, localEventMeshMap); + } + log.info("doRebalance end===========startTime:{}, cost:{}", startTime, System.currentTimeMillis() - startTime); + } + + private Map queryLocalEventMeshMap(String cluster) { + Map localEventMeshMap = null; + List eventMeshDataInfoList = null; + try { + eventMeshDataInfoList = eventMeshTCPServer.getMetaStorage().findEventMeshInfoByCluster(cluster); + + if (eventMeshDataInfoList == null || CollectionUtils.isEmpty(eventMeshDataInfoList)) { + log.warn("doRebalance failed,query eventmesh instances is null from registry,cluster:{}", cluster); + return Collections.emptyMap(); + } + localEventMeshMap = new HashMap<>(); + String localIdc = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshIDC(); + for (EventMeshDataInfo eventMeshDataInfo : eventMeshDataInfoList) { + String idc = eventMeshDataInfo.getEventMeshName().split("-")[0]; + if (StringUtils.isNotBlank(idc) && StringUtils.equals(idc, localIdc)) { + localEventMeshMap.put(eventMeshDataInfo.getEventMeshName(), eventMeshDataInfo.getEndpoint()); + } + } + + if (0 == localEventMeshMap.size()) { + log.warn("doRebalance failed,query eventmesh instances of localIDC is null from registry,localIDC:{},cluster:{}", + localIdc, cluster); + return Collections.emptyMap(); + } + } catch (Exception e) { + log.warn("doRebalance failed,findEventMeshInfoByCluster failed,cluster:{},errMsg:{}", cluster, e); + return Collections.emptyMap(); + } + + return localEventMeshMap; + } + + private void doRebalanceByGroup(String cluster, String group, String purpose, Map eventMeshMap) throws Exception { + log.info("doRebalanceByGroup start, cluster:{}, group:{}, purpose:{}", cluster, group, purpose); + + // query distribute data of local idc + Map clientDistributionMap = queryLocalEventMeshDistributeData(cluster, group, purpose, + eventMeshMap); + if (MapUtils.isEmpty(clientDistributionMap)) { + return; + } + + doRebalanceRedirect(eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshName(), group, purpose, + eventMeshMap, clientDistributionMap); + log.info("doRebalanceByGroup end, cluster:{}, group:{}, purpose:{}", cluster, group, purpose); + + } + + private void doRebalanceRedirect(String currEventMeshName, String group, String purpose, Map eventMeshMap, + Map clientDistributionMap) throws Exception { + if (MapUtils.isEmpty(clientDistributionMap)) { + return; + } + + // calculate client num need to redirect in currEventMesh + int judge = calculateRedirectNum(currEventMeshName, group, purpose, clientDistributionMap); + + if (judge > 0) { + + // select redirect target eventmesh list + List eventMeshRecommendResult = selectRedirectEventMesh(group, eventMeshMap, clientDistributionMap, + judge, currEventMeshName); + if (eventMeshRecommendResult == null || eventMeshRecommendResult.size() != judge) { + log.warn("doRebalance failed,recommendEventMeshNum is not consistent,recommendResult:{},judge:{}", + eventMeshRecommendResult, judge); + return; + } + + // do redirect + doRedirect(group, purpose, judge, eventMeshRecommendResult); + } else { + log.info("rebalance condition not satisfy,group:{}, purpose:{},judge:{}", group, purpose, judge); + } + } + + private void doRedirect(String group, String purpose, int judge, List eventMeshRecommendResult) throws Exception { + log.info("doRebalance redirect start---------------------group:{},judge:{}", group, judge); + Set sessionSet = null; + if (EventMeshConstants.PURPOSE_SUB.equals(purpose)) { + sessionSet = eventMeshTCPServer.getClientSessionGroupMapping().getClientGroupMap().get(group).getGroupConsumerSessions(); + } else if (EventMeshConstants.PURPOSE_PUB.equals(purpose)) { + sessionSet = eventMeshTCPServer.getClientSessionGroupMapping().getClientGroupMap().get(group).getGroupProducerSessions(); + } else { + log.warn("doRebalance failed,param is illegal, group:{}, purpose:{}", group, purpose); + return; + } + List sessionList = new ArrayList<>(sessionSet); + Collections.shuffle(new ArrayList<>(sessionList)); + + for (int i = 0; i < judge; i++) { + String newProxyIp = eventMeshRecommendResult.get(i).split(":")[0]; + String newProxyPort = eventMeshRecommendResult.get(i).split(":")[1]; + String redirectSessionAddr = EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer.getTcpThreadPoolGroup(), newProxyIp, + Integer.parseInt(newProxyPort), sessionList.get(i), eventMeshTCPServer.getClientSessionGroupMapping()); + log.info("doRebalance,redirect sessionAddr:{}", redirectSessionAddr); + ThreadUtils.sleep(eventMeshTCPServer.getEventMeshTCPConfiguration().getSleepIntervalInRebalanceRedirectMills(), TimeUnit.MILLISECONDS); + } + log.info("doRebalance redirect end---------------------group:{}", group); + } + + private List selectRedirectEventMesh(String group, Map eventMeshMap, + Map clientDistributionMap, int judge, + String eventMeshName) throws Exception { + EventMeshRecommendStrategy eventMeshRecommendStrategy = new EventMeshRecommendImpl(eventMeshTCPServer); + return eventMeshRecommendStrategy.calculateRedirectRecommendEventMesh(eventMeshMap, clientDistributionMap, + group, judge, eventMeshName); + } + + public int calculateRedirectNum(String eventMeshName, String group, String purpose, Map clientDistributionMap) throws Exception { + int sum = 0; + for (Integer item : clientDistributionMap.values()) { + sum += item; + } + int currentNum = 0; + if (clientDistributionMap.get(eventMeshName) != null) { + currentNum = clientDistributionMap.get(eventMeshName); + } + int avgNum = sum / clientDistributionMap.size(); + int modNum = sum % clientDistributionMap.size(); + + List eventMeshList = new ArrayList<>(clientDistributionMap.keySet()); + Collections.sort(eventMeshList); + int index = -1; + for (int i = 0; i < Math.min(modNum, eventMeshList.size()); i++) { + if (StringUtils.equals(eventMeshName, eventMeshList.get(i))) { + index = i; + break; + } + } + int rebalanceResult = 0; + if (avgNum == 0) { + rebalanceResult = 1; + } else { + rebalanceResult = (modNum != 0 && index < modNum && index >= 0) ? avgNum + 1 : avgNum; + } + log.info("rebalance caculateRedirectNum,group:{}, purpose:{},sum:{},avgNum:{}," + + + "modNum:{}, index:{}, currentNum:{}, rebalanceResult:{}", group, purpose, sum, + avgNum, modNum, index, currentNum, rebalanceResult); + return currentNum - rebalanceResult; + } + + private Map queryLocalEventMeshDistributeData(String cluster, String group, String purpose, + Map eventMeshMap) { + Map localEventMeshDistributeData = null; + Map> eventMeshClientDistributionDataMap = null; + try { + eventMeshClientDistributionDataMap = eventMeshTCPServer.getMetaStorage().findEventMeshClientDistributionData( + cluster, group, purpose); + + if (MapUtils.isEmpty(eventMeshClientDistributionDataMap)) { + log.warn("doRebalance failed,found no distribute data in regitry, cluster:{}, group:{}, purpose:{}", + cluster, group, purpose); + return Collections.emptyMap(); + } + + localEventMeshDistributeData = new HashMap<>(); + String localIdc = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshIDC(); + for (Map.Entry> entry : eventMeshClientDistributionDataMap.entrySet()) { + String idc = entry.getKey().split("-")[0]; + if (StringUtils.isNotBlank(idc) && StringUtils.equals(idc, localIdc)) { + localEventMeshDistributeData.put(entry.getKey(), entry.getValue().get(purpose)); + } + } + + if (0 == localEventMeshDistributeData.size()) { + log.warn("doRebalance failed,found no distribute data of localIDC in regitry,cluster:{},group:{}, purpose:{},localIDC:{}", + cluster, group, purpose, localIdc); + return Collections.emptyMap(); + } + + log.info("before revert clientDistributionMap:{}, group:{}, purpose:{}", localEventMeshDistributeData, + group, purpose); + for (String eventMeshName : localEventMeshDistributeData.keySet()) { + if (!eventMeshMap.containsKey(eventMeshName)) { + log.warn( + "doRebalance failed,exist eventMesh not register but exist in " + + "distributionMap,cluster:{},grpup:{},purpose:{},eventMeshName:{}", + cluster, group, purpose, eventMeshName); + return Collections.emptyMap(); + } + } + for (String eventMesh : eventMeshMap.keySet()) { + if (!localEventMeshDistributeData.containsKey(eventMesh)) { + localEventMeshDistributeData.put(eventMesh, 0); + } + } + log.info("after revert clientDistributionMap:{}, group:{}, purpose:{}", localEventMeshDistributeData, + group, purpose); + } catch (Exception e) { + log.warn("doRebalance failed,cluster:{},group:{},purpose:{},findProxyClientDistributionData failed, errMsg:{}", + cluster, group, purpose, e); + return Collections.emptyMap(); + } + + return localEventMeshDistributeData; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceService.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceService.java index 560cf40e24..913ac31036 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceService.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceService.java @@ -17,38 +17,36 @@ package org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance; +import org.apache.eventmesh.common.EventMeshThreadFactory; import org.apache.eventmesh.common.ThreadPoolFactory; import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.util.EventMeshThreadFactoryImpl; -import org.apache.eventmesh.runtime.util.EventMeshUtil; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class EventMeshRebalanceService { - protected final Logger logger = LoggerFactory.getLogger(EventMeshRebalanceService.class); - private EventMeshTCPServer eventMeshTCPServer; + private final EventMeshTCPServer eventMeshTCPServer; - private Integer rebalanceIntervalMills; + private final Integer rebalanceIntervalMills; - private EventMeshRebalanceStrategy rebalanceStrategy; + private final EventMeshRebalanceStrategy rebalanceStrategy; private ScheduledExecutorService serviceRebalanceScheduler; public EventMeshRebalanceService(EventMeshTCPServer eventMeshTCPServer, EventMeshRebalanceStrategy rebalanceStrategy) { this.eventMeshTCPServer = eventMeshTCPServer; this.rebalanceStrategy = rebalanceStrategy; - this.rebalanceIntervalMills = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpRebalanceIntervalInMills; + this.rebalanceIntervalMills = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpRebalanceIntervalInMills(); } public void init() { - this.serviceRebalanceScheduler = ThreadPoolFactory.createScheduledExecutor(5, new EventMeshThreadFactoryImpl("proxy-rebalance-sch", true)); - logger.info("rebalance service inited......"); + this.serviceRebalanceScheduler = ThreadPoolFactory.createScheduledExecutor(5, new EventMeshThreadFactory("proxy-rebalance-sch", true)); + log.info("rebalance service inited ......"); } public void start() throws Exception { @@ -57,18 +55,18 @@ public void start() throws Exception { try { rebalanceStrategy.doRebalance(); } catch (Exception ex) { - logger.error("RebalanceByService failed", ex); + log.error("RebalanceByService failed", ex); } }, rebalanceIntervalMills, rebalanceIntervalMills, TimeUnit.MILLISECONDS); - logger.info("rebalance service started......"); + log.info("rebalance service started......"); } public void shutdown() { this.serviceRebalanceScheduler.shutdown(); - logger.info("rebalance service shutdown......"); + log.info("rebalance service shutdown......"); } - public void printRebalanceThreadPoolState() { - EventMeshUtil.printState((ThreadPoolExecutor) serviceRebalanceScheduler); + public int getRebalanceThreadPoolQueueSize() { + return ((ThreadPoolExecutor) serviceRebalanceScheduler).getQueue().size(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceStrategy.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceStrategy.java index b14e602a82..6f1753c571 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceStrategy.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventMeshRebalanceStrategy.java @@ -21,5 +21,6 @@ * EventMeshRebalanceStrategy */ public interface EventMeshRebalanceStrategy { + void doRebalance() throws Exception; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventmeshRebalanceImpl.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventmeshRebalanceImpl.java deleted file mode 100644 index ad787f8e70..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/rebalance/EventmeshRebalanceImpl.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.rebalance; - -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendStrategy; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; - -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventmeshRebalanceImpl implements EventMeshRebalanceStrategy { - - protected final Logger logger = LoggerFactory.getLogger(EventmeshRebalanceImpl.class); - - private EventMeshTCPServer eventMeshTCPServer; - - public EventmeshRebalanceImpl(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - @Override - public void doRebalance() throws Exception { - long startTime = System.currentTimeMillis(); - logger.info("doRebalance start===========startTime:{}", startTime); - - Set groupSet = eventMeshTCPServer.getClientSessionGroupMapping().getClientGroupMap().keySet(); - if (CollectionUtils.isEmpty(groupSet)) { - logger.warn("doRebalance failed,eventmesh has no group, please check eventmeshData"); - return; - } - - final String cluster = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshCluster; - //get eventmesh of local idc - Map localEventMeshMap = queryLocalEventMeshMap(cluster); - if (localEventMeshMap == null || localEventMeshMap.size() == 0) { - return; - } - - for (String group : groupSet) { - doRebalanceByGroup(cluster, group, EventMeshConstants.PURPOSE_SUB, localEventMeshMap); - doRebalanceByGroup(cluster, group, EventMeshConstants.PURPOSE_PUB, localEventMeshMap); - } - logger.info("doRebalance end===========startTime:{}, cost:{}", startTime, System.currentTimeMillis() - startTime); - } - - private Map queryLocalEventMeshMap(String cluster) { - Map localEventMeshMap = null; - List eventMeshDataInfoList = null; - try { - eventMeshDataInfoList = eventMeshTCPServer.getRegistry().findEventMeshInfoByCluster(cluster); - - if (eventMeshDataInfoList == null || CollectionUtils.isEmpty(eventMeshDataInfoList)) { - logger.warn("doRebalance failed,query eventmesh instances is null from registry,cluster:{}", cluster); - return null; - } - localEventMeshMap = new HashMap<>(); - String localIdc = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshIDC; - for (EventMeshDataInfo eventMeshDataInfo : eventMeshDataInfoList) { - String idc = eventMeshDataInfo.getEventMeshName().split("-")[0]; - if (StringUtils.isNotBlank(idc) && StringUtils.equals(idc, localIdc)) { - localEventMeshMap.put(eventMeshDataInfo.getEventMeshName(), eventMeshDataInfo.getEndpoint()); - } - } - - if (0 == localEventMeshMap.size()) { - logger.warn("doRebalance failed,query eventmesh instances of localIDC is null from registry,localIDC:{},cluster:{}", - localIdc, cluster); - return null; - } - } catch (Exception e) { - logger.warn("doRebalance failed,findEventMeshInfoByCluster failed,cluster:{},errMsg:{}", cluster, e); - return null; - } - - return localEventMeshMap; - } - - private void doRebalanceByGroup(String cluster, String group, String purpose, Map eventMeshMap) throws Exception { - logger.info("doRebalanceByGroup start, cluster:{}, group:{}, purpose:{}", cluster, group, purpose); - - //query distribute data of loacl idc - Map clientDistributionMap = queryLocalEventMeshDistributeData(cluster, group, purpose, - eventMeshMap); - if (clientDistributionMap == null || clientDistributionMap.size() == 0) { - return; - } - - doRebalanceRedirect(eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshName, group, purpose, - eventMeshMap, clientDistributionMap); - logger.info("doRebalanceByGroup end, cluster:{}, group:{}, purpose:{}", cluster, group, purpose); - - } - - private void doRebalanceRedirect(String currEventMeshName, String group, String purpose, Map eventMeshMap, - Map clientDistributionMap) throws Exception { - if (clientDistributionMap == null || clientDistributionMap.size() == 0) { - return; - } - - //caculate client num need to redirect in currEventMesh - int judge = caculateRedirectNum(currEventMeshName, group, purpose, clientDistributionMap); - - if (judge > 0) { - - //select redirect target eventmesh lisg - List eventMeshRecommendResult = selectRedirectEventMesh(group, eventMeshMap, clientDistributionMap, - judge, currEventMeshName); - if (eventMeshRecommendResult == null || eventMeshRecommendResult.size() != judge) { - logger.warn("doRebalance failed,recommendEventMeshNum is not consistent,recommendResult:{},judge:{}", - eventMeshRecommendResult, judge); - return; - } - - //do redirect - doRedirect(group, purpose, judge, eventMeshRecommendResult); - } else { - logger.info("rebalance condition not satisfy,group:{}, purpose:{},judge:{}", group, purpose, judge); - } - } - - private void doRedirect(String group, String purpose, int judge, List eventMeshRecommendResult) throws Exception { - logger.info("doRebalance redirect start---------------------group:{},judge:{}", group, judge); - Set sessionSet = null; - if (EventMeshConstants.PURPOSE_SUB.equals(purpose)) { - sessionSet = eventMeshTCPServer.getClientSessionGroupMapping().getClientGroupMap().get(group).getGroupConsumerSessions(); - } else if (EventMeshConstants.PURPOSE_PUB.equals(purpose)) { - sessionSet = eventMeshTCPServer.getClientSessionGroupMapping().getClientGroupMap().get(group).getGroupProducerSessions(); - } else { - logger.warn("doRebalance failed,param is illegal, group:{}, purpose:{}", group, purpose); - return; - } - List sessionList = new ArrayList<>(sessionSet); - Collections.shuffle(new ArrayList<>(sessionList)); - - for (int i = 0; i < judge; i++) { - String newProxyIp = eventMeshRecommendResult.get(i).split(":")[0]; - String newProxyPort = eventMeshRecommendResult.get(i).split(":")[1]; - String redirectSessionAddr = EventMeshTcp2Client.redirectClient2NewEventMesh(eventMeshTCPServer, newProxyIp, - Integer.parseInt(newProxyPort), sessionList.get(i), eventMeshTCPServer.getClientSessionGroupMapping()); - logger.info("doRebalance,redirect sessionAddr:{}", redirectSessionAddr); - try { - Thread.sleep(eventMeshTCPServer.getEventMeshTCPConfiguration().sleepIntervalInRebalanceRedirectMills); - } catch (InterruptedException e) { - logger.warn("Thread.sleep occur InterruptedException", e); - } - } - logger.info("doRebalance redirect end---------------------group:{}", group); - } - - private List selectRedirectEventMesh(String group, Map eventMeshMap, - Map clientDistributionMap, int judge, - String evenMeshName) throws Exception { - EventMeshRecommendStrategy eventMeshRecommendStrategy = new EventMeshRecommendImpl(eventMeshTCPServer); - return eventMeshRecommendStrategy.calculateRedirectRecommendEventMesh(eventMeshMap, clientDistributionMap, - group, judge, evenMeshName); - } - - public int caculateRedirectNum(String eventMeshName, String group, String purpose, - Map clientDistributionMap) throws Exception { - int sum = 0; - for (Integer item : clientDistributionMap.values()) { - sum += item; - } - int currentNum = 0; - if (clientDistributionMap.get(eventMeshName) != null) { - currentNum = clientDistributionMap.get(eventMeshName); - } - int avgNum = sum / clientDistributionMap.size(); - int modNum = sum % clientDistributionMap.size(); - - List eventMeshList = new ArrayList<>(clientDistributionMap.keySet()); - Collections.sort(eventMeshList); - int index = -1; - for (int i = 0; i < Math.min(modNum, eventMeshList.size()); i++) { - if (StringUtils.equals(eventMeshName, eventMeshList.get(i))) { - index = i; - break; - } - } - int rebalanceResult = 0; - if (avgNum == 0) { - rebalanceResult = 1; - } else { - rebalanceResult = (modNum != 0 && index < modNum && index >= 0) ? avgNum + 1 : avgNum; - } - logger.info("rebalance caculateRedirectNum,group:{}, purpose:{},sum:{},avgNum:{}," - + - "modNum:{}, index:{}, currentNum:{}, rebalanceResult:{}", group, purpose, sum, - avgNum, modNum, index, currentNum, rebalanceResult); - return currentNum - rebalanceResult; - } - - private Map queryLocalEventMeshDistributeData(String cluster, String group, String purpose, - Map eventMeshMap) { - Map localEventMeshDistributeData = null; - Map> eventMeshClientDistributionDataMap = null; - try { - eventMeshClientDistributionDataMap = eventMeshTCPServer.getRegistry().findEventMeshClientDistributionData( - cluster, group, purpose); - - if (eventMeshClientDistributionDataMap == null || eventMeshClientDistributionDataMap.size() == 0) { - logger.warn("doRebalance failed,found no distribute data in regitry, cluster:{}, group:{}, purpose:{}", - cluster, group, purpose); - return null; - } - - localEventMeshDistributeData = new HashMap<>(); - String localIdc = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshIDC; - for (Map.Entry> entry : eventMeshClientDistributionDataMap.entrySet()) { - String idc = entry.getKey().split("-")[0]; - if (StringUtils.isNotBlank(idc) && StringUtils.equals(idc, localIdc)) { - localEventMeshDistributeData.put(entry.getKey(), entry.getValue().get(purpose)); - } - } - - if (0 == localEventMeshDistributeData.size()) { - logger.warn("doRebalance failed,found no distribute data of localIDC in regitry,cluster:{},group:{}, purpose:{},localIDC:{}", - cluster, group, purpose, localIdc); - return null; - } - - logger.info("before revert clientDistributionMap:{}, group:{}, purpose:{}", localEventMeshDistributeData, - group, purpose); - for (String eventMeshName : localEventMeshDistributeData.keySet()) { - if (!eventMeshMap.keySet().contains(eventMeshName)) { - logger.warn( - "doRebalance failed,exist eventMesh not register but exist in " - + "distributionMap,cluster:{},grpup:{},purpose:{},eventMeshName:{}", - cluster, group, purpose, eventMeshName); - return null; - } - } - for (String eventMesh : eventMeshMap.keySet()) { - if (!localEventMeshDistributeData.keySet().contains(eventMesh)) { - localEventMeshDistributeData.put(eventMesh, 0); - } - } - logger.info("after revert clientDistributionMap:{}, group:{}, purpose:{}", localEventMeshDistributeData, - group, purpose); - } catch (Exception e) { - logger.warn("doRebalance failed,cluster:{},group:{},purpose:{},findProxyClientDistributionData failed, errMsg:{}", - cluster, group, purpose, e); - return null; - } - - return localEventMeshDistributeData; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendImpl.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendImpl.java index 290e3d4ffb..678e1f4c30 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendImpl.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendImpl.java @@ -17,7 +17,7 @@ package org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; import org.apache.eventmesh.runtime.util.ValueComparator; @@ -30,189 +30,191 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class EventMeshRecommendImpl implements EventMeshRecommendStrategy { - protected final Logger logger = LoggerFactory.getLogger(EventMeshRecommendImpl.class); + private static final int DEFAULT_PROXY_NUM = 1; - private EventMeshTCPServer eventMeshTCPServer; + private final transient EventMeshTCPServer eventMeshTCPServer; - public EventMeshRecommendImpl(EventMeshTCPServer eventMeshTCPServer) { + public EventMeshRecommendImpl(final EventMeshTCPServer eventMeshTCPServer) { this.eventMeshTCPServer = eventMeshTCPServer; } @Override - public String calculateRecommendEventMesh(String group, String purpose) throws Exception { - List eventMeshDataInfoList = null; - if (StringUtils.isBlank(group) || StringUtils.isBlank(purpose)) { - logger.warn("EventMeshRecommend failed,params illegal,group:{},purpose:{}", group, purpose); + public String calculateRecommendEventMesh(final String group, final String purpose) throws Exception { + List eventMeshDataInfoList; + + if (StringUtils.isAnyBlank(group, purpose)) { + log.warn("EventMeshRecommend failed,params illegal,group:{},purpose:{}", group, purpose); return null; } - final String cluster = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshCluster; + + final String cluster = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshCluster(); try { - eventMeshDataInfoList = eventMeshTCPServer.getRegistry().findEventMeshInfoByCluster(cluster); + eventMeshDataInfoList = eventMeshTCPServer.getMetaStorage().findEventMeshInfoByCluster(cluster); } catch (Exception e) { - logger.warn("EventMeshRecommend failed, findEventMeshInfoByCluster failed, cluster:{}, group:{}, purpose:{}, errMsg:{}", - cluster, group, purpose, e); + log.warn("EventMeshRecommend failed, findEventMeshInfoByCluster failed, cluster:{}, group:{}, purpose:{}, errMsg:{}", + cluster, group, purpose, e); return null; } - if (eventMeshDataInfoList == null || CollectionUtils.isEmpty(eventMeshDataInfoList)) { - logger.warn("EventMeshRecommend failed,not find eventMesh instances from registry,cluster:{},group:{},purpose:{}", - cluster, group, purpose); + if (CollectionUtils.isEmpty(eventMeshDataInfoList)) { + log.warn("EventMeshRecommend failed, not find eventMesh instances from registry, cluster:{},group:{},purpose:{}", + cluster, group, purpose); return null; } - Map localEventMeshMap = new HashMap<>(); - Map remoteEventMeshMap = new HashMap<>(); - String localIdc = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshIDC; - for (EventMeshDataInfo eventMeshDataInfo : eventMeshDataInfoList) { + final Map localEventMeshMap = new HashMap<>(); + final Map remoteEventMeshMap = new HashMap<>(); + final String localIdc = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshIDC(); + for (final EventMeshDataInfo eventMeshDataInfo : eventMeshDataInfoList) { String idc = eventMeshDataInfo.getEventMeshName().split("-")[0]; if (StringUtils.isNotBlank(idc)) { - if (StringUtils.equals(idc, localIdc)) { - localEventMeshMap.put(eventMeshDataInfo.getEventMeshName(), eventMeshDataInfo.getEndpoint()); - } else { - remoteEventMeshMap.put(eventMeshDataInfo.getEventMeshName(), eventMeshDataInfo.getEndpoint()); - } + final String dummy = StringUtils.equals(idc, localIdc) + ? localEventMeshMap.put(eventMeshDataInfo.getEventMeshName(), eventMeshDataInfo.getEndpoint()) + : remoteEventMeshMap.put(eventMeshDataInfo.getEventMeshName(), eventMeshDataInfo.getEndpoint()); } else { - logger.error("EventMeshName may be illegal,idc is null,eventMeshName:{}", eventMeshDataInfo.getEventMeshName()); + log.error("EventMeshName may be illegal,idc is null,eventMeshName:{}", eventMeshDataInfo.getEventMeshName()); } } - if (localEventMeshMap.size() == 0 && remoteEventMeshMap.size() == 0) { - logger.warn("EventMeshRecommend failed,find no legal eventMesh instances from registry,localIDC:{}", localIdc); - return null; - } - if (localEventMeshMap.size() > 0) { - //recommend eventmesh of local idc + if (MapUtils.isNotEmpty(localEventMeshMap)) { + // recommend eventmesh of local idc return recommendProxyByDistributeData(cluster, group, purpose, localEventMeshMap, true); - } else if (remoteEventMeshMap.size() > 0) { - //recommend eventmesh of other idc + } else if (MapUtils.isNotEmpty(remoteEventMeshMap)) { + // recommend eventmesh of other idc return recommendProxyByDistributeData(cluster, group, purpose, remoteEventMeshMap, false); } else { - logger.error("localEventMeshMap or remoteEventMeshMap size error"); + log.error("localEventMeshMap or remoteEventMeshMap size error"); return null; } } @Override - public List calculateRedirectRecommendEventMesh(Map eventMeshMap, - Map clientDistributeMap, String group, - int recommendProxyNum, String eventMeshName) throws Exception { - if (recommendProxyNum < 1) { - return null; - } - logger.info("eventMeshMap:{},clientDistributionMap:{},group:{},recommendNum:{},currEventMeshName:{}", - eventMeshMap, clientDistributeMap, group, recommendProxyNum, eventMeshName); - //find eventmesh with least client - List> list = new ArrayList<>(); - ValueComparator vc = new ValueComparator(); - for (Map.Entry entry : clientDistributeMap.entrySet()) { - list.add(entry); + public List calculateRedirectRecommendEventMesh(final Map eventMeshMap, + final Map clientDistributedMap, + final String group, + final int recommendProxyNum, + final String eventMeshName) throws Exception { + Objects.requireNonNull(eventMeshMap, "eventMeshMap can not be null"); + Objects.requireNonNull(clientDistributedMap, "clientDistributedMap can not be null"); + + if (recommendProxyNum < DEFAULT_PROXY_NUM || MapUtils.isEmpty(clientDistributedMap)) { + return new ArrayList(); } - Collections.sort(list, vc); - logger.info("clientDistributionMap after sort:{}", list); - List recommendProxyList = new ArrayList<>(recommendProxyNum); + log.info("eventMeshMap:{},clientDistributionMap:{},group:{},recommendNum:{},currEventMeshName:{}", + eventMeshMap, clientDistributedMap, group, recommendProxyNum, eventMeshName); + + // find eventmesh with the least client + final List> clientDistributedList = new ArrayList<>(); + final ValueComparator vc = new ValueComparator(); + clientDistributedMap.entrySet().forEach(clientDistributedList::add); + Collections.sort(clientDistributedList, vc); + + log.info("clientDistributedLists after sort:{}", clientDistributedList); + + final List recommendProxyList = new ArrayList<>(recommendProxyNum); while (recommendProxyList.size() < recommendProxyNum) { - Map.Entry minProxyItem = list.get(0); - int currProxyNum = clientDistributeMap.get(eventMeshName); + final Map.Entry minProxyItem = clientDistributedList.get(0); + final int currProxyNum = clientDistributedMap.get(eventMeshName); recommendProxyList.add(eventMeshMap.get(minProxyItem.getKey())); - clientDistributeMap.put(minProxyItem.getKey(), minProxyItem.getValue() + 1); - clientDistributeMap.put(eventMeshName, currProxyNum - 1); - Collections.sort(list, vc); - logger.info("clientDistributionMap after sort:{}", list); + clientDistributedMap.put(minProxyItem.getKey(), minProxyItem.getValue() + 1); + clientDistributedMap.put(eventMeshName, currProxyNum - 1); + Collections.sort(clientDistributedList, vc); + log.info("clientDistributedList after sort:{}", clientDistributedList); } - logger.info("choose proxys with min instance num, group:{}, recommendProxyNum:{}, recommendProxyList:{}", - group, recommendProxyNum, recommendProxyList); + + log.info("choose proxys with min instance num, group:{}, recommendProxyNum:{}, recommendProxyList:{}", + group, recommendProxyNum, recommendProxyList); return recommendProxyList; } - private String recommendProxyByDistributeData(String cluster, String group, String purpose, - Map eventMeshMap, boolean caculateLocal) { - logger.info("eventMeshMap:{},cluster:{},group:{},purpose:{},caculateLocal:{}", eventMeshMap, cluster, - group, purpose, caculateLocal); + private String recommendProxyByDistributeData(final String cluster, final String group, final String purpose, + final Map eventMeshMap, final boolean caculateLocal) { + Objects.requireNonNull(eventMeshMap, "eventMeshMap can not be null"); + + log.info("eventMeshMap:{},cluster:{},group:{},purpose:{},caculateLocal:{}", eventMeshMap, cluster, group, purpose, caculateLocal); - String recommendProxyAddr = null; - List tmpProxyAddrList = null; Map> eventMeshClientDistributionDataMap = null; try { - eventMeshClientDistributionDataMap = eventMeshTCPServer.getRegistry().findEventMeshClientDistributionData( - cluster, group, purpose); + eventMeshClientDistributionDataMap = eventMeshTCPServer.getMetaStorage().findEventMeshClientDistributionData( + cluster, group, purpose); } catch (Exception e) { - logger.warn("EventMeshRecommend failed,findEventMeshClientDistributionData failed," - + "cluster:{},group:{},purpose:{}, errMsg:{}", cluster, group, purpose, e); + log.warn("EventMeshRecommend failed,findEventMeshClientDistributionData failed," + + "cluster:{},group:{},purpose:{}, errMsg:{}", cluster, group, purpose, e); } - if (eventMeshClientDistributionDataMap == null || MapUtils.isEmpty(eventMeshClientDistributionDataMap)) { - tmpProxyAddrList = new ArrayList<>(eventMeshMap.values()); + String recommendProxyAddr; + if (MapUtils.isEmpty(eventMeshClientDistributionDataMap)) { + final List tmpProxyAddrList = new ArrayList<>(eventMeshMap.values()); + if (CollectionUtils.isEmpty(tmpProxyAddrList)) { + return null; + } + Collections.shuffle(tmpProxyAddrList); recommendProxyAddr = tmpProxyAddrList.get(0); - logger.info("No distribute data in registry,cluster:{}, group:{},purpose:{}, recommendProxyAddr:{}", - cluster, group, purpose, recommendProxyAddr); + log.info("No distribute data in registry,cluster:{}, group:{},purpose:{}, recommendProxyAddr:{}", + cluster, group, purpose, recommendProxyAddr); return recommendProxyAddr; } - Map localClientDistributionMap = new HashMap<>(); - Map remoteClientDistributionMap = new HashMap<>(); - for (Map.Entry> entry : eventMeshClientDistributionDataMap.entrySet()) { - String idc = entry.getKey().split("-")[0]; + final Map localClientDistributionMap = new HashMap<>(); + final Map remoteClientDistributionMap = new HashMap<>(); + + eventMeshClientDistributionDataMap.entrySet().forEach(entry -> { + final String idc = entry.getKey().split("-")[0]; if (StringUtils.isNotBlank(idc)) { - if (StringUtils.equals(idc, eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshIDC)) { + if (StringUtils.equals(idc, eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshIDC())) { localClientDistributionMap.put(entry.getKey(), entry.getValue().get(purpose)); } else { remoteClientDistributionMap.put(entry.getKey(), entry.getValue().get(purpose)); } } else { - logger.error("eventMeshName may be illegal,idc is null,eventMeshName:{}", entry.getKey()); + log.error("eventMeshName may be illegal,idc is null,eventMeshName:{}", entry.getKey()); } - } + }); + recommendProxyAddr = recommendProxy(eventMeshMap, (caculateLocal == true) ? localClientDistributionMap - : remoteClientDistributionMap, group); + : remoteClientDistributionMap, group); + + log.info("eventMeshMap:{},group:{},purpose:{},caculateLocal:{},recommendProxyAddr:{}", + eventMeshMap, group, purpose, caculateLocal, recommendProxyAddr); - logger.info("eventMeshMap:{},group:{},purpose:{},caculateLocal:{},recommendProxyAddr:{}", eventMeshMap, - group, purpose, caculateLocal, recommendProxyAddr); return recommendProxyAddr; } - private String recommendProxy(Map eventMeshMap, Map clientDistributionMap, String group) { - logger.info("eventMeshMap:{},clientDistributionMap:{},group:{}", eventMeshMap, clientDistributionMap, group); - String recommendProxy = null; + private String recommendProxy(final Map eventMeshMap, + final Map clientDistributionMap, + final String group) { + Objects.requireNonNull(eventMeshMap, "eventMeshMap can not be null"); + Objects.requireNonNull(clientDistributionMap, "clientDistributionMap can not be null"); - for (String proxyName : clientDistributionMap.keySet()) { - if (!eventMeshMap.keySet().contains(proxyName)) { - logger.warn("exist proxy not register but exist in distributionMap,proxy:{}", proxyName); - return null; - } - } - for (String proxy : eventMeshMap.keySet()) { - if (!clientDistributionMap.keySet().contains(proxy)) { - clientDistributionMap.put(proxy, 0); - } - } + log.info("eventMeshMap:{},clientDistributionMap:{},group:{}", eventMeshMap, clientDistributionMap, group); - //select the eventmesh with least instances - List> list = new ArrayList<>(); - ValueComparator vc = new ValueComparator(); - for (Map.Entry entry : clientDistributionMap.entrySet()) { - list.add(entry); + if (!eventMeshMap.keySet().containsAll(clientDistributionMap.keySet())) { + log.warn("exist proxy not register but exist in distributionMap"); + return null; } - if (list.size() == 0) { - logger.error("no legal distribute data,check eventMeshMap and distributeData, group:{}", group); + + eventMeshMap.keySet().forEach(proxy -> clientDistributionMap.putIfAbsent(proxy, 0)); + + // select the eventmesh with least instances + if (MapUtils.isEmpty(clientDistributionMap)) { + log.error("no legal distribute data,check eventMeshMap and distributeData, group:{}", group); return null; } else { - Collections.sort(list, vc); - logger.info("clientDistributionMap after sort:{}", list); - recommendProxy = eventMeshMap.get(list.get(0).getKey()); - return recommendProxy; + final List> list = new ArrayList<>(); + clientDistributionMap.entrySet().forEach(list::add); + Collections.sort(list, new ValueComparator()); + log.info("clientDistributionMap after sort:{}", list); + return eventMeshMap.get(list.get(0).getKey()); } } - private List calculate(Map proxyMap, Map clientDistributionMap, - String group, int recommendProxyNum) { - return null; - } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendStrategy.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendStrategy.java index 515cf3bc83..9a916aa42b 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendStrategy.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/recommend/EventMeshRecommendStrategy.java @@ -24,9 +24,10 @@ * EventMeshRecommendStrategy */ public interface EventMeshRecommendStrategy { + String calculateRecommendEventMesh(String group, String purpose) throws Exception; List calculateRedirectRecommendEventMesh(Map eventMeshMap, - Map clientDistributeMap, String group, - int recommendNum, String eventMeshName) throws Exception; + Map clientDistributeMap, String group, + int recommendNum, String eventMeshName) throws Exception; } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/Session.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/Session.java index 5c7234e02f..e061f61c29 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/Session.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/Session.java @@ -25,6 +25,8 @@ import org.apache.eventmesh.common.protocol.tcp.OPStatus; import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientGroupWrapper; @@ -39,7 +41,11 @@ import java.lang.ref.WeakReference; import java.net.InetSocketAddress; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.locks.ReentrantLock; import org.slf4j.Logger; @@ -50,153 +56,115 @@ import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -public class Session { +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; - protected final Logger messageLogger = LoggerFactory.getLogger("message"); +@Slf4j +public class Session { - private final Logger subscribeLogger = LoggerFactory.getLogger("subscribeLogger"); + protected static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final Logger SUBSCRIB_LOGGER = LoggerFactory.getLogger("subscribeLogger"); + @Setter + @Getter private UserAgent client; + @Setter + @Getter private InetSocketAddress remoteAddress; + @Setter + @Getter protected ChannelHandlerContext context; + @Setter + @Getter private WeakReference clientGroupWrapper; + @Setter + @Getter private EventMeshTCPConfiguration eventMeshTCPConfiguration; + @Setter + @Getter private SessionPusher pusher; + @Setter + @Getter private SessionSender sender; - private long createTime = System.currentTimeMillis(); + private final long createTime = System.currentTimeMillis(); + @Setter + @Getter private long lastHeartbeatTime = System.currentTimeMillis(); - private long isolateTime = 0; + @Setter + @Getter + private long isolateTime; + @Setter + @Getter private SessionContext sessionContext = new SessionContext(this); - private boolean listenRspSend = false; + private volatile boolean listenRspSend; - private ReentrantLock listenRspLock = new ReentrantLock(); + private final ReentrantLock listenRspLock = new ReentrantLock(); - private String listenRequestSeq = null; + @Setter + @Getter + private String listenRequestSeq; + @Setter + @Getter protected SessionState sessionState = SessionState.CREATED; - public InetSocketAddress getRemoteAddress() { - return remoteAddress; - } - - public void setRemoteAddress(InetSocketAddress remoteAddress) { - this.remoteAddress = remoteAddress; - } - - public long getLastHeartbeatTime() { - return lastHeartbeatTime; - } + @Setter + @Getter + private String sessionId = UUID.randomUUID().toString(); public void notifyHeartbeat(long heartbeatTime) throws Exception { this.lastHeartbeatTime = heartbeatTime; } - public SessionState getSessionState() { - return sessionState; - } - - public void setSessionState(SessionState sessionState) { - this.sessionState = sessionState; - } - - public void setClient(UserAgent client) { - this.client = client; - } - - public SessionPusher getPusher() { - return pusher; - } - - public void setPusher(SessionPusher pusher) { - this.pusher = pusher; - } - - public SessionSender getSender() { - return sender; - } - - public void setSender(SessionSender sender) { - this.sender = sender; - } - - public void setLastHeartbeatTime(long lastHeartbeatTime) { - this.lastHeartbeatTime = lastHeartbeatTime; - } - - public SessionContext getSessionContext() { - return sessionContext; - } - - public void setSessionContext(SessionContext sessionContext) { - this.sessionContext = sessionContext; - } - - public ChannelHandlerContext getContext() { - return context; - } - - public void setContext(ChannelHandlerContext context) { - this.context = context; - } - - public UserAgent getClient() { - return client; - } - - public String getListenRequestSeq() { - return listenRequestSeq; - } - - public void setListenRequestSeq(String listenRequestSeq) { - this.listenRequestSeq = listenRequestSeq; - } - public void subscribe(List items) throws Exception { for (SubscriptionItem item : items) { - sessionContext.subscribeTopics.putIfAbsent(item.getTopic(), item); - clientGroupWrapper.get().subscribe(item); + sessionContext.getSubscribeTopics().putIfAbsent(item.getTopic(), item); + Objects.requireNonNull(clientGroupWrapper.get()).subscribe(item); - clientGroupWrapper.get().getMqProducerWrapper().getMeshMQProducer().checkTopicExist(item.getTopic()); + Objects.requireNonNull(clientGroupWrapper.get()).getMqProducerWrapper().getMeshMQProducer() + .checkTopicExist(item.getTopic()); - clientGroupWrapper.get().addSubscription(item, this); - subscribeLogger.info("subscribe|succeed|topic={}|user={}", item.getTopic(), client); + Objects.requireNonNull(clientGroupWrapper.get()).addSubscription(item, this); + SUBSCRIB_LOGGER.info("subscribe|succeed|topic={}|user={}", item.getTopic(), client); } } public void unsubscribe(List items) throws Exception { for (SubscriptionItem item : items) { - sessionContext.subscribeTopics.remove(item.getTopic()); - clientGroupWrapper.get().removeSubscription(item, this); + sessionContext.getSubscribeTopics().remove(item.getTopic()); + Objects.requireNonNull(clientGroupWrapper.get()).removeSubscription(item, this); - if (!clientGroupWrapper.get().hasSubscription(item.getTopic())) { - clientGroupWrapper.get().unsubscribe(item); - subscribeLogger.info("unSubscribe|succeed|topic={}|lastUser={}", item.getTopic(), client); + if (!Objects.requireNonNull(clientGroupWrapper.get()).hasSubscription(item.getTopic())) { + Objects.requireNonNull(clientGroupWrapper.get()).unsubscribe(item); + SUBSCRIB_LOGGER.info("unSubscribe|succeed|topic={}|lastUser={}", item.getTopic(), client); } } } - public EventMeshTcpSendResult upstreamMsg(Header header, CloudEvent event, SendCallback sendCallback, long startTime, long taskExecuteTime) { + public EventMeshTcpSendResult upstreamMsg(Header header, CloudEvent event, SendCallback sendCallback, + long startTime, long taskExecuteTime) { String topic = event.getSubject(); - sessionContext.sendTopics.putIfAbsent(topic, topic); + sessionContext.getSendTopics().putIfAbsent(topic, topic); return sender.send(header, event, sendCallback, startTime, taskExecuteTime); } public void downstreamMsg(DownStreamMsgContext downStreamMsgContext) { long currTime = System.currentTimeMillis(); - trySendListenResponse(new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), "succeed", getListenRequestSeq()), currTime, currTime); + trySendListenResponse(new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), "succeed", + getListenRequestSeq()), currTime, currTime); pusher.push(downStreamMsgContext); } @@ -208,48 +176,41 @@ public boolean isIsolated() { public void write2Client(final Package pkg) { try { - if (SessionState.CLOSED.equals(sessionState)) { + if (SessionState.CLOSED == sessionState) { return; } + context.writeAndFlush(pkg).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (!future.isSuccess()) { - messageLogger.error("write2Client fail, pkg[{}] session[{}]", pkg, this); - } else { - clientGroupWrapper.get().getEventMeshTcpMonitor().getTcpSummaryMetrics().getEventMesh2clientMsgNum() - .incrementAndGet(); - } + new ChannelFutureListener() { + + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + MESSAGE_LOGGER.error("write2Client fail, pkg[{}] session[{}]", pkg, this); + } else { + Objects.requireNonNull(clientGroupWrapper.get()) + .getEventMeshTcpMetricsManager().eventMesh2clientMsgNumIncrement(IPUtils.parseChannelRemoteAddr(future.channel())); } } - ); + }); } catch (Exception e) { - logger.error("exception while write2Client", e); + log.error("exception while write2Client", e); } } @Override public String toString() { - return "Session{" - + - "sysId=" + clientGroupWrapper.get().getSysId() - + - ",remoteAddr=" + RemotingHelper.parseSocketAddressAddr(remoteAddress) - + - ",client=" + client - + - ",sessionState=" + sessionState - + - ",sessionContext=" + sessionContext - + - ",pusher=" + pusher - + - ",sender=" + sender - + - ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) - + - ",lastHeartbeatTime=" + DateFormatUtils.format(lastHeartbeatTime, EventMeshConstants.DATE_FORMAT) + '}'; + Map sessionJson = new HashMap<>(); + sessionJson.put("sysId", Objects.requireNonNull(clientGroupWrapper.get()).getSysId()); + sessionJson.put("remoteAddr", RemotingHelper.parseSocketAddressAddr(remoteAddress)); + sessionJson.put("client", client); + sessionJson.put("sessionState", sessionState); + sessionJson.put("sessionContext", sessionContext); + sessionJson.put("pusher", pusher); + sessionJson.put("sender", sender); + sessionJson.put("createTime", DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT)); + sessionJson.put("lastHeartbeatTime", DateFormatUtils.format(lastHeartbeatTime, EventMeshConstants.DATE_FORMAT)); + return JsonUtils.toJSONString(sessionJson); } @Override @@ -261,24 +222,32 @@ public boolean equals(Object o) { return false; } Session session = (Session) o; - if (client != null ? !client.equals(session.client) : session.client != null) { + if (!Objects.equals(client, session.client)) { return false; } - if (context != null ? !context.equals(session.context) : session.context != null) { + if (!Objects.equals(context, session.context)) { return false; } - if (sessionState != null ? !sessionState.equals(session.sessionState) : session.sessionState != null) { - return false; - } - return true; - } - public WeakReference getClientGroupWrapper() { - return clientGroupWrapper; + return Objects.equals(sessionState, session.sessionState); + } - public void setClientGroupWrapper(WeakReference clientGroupWrapper) { - this.clientGroupWrapper = clientGroupWrapper; + @Override + public int hashCode() { + int result = 1001; // primeNumber + if (client != null) { + result += 31 * result + Objects.hash(client); + } + + if (context != null) { + result += 31 * result + Objects.hash(context); + } + + if (sessionState != null) { + result += 31 * result + Objects.hash(sessionState); + } + return result; } public Session(UserAgent client, ChannelHandlerContext context, EventMeshTCPConfiguration eventMeshTCPConfiguration) { @@ -290,49 +259,35 @@ public Session(UserAgent client, ChannelHandlerContext context, EventMeshTCPConf this.pusher = new SessionPusher(this); } - public EventMeshTCPConfiguration getEventMeshTCPConfiguration() { - return eventMeshTCPConfiguration; - } - - public void setEventMeshTCPConfiguration(EventMeshTCPConfiguration eventMeshTCPConfiguration) { - this.eventMeshTCPConfiguration = eventMeshTCPConfiguration; - } - public void trySendListenResponse(Header header, long startTime, long taskExecuteTime) { - if (!listenRspSend) { - if (listenRspLock.tryLock()) { - if (!listenRspSend) { - if (header == null) { - header = new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), "succeed", null); - } - Package msg = new Package(); - msg.setHeader(header); - - // TODO: if startTime is modified - Utils.writeAndFlush(msg, startTime, taskExecuteTime, context, this); - listenRspSend = true; + if (!listenRspSend && listenRspLock.tryLock()) { + try { + if (listenRspSend) { + return; } + if (header == null) { + header = new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), "succeed", null); + } + Package msg = new Package(); + msg.setHeader(header); + + // TODO: if startTime is modified + Utils.writeAndFlush(msg, startTime, taskExecuteTime, context, this); + listenRspSend = true; + } finally { listenRspLock.unlock(); } } } - public long getIsolateTime() { - return isolateTime; - } - - public void setIsolateTime(long isolateTime) { - this.isolateTime = isolateTime; - } - public boolean isAvailable(String topic) { if (SessionState.CLOSED == sessionState) { - logger.warn("session is not available because session has been closed,topic:{},client:{}", topic, client); + log.warn("session is not available because session has been closed,topic:{},client:{}", topic, client); return false; } - if (!sessionContext.subscribeTopics.containsKey(topic)) { - logger.warn("session is not available because session has not subscribe topic:{},client:{}", topic, client); + if (!sessionContext.getSubscribeTopics().containsKey(topic)) { + log.warn("session is not available because session has not subscribe topic:{},client:{}", topic, client); return false; } @@ -341,7 +296,7 @@ public boolean isAvailable(String topic) { public boolean isRunning() { if (SessionState.RUNNING != sessionState) { - logger.warn("session is not running, state:{} client:{}", sessionState, client); + log.warn("session is not running, state:{} client:{}", sessionState, client); return false; } return true; diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/SessionContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/SessionContext.java index 802b6e1c0e..e12405f4bc 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/SessionContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/SessionContext.java @@ -24,13 +24,17 @@ import java.util.concurrent.ConcurrentHashMap; +import lombok.Getter; + public class SessionContext { private Session session; - public ConcurrentHashMap sendTopics = new ConcurrentHashMap(); + @Getter + private final ConcurrentHashMap sendTopics = new ConcurrentHashMap<>(64); - public ConcurrentHashMap subscribeTopics = new ConcurrentHashMap(); + @Getter + private final ConcurrentHashMap subscribeTopics = new ConcurrentHashMap<>(64); public long createTime = System.currentTimeMillis(); @@ -41,7 +45,7 @@ public SessionContext(Session session) { @Override public String toString() { return "SessionContext{subscribeTopics=" + subscribeTopics - + ",sendTopics=" + sendTopics.keySet() - + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + "}"; + + ",sendTopics=" + sendTopics.keySet() + + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + "}"; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/ClientAckContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/ClientAckContext.java index ffcf936838..7857c342bd 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/ClientAckContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/ClientAckContext.java @@ -27,15 +27,14 @@ import org.apache.commons.lang3.time.DateFormatUtils; import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.Objects; import io.cloudevents.CloudEvent; -public class ClientAckContext { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class ClientAckContext { private String seq; @@ -47,7 +46,7 @@ public class ClientAckContext { private List events; - private MQConsumerWrapper consumer; + private final MQConsumerWrapper consumer; public ClientAckContext(String seq, AbstractContext context, List events, MQConsumerWrapper consumer) { this.seq = seq; @@ -55,7 +54,8 @@ public ClientAckContext(String seq, AbstractContext context, List ev this.events = events; this.consumer = consumer; this.createTime = System.currentTimeMillis(); - String ttlStr = events.get(0).getExtension(EventMeshConstants.PROPERTY_MESSAGE_TTL).toString(); + String ttlStr = events.get(0).getExtension(EventMeshConstants.PROPERTY_MESSAGE_TTL) == null ? "" + : Objects.requireNonNull(events.get(0).getExtension(EventMeshConstants.PROPERTY_MESSAGE_TTL)).toString(); long ttl = StringUtils.isNumeric(ttlStr) ? Long.parseLong(ttlStr) : EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS; this.expireTime = System.currentTimeMillis() + ttl; } @@ -111,25 +111,25 @@ public MQConsumerWrapper getConsumer() { public void ackMsg() { if (consumer != null && context != null && events != null) { consumer.updateOffset(events, context); - logger.info("ackMsg topic:{}, bizSeq:{}", events.get(0).getSubject(), EventMeshUtil.getMessageBizSeq(events.get(0))); + log.info("ackMsg topic:{}, bizSeq:{}", events.get(0).getSubject(), EventMeshUtil.getMessageBizSeq(events.get(0))); } else { - logger.warn("ackMsg failed,consumer is null:{}, context is null:{} , msgs is null:{}", - consumer == null, context == null, events == null); + log.warn("ackMsg failed,consumer is null:{}, context is null:{} , msgs is null:{}", + consumer == null, context == null, events == null); } } @Override public String toString() { return "ClientAckContext{" - + - ",seq=" + seq - + - //TODO ",consumer=" + consumer.getDefaultMQPushConsumer().getMessageModel() + - // ",consumerGroup=" + consumer.getDefaultMQPushConsumer().getConsumerGroup() + - ",topic=" + (CollectionUtils.size(events) > 0 ? events.get(0).getSubject() : null) - + - ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) - + - ",expireTime=" + DateFormatUtils.format(expireTime, EventMeshConstants.DATE_FORMAT) + '}'; + + + ",seq=" + seq + + + // TODO ",consumer=" + consumer.getDefaultMQPushConsumer().getMessageModel() + + // ",consumerGroup=" + consumer.getDefaultMQPushConsumer().getConsumerGroup() + + ",topic=" + (CollectionUtils.size(events) > 0 ? events.get(0).getSubject() : null) + + + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + + + ",expireTime=" + DateFormatUtils.format(expireTime, EventMeshConstants.DATE_FORMAT) + '}'; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/DownStreamMsgContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/DownStreamMsgContext.java index d01469c7d6..1a4d53f3dc 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/DownStreamMsgContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/DownStreamMsgContext.java @@ -22,8 +22,8 @@ import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.plugin.MQConsumerWrapper; +import org.apache.eventmesh.runtime.core.protocol.RetryContext; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.RetryContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.ServerGlobal; @@ -32,35 +32,39 @@ import java.util.ArrayList; import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.Objects; import io.cloudevents.CloudEvent; -public class DownStreamMsgContext extends RetryContext { +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class DownStreamMsgContext extends RetryContext { - public Session session; + @Getter + @Setter + private Session session; - public AbstractContext consumeConcurrentlyContext; + private final AbstractContext consumeConcurrentlyContext; - public MQConsumerWrapper consumer; + private final MQConsumerWrapper consumer; - public SubscriptionItem subscriptionItem; + @Getter + private final SubscriptionItem subscriptionItem; - public long lastPushTime; + private long lastPushTime; - private long createTime; + private final long createTime; - private long expireTime; + private final long expireTime; - public boolean msgFromOtherEventMesh; + private final boolean msgFromOtherEventMesh; public DownStreamMsgContext(CloudEvent event, Session session, MQConsumerWrapper consumer, - AbstractContext consumeConcurrentlyContext, boolean msgFromOtherEventMesh, - SubscriptionItem subscriptionItem) { + AbstractContext consumeConcurrentlyContext, boolean msgFromOtherEventMesh, + SubscriptionItem subscriptionItem) { this.seq = String.valueOf(ServerGlobal.getInstance().getMsgCounter().incrementAndGet()); this.event = event; this.session = session; @@ -70,8 +74,7 @@ public DownStreamMsgContext(CloudEvent event, Session session, MQConsumerWrapper this.createTime = System.currentTimeMillis(); this.subscriptionItem = subscriptionItem; String ttlStr = (String) event.getExtension("TTL"); - long ttl = StringUtils.isNumeric(ttlStr) ? Long.parseLong(ttlStr) : - EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS; + long ttl = StringUtils.isNumeric(ttlStr) ? Long.parseLong(ttlStr) : EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS; this.expireTime = System.currentTimeMillis() + ttl; this.msgFromOtherEventMesh = msgFromOtherEventMesh; } @@ -82,47 +85,46 @@ public boolean isExpire() { public void ackMsg() { if (consumer != null && consumeConcurrentlyContext != null && event != null) { - List events = new ArrayList(); + List events = new ArrayList<>(); events.add(event); consumer.updateOffset(events, consumeConcurrentlyContext); - logger.info("ackMsg seq:{}, topic:{}, bizSeq:{}", seq, events.get(0).getSubject(), - events.get(0).getExtension(EventMeshConstants.PROPERTY_MESSAGE_KEYS)); + log.info("ackMsg seq:{}, topic:{}, bizSeq:{}", seq, events.get(0).getSubject(), + events.get(0).getExtension(EventMeshConstants.PROPERTY_MESSAGE_KEYS)); } else { - logger.warn("ackMsg seq:{} failed,consumer is null:{}, context is null:{} , msgs is null:{}", seq, - consumer == null, consumeConcurrentlyContext == null, event == null); + log.warn("ackMsg seq:{} failed,consumer is null:{}, context is null:{} , msgs is null:{}", seq, + consumer == null, consumeConcurrentlyContext == null, event == null); } } @Override public String toString() { return "DownStreamMsgContext{" - + - ",seq=" + seq - + - ",client=" + (session == null ? null : session.getClient()) - + - ",retryTimes=" + retryTimes - + - ",consumer=" + consumer - + - // todo ",consumerGroup=" + consumer.getClass().getConsumerGroup() + - ",topic=" + event.getSubject() - + - ",subscriptionItem=" + subscriptionItem - + - ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) - + - ",executeTime=" + DateFormatUtils.format(executeTime, EventMeshConstants.DATE_FORMAT) - + - ",lastPushTime=" + DateFormatUtils.format(lastPushTime, EventMeshConstants.DATE_FORMAT) - + '}'; + + + ",seq=" + seq + + + ",client=" + (session == null ? null : session.getClient()) + + + ",retryTimes=" + retryTimes + + + ",consumer=" + consumer + + + // todo ",consumerGroup=" + consumer.getClass().getConsumerGroup() + + ",topic=" + event.getSubject() + + + ",subscriptionItem=" + subscriptionItem + + + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + + + ",executeTime=" + DateFormatUtils.format(executeTime, EventMeshConstants.DATE_FORMAT) + + + ",lastPushTime=" + DateFormatUtils.format(lastPushTime, EventMeshConstants.DATE_FORMAT) + + '}'; } - @Override public void retry() { try { - logger.info("retry downStream msg start,seq:{},retryTimes:{},bizSeq:{}", this.seq, this.retryTimes, - EventMeshUtil.getMessageBizSeq(this.event)); + log.info("retry downStream msg start,seq:{},retryTimes:{},bizSeq:{}", this.seq, this.retryTimes, + EventMeshUtil.getMessageBizSeq(this.event)); if (isRetryMsgTimeout(this)) { return; @@ -130,27 +132,27 @@ public void retry() { this.retryTimes++; this.lastPushTime = System.currentTimeMillis(); - Session rechoosen = null; + Session rechoosen; String topic = this.event.getSubject(); - if (!SubscriptionMode.BROADCASTING.equals(this.subscriptionItem.getMode())) { - rechoosen = this.session.getClientGroupWrapper() - .get().getDownstreamDispatchStrategy().select(this.session.getClientGroupWrapper().get().getSysId(), - topic, this.session.getClientGroupWrapper().get().getGroupConsumerSessions()); + if (SubscriptionMode.BROADCASTING != this.subscriptionItem.getMode()) { + rechoosen = Objects.requireNonNull(this.session.getClientGroupWrapper().get()) + .getDownstreamDispatchStrategy().select(Objects.requireNonNull(this.session.getClientGroupWrapper().get()).getSysId(), + topic, Objects.requireNonNull(this.session.getClientGroupWrapper().get()).getGroupConsumerSessions()); } else { rechoosen = this.session; } if (rechoosen == null) { - logger.warn("retry, found no session to downstream msg,seq:{}, retryTimes:{}, bizSeq:{}", this.seq, - this.retryTimes, EventMeshUtil.getMessageBizSeq(this.event)); + log.warn("retry, found no session to downstream msg,seq:{}, retryTimes:{}, bizSeq:{}", this.seq, + this.retryTimes, EventMeshUtil.getMessageBizSeq(this.event)); } else { this.session = rechoosen; rechoosen.downstreamMsg(this); - logger.info("retry downStream msg end,seq:{},retryTimes:{},bizSeq:{}", this.seq, this.retryTimes, - EventMeshUtil.getMessageBizSeq(this.event)); + log.info("retry downStream msg end,seq:{},retryTimes:{},bizSeq:{}", this.seq, this.retryTimes, + EventMeshUtil.getMessageBizSeq(this.event)); } } catch (Exception e) { - logger.error("retry-dispatcher error!", e); + log.error("retry-dispatcher error!", e); } } @@ -158,7 +160,6 @@ private boolean isRetryMsgTimeout(DownStreamMsgContext downStreamMsgContext) { boolean flag = false; String ttlStr = (String) downStreamMsgContext.event.getExtension(EventMeshConstants.PROPERTY_MESSAGE_TTL); long ttl = StringUtils.isNumeric(ttlStr) ? Long.parseLong(ttlStr) : EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS; - ; String storeTimeStr = (String) downStreamMsgContext.event.getExtension(EventMeshConstants.STORE_TIME); long storeTimestamp = StringUtils.isNumeric(storeTimeStr) ? Long.parseLong(storeTimeStr) : 0; @@ -167,12 +168,12 @@ private boolean isRetryMsgTimeout(DownStreamMsgContext downStreamMsgContext) { String arriveTimeStr = (String) downStreamMsgContext.event.getExtension(EventMeshConstants.ARRIVE_TIME); long accessCost = StringUtils.isNumeric(arriveTimeStr) ? System.currentTimeMillis() - Long.parseLong(arriveTimeStr) - : 0; + : 0; double elapseTime = brokerCost + accessCost; if (elapseTime >= ttl) { - logger.warn("discard the retry because timeout, seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq, - downStreamMsgContext.retryTimes, EventMeshUtil.getMessageBizSeq(downStreamMsgContext.event)); + log.warn("discard the retry because timeout, seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq, + downStreamMsgContext.retryTimes, EventMeshUtil.getMessageBizSeq(downStreamMsgContext.event)); flag = true; eventMeshAckMsg(downStreamMsgContext); } @@ -182,14 +183,18 @@ private boolean isRetryMsgTimeout(DownStreamMsgContext downStreamMsgContext) { /** * eventMesh ack msg * - * @param downStreamMsgContext + * @param downStreamMsgContext Down Stream Message Context */ private void eventMeshAckMsg(DownStreamMsgContext downStreamMsgContext) { - List msgExts = new ArrayList(); + List msgExts = new ArrayList<>(); msgExts.add(downStreamMsgContext.event); - logger.warn("eventMeshAckMsg topic:{}, seq:{}, bizSeq:{}", downStreamMsgContext.event.getSubject(), - downStreamMsgContext.seq, downStreamMsgContext.event.getExtension(EventMeshConstants.PROPERTY_MESSAGE_KEYS)); + log.warn("eventMeshAckMsg topic:{}, seq:{}, bizSeq:{}", downStreamMsgContext.event.getSubject(), + downStreamMsgContext.seq, downStreamMsgContext.event.getExtension(EventMeshConstants.PROPERTY_MESSAGE_KEYS)); downStreamMsgContext.consumer.updateOffset(msgExts, downStreamMsgContext.consumeConcurrentlyContext); } + @Override + public void doRun() { + retry(); + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/PushContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/PushContext.java index 7b721467f3..f1caa1c606 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/PushContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/PushContext.java @@ -25,22 +25,20 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class PushContext { - public Logger logger = LoggerFactory.getLogger(this.getClass()); + private final SessionPusher sessionPusher; - private SessionPusher sessionPusher; + public final AtomicLong deliveredMsgsCount = new AtomicLong(0); - public AtomicLong deliveredMsgsCount = new AtomicLong(0); + public final AtomicLong deliverFailMsgsCount = new AtomicLong(0); - public AtomicLong deliverFailMsgsCount = new AtomicLong(0); + private final ConcurrentHashMap unAckMsg = new ConcurrentHashMap<>(); - private ConcurrentHashMap unAckMsg = new ConcurrentHashMap(); - - private long createTime = System.currentTimeMillis(); + private final long createTime = System.currentTimeMillis(); public PushContext(SessionPusher sessionPusher) { this.sessionPusher = sessionPusher; @@ -56,14 +54,13 @@ public void deliverFailMsgCount() { public void unAckMsg(String seq, DownStreamMsgContext downStreamMsgContext) { unAckMsg.put(seq, downStreamMsgContext); - logger.info("put msg in unAckMsg,seq:{},unAckMsgSize:{}", seq, getTotalUnackMsgs()); + log.info("put msg in unAckMsg,seq:{},unAckMsgSize:{}", seq, getTotalUnackMsgs()); } public int getTotalUnackMsgs() { return unAckMsg.size(); } - public ConcurrentHashMap getUnAckMsg() { return unAckMsg; } @@ -71,13 +68,13 @@ public ConcurrentHashMap getUnAckMsg() { @Override public String toString() { return "PushContext{" - + - "deliveredMsgsCount=" + deliveredMsgsCount.longValue() - + - ",deliverFailCount=" + deliverFailMsgsCount.longValue() - + - ",unAckMsg=" + CollectionUtils.size(unAckMsg) - + - ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + '}'; + + + "deliveredMsgsCount=" + deliveredMsgsCount.longValue() + + + ",deliverFailCount=" + deliverFailMsgsCount.longValue() + + + ",unAckMsg=" + CollectionUtils.size(unAckMsg) + + + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + '}'; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/SessionPusher.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/SessionPusher.java index f368063889..75a6e62d9d 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/SessionPusher.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/push/SessionPusher.java @@ -18,48 +18,51 @@ package org.apache.eventmesh.runtime.core.protocol.tcp.client.session.push; import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; import org.apache.eventmesh.common.protocol.tcp.Header; import org.apache.eventmesh.common.protocol.tcp.OPStatus; import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.protocol.api.ProtocolAdaptor; import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.trace.TraceUtils; import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.TraceUtils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; import org.apache.commons.collections4.CollectionUtils; +import java.util.Arrays; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.cloudevents.core.builder.CloudEventBuilder; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.opentelemetry.api.trace.Span; -public class SessionPusher { +import lombok.extern.slf4j.Slf4j; - private final Logger messageLogger = LoggerFactory.getLogger("message"); +@Slf4j +public class SessionPusher { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - private AtomicLong deliveredMsgsCount = new AtomicLong(0); + private final AtomicLong deliveredMsgsCount = new AtomicLong(0); - private AtomicLong deliverFailMsgsCount = new AtomicLong(0); + private final AtomicLong deliverFailMsgsCount = new AtomicLong(0); - private ConcurrentHashMap downStreamMap = new ConcurrentHashMap(); + private final ConcurrentHashMap downStreamMap = new ConcurrentHashMap<>(); - private Session session; + private final Session session; public SessionPusher(Session session) { this.session = session; @@ -78,9 +81,9 @@ public String toString() { public void push(final DownStreamMsgContext downStreamMsgContext) { Command cmd; - if (SubscriptionMode.BROADCASTING.equals(downStreamMsgContext.subscriptionItem.getMode())) { + if (SubscriptionMode.BROADCASTING == downStreamMsgContext.getSubscriptionItem().getMode()) { cmd = Command.BROADCAST_MESSAGE_TO_CLIENT; - } else if (SubscriptionType.SYNC.equals(downStreamMsgContext.subscriptionItem.getType())) { + } else if (SubscriptionType.SYNC == downStreamMsgContext.getSubscriptionItem().getType()) { cmd = Command.REQUEST_TO_CLIENT; } else { cmd = Command.ASYNC_MESSAGE_TO_CLIENT; @@ -88,7 +91,7 @@ public void push(final DownStreamMsgContext downStreamMsgContext) { String protocolType = Objects.requireNonNull(downStreamMsgContext.event.getExtension(Constants.PROTOCOL_TYPE)).toString(); - ProtocolAdaptor protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + ProtocolAdaptor protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); Package pkg = new Package(); @@ -99,72 +102,66 @@ public void push(final DownStreamMsgContext downStreamMsgContext) { .withExtension(EventMeshConstants.RSP_IDC, session.getClient().getIdc()) .withExtension(EventMeshConstants.RSP_IP, session.getClient().getHost()) .build(); - EventMeshMessage body = null; - int retCode = 0; - String retMsg = null; try { pkg = (Package) protocolAdaptor.fromCloudEvent(downStreamMsgContext.event); pkg.setHeader(new Header(cmd, OPStatus.SUCCESS.getCode(), null, downStreamMsgContext.seq)); pkg.getHeader().putProperty(Constants.PROTOCOL_TYPE, protocolType); - messageLogger.info("pkg|mq2eventMesh|cmd={}|mqMsg={}|user={}", cmd, pkg, session.getClient()); + MESSAGE_LOGGER.info("pkg|mq2eventMesh|cmd={}|mqMsg={}|user={}", cmd, pkg, session.getClient()); } catch (Exception e) { - pkg.setHeader(new Header(cmd, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), downStreamMsgContext.seq)); - retCode = -1; - retMsg = e.toString(); + pkg.setHeader(new Header(cmd, OPStatus.FAIL.getCode(), Arrays.toString(e.getStackTrace()), downStreamMsgContext.seq)); } finally { - session.getClientGroupWrapper().get().getEventMeshTcpMonitor().getTcpSummaryMetrics().getEventMesh2clientMsgNum().incrementAndGet(); + Objects.requireNonNull(session.getClientGroupWrapper().get()).getEventMeshTcpMetricsManager() + .eventMesh2clientMsgNumIncrement(IPUtils.parseChannelRemoteAddr(downStreamMsgContext.getSession().getContext().channel())); - //TODO uploadTrace + // TODO uploadTrace String protocolVersion = Objects.requireNonNull(downStreamMsgContext.event.getSpecVersion()).toString(); Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, downStreamMsgContext.event), EventMeshTraceConstants.TRACE_DOWNSTREAM_EVENTMESH_CLIENT_SPAN, false); try { - session.getContext().writeAndFlush(pkg).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { + Package finalPkg = pkg; + session.getContext().channel().eventLoop().execute(() -> { + session.getContext().writeAndFlush(finalPkg).addListener( + (ChannelFutureListener) future -> { if (!future.isSuccess()) { - logger.error("downstreamMsg fail,seq:{}, retryTimes:{}, event:{}", downStreamMsgContext.seq, + log.error("downstreamMsg fail,seq:{}, retryTimes:{}, event:{}", downStreamMsgContext.seq, downStreamMsgContext.retryTimes, downStreamMsgContext.event); deliverFailMsgsCount.incrementAndGet(); - //how long to isolate client when push fail + // how long to isolate client when push fail long isolateTime = System.currentTimeMillis() - + session.getEventMeshTCPConfiguration().eventMeshTcpPushFailIsolateTimeInMills; + + session.getEventMeshTCPConfiguration().getEventMeshTcpPushFailIsolateTimeInMills(); session.setIsolateTime(isolateTime); - logger.warn("isolate client:{},isolateTime:{}", session.getClient(), isolateTime); - - //retry - long delayTime = SubscriptionType.SYNC.equals(downStreamMsgContext.subscriptionItem.getType()) - ? session.getEventMeshTCPConfiguration().eventMeshTcpMsgRetrySyncDelayInMills - : session.getEventMeshTCPConfiguration().eventMeshTcpMsgRetryAsyncDelayInMills; - downStreamMsgContext.delay(delayTime); - session.getClientGroupWrapper().get().getEventMeshTcpRetryer().pushRetry(downStreamMsgContext); + log.warn("isolate client:{},isolateTime:{}", session.getClient(), isolateTime); + + // retry + long delayTime = SubscriptionType.SYNC == downStreamMsgContext.getSubscriptionItem().getType() + ? session.getEventMeshTCPConfiguration().getEventMeshTcpMsgRetrySyncDelayInMills() + : session.getEventMeshTCPConfiguration().getEventMeshTcpMsgRetryAsyncDelayInMills(); + Objects.requireNonNull(session.getClientGroupWrapper().get()).getTcpRetryer() + .newTimeout(downStreamMsgContext, delayTime, TimeUnit.MILLISECONDS); } else { deliveredMsgsCount.incrementAndGet(); - logger.info("downstreamMsg success,seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq, + log.info("downstreamMsg success,seq:{}, retryTimes:{}, bizSeq:{}", downStreamMsgContext.seq, downStreamMsgContext.retryTimes, EventMeshUtil.getMessageBizSeq(downStreamMsgContext.event)); if (session.isIsolated()) { - logger.info("cancel isolated,client:{}", session.getClient()); + log.info("cancel isolated,client:{}", session.getClient()); session.setIsolateTime(System.currentTimeMillis()); } } - } - } - ); + }); + }); } finally { TraceUtils.finishSpan(span, downStreamMsgContext.event); } - } } public void unAckMsg(String seq, DownStreamMsgContext downStreamMsgContext) { downStreamMap.put(seq, downStreamMsgContext); - logger.info("put msg in unAckMsg,seq:{},unAckMsgSize:{}", seq, getTotalUnackMsgs()); + log.info("put msg in unAckMsg,seq:{},unAckMsgSize:{}", seq, getTotalUnackMsgs()); } public int getTotalUnackMsgs() { diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/EventMeshTcpRetryer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/EventMeshTcpRetryer.java deleted file mode 100644 index 55641ae97a..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/EventMeshTcpRetryer.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry; - -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; -import org.apache.eventmesh.runtime.util.EventMeshThreadFactoryImpl; -import org.apache.eventmesh.runtime.util.EventMeshUtil; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventMeshTcpRetryer { - - public static Logger logger = LoggerFactory.getLogger(EventMeshTcpRetryer.class); - - private EventMeshTCPServer eventMeshTCPServer; - - private DelayQueue retrys = new DelayQueue(); - - private ThreadPoolExecutor pool = new ThreadPoolExecutor(3, - 3, - 60000, - TimeUnit.MILLISECONDS, new ArrayBlockingQueue(1000), - new EventMeshThreadFactoryImpl("eventMesh-tcp-retry", true), - new ThreadPoolExecutor.AbortPolicy()); - - private Thread dispatcher; - - public EventMeshTcpRetryer(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - public EventMeshTCPServer getEventMeshTCPServer() { - return eventMeshTCPServer; - } - - public void setEventMeshTCPServer(EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - } - - public void pushRetry(RetryContext retryContext) { - if (retrys.size() >= eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpMsgRetryQueueSize) { - logger.error("pushRetry fail,retrys is too much,allow max retryQueueSize:{}, retryTimes:{}, seq:{}, bizSeq:{}", - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpMsgRetryQueueSize, retryContext.retryTimes, - retryContext.seq, EventMeshUtil.getMessageBizSeq(retryContext.event)); - return; - } - - int maxRetryTimes = eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpMsgAsyncRetryTimes; - if (retryContext instanceof DownStreamMsgContext) { - DownStreamMsgContext downStreamMsgContext = (DownStreamMsgContext) retryContext; - maxRetryTimes = SubscriptionType.SYNC.equals(downStreamMsgContext.subscriptionItem.getType()) - ? eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpMsgSyncRetryTimes : - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshTcpMsgAsyncRetryTimes; - } - - if (retryContext.retryTimes >= maxRetryTimes) { - logger.warn("pushRetry fail,retry over maxRetryTimes:{}, retryTimes:{}, seq:{}, bizSeq:{}", maxRetryTimes, - retryContext.retryTimes, retryContext.seq, EventMeshUtil.getMessageBizSeq(retryContext.event)); - return; - } - - retrys.offer(retryContext); - logger.info("pushRetry success,seq:{}, retryTimes:{}, bizSeq:{}", retryContext.seq, retryContext.retryTimes, - EventMeshUtil.getMessageBizSeq(retryContext.event)); - } - - public void init() { - dispatcher = new Thread(() -> { - try { - RetryContext retryContext; - while ((retryContext = retrys.take()) != null) { - pool.execute(retryContext::retry); - } - } catch (Exception e) { - logger.error("retry-dispatcher error!", e); - } - }, "retry-dispatcher"); - dispatcher.setDaemon(true); - logger.info("EventMeshTcpRetryer inited......"); - } - - public void start() throws Exception { - dispatcher.start(); - logger.info("EventMeshTcpRetryer started......"); - } - - public void shutdown() { - pool.shutdown(); - logger.info("EventMeshTcpRetryer shutdown......"); - } - - public int getRetrySize() { - return retrys.size(); - } - - public void printRetryThreadPoolState() { - //ThreadPoolHelper.printState(pool); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/RetryContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/RetryContext.java deleted file mode 100644 index 9a5359ee01..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/RetryContext.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry; - -import java.util.concurrent.Delayed; -import java.util.concurrent.TimeUnit; - -import io.cloudevents.CloudEvent; - -public abstract class RetryContext implements Delayed { - - public CloudEvent event; - - public String seq; - - public int retryTimes = 0; - - public long executeTime = System.currentTimeMillis(); - - public RetryContext delay(long delay) { - this.executeTime = System.currentTimeMillis() + (retryTimes + 1) * delay; - return this; - } - - @Override - public int compareTo(Delayed delayed) { - RetryContext obj = (RetryContext) delayed; - if (this.executeTime > obj.executeTime) { - return 1; - } else if (this.executeTime == obj.executeTime) { - return 0; - } else { - return -1; - } - } - - @Override - public long getDelay(TimeUnit unit) { - return unit.convert(this.executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); - } - - public abstract void retry(); -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/TcpRetryer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/TcpRetryer.java new file mode 100644 index 0000000000..4112994400 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/retry/TcpRetryer.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry; + +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.retry.api.AbstractRetryer; +import org.apache.eventmesh.retry.api.timer.TimerTask; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.protocol.RetryContext; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; +import org.apache.eventmesh.runtime.util.EventMeshUtil; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TcpRetryer extends AbstractRetryer { + + private EventMeshTCPServer eventMeshTCPServer; + + public TcpRetryer(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + } + + public EventMeshTCPServer getEventMeshTCPServer() { + return eventMeshTCPServer; + } + + public void setEventMeshTCPServer(EventMeshTCPServer eventMeshTCPServer) { + this.eventMeshTCPServer = eventMeshTCPServer; + } + + @Override + public void newTimeout(TimerTask timerTask, long delay, TimeUnit timeUnit) { + RetryContext retryContext = (RetryContext) timerTask; + + int maxRetryTimes = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpMsgAsyncRetryTimes(); + if (retryContext instanceof DownStreamMsgContext) { + DownStreamMsgContext downStreamMsgContext = (DownStreamMsgContext) retryContext; + maxRetryTimes = SubscriptionType.SYNC == downStreamMsgContext.getSubscriptionItem().getType() + ? eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpMsgSyncRetryTimes() + : eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpMsgAsyncRetryTimes(); + } + + if (retryContext.retryTimes >= maxRetryTimes) { + log.warn("pushRetry fail,retry over maxRetryTimes:{}, retryTimes:{}, seq:{}, bizSeq:{}", maxRetryTimes, + retryContext.retryTimes, retryContext.seq, EventMeshUtil.getMessageBizSeq(retryContext.event)); + return; + } + + super.newTimeout(timerTask, delay, timeUnit); + + log.info("pushRetry success,seq:{}, retryTimes:{}, bizSeq:{}", retryContext.seq, retryContext.retryTimes, + EventMeshUtil.getMessageBizSeq(retryContext.event)); + + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/EventMeshTcpSendResult.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/EventMeshTcpSendResult.java index 61c4d041e4..d9746c425a 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/EventMeshTcpSendResult.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/EventMeshTcpSendResult.java @@ -19,11 +19,11 @@ public class EventMeshTcpSendResult { - private String seq; + private final String seq; - private EventMeshTcpSendStatus sendStatus; + private final EventMeshTcpSendStatus sendStatus; - private String detail; + private final String detail; public EventMeshTcpSendResult(String seq, EventMeshTcpSendStatus sendStatus, String detail) { this.seq = seq; @@ -46,7 +46,7 @@ public String getDetail() { @Override public String toString() { return "EventMeshTcpSendResult{seq=" + seq - + ",sendStatus=" + sendStatus - + ",detail=" + detail + "}"; + + ",sendStatus=" + sendStatus + + ",detail=" + detail + "}"; } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/SessionSender.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/SessionSender.java index b9e4e81758..1b455514dc 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/SessionSender.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/SessionSender.java @@ -20,6 +20,7 @@ import org.apache.eventmesh.api.RequestReplyCallback; import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.ProtocolTransportObject; import org.apache.eventmesh.common.protocol.tcp.Command; import org.apache.eventmesh.common.protocol.tcp.Header; import org.apache.eventmesh.common.protocol.tcp.OPStatus; @@ -28,8 +29,8 @@ import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.trace.TraceUtils; import org.apache.eventmesh.runtime.util.EventMeshUtil; +import org.apache.eventmesh.runtime.util.TraceUtils; import org.apache.eventmesh.runtime.util.Utils; import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; @@ -48,20 +49,22 @@ import io.cloudevents.core.builder.CloudEventBuilder; import io.opentelemetry.api.trace.Span; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class SessionSender { - private final Logger messageLogger = LoggerFactory.getLogger("message"); - private final Logger logger = LoggerFactory.getLogger(SessionSender.class); + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); - private Session session; + private final transient Session session; - public long createTime = System.currentTimeMillis(); + public final transient long createTime = System.currentTimeMillis(); - public AtomicLong upMsgs = new AtomicLong(0); + public final transient AtomicLong upMsgs = new AtomicLong(0); - public AtomicLong failMsgCount = new AtomicLong(0); + public final transient AtomicLong failMsgCount = new AtomicLong(0); - private static final int TRY_PERMIT_TIME_OUT = 5; + public static final int TRY_PERMIT_TIME_OUT = 5; @Override public String toString() { @@ -78,18 +81,19 @@ public Semaphore getUpstreamBuff() { return upstreamBuff; } - private Semaphore upstreamBuff; + private final Semaphore upstreamBuff; public SessionSender(Session session) { this.session = session; - this.upstreamBuff = new Semaphore(session.getEventMeshTCPConfiguration().eventMeshTcpSessionUpstreamBufferSize); + this.upstreamBuff = new Semaphore(session.getEventMeshTCPConfiguration().getEventMeshTcpSessionUpstreamBufferSize()); } - public EventMeshTcpSendResult send(Header header, CloudEvent event, SendCallback sendCallback, long startTime, long taskExecuteTime) { + public EventMeshTcpSendResult send(Header header, CloudEvent event, SendCallback sendCallback, long startTime, + long taskExecuteTime) { try { if (upstreamBuff.tryAcquire(TRY_PERMIT_TIME_OUT, TimeUnit.MILLISECONDS)) { upMsgs.incrementAndGet(); - UpStreamMsgContext upStreamMsgContext = null; + UpStreamMsgContext upStreamMsgContext; Command cmd = header.getCmd(); String protocolVersion = header.getProperty(Constants.PROTOCOL_VERSION).toString(); @@ -102,10 +106,11 @@ public EventMeshTcpSendResult send(Header header, CloudEvent event, SendCallback } upStreamMsgContext = new UpStreamMsgContext(session, event, header, startTime, taskExecuteTime); - Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), + Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, + event), EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_CLIENT_SPAN, false); try { - session.getClientGroupWrapper().get() + Objects.requireNonNull(session.getClientGroupWrapper().get()) .request(upStreamMsgContext, initSyncRRCallback(header, startTime, taskExecuteTime, event), ttl); upstreamBuff.release(); @@ -121,54 +126,60 @@ public EventMeshTcpSendResult send(Header header, CloudEvent event, SendCallback } upStreamMsgContext = new UpStreamMsgContext(session, event, header, startTime, taskExecuteTime); - session.getClientGroupWrapper().get().reply(upStreamMsgContext); + Objects.requireNonNull(session.getClientGroupWrapper().get()).reply(upStreamMsgContext); upstreamBuff.release(); } else { upStreamMsgContext = new UpStreamMsgContext(session, event, header, startTime, taskExecuteTime); - Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, event), + Span span = TraceUtils.prepareClientSpan(EventMeshUtil.getCloudEventExtensionMap(protocolVersion, + event), EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_CLIENT_SPAN, false); try { - session.getClientGroupWrapper().get() + Objects.requireNonNull(session.getClientGroupWrapper().get()) .send(upStreamMsgContext, sendCallback); } finally { TraceUtils.finishSpan(span, event); } } - - session.getClientGroupWrapper().get().getEventMeshTcpMonitor().getTcpSummaryMetrics().getEventMesh2mqMsgNum().incrementAndGet(); + Objects.requireNonNull(session.getClientGroupWrapper().get()).getEventMeshTcpMetricsManager().eventMesh2mqMsgNumIncrement(); } else { - logger.warn("send too fast,session flow control,session:{}", session.getClient()); - return new EventMeshTcpSendResult(header.getSeq(), EventMeshTcpSendStatus.SEND_TOO_FAST, EventMeshTcpSendStatus.SEND_TOO_FAST.name()); + log.warn("send too fast,session flow control,session:{}", session.getClient()); + return new EventMeshTcpSendResult(header.getSeq(), EventMeshTcpSendStatus.SEND_TOO_FAST, + EventMeshTcpSendStatus.SEND_TOO_FAST.name()); } } catch (Exception e) { - logger.warn("SessionSender send failed", e); + log.warn("SessionSender send failed", e); if (!(e instanceof InterruptedException)) { upstreamBuff.release(); } failMsgCount.incrementAndGet(); - return new EventMeshTcpSendResult(header.getSeq(), EventMeshTcpSendStatus.OTHER_EXCEPTION, e.getCause().toString()); + return new EventMeshTcpSendResult(header.getSeq(), EventMeshTcpSendStatus.OTHER_EXCEPTION, + e.getCause().toString()); } - return new EventMeshTcpSendResult(header.getSeq(), EventMeshTcpSendStatus.SUCCESS, EventMeshTcpSendStatus.SUCCESS.name()); + return new EventMeshTcpSendResult(header.getSeq(), EventMeshTcpSendStatus.SUCCESS, + EventMeshTcpSendStatus.SUCCESS.name()); } - private RequestReplyCallback initSyncRRCallback(Header header, long startTime, long taskExecuteTime, CloudEvent cloudEvent) { + private RequestReplyCallback initSyncRRCallback(Header header, long startTime, long taskExecuteTime, + CloudEvent cloudEvent) { return new RequestReplyCallback() { + @Override public void onSuccess(CloudEvent event) { String seq = header.getSeq(); // TODO: How to assign values here event = CloudEventBuilder.from(event) .withExtension(EventMeshConstants.RSP_MQ2EVENTMESH_TIMESTAMP, String.valueOf(System.currentTimeMillis())) - .withExtension(EventMeshConstants.RSP_RECEIVE_EVENTMESH_IP, session.getEventMeshTCPConfiguration().eventMeshServerIp) + .withExtension(EventMeshConstants.RSP_RECEIVE_EVENTMESH_IP, + session.getEventMeshTCPConfiguration().getEventMeshServerIp()) .build(); - session.getClientGroupWrapper().get().getEventMeshTcpMonitor().getTcpSummaryMetrics().getMq2eventMeshMsgNum().incrementAndGet(); + Objects.requireNonNull(session.getClientGroupWrapper().get()).getEventMeshTcpMetricsManager().mq2eventMeshMsgNumIncrement(); Command cmd; - if (header.getCmd().equals(Command.REQUEST_TO_SERVER)) { + if (Command.REQUEST_TO_SERVER == header.getCmd()) { cmd = Command.RESPONSE_TO_CLIENT; } else { - messageLogger.error("invalid message|messageHeader={}|event={}", header, event); + MESSAGE_LOGGER.error("invalid message|messageHeader={}|event={}", header, event); return; } event = CloudEventBuilder.from(event) @@ -176,7 +187,7 @@ public void onSuccess(CloudEvent event) { .build(); String protocolType = Objects.requireNonNull(event.getExtension(Constants.PROTOCOL_TYPE)).toString(); - ProtocolAdaptor protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); + ProtocolAdaptor protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor(protocolType); Package pkg = new Package(); @@ -195,10 +206,16 @@ public void onSuccess(CloudEvent event) { @Override public void onException(Throwable e) { - messageLogger.error("exception occur while sending RR message|user={}", session.getClient(), new Exception(e)); + MESSAGE_LOGGER.error("exception occur while sending RR message|user={}", session.getClient(), + new Exception(e)); - TraceUtils.finishSpanWithException(session.getContext(), cloudEvent, "exception occur while sending RR message", e); + TraceUtils.finishSpanWithException(session.getContext(), cloudEvent, + "exception occur while sending RR message", e); } }; } + + public AtomicLong getFailMsgCount() { + return failMsgCount; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/UpStreamMsgContext.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/UpStreamMsgContext.java index 74b140a64e..d6730a9840 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/UpStreamMsgContext.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/session/send/UpStreamMsgContext.java @@ -25,32 +25,33 @@ import org.apache.eventmesh.common.protocol.tcp.OPStatus; import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.RetryContext; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.retry.RetryContext; import org.apache.eventmesh.runtime.util.EventMeshUtil; import org.apache.eventmesh.runtime.util.Utils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.Objects; +import java.util.concurrent.TimeUnit; import io.cloudevents.CloudEvent; -public class UpStreamMsgContext extends RetryContext { +import lombok.extern.slf4j.Slf4j; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class UpStreamMsgContext extends RetryContext { - private Session session; + private final Session session; - private long createTime = System.currentTimeMillis(); + private final long createTime = System.currentTimeMillis(); - private Header header; + private final Header header; - private long startTime; + private final long startTime; - private long taskExecuteTime; + private final long taskExecuteTime; public UpStreamMsgContext(Session session, CloudEvent event, Header header, long startTime, long taskExecuteTime) { this.seq = header.getSeq(); @@ -76,17 +77,16 @@ public long getCreateTime() { @Override public String toString() { return "UpStreamMsgContext{seq=" + seq - + ",topic=" + event.getSubject() - + ",client=" + session.getClient() - + ",retryTimes=" + retryTimes - + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + "}" - + ",executeTime=" + DateFormatUtils.format(executeTime, EventMeshConstants.DATE_FORMAT); + + ",topic=" + event.getSubject() + + ",client=" + session.getClient() + + ",retryTimes=" + retryTimes + + ",createTime=" + DateFormatUtils.format(createTime, EventMeshConstants.DATE_FORMAT) + "}" + + ",executeTime=" + DateFormatUtils.format(executeTime, EventMeshConstants.DATE_FORMAT); } - @Override public void retry() { - logger.info("retry upStream msg start,seq:{},retryTimes:{},bizSeq:{}", this.seq, this.retryTimes, - EventMeshUtil.getMessageBizSeq(this.event)); + log.info("retry upStream msg start,seq:{},retryTimes:{},bizSeq:{}", this.seq, this.retryTimes, + EventMeshUtil.getMessageBizSeq(this.event)); try { Command replyCmd = getReplyCmd(header.getCmd()); @@ -100,14 +100,14 @@ public void retry() { createSendCallback(replyCmd, taskExecuteTime, event, this), startTime, taskExecuteTime); if (StringUtils.equals(EventMeshTcpSendStatus.SUCCESS.name(), sendStatus.getSendStatus().name())) { - logger.info("pkg|eventMesh2mq|cmd={}|event={}|user={}|wait={}ms|cost={}ms", header.getCmd(), event, + log.info("pkg|eventMesh2mq|cmd={}|event={}|user={}|wait={}ms|cost={}ms", header.getCmd(), event, session.getClient(), taskExecuteTime - startTime, sendTime - startTime); } else { throw new Exception(sendStatus.getDetail()); } } } catch (Exception e) { - logger.error("TCP UpstreamMsg Retry error", e); + log.error("TCP UpstreamMsg Retry error", e); } } @@ -116,13 +116,13 @@ protected SendCallback createSendCallback(Command replyCmd, long taskExecuteTime Package msg = new Package(); return new SendCallback() { + @Override public void onSuccess(SendResult sendResult) { session.getSender().getUpstreamBuff().release(); - logger.info("upstreamMsg message success|user={}|callback cost={}", session.getClient(), - System.currentTimeMillis() - createTime); - if (replyCmd.equals(Command.BROADCAST_MESSAGE_TO_SERVER_ACK) || replyCmd.equals(Command - .ASYNC_MESSAGE_TO_SERVER_ACK)) { + log.info("upstreamMsg message success|user={}|callback cost={}", session.getClient(), + System.currentTimeMillis() - createTime); + if (replyCmd == Command.BROADCAST_MESSAGE_TO_SERVER_ACK || replyCmd == Command.ASYNC_MESSAGE_TO_SERVER_ACK) { msg.setHeader(new Header(replyCmd, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), seq)); msg.setBody(event); Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); @@ -134,13 +134,12 @@ public void onException(OnExceptionContext context) { session.getSender().getUpstreamBuff().release(); // retry - // reset delay time - retryContext.delay(10000); - session.getClientGroupWrapper().get().getEventMeshTcpRetryer().pushRetry(retryContext); + Objects.requireNonNull(session.getClientGroupWrapper().get()).getTcpRetryer() + .newTimeout(retryContext, 10, TimeUnit.SECONDS); - session.getSender().failMsgCount.incrementAndGet(); - logger.error("upstreamMsg mq message error|user={}|callback cost={}, errMsg={}", session.getClient(), - System.currentTimeMillis() - createTime, new Exception(context.getException())); + session.getSender().getFailMsgCount().incrementAndGet(); + log.error("upstreamMsg mq message error|user={}|callback cost={}, errMsg={}", session.getClient(), + System.currentTimeMillis() - createTime, new Exception(context.getException())); msg.setHeader(new Header(replyCmd, OPStatus.FAIL.getCode(), context.getException().toString(), seq)); msg.setBody(event); Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); @@ -161,4 +160,9 @@ private Command getReplyCmd(Command cmd) { return cmd; } } + + @Override + public void doRun() throws Exception { + retry(); + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/AbstractTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/AbstractTask.java deleted file mode 100644 index 560ccf4be6..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/AbstractTask.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; - -public abstract class AbstractTask implements Runnable { - - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - - protected Package pkg; - protected ChannelHandlerContext ctx; - protected Session session; - protected long startTime; - protected EventMeshTCPServer eventMeshTCPServer; - - public AbstractTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - this.eventMeshTCPServer = eventMeshTCPServer; - this.pkg = pkg; - this.ctx = ctx; - this.session = eventMeshTCPServer.getClientSessionGroupMapping().getSession(ctx); - this.startTime = startTime; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/GoodbyeTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/GoodbyeTask.java deleted file mode 100644 index 0eeabf2dcd..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/GoodbyeTask.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import static org.apache.eventmesh.common.protocol.tcp.Command.CLIENT_GOODBYE_RESPONSE; - -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.util.Utils; - -import io.netty.channel.ChannelHandlerContext; - -public class GoodbyeTask extends AbstractTask { - - public GoodbyeTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Package msg = new Package(); - try { - if (pkg.getHeader().getCmd() == Command.SERVER_GOODBYE_RESPONSE) { - logger.info("client|address={}| has reject ", session.getContext().channel().remoteAddress()); - } else { - msg.setHeader( - new Header(CLIENT_GOODBYE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), - pkg.getHeader().getSeq())); - } - } catch (Exception e) { - logger.error("GoodbyeTask failed|user={}|errMsg={}", session.getClient(), e); - msg.setHeader(new Header(CLIENT_GOODBYE_RESPONSE, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), pkg - .getHeader().getSeq())); - } finally { - this.eventMeshTCPServer.getScheduler().submit(new Runnable() { - @Override - public void run() { - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - } - }); - //session.write2Client(msg); - } - EventMeshTcp2Client - .closeSessionIfTimeout(this.eventMeshTCPServer, session, eventMeshTCPServer.getClientSessionGroupMapping()); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/HeartBeatTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/HeartBeatTask.java deleted file mode 100644 index 099b34638b..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/HeartBeatTask.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import static org.apache.eventmesh.common.protocol.tcp.Command.HEARTBEAT_REQUEST; -import static org.apache.eventmesh.common.protocol.tcp.Command.HEARTBEAT_RESPONSE; - -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.Utils; - -import io.netty.channel.ChannelHandlerContext; - -public class HeartBeatTask extends AbstractTask { - - public HeartBeatTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Package res = new Package(); - try { - //do acl check in heartbeat - if (eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - Acl.doAclCheckInTcpHeartbeat(remoteAddr, session.getClient(), HEARTBEAT_REQUEST.value()); - } - - if (session != null) { - session.notifyHeartbeat(startTime); - } - res.setHeader(new Header(HEARTBEAT_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); - } catch (Exception e) { - logger.error("HeartBeatTask failed|user={}|errMsg={}", session.getClient(), e); - res.setHeader(new Header(HEARTBEAT_RESPONSE, OPStatus.FAIL.getCode(), "exception while " - + "heartbeating", pkg.getHeader().getSeq())); - } finally { - Utils.writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/HelloTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/HelloTask.java deleted file mode 100644 index bde0659064..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/HelloTask.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import static org.apache.eventmesh.common.protocol.tcp.Command.HELLO_REQUEST; -import static org.apache.eventmesh.common.protocol.tcp.Command.HELLO_RESPONSE; - -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.common.ServiceState; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.Utils; - -import org.apache.commons.lang3.StringUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; - -public class HelloTask extends AbstractTask { - - private final Logger messageLogger = LoggerFactory.getLogger("message"); - - public HelloTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Package res = new Package(); - Session session = null; - UserAgent user = (UserAgent) pkg.getBody(); - try { - //do acl check in connect - if (eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - Acl.doAclCheckInTcpConnect(remoteAddr, user, HELLO_REQUEST.value()); - } - - if (eventMeshTCPServer.getEventMeshServer().getServiceState() != ServiceState.RUNNING) { - logger.error("server state is not running:{}", eventMeshTCPServer.getEventMeshServer().getServiceState()); - throw new Exception("server state is not running, maybe deploying..."); - } - - validateUserAgent(user); - session = eventMeshTCPServer.getClientSessionGroupMapping().createSession(user, ctx); - res.setHeader(new Header(HELLO_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); - Utils.writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); - } catch (Throwable e) { - messageLogger.error("HelloTask failed|address={},errMsg={}", ctx.channel().remoteAddress(), e); - res.setHeader(new Header(HELLO_RESPONSE, OPStatus.FAIL.getCode(), e.getStackTrace().toString(), pkg - .getHeader().getSeq())); - ctx.writeAndFlush(res).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (!future.isSuccess()) { - Utils.logFailedMessageFlow(future, res, user, startTime, taskExecuteTime); - } else { - Utils.logSucceedMessageFlow(res, user, startTime, taskExecuteTime); - } - logger.warn("HelloTask failed,close session,addr:{}", ctx.channel().remoteAddress()); - eventMeshTCPServer.getClientSessionGroupMapping().closeSession(ctx); - } - } - ); - } - } - - private void validateUserAgent(UserAgent user) throws Exception { - if (user == null) { - throw new Exception("client info cannot be null"); - } - - if (user.getVersion() == null) { - throw new Exception("client version cannot be null"); - } - - if (!(StringUtils.equals(EventMeshConstants.PURPOSE_PUB, user.getPurpose()) || StringUtils.equals( - EventMeshConstants.PURPOSE_SUB, user.getPurpose()))) { - - throw new Exception("client purpose config is error"); - } - - if (StringUtils.isBlank(user.getGroup())) { - throw new Exception("client group cannot be null"); - } - - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/ListenTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/ListenTask.java deleted file mode 100644 index 8c606154ab..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/ListenTask.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import static org.apache.eventmesh.common.protocol.tcp.Command.LISTEN_RESPONSE; - -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; - -import io.netty.channel.ChannelHandlerContext; - -public class ListenTask extends AbstractTask { - - public ListenTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Header header = new Header(LISTEN_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq()); - session.setListenRequestSeq(pkg.getHeader().getSeq()); - try { - synchronized (session) { - eventMeshTCPServer.getClientSessionGroupMapping().readySession(session); - } - } catch (Exception e) { - logger.error("ListenTask failed|user={}|errMsg={}", session.getClient(), e); - Integer status = OPStatus.FAIL.getCode(); - header = new Header(LISTEN_RESPONSE, status, e.toString(), pkg.getHeader().getSeq()); - } finally { - //check to avoid send repeatedly - session.trySendListenResponse(header, startTime, taskExecuteTime); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/MessageAckTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/MessageAckTask.java deleted file mode 100644 index a01615babc..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/MessageAckTask.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.push.DownStreamMsgContext; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; - -public class MessageAckTask extends AbstractTask { - - private final Logger messageLogger = LoggerFactory.getLogger("message"); - - public MessageAckTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - String seq = pkg.getHeader().getSeq(); - Command cmd = pkg.getHeader().getCmd(); - - if (seq == null) { - logger.error("MessageAckTask failed, seq cannot be null|user={}", session.getClient()); - return; - } - DownStreamMsgContext downStreamMsgContext = session.getPusher().getUnAckMsg().get(seq); - // ack non-broadcast msg - if (downStreamMsgContext != null) { - downStreamMsgContext.ackMsg(); - session.getPusher().getUnAckMsg().remove(seq); - } else { - if (!cmd.equals(Command.RESPONSE_TO_CLIENT_ACK)) { - logger.warn("MessageAckTask, seq:{}, downStreamMsgContext not in downStreamMap,client:{}", - seq, session.getClient()); - } - } - messageLogger.info("pkg|c2eventMesh|cmd={}|seq=[{}]|user={}|wait={}ms|cost={}ms", cmd, seq, session.getClient(), - taskExecuteTime - startTime, System.currentTimeMillis() - startTime); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/MessageTransferTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/MessageTransferTask.java deleted file mode 100644 index cb249a0cfa..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/MessageTransferTask.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import static org.apache.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER; - -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.protocol.api.ProtocolAdaptor; -import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.EventMeshTcpSendResult; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.EventMeshTcpSendStatus; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.send.UpStreamMsgContext; -import org.apache.eventmesh.runtime.trace.AttributeKeys; -import org.apache.eventmesh.runtime.trace.SpanKey; -import org.apache.eventmesh.runtime.trace.TraceUtils; -import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.Utils; -import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; - -import org.apache.commons.lang3.StringUtils; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Context; - -public class MessageTransferTask extends AbstractTask { - - private final Logger messageLogger = LoggerFactory.getLogger("message"); - - private static final int TRY_PERMIT_TIME_OUT = 5; - - public MessageTransferTask(Package pkg, ChannelHandlerContext ctx, long startTime, - EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Command cmd = pkg.getHeader().getCmd(); - - try { - if (eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerTraceEnable && !RESPONSE_TO_SERVER.equals(cmd)) { - //attach the span to the server context - Span span = TraceUtils.prepareServerSpan(pkg.getHeader().getProperties(), - EventMeshTraceConstants.TRACE_UPSTREAM_EVENTMESH_SERVER_SPAN, - startTime, TimeUnit.MILLISECONDS, true); - Context context = Context.current().with(SpanKey.SERVER_KEY, span); - //put the context in channel - ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).set(context); - } - } catch (Throwable ex) { - logger.warn("upload trace fail in MessageTransferTask[server-span-start]", ex); - } - - - Command replyCmd = getReplyCmd(cmd); - Package msg = new Package(); - - int retCode = 0; - EventMeshTcpSendResult sendStatus; - CloudEvent event = null; - - try { - String protocolType = "eventmeshmessage"; - if (pkg.getHeader().getProperties() != null - && pkg.getHeader().getProperty(Constants.PROTOCOL_TYPE) != null) { - protocolType = (String) pkg.getHeader().getProperty(Constants.PROTOCOL_TYPE); - } - ProtocolAdaptor protocolAdaptor = - ProtocolPluginFactory.getProtocolAdaptor(protocolType); - event = protocolAdaptor.toCloudEvent(pkg); - - if (event == null) { - throw new Exception("event is null"); - } - - String content = new String(event.getData().toBytes(), StandardCharsets.UTF_8); - if (content.length() > eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshEventSize) { - throw new Exception("event size exceeds the limit: " - + eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshEventSize); - } - - //do acl check in sending msg - if (eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - Acl.doAclCheckInTcpSend(remoteAddr, session.getClient(), event.getSubject(), - cmd.value()); - } - - if (!eventMeshTCPServer.getRateLimiter() - .tryAcquire(TRY_PERMIT_TIME_OUT, TimeUnit.MILLISECONDS)) { - - msg.setHeader(new Header(replyCmd, OPStatus.FAIL.getCode(), - "Tps overload, global flow control", - pkg.getHeader().getSeq())); - ctx.writeAndFlush(msg).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - Utils.logSucceedMessageFlow(msg, session.getClient(), startTime, - taskExecuteTime); - } - } - ); - - TraceUtils.finishSpanWithException(ctx, event, "Tps overload, global flow control", - null); - - logger.warn( - "======Tps overload, global flow control, rate:{}! PLEASE CHECK!========", - eventMeshTCPServer.getRateLimiter().getRate()); - return; - } - - synchronized (session) { - long sendTime = System.currentTimeMillis(); - event = addTimestamp(event, cmd, sendTime); - - sendStatus = session - .upstreamMsg(pkg.getHeader(), event, - createSendCallback(replyCmd, taskExecuteTime, event), - startTime, taskExecuteTime); - - if (StringUtils.equals(EventMeshTcpSendStatus.SUCCESS.name(), - sendStatus.getSendStatus().name())) { - messageLogger.info("pkg|eventMesh2mq|cmd={}|Msg={}|user={}|wait={}ms|cost={}ms", - cmd, event, - session.getClient(), taskExecuteTime - startTime, sendTime - startTime); - } else { - throw new Exception(sendStatus.getDetail()); - } - } - } catch (Exception e) { - logger.error("MessageTransferTask failed|cmd={}|event={}|user={}", cmd, event, - session.getClient(), - e); - - if (!cmd.equals(RESPONSE_TO_SERVER)) { - msg.setHeader( - new Header(replyCmd, OPStatus.FAIL.getCode(), e.toString(), - pkg.getHeader() - .getSeq())); - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - - if (event != null) { - TraceUtils.finishSpanWithException(ctx, event, "MessageTransferTask failed", e); - } - } - } - } - - private CloudEvent addTimestamp(CloudEvent event, Command cmd, long sendTime) { - if (cmd.equals(RESPONSE_TO_SERVER)) { - event = CloudEventBuilder.from(event) - .withExtension(EventMeshConstants.RSP_C2EVENTMESH_TIMESTAMP, - String.valueOf(startTime)) - .withExtension(EventMeshConstants.RSP_EVENTMESH2MQ_TIMESTAMP, - String.valueOf(sendTime)) - .withExtension(EventMeshConstants.RSP_SEND_EVENTMESH_IP, - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerIp) - .build(); - } else { - event = CloudEventBuilder.from(event) - .withExtension(EventMeshConstants.REQ_C2EVENTMESH_TIMESTAMP, - String.valueOf(startTime)) - .withExtension(EventMeshConstants.REQ_EVENTMESH2MQ_TIMESTAMP, - String.valueOf(sendTime)) - .withExtension(EventMeshConstants.REQ_SEND_EVENTMESH_IP, - eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerIp) - .build(); - } - return event; - } - - private Command getReplyCmd(Command cmd) { - switch (cmd) { - case REQUEST_TO_SERVER: - return Command.RESPONSE_TO_CLIENT; - case ASYNC_MESSAGE_TO_SERVER: - return Command.ASYNC_MESSAGE_TO_SERVER_ACK; - case BROADCAST_MESSAGE_TO_SERVER: - return Command.BROADCAST_MESSAGE_TO_SERVER_ACK; - default: - return cmd; - } - } - - protected SendCallback createSendCallback(Command replyCmd, long taskExecuteTime, - CloudEvent event) { - final long createTime = System.currentTimeMillis(); - Package msg = new Package(); - - return new SendCallback() { - @Override - public void onSuccess(SendResult sendResult) { - session.getSender().getUpstreamBuff().release(); - messageLogger.info("upstreamMsg message success|user={}|callback cost={}", - session.getClient(), - System.currentTimeMillis() - createTime); - if (replyCmd.equals(Command.BROADCAST_MESSAGE_TO_SERVER_ACK) - || replyCmd.equals(Command.ASYNC_MESSAGE_TO_SERVER_ACK)) { - msg.setHeader( - new Header(replyCmd, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), - pkg.getHeader().getSeq())); - msg.setBody(event); - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), - session); - - //async request need finish span when callback, rr request will finish span when rrCallback - TraceUtils.finishSpan(ctx, event); - } - } - - @Override - public void onException(OnExceptionContext context) { - session.getSender().getUpstreamBuff().release(); - - // retry - UpStreamMsgContext upStreamMsgContext = new UpStreamMsgContext( - session, event, pkg.getHeader(), startTime, taskExecuteTime); - upStreamMsgContext.delay(10000); - session.getClientGroupWrapper().get().getEventMeshTcpRetryer() - .pushRetry(upStreamMsgContext); - - session.getSender().failMsgCount.incrementAndGet(); - messageLogger - .error("upstreamMsg mq message error|user={}|callback cost={}, errMsg={}", - session.getClient(), - (System.currentTimeMillis() - createTime), - new Exception(context.getException())); - msg.setHeader( - new Header(replyCmd, OPStatus.FAIL.getCode(), context.getException().toString(), - pkg.getHeader().getSeq())); - msg.setBody(event); - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - - //both rr request and async request need finish span when reqeust fail - if (!replyCmd.equals(RESPONSE_TO_SERVER)) { - //upload trace - TraceUtils.finishSpanWithException(ctx, event, - "upload trace fail in MessageTransferTask.createSendCallback.onException", - context.getException()); - } - } - }; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/RecommendTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/RecommendTask.java deleted file mode 100644 index 6499e8e948..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/RecommendTask.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import static org.apache.eventmesh.common.protocol.tcp.Command.RECOMMEND_RESPONSE; -import static org.apache.eventmesh.runtime.util.Utils.writeAndFlush; - -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendStrategy; - -import org.apache.commons.lang3.StringUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; - -public class RecommendTask extends AbstractTask { - - private final Logger messageLogger = LoggerFactory.getLogger("message"); - - public RecommendTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Package res = new Package(); - try { - if (!eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerRegistryEnable) { - throw new Exception("registry enable config is false, not support"); - } - UserAgent user = (UserAgent) pkg.getBody(); - validateUserAgent(user); - String group = getGroupOfClient(user); - EventMeshRecommendStrategy eventMeshRecommendStrategy = new EventMeshRecommendImpl(eventMeshTCPServer); - String eventMeshRecommendResult = eventMeshRecommendStrategy.calculateRecommendEventMesh(group, user.getPurpose()); - res.setHeader(new Header(RECOMMEND_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader().getSeq())); - res.setBody(eventMeshRecommendResult); - } catch (Exception e) { - messageLogger.error("RecommendTask failed|address={}|errMsg={}", ctx.channel().remoteAddress(), e); - res.setHeader(new Header(RECOMMEND_RESPONSE, OPStatus.FAIL.getCode(), e.toString(), pkg - .getHeader().getSeq())); - - } finally { - writeAndFlush(res, startTime, taskExecuteTime, session.getContext(), session); - //session.write2Client(res); - } - } - - private void validateUserAgent(UserAgent user) throws Exception { - if (user == null) { - throw new Exception("client info cannot be null"); - } - - if (user.getVersion() == null) { - throw new Exception("client version cannot be null"); - } - - if (user.getUsername() == null) { - throw new Exception("client wemqUser cannot be null"); - } - - if (user.getPassword() == null) { - throw new Exception("client wemqPasswd cannot be null"); - } - - if (!(StringUtils.equals(EventMeshConstants.PURPOSE_PUB, user.getPurpose()) || StringUtils.equals( - EventMeshConstants.PURPOSE_SUB, user.getPurpose()))) { - throw new Exception("client purpose config is error"); - } - } - - private String getGroupOfClient(UserAgent userAgent) { - if (userAgent == null) { - return null; - } - return userAgent.getGroup(); - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/SubscribeTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/SubscribeTask.java deleted file mode 100644 index 852636c37d..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/SubscribeTask.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.protocol.tcp.Subscription; -import org.apache.eventmesh.runtime.acl.Acl; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.util.RemotingHelper; -import org.apache.eventmesh.runtime.util.Utils; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; - -public class SubscribeTask extends AbstractTask { - - private final Logger messageLogger = LoggerFactory.getLogger("message"); - - public SubscribeTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Package msg = new Package(); - try { - Subscription subscriptionInfo = (Subscription) pkg.getBody(); - if (subscriptionInfo == null) { - throw new Exception("subscriptionInfo is null"); - } - - List subscriptionItems = new ArrayList<>(); - for (int i = 0; i < subscriptionInfo.getTopicList().size(); i++) { - SubscriptionItem item = subscriptionInfo.getTopicList().get(i); - - //do acl check for receive msg - if (eventMeshTCPServer.getEventMeshTCPConfiguration().eventMeshServerSecurityEnable) { - String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); - Acl.doAclCheckInTcpReceive(remoteAddr, session.getClient(), item.getTopic(), Command.SUBSCRIBE_REQUEST.value()); - } - - subscriptionItems.add(item); - } - synchronized (session) { - session.subscribe(subscriptionItems); - messageLogger.info("SubscribeTask succeed|user={}|topics={}", session.getClient(), subscriptionItems); - } - msg.setHeader(new Header(Command.SUBSCRIBE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader() - .getSeq())); - } catch (Exception e) { - messageLogger.error("SubscribeTask failed|user={}|errMsg={}", session.getClient(), e); - msg.setHeader(new Header(Command.SUBSCRIBE_RESPONSE, OPStatus.FAIL.getCode(), e.toString(), pkg.getHeader() - .getSeq())); - } finally { - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - } - } - - -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/UnSubscribeTask.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/UnSubscribeTask.java deleted file mode 100644 index 15e3f70326..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/core/protocol/tcp/client/task/UnSubscribeTask.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.core.protocol.tcp.client.task; - -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.OPStatus; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.util.Utils; - -import org.apache.commons.collections4.MapUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; - -public class UnSubscribeTask extends AbstractTask { - - private final Logger messageLogger = LoggerFactory.getLogger("message"); - - public UnSubscribeTask(Package pkg, ChannelHandlerContext ctx, long startTime, EventMeshTCPServer eventMeshTCPServer) { - super(pkg, ctx, startTime, eventMeshTCPServer); - } - - @Override - public void run() { - long taskExecuteTime = System.currentTimeMillis(); - Package msg = new Package(); - try { - synchronized (session) { - List topics = new ArrayList(); - if (MapUtils.isNotEmpty(session.getSessionContext().subscribeTopics)) { - for (Map.Entry entry : session.getSessionContext().subscribeTopics.entrySet()) { - topics.add(entry.getValue()); - } - session.unsubscribe(topics); - messageLogger.info("UnSubscriberTask succeed|user={}|topics={}", session.getClient(), topics); - } - } - msg.setHeader(new Header(Command.UNSUBSCRIBE_RESPONSE, OPStatus.SUCCESS.getCode(), OPStatus.SUCCESS.getDesc(), pkg.getHeader() - .getSeq())); - } catch (Exception e) { - messageLogger.error("UnSubscribeTask failed|user={}|errMsg={}", session.getClient(), e); - msg.setHeader(new Header(Command.UNSUBSCRIBE_RESPONSE, OPStatus.FAIL.getCode(), "exception while " - + - "unSubscribing", pkg.getHeader().getSeq())); - } finally { - Utils.writeAndFlush(msg, startTime, taskExecuteTime, session.getContext(), session); - } - } - - -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/meta/MetaStorage.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/meta/MetaStorage.java new file mode 100644 index 0000000000..41da6994f7 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/meta/MetaStorage.java @@ -0,0 +1,148 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.meta; + +import org.apache.eventmesh.api.exception.MetaException; +import org.apache.eventmesh.api.meta.MetaService; +import org.apache.eventmesh.api.meta.MetaServiceListener; +import org.apache.eventmesh.api.meta.bo.EventMeshAppSubTopicInfo; +import org.apache.eventmesh.api.meta.bo.EventMeshServicePubTopicInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshDataInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshRegisterInfo; +import org.apache.eventmesh.api.meta.dto.EventMeshUnRegisterInfo; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MetaStorage { + + private static final Map META_CACHE = new HashMap<>(16); + + private MetaService metaService; + + private final AtomicBoolean inited = new AtomicBoolean(false); + + private final AtomicBoolean started = new AtomicBoolean(false); + + private final AtomicBoolean shutdown = new AtomicBoolean(false); + + private MetaStorage() { + + } + + public static MetaStorage getInstance(String metaPluginType) { + return META_CACHE.computeIfAbsent(metaPluginType, MetaStorage::metaStorageBuilder); + } + + private static MetaStorage metaStorageBuilder(String metaPluginType) { + MetaService metaServiceExt = EventMeshExtensionFactory.getExtension(MetaService.class, metaPluginType); + if (metaServiceExt == null) { + String errorMsg = "can't load the metaService plugin, please check."; + log.error(errorMsg); + throw new RuntimeException(errorMsg); + } + MetaStorage metaStorage = new MetaStorage(); + metaStorage.metaService = metaServiceExt; + + return metaStorage; + } + + public void init() throws MetaException { + if (!inited.compareAndSet(false, true)) { + return; + } + metaService.init(); + } + + public void start() throws MetaException { + if (!started.compareAndSet(false, true)) { + return; + } + metaService.start(); + } + + public void shutdown() throws MetaException { + inited.compareAndSet(true, false); + started.compareAndSet(true, false); + if (!shutdown.compareAndSet(false, true)) { + return; + } + synchronized (this) { + metaService.shutdown(); + } + } + + public List findEventMeshInfoByCluster(String clusterName) throws MetaException { + return metaService.findEventMeshInfoByCluster(clusterName); + } + + public List findAllEventMeshInfo() throws MetaException { + return metaService.findAllEventMeshInfo(); + } + + public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) + throws MetaException { + return metaService.findEventMeshClientDistributionData(clusterName, group, purpose); + } + + public void registerMetadata(Map metadata) { + metaService.registerMetadata(metadata); + } + + public void updateMetaData(Map metadata) { + metaService.updateMetaData(metadata); + } + + public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws MetaException { + return metaService.register(eventMeshRegisterInfo); + } + + public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws MetaException { + return metaService.unRegister(eventMeshUnRegisterInfo); + } + + public List findEventMeshServicePubTopicInfos() throws Exception { + return metaService.findEventMeshServicePubTopicInfos(); + } + + public EventMeshAppSubTopicInfo findEventMeshAppSubTopicInfo(String group) throws Exception { + return metaService.findEventMeshAppSubTopicInfoByGroup(group); + } + + public Map getMetaData(String key, boolean fuzzyEnabled) { + return metaService.getMetaData(key, fuzzyEnabled); + } + + public void getMetaDataWithListener(MetaServiceListener metaServiceListener, String key) throws Exception { + metaService.getMetaDataWithListener(metaServiceListener, key); + } + + public AtomicBoolean getInited() { + return inited; + } + + public AtomicBoolean getStarted() { + return started; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/EventMeshMetricsManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/EventMeshMetricsManager.java new file mode 100644 index 0000000000..a796ad81a5 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/EventMeshMetricsManager.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics; + +import org.apache.eventmesh.metrics.api.MetricsRegistry; +import org.apache.eventmesh.metrics.api.model.Metric; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * EventMeshMetricsManager class manages the metrics for EventMesh. + */ +public class EventMeshMetricsManager { + + private List metricsRegistries = new ArrayList<>(64); + private List metrics = new ArrayList<>(64); + private List metricsManagers = new ArrayList<>(32); + + /** + * Constructs an EventMeshMetricsManager with the provided metrics registries. + * + * @param metricsRegistries The list of metrics registries. + */ + public EventMeshMetricsManager(final List metricsRegistries) { + if (Objects.nonNull(metricsRegistries)) { + this.metricsRegistries.addAll(metricsRegistries); + } + } + + /** + * Constructs an EventMeshMetricsManager. + */ + public EventMeshMetricsManager() { + } + + /** + * Retrieves the list of metrics registries. + * + * @return The list of metrics registries. + */ + public List getMetricsRegistries() { + return metricsRegistries; + } + + /** + * Adds the provided metrics registries to the existing list. + * + * @param metricsRegistries The list of metrics registries to add. + */ + public void addMetricsRegistries(List metricsRegistries) { + if (Objects.nonNull(metricsRegistries)) { + this.metricsRegistries.addAll(metricsRegistries); + } + } + + /** + * Adds the provided metrics to the existing list. + * + * @param metrics The list of metrics to add. + */ + public void addMetrics(List metrics) { + if (Objects.nonNull(metrics)) { + this.metrics.addAll(metrics); + } + } + + /** + * Adds a metric manager to the list of metrics managers. + * + * @param metricsManager The metric manager to add. + */ + public void addMetricManager(final MetricsManager metricsManager) { + this.metricsManagers.add(metricsManager); + } + + /** + * Adds a metric to the existing list of metrics. + * + * @param metric The metric to add. + */ + public void addMetric(Metric metric) { + if (Objects.nonNull(metric)) { + this.metrics.add(metric); + } + } + + /** + * Initializes the EventMeshMetricsManager by registering the metrics with the metrics registries. + */ + public void init() { + MetricsUtils.registerMetrics(metricsRegistries); + // Register metrics + metricsRegistries.stream().forEach(metricsRegistry -> metricsRegistry.register(metrics)); + } + + /** + * Starts the metrics managers and metrics registries. + */ + public void start() { + metricsManagers.stream().forEach(MetricsManager::start); + metricsRegistries.stream().forEach(MetricsRegistry::start); + } + + /** + * Shuts down the metrics registries and metrics managers. + */ + public void shutdown() { + metricsRegistries.stream().forEach(MetricsRegistry::showdown); + metricsManagers.stream().forEach(MetricsManager::shutdown); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/GeneralMetrics.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/GeneralMetrics.java new file mode 100644 index 0000000000..0043a32e25 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/GeneralMetrics.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics; + +import org.apache.eventmesh.metrics.api.model.InstrumentFurther; +import org.apache.eventmesh.metrics.api.model.LongCounterMetric; +import org.apache.eventmesh.metrics.api.model.Metric; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class GeneralMetrics { + + private static final String METRIC_NAME = "general"; + + private static final String GENERAL_METRICS_NAME_PREFIX = "eventmesh.general."; + + protected static final Map metrics = new HashMap<>(32); + + //message number of client(TCP,HTTP,GRPC) send to EventMesh + protected static final LongCounterMetric client2eventMeshMsgNum; + + //message number of EventMesh send to MQ + protected static final LongCounterMetric eventMesh2mqMsgNum; + + //message number of MQ send to EventMesh + protected static final LongCounterMetric mq2eventMeshMsgNum; + + //message number of EventMesh send to client(TCP,HTTP,GRPC) + protected static final LongCounterMetric eventMesh2clientMsgNum; + + static { + InstrumentFurther furtherCl2Em = new InstrumentFurther(); + furtherCl2Em.setUnit(MetricInstrumentUnit.SINGLETON); + furtherCl2Em.setDescription("message number of client send to EventMesh"); + furtherCl2Em.setName(GENERAL_METRICS_NAME_PREFIX + "client.eventmesh.message.num"); + client2eventMeshMsgNum = new LongCounterMetric(furtherCl2Em, METRIC_NAME); + metrics.put("client2eventMeshMsgNum", client2eventMeshMsgNum); + + InstrumentFurther furtherEm2Mq = new InstrumentFurther(); + furtherEm2Mq.setUnit(MetricInstrumentUnit.SINGLETON); + furtherEm2Mq.setDescription("message number of EventMesh send to MQ"); + furtherEm2Mq.setName(GENERAL_METRICS_NAME_PREFIX + "eventmesh.mq.message.num"); + eventMesh2mqMsgNum = new LongCounterMetric(furtherEm2Mq, METRIC_NAME); + metrics.put("eventMesh2mqMsgNum", eventMesh2mqMsgNum); + + InstrumentFurther furtherMq2Em = new InstrumentFurther(); + furtherMq2Em.setUnit(MetricInstrumentUnit.SINGLETON); + furtherMq2Em.setDescription("message number of MQ send to EventMesh"); + furtherMq2Em.setName(GENERAL_METRICS_NAME_PREFIX + "mq.eventmesh.message.num"); + mq2eventMeshMsgNum = new LongCounterMetric(furtherMq2Em, METRIC_NAME); + metrics.put("mq2eventMeshMsgNum", mq2eventMeshMsgNum); + + InstrumentFurther furtherEm2Cl = new InstrumentFurther(); + furtherEm2Cl.setUnit(MetricInstrumentUnit.SINGLETON); + furtherEm2Cl.setDescription("message number of EventMesh send to client"); + furtherEm2Cl.setName(GENERAL_METRICS_NAME_PREFIX + "eventmesh.client.message.num"); + eventMesh2clientMsgNum = new LongCounterMetric(furtherEm2Cl, METRIC_NAME); + metrics.put("eventMesh2clientMsgNum", eventMesh2clientMsgNum); + } + + public static Collection getMetrics() { + return metrics.values(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricInstrumentUnit.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricInstrumentUnit.java new file mode 100644 index 0000000000..2186cbb447 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricInstrumentUnit.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics; + + +public class MetricInstrumentUnit { + + private MetricInstrumentUnit() { + + } + + public static final String SINGLETON = "1"; + + public static final String TPS = "tps"; + + public static final String MILLISECONDS = "ms"; + + public static final String PERCENT = "%"; + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricsManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricsManager.java new file mode 100644 index 0000000000..a1e333e482 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricsManager.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics; + +import org.apache.eventmesh.metrics.api.model.Metric; + +import java.util.List; + +/** + * MetricsManager is an interface for managing metrics. + */ +public interface MetricsManager { + + /** + * Retrieves the list of metrics. + * + * @return The list of metrics. + */ + List getMetrics(); + + /** + * Retrieves the name of the MetricsManager. + * + * @return The name of the MetricsManager. + */ + String getName(); + + /** + * Starts the MetricsManager. + */ + void start(); + + /** + * Shuts down the MetricsManager. + */ + void shutdown(); +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricsUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricsUtils.java new file mode 100644 index 0000000000..fb0e5d378d --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MetricsUtils.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics; + + +import org.apache.eventmesh.metrics.api.MetricsRegistry; + +import org.apache.commons.collections4.MapUtils; + +import java.util.List; +import java.util.Map; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; + +import lombok.experimental.UtilityClass; + +/** + * Managing general metrics. + */ +@UtilityClass +public class MetricsUtils { + + private static Attributes EMPTY_ATTRIBUTES = Attributes.builder().build(); + + /** + * Registers the general metrics with the provided metrics registries. + * + * @param metricsRegistries The list of metrics registries. + */ + public static void registerMetrics(final List metricsRegistries) { + metricsRegistries.forEach(metricsRegistry -> metricsRegistry.register(GeneralMetrics.getMetrics())); + } + + /** + * Increments the client-to-EventMesh message count metric by 1, with the given attributes. + * + * @param attributes The attributes for the metric. + */ + public static void incrementClientToEventMeshMsgNum(final Map attributes) { + GeneralMetrics.client2eventMeshMsgNum.getInstrument().add(1, buildAttributes(attributes)); + } + + /** + * Increments the client-to-EventMesh message count metric by a specific count, with the given attributes. + * + * @param attributes The attributes for the metric. + * @param count The count to increment the metric by. + */ + public static void incrementClientToEventMeshMsgNum(final Map attributes, final int count) { + GeneralMetrics.client2eventMeshMsgNum.getInstrument().add(count, buildAttributes(attributes)); + } + + /** + * Increments the EventMesh-to-MQ message count metric by 1, with the given attributes. + * + * @param attributes The attributes for the metric. + */ + public static void incrementEventMeshToMQMsgNum(final Map attributes) { + GeneralMetrics.eventMesh2mqMsgNum.getInstrument().add(1, buildAttributes(attributes)); + } + + /** + * Increments the MQ-to-EventMesh message count metric by 1, with the given attributes. + * + * @param attributes The attributes for the metric. + */ + public static void incrementMQToEventMeshMsgNum(final Map attributes) { + GeneralMetrics.mq2eventMeshMsgNum.getInstrument().add(1, buildAttributes(attributes)); + } + + /** + * Increments the EventMesh-to-client message count metric by 1, with the given attributes. + * + * @param attributes The attributes for the metric. + */ + public static void incrementEventMeshToClientMsgNum(final Map attributes) { + GeneralMetrics.eventMesh2clientMsgNum.getInstrument().add(1, buildAttributes(attributes)); + } + + /** + * Builds the attributes from the provided map. + * + * @param attributes The map of attributes. + * @return The built attributes. + */ + public static Attributes buildAttributes(final Map attributes) { + if (MapUtils.isEmpty(attributes)) { + return EMPTY_ATTRIBUTES; + } + AttributesBuilder attributesBuilder = Attributes.builder(); + attributes.forEach(attributesBuilder::put); + return attributesBuilder.build(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MonitorMetricConstants.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MonitorMetricConstants.java index 60a2360ca1..3f2a3e8b20 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MonitorMetricConstants.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/MonitorMetricConstants.java @@ -18,9 +18,10 @@ package org.apache.eventmesh.runtime.metrics; public class MonitorMetricConstants { - public static final String EVENTMESH_MONITOR_FORMAT_COMMON = "{\"protocol\":\"%s\",\"s\":\"%s\",\"t\":\"%s\"}"; - public static final String EVENTMESH_TCP_MONITOR_FORMAT_THREADPOOL = "{\"threadPoolName\":\"%s\",\"s\":\"%s\",\"t\":\"%s\"}"; + public static final String EVENTMESH_MONITOR_FORMAT_COMMON = "{\"protocol\":\"{}\",\"s\":\"{}\",\"t\":\"{}\"}"; + + public static final String EVENTMESH_TCP_MONITOR_FORMAT_THREADPOOL = "{\"threadPoolName\":\"{}\",\"s\":\"{}\",\"t\":\"{}\"}"; public static final String CLIENT_2_EVENTMESH_TPS = "client2eventMeshTPS"; public static final String EVENTMESH_2_MQ_TPS = "eventMesh2mqTPS"; @@ -37,4 +38,5 @@ public class MonitorMetricConstants { public static final String POOL_SIZE = "poolSize"; public static final String ACTIVE_COUNT = "activeCount"; public static final String COMPLETED_TASK = "completedTask"; + } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/grpc/EventMeshGrpcMetricsManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/grpc/EventMeshGrpcMetricsManager.java new file mode 100644 index 0000000000..2710474818 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/grpc/EventMeshGrpcMetricsManager.java @@ -0,0 +1,148 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.grpc; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.MetricsConstants; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.enums.ProtocolType; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.metrics.api.MetricsRegistry; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.metrics.MetricsManager; +import org.apache.eventmesh.runtime.metrics.MetricsUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshGrpcMetricsManager implements MetricsManager { + + private static final long DELAY_MILLS = 60 * 1000; + private static final long SCHEDULE_PERIOD_MILLS = 60 * 1000; + private static final int SCHEDULE_THREAD_SIZE = 1; + private static final String THREAD_NAME_PREFIX = "eventMesh-grpc-monitor-scheduler"; + + private final Map labelMap = new HashMap<>(); + + private final EventMeshGrpcServer eventMeshGrpcServer; + private final List metricsRegistries; + + private final ScheduledExecutorService scheduler; + private ScheduledFuture scheduleTask; + + private final GrpcMetrics grpcMetrics; + + public EventMeshGrpcMetricsManager(EventMeshGrpcServer eventMeshGrpcServer, List metricsRegistries) { + this.eventMeshGrpcServer = Preconditions.checkNotNull(eventMeshGrpcServer); + this.metricsRegistries = Preconditions.checkNotNull(metricsRegistries); + this.grpcMetrics = new GrpcMetrics(eventMeshGrpcServer, labelMap); + this.scheduler = ThreadPoolFactory.createScheduledExecutor(SCHEDULE_THREAD_SIZE, new EventMeshThreadFactory(THREAD_NAME_PREFIX, true)); + init(); + } + + private void init() { + String eventMeshServerIp = this.eventMeshGrpcServer.getEventMeshGrpcConfiguration().getEventMeshServerIp(); + int eventMeshTcpServerPort = this.eventMeshGrpcServer.getEventMeshGrpcConfiguration().getGrpcServerPort(); + labelMap.put(MetricsConstants.RPC_SYSTEM, "grpc"); + labelMap.put(MetricsConstants.RPC_SERVICE, this.eventMeshGrpcServer.getClass().getName()); + labelMap.put(MetricsConstants.GRPC_NET_PEER_NAME, Optional.ofNullable(eventMeshServerIp).orElse(IPUtils.getLocalAddress())); + labelMap.put(MetricsConstants.GRPC_NET_PEER_PORT, Integer.toString(eventMeshTcpServerPort)); + } + + @Override + public void start() { + // update tps metrics and clear counter + scheduleTask = scheduler.scheduleAtFixedRate(() -> { + grpcMetrics.refreshTpsMetrics(SCHEDULE_PERIOD_MILLS); + grpcMetrics.clearAllMessageCounter(); + grpcMetrics.setRetrySize(0); + grpcMetrics.setSubscribeTopicNum(eventMeshGrpcServer.getConsumerManager().getAllConsumerTopic().size()); + }, DELAY_MILLS, SCHEDULE_PERIOD_MILLS, TimeUnit.MILLISECONDS); + } + + public void recordReceiveMsgFromClient(final String clientAddress) { + grpcMetrics.getClient2EventMeshMsgNum().incrementAndGet(); + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.GRPC.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementClientToEventMeshMsgNum(attributes); + } + + public void recordReceiveMsgFromClient(final int count, String clientAddress) { + grpcMetrics.getClient2EventMeshMsgNum().addAndGet(count); + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.GRPC.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementClientToEventMeshMsgNum(attributes, count); + } + + public void recordSendMsgToQueue() { + grpcMetrics.getEventMesh2MqMsgNum().incrementAndGet(); + Map attributes = new HashMap<>(labelMap); + MetricsUtils.incrementEventMeshToMQMsgNum(attributes); + } + + public void recordReceiveMsgFromQueue() { + grpcMetrics.getMq2EventMeshMsgNum().incrementAndGet(); + Map attributes = new HashMap<>(labelMap); + MetricsUtils.incrementMQToEventMeshMsgNum(attributes); + } + + public void recordSendMsgToClient(final String clientAddress) { + grpcMetrics.getEventMesh2ClientMsgNum().incrementAndGet(); + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.TCP.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementEventMeshToClientMsgNum(attributes); + } + + public void recordGrpcPublishHandleCost(long costTime, String clientAddress) { + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.TCP.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + grpcMetrics.recordGrpcPublishHandleCost(costTime, MetricsUtils.buildAttributes(attributes)); + } + + @Override + public void shutdown() { + scheduleTask.cancel(true); + scheduler.shutdown(); + } + + @Override + public List getMetrics() { + return new ArrayList<>(grpcMetrics.getMetrics()); + } + + @Override + public String getName() { + return this.getClass().getName(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/grpc/GrpcMetrics.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/grpc/GrpcMetrics.java new file mode 100644 index 0000000000..8bb8fa9edc --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/grpc/GrpcMetrics.java @@ -0,0 +1,263 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.grpc; + +import org.apache.eventmesh.common.Pair; +import org.apache.eventmesh.metrics.api.model.DoubleHistogramMetric; +import org.apache.eventmesh.metrics.api.model.InstrumentFurther; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.metrics.api.model.NoopDoubleHistogram; +import org.apache.eventmesh.metrics.api.model.ObservableDoubleGaugeMetric; +import org.apache.eventmesh.metrics.api.model.ObservableLongGaugeMetric; +import org.apache.eventmesh.runtime.boot.EventMeshGrpcServer; +import org.apache.eventmesh.runtime.metrics.MetricInstrumentUnit; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.InstrumentSelector; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.View; + +public class GrpcMetrics { + + private static final String GRPC_METRICS_NAME_PREFIX = "eventmesh.grpc."; + + private static final String METRIC_NAME = "GRPC"; + + private static double ms = 1; + + private static double s = 1000 * ms; + + private final EventMeshGrpcServer eventMeshGrpcServer; + + private final AtomicLong client2EventMeshMsgNum; + private final AtomicLong eventMesh2MqMsgNum; + private final AtomicLong mq2EventMeshMsgNum; + private final AtomicLong eventMesh2ClientMsgNum; + + private volatile double client2EventMeshTPS; + private volatile double eventMesh2ClientTPS; + private volatile double eventMesh2MqTPS; + private volatile double mq2EventMeshTPS; + + private volatile long retrySize; + private volatile long subscribeTopicNum; + + private final DoubleHistogram grpcPublishHandleCost = new NoopDoubleHistogram(); + + private ObservableDoubleGaugeMetric mq2eventMeshTPSGauge; + + private ObservableDoubleGaugeMetric client2eventMeshTPSGauge; + + private ObservableDoubleGaugeMetric eventMesh2clientTPSGauge; + + private ObservableDoubleGaugeMetric eventMesh2mqTPSGauge; + + private ObservableLongGaugeMetric subTopicGauge; + + private DoubleHistogramMetric grpcPublishHandleCostHistogram; + + private final Map metrics = new HashMap<>(32); + + private final Map labelMap; + + public GrpcMetrics(final EventMeshGrpcServer eventMeshGrpcServer, final Map labelMap) { + this.eventMeshGrpcServer = eventMeshGrpcServer; + this.labelMap = labelMap; + this.client2EventMeshMsgNum = new AtomicLong(0); + this.eventMesh2MqMsgNum = new AtomicLong(0); + this.mq2EventMeshMsgNum = new AtomicLong(0); + this.eventMesh2ClientMsgNum = new AtomicLong(0); + initMetric(); + } + + private void initMetric() { + final Map commonAttributes = new HashMap<>(labelMap); + + InstrumentFurther furtherTopic = new InstrumentFurther(); + furtherTopic.setUnit(MetricInstrumentUnit.SINGLETON); + furtherTopic.setDescription("Number of grpc client subscribe for topic"); + furtherTopic.setName(GRPC_METRICS_NAME_PREFIX + "sub.topic.num"); + subTopicGauge = new ObservableLongGaugeMetric(furtherTopic, METRIC_NAME, buildSubTopicSupplier()); + subTopicGauge.putAll(commonAttributes); + metrics.put("subTopicGauge", subTopicGauge); + + InstrumentFurther furtherCl2Em = new InstrumentFurther(); + furtherCl2Em.setUnit(MetricInstrumentUnit.TPS); + furtherCl2Em.setDescription("Tps of client to EventMesh."); + furtherCl2Em.setName(GRPC_METRICS_NAME_PREFIX + "client.eventmesh.tps"); + client2eventMeshTPSGauge = new ObservableDoubleGaugeMetric(furtherCl2Em, METRIC_NAME, () -> GrpcMetrics.this.client2EventMeshTPS); + client2eventMeshTPSGauge.putAll(commonAttributes); + metrics.put("client2eventMeshTPSGauge", client2eventMeshTPSGauge); + + InstrumentFurther furtherEm2Cl = new InstrumentFurther(); + furtherEm2Cl.setUnit(MetricInstrumentUnit.TPS); + furtherEm2Cl.setDescription("Tps of EventMesh to client."); + furtherEm2Cl.setName(GRPC_METRICS_NAME_PREFIX + "eventmesh.client.tps"); + eventMesh2clientTPSGauge = new ObservableDoubleGaugeMetric(furtherEm2Cl, METRIC_NAME, () -> GrpcMetrics.this.eventMesh2ClientTPS); + eventMesh2clientTPSGauge.putAll(commonAttributes); + metrics.put("eventMesh2clientTPSGauge", eventMesh2clientTPSGauge); + + InstrumentFurther furtherEm2Mq = new InstrumentFurther(); + furtherEm2Mq.setUnit(MetricInstrumentUnit.TPS); + furtherEm2Mq.setDescription("Tps of EventMesh to MQ."); + furtherEm2Mq.setName(GRPC_METRICS_NAME_PREFIX + "eventmesh.mq.tps"); + eventMesh2mqTPSGauge = new ObservableDoubleGaugeMetric(furtherEm2Mq, METRIC_NAME, () -> GrpcMetrics.this.eventMesh2MqTPS); + eventMesh2mqTPSGauge.putAll(commonAttributes); + metrics.put("eventMesh2mqTPSGauge", eventMesh2mqTPSGauge); + + InstrumentFurther furtherMq2Em = new InstrumentFurther(); + furtherMq2Em.setUnit(MetricInstrumentUnit.TPS); + furtherMq2Em.setDescription("Tps of MQ to EventMesh."); + furtherMq2Em.setName(GRPC_METRICS_NAME_PREFIX + "mq.eventmesh.tps"); + mq2eventMeshTPSGauge = new ObservableDoubleGaugeMetric(furtherMq2Em, METRIC_NAME, () -> GrpcMetrics.this.mq2EventMeshTPS); + mq2eventMeshTPSGauge.putAll(commonAttributes); + metrics.put("mq2eventMeshTPSGauge", mq2eventMeshTPSGauge); + + InstrumentFurther furtherGrpcPublishHandleCost = new InstrumentFurther(); + furtherGrpcPublishHandleCost.setUnit(MetricInstrumentUnit.MILLISECONDS); + furtherGrpcPublishHandleCost.setDescription("Grpc publish handle cost time"); + String grpcPublishHandleCostName = GRPC_METRICS_NAME_PREFIX + "publish.handle.cost"; + furtherGrpcPublishHandleCost.setName(grpcPublishHandleCostName); + Pair pair = buildGrpcPublishHandleCostMetricsView(grpcPublishHandleCostName); + furtherGrpcPublishHandleCost.putExt(InstrumentFurther.INSTRUMENT_VIEW, pair); + grpcPublishHandleCostHistogram = new DoubleHistogramMetric(furtherGrpcPublishHandleCost, METRIC_NAME); + metrics.put("grpcPublishHandleCost", grpcPublishHandleCostHistogram); + } + + private Pair buildGrpcPublishHandleCostMetricsView(String metricName) { + List latencyBuckets = Arrays.asList( + 1 * ms, 3 * ms, 5 * ms, + 10 * ms, 30 * ms, 50 * ms, + 100 * ms, 300 * ms, 500 * ms, + 1 * s, 3 * s, 5 * s, 10 * s); + View view = View.builder() + .setAggregation(Aggregation.explicitBucketHistogram(latencyBuckets)) + .build(); + InstrumentSelector selector = InstrumentSelector.builder() + .setType(InstrumentType.HISTOGRAM) + .setName(metricName) + .build(); + + return new Pair<>(selector, view); + } + + public void recordGrpcPublishHandleCost(long time, Attributes attributes) { + grpcPublishHandleCostHistogram.getInstrument().record(time, attributes); + } + + /** + * Count the number of GRPC clients subscribed to a topic. + * + * @return Supplier + */ + private Supplier buildSubTopicSupplier() { + return () -> (long) this.eventMeshGrpcServer.getConsumerManager().getAllConsumerTopic().size(); + } + + public void clearAllMessageCounter() { + client2EventMeshMsgNum.set(0L); + eventMesh2MqMsgNum.set(0L); + mq2EventMeshMsgNum.set(0L); + eventMesh2ClientMsgNum.set(0L); + } + + public void refreshTpsMetrics(long intervalMills) { + BigDecimal intervalMillisBD = BigDecimal.valueOf(intervalMills); + // Calculate TPS for client2EventMesh messages + client2EventMeshTPS = BigDecimal.valueOf(1000).multiply(BigDecimal.valueOf(client2EventMeshMsgNum.get())) + .divide(intervalMillisBD, 2, RoundingMode.HALF_UP).doubleValue(); + + // Calculate TPS for eventMesh2Client messages + eventMesh2ClientTPS = BigDecimal.valueOf(1000).multiply(BigDecimal.valueOf(eventMesh2ClientMsgNum.get())) + .divide(intervalMillisBD, 2, RoundingMode.HALF_UP).doubleValue(); + + // Calculate TPS for eventMesh2Mq messages + eventMesh2MqTPS = BigDecimal.valueOf(1000).multiply(BigDecimal.valueOf(eventMesh2MqMsgNum.get())) + .divide(intervalMillisBD, 2, RoundingMode.HALF_UP).doubleValue(); + + // Calculate TPS for mq2EventMesh messages + mq2EventMeshTPS = BigDecimal.valueOf(1000).multiply(BigDecimal.valueOf(mq2EventMeshMsgNum.get())) + .divide(intervalMillisBD, 2, RoundingMode.HALF_UP).doubleValue(); + + } + + public Collection getMetrics() { + return metrics.values(); + } + + public AtomicLong getClient2EventMeshMsgNum() { + return client2EventMeshMsgNum; + } + + public AtomicLong getEventMesh2MqMsgNum() { + return eventMesh2MqMsgNum; + } + + public AtomicLong getMq2EventMeshMsgNum() { + return mq2EventMeshMsgNum; + } + + public AtomicLong getEventMesh2ClientMsgNum() { + return eventMesh2ClientMsgNum; + } + + public double getClient2EventMeshTPS() { + return client2EventMeshTPS; + } + + public double getEventMesh2ClientTPS() { + return eventMesh2ClientTPS; + } + + public double getEventMesh2MqTPS() { + return eventMesh2MqTPS; + } + + public double getMq2EventMeshTPS() { + return mq2EventMeshTPS; + } + + public long getRetrySize() { + return retrySize; + } + + public void setRetrySize(long retrySize) { + this.retrySize = retrySize; + } + + public long getSubscribeTopicNum() { + return subscribeTopicNum; + } + + public void setSubscribeTopicNum(long subscribeTopicNum) { + this.subscribeTopicNum = subscribeTopicNum; + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/EventMeshHttpMetricsManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/EventMeshHttpMetricsManager.java new file mode 100644 index 0000000000..1ee6e8de35 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/EventMeshHttpMetricsManager.java @@ -0,0 +1,242 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.http; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.MetricsConstants; +import org.apache.eventmesh.common.enums.ProtocolType; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.metrics.api.MetricsRegistry; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; +import org.apache.eventmesh.runtime.metrics.MetricsManager; +import org.apache.eventmesh.runtime.metrics.MetricsUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshHttpMetricsManager implements MetricsManager { + + private Map labelMap = new HashMap<>(); + + private final EventMeshHTTPServer eventMeshHTTPServer; + + private final List metricsRegistries; + + private final HttpMetrics httpMetrics; + + public EventMeshHttpMetricsManager(final EventMeshHTTPServer eventMeshHTTPServer, + final List metricsRegistries) { + Objects.requireNonNull(eventMeshHTTPServer, "EventMeshHTTPServer can not be null"); + Objects.requireNonNull(metricsRegistries, "List can not be null"); + + this.eventMeshHTTPServer = eventMeshHTTPServer; + this.metricsRegistries = metricsRegistries; + init(); + this.httpMetrics = new HttpMetrics( + eventMeshHTTPServer.getHttpThreadPoolGroup().getBatchMsgExecutor(), + eventMeshHTTPServer.getHttpThreadPoolGroup().getSendMsgExecutor(), + eventMeshHTTPServer.getHttpThreadPoolGroup().getPushMsgExecutor(), + new DelayQueue<>(), + labelMap); + } + + private void init() { + boolean useTls = eventMeshHTTPServer.getEventMeshHttpConfiguration().isEventMeshServerUseTls(); + String eventMeshServerIp = this.eventMeshHTTPServer.getEventMeshHttpConfiguration().getEventMeshServerIp(); + int httpServerPort = this.eventMeshHTTPServer.getEventMeshHttpConfiguration().getHttpServerPort(); + this.labelMap.put(MetricsConstants.HTTP_HTTP_SCHEME, useTls ? "https" : "http"); + this.labelMap.put(MetricsConstants.HTTP_HTTP_FLAVOR, "1.1"); + this.labelMap.put(MetricsConstants.HTTP_NET_HOST_NAME, Optional.ofNullable(eventMeshServerIp).orElse(IPUtils.getLocalAddress())); + this.labelMap.put(MetricsConstants.HTTP_NET_HOST_PORT, Integer.toString(httpServerPort)); + this.labelMap.put(MetricsConstants.RPC_SYSTEM, "HTTP"); + this.labelMap.put(MetricsConstants.RPC_SERVICE, this.eventMeshHTTPServer.getClass().getName()); + if (log.isInfoEnabled()) { + log.info("HTTPMetricsServer initialized."); + } + } + + @Override + public void start() { + + metricsSchedule.scheduleAtFixedRate(() -> { + try { + httpMetrics.snapshotHTTPTPS(); + httpMetrics.snapshotSendBatchMsgTPS(); + httpMetrics.snapshotSendMsgTPS(); + httpMetrics.snapshotPushMsgTPS(); + } catch (Exception ex) { + log.error("eventMesh snapshot tps metrics err", ex); + } + }, 0, 1000, TimeUnit.MILLISECONDS); + + metricsSchedule.scheduleAtFixedRate(() -> { + try { + logPrintServerMetrics(httpMetrics, eventMeshHTTPServer); + } catch (Exception ex) { + log.error("eventMesh print metrics err", ex); + } + }, 1000, 30 * 1000, TimeUnit.MILLISECONDS); + + if (log.isInfoEnabled()) { + log.info("HTTPMetricsServer started."); + } + } + + public void recordReceiveMsgFromClient(final String clientAddress) { + + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.GRPC.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementClientToEventMeshMsgNum(attributes); + } + + public void recordReceiveMsgFromClient(final int count, String clientAddress) { + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.GRPC.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementClientToEventMeshMsgNum(attributes, count); + } + + public void recordSendMsgToQueue() { + Map attributes = new HashMap<>(labelMap); + MetricsUtils.incrementEventMeshToMQMsgNum(attributes); + } + + public void recordReceiveMsgFromQueue() { + Map attributes = new HashMap<>(labelMap); + MetricsUtils.incrementMQToEventMeshMsgNum(attributes); + } + + public void recordSendMsgToClient(final String clientAddress) { + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.TCP.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementEventMeshToClientMsgNum(attributes); + } + + + @Override + public void shutdown() { + metricsSchedule.shutdown(); + } + + private static ScheduledExecutorService metricsSchedule = Executors.newScheduledThreadPool(2, + new EventMeshThreadFactory("eventMesh-metrics", true)); + + // todo: move this into standalone metrics plugin + + private void logPrintServerMetrics(final HttpMetrics summaryMetrics, + final EventMeshHTTPServer eventMeshHTTPServer) { + if (log.isInfoEnabled()) { + log.info("===========================================HTTP SERVER METRICS=================================================="); + + log.info("maxHTTPTPS: {}, avgHTTPTPS: {}, maxHTTPCOST: {}, avgHTTPCOST: {}, avgHTTPBodyDecodeCost: {}, httpDiscard: {}", + summaryMetrics.maxHTTPTPS(), + summaryMetrics.avgHTTPTPS(), + summaryMetrics.maxHTTPCost(), + summaryMetrics.avgHTTPCost(), + summaryMetrics.avgHTTPBodyDecodeCost(), + summaryMetrics.getHttpDiscard()); + } + + summaryMetrics.httpStatInfoClear(); + + if (log.isInfoEnabled()) { + log.info("maxBatchSendMsgTPS: {}, avgBatchSendMsgTPS: {}, sum: {}. sumFail: {}, sumFailRate: {}, discard : {}", + summaryMetrics.maxSendBatchMsgTPS(), + summaryMetrics.avgSendBatchMsgTPS(), + summaryMetrics.getSendBatchMsgNumSum(), + summaryMetrics.getSendBatchMsgFailNumSum(), + summaryMetrics.getSendBatchMsgFailRate(), + summaryMetrics.getSendBatchMsgDiscardNumSum() + ); + } + + summaryMetrics.cleanSendBatchStat(); + + if (log.isInfoEnabled()) { + log.info("maxSendMsgTPS: {}, avgSendMsgTPS: {}, sum: {}, sumFail: {}, sumFailRate: {}, replyMsg: {}, replyFail: {}", + summaryMetrics.maxSendMsgTPS(), + summaryMetrics.avgSendMsgTPS(), + summaryMetrics.getSendMsgNumSum(), + summaryMetrics.getSendMsgFailNumSum(), + summaryMetrics.getSendMsgFailRate(), + summaryMetrics.getReplyMsgNumSum(), + summaryMetrics.getReplyMsgFailNumSum() + ); + } + + summaryMetrics.cleanSendMsgStat(); + + if (log.isInfoEnabled()) { + log.info( + "maxPushMsgTPS: {}, avgPushMsgTPS: {}, sum: {}, sumFail: {}, sumFailRate: {}, maxClientLatency: {}, avgClientLatency: {}", + summaryMetrics.maxPushMsgTPS(), + summaryMetrics.avgPushMsgTPS(), + summaryMetrics.getHttpPushMsgNumSum(), + summaryMetrics.getHttpPushFailNumSum(), + summaryMetrics.getHttpPushMsgFailRate(), + summaryMetrics.maxHTTPPushLatency(), + summaryMetrics.avgHTTPPushLatency() + ); + } + + summaryMetrics.cleanHttpPushMsgStat(); + + if (log.isInfoEnabled()) { + log.info("batchMsgQ: {}, sendMsgQ: {}, pushMsgQ: {}", + eventMeshHTTPServer.getHttpThreadPoolGroup().getBatchMsgExecutor().getQueue().size(), + eventMeshHTTPServer.getHttpThreadPoolGroup().getSendMsgExecutor().getQueue().size(), + eventMeshHTTPServer.getHttpThreadPoolGroup().getPushMsgExecutor().getQueue().size()); + } + + if (log.isInfoEnabled()) { + log.info("batchAvgSend2MQCost: {}, avgSend2MQCost: {}, avgReply2MQCost: {}", + summaryMetrics.avgBatchSendMsgCost(), + summaryMetrics.avgSendMsgCost(), + summaryMetrics.avgReplyMsgCost()); + } + summaryMetrics.send2MQStatInfoClear(); + } + + public HttpMetrics getHttpMetrics() { + return httpMetrics; + } + + @Override + public List getMetrics() { + return new ArrayList<>(httpMetrics.getMetrics()); + } + + @Override + public String getName() { + return this.getClass().getName(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/HTTPMetricsServer.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/HTTPMetricsServer.java deleted file mode 100644 index 80fdc4d497..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/HTTPMetricsServer.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.metrics.http; - -import org.apache.eventmesh.metrics.api.MetricsRegistry; -import org.apache.eventmesh.metrics.api.model.HttpSummaryMetrics; -import org.apache.eventmesh.runtime.boot.EventMeshHTTPServer; - -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class HTTPMetricsServer { - - private EventMeshHTTPServer eventMeshHTTPServer; - - private Logger httpLogger = LoggerFactory.getLogger("httpMonitor"); - - private Logger logger = LoggerFactory.getLogger(this.getClass()); - - private List metricsRegistries; - - private final HttpSummaryMetrics summaryMetrics; - - public HTTPMetricsServer(EventMeshHTTPServer eventMeshHTTPServer, List metricsRegistries) { - this.eventMeshHTTPServer = eventMeshHTTPServer; - this.metricsRegistries = metricsRegistries; - this.summaryMetrics = new HttpSummaryMetrics( - eventMeshHTTPServer.batchMsgExecutor, - eventMeshHTTPServer.sendMsgExecutor, - eventMeshHTTPServer.pushMsgExecutor, - eventMeshHTTPServer.getHttpRetryer().getFailedQueue()); - } - - public void init() throws Exception { - metricsRegistries.forEach(MetricsRegistry::start); - logger.info("HTTPMetricsServer initialized......"); - } - - public void start() throws Exception { - metricsRegistries.forEach(metricsRegistry -> { - metricsRegistry.register(summaryMetrics); - logger.info("Register httpMetrics to " + metricsRegistry.getClass().getName()); - }); - metricsSchedule.scheduleAtFixedRate(() -> { - try { - summaryMetrics.snapshotHTTPTPS(); - summaryMetrics.snapshotSendBatchMsgTPS(); - summaryMetrics.snapshotSendMsgTPS(); - summaryMetrics.snapshotPushMsgTPS(); - } catch (Exception ex) { - logger.warn("eventMesh snapshot tps metrics err", ex); - } - }, 0, 1000, TimeUnit.MILLISECONDS); - - metricsSchedule.scheduleAtFixedRate(() -> { - try { - logPrintServerMetrics(); - } catch (Exception ex) { - logger.warn("eventMesh print metrics err", ex); - } - }, 1000, 30 * 1000, TimeUnit.MILLISECONDS); - - logger.info("HTTPMetricsServer started......"); - } - - public void shutdown() throws Exception { - metricsSchedule.shutdown(); - metricsRegistries.forEach(MetricsRegistry::showdown); - logger.info("HTTPMetricsServer shutdown......"); - } - - protected static ScheduledExecutorService metricsSchedule = Executors.newScheduledThreadPool(2, new ThreadFactory() { - private AtomicInteger seq = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - seq.incrementAndGet(); - Thread t = new Thread(r, "eventMesh-metrics-" + seq.get()); - t.setDaemon(true); - return t; - } - }); - - // todo: move this into standalone metrics plugin - private void logPrintServerMetrics() { - httpLogger.info("===========================================SERVER METRICS=================================================="); - - httpLogger.info(String.format(HttpSummaryMetrics.EVENTMESH_MONITOR_FORMAT_HTTP, - summaryMetrics.maxHTTPTPS(), - summaryMetrics.avgHTTPTPS(), - summaryMetrics.maxHTTPCost(), - summaryMetrics.avgHTTPCost(), - summaryMetrics.avgHTTPBodyDecodeCost(), - summaryMetrics.getHttpDiscard())); - summaryMetrics.httpStatInfoClear(); - - httpLogger.info(String.format(HttpSummaryMetrics.EVENTMESH_MONITOR_FORMAT_BATCHSENDMSG, - summaryMetrics.maxSendBatchMsgTPS(), - summaryMetrics.avgSendBatchMsgTPS(), - summaryMetrics.getSendBatchMsgNumSum(), - summaryMetrics.getSendBatchMsgFailNumSum(), - summaryMetrics.getSendBatchMsgFailRate(), - summaryMetrics.getSendBatchMsgDiscardNumSum() - )); - summaryMetrics.cleanSendBatchStat(); - - httpLogger.info(String.format(HttpSummaryMetrics.EVENTMESH_MONITOR_FORMAT_SENDMSG, - summaryMetrics.maxSendMsgTPS(), - summaryMetrics.avgSendMsgTPS(), - summaryMetrics.getSendMsgNumSum(), - summaryMetrics.getSendMsgFailNumSum(), - summaryMetrics.getSendMsgFailRate(), - summaryMetrics.getReplyMsgNumSum(), - summaryMetrics.getReplyMsgFailNumSum() - )); - summaryMetrics.cleanSendMsgStat(); - - httpLogger.info(String.format(HttpSummaryMetrics.EVENTMESH_MONITOR_FORMAT_PUSHMSG, - summaryMetrics.maxPushMsgTPS(), - summaryMetrics.avgPushMsgTPS(), - summaryMetrics.getHttpPushMsgNumSum(), - summaryMetrics.getHttpPushFailNumSum(), - summaryMetrics.getHttpPushMsgFailRate(), - summaryMetrics.maxHTTPPushLatency(), - summaryMetrics.avgHTTPPushLatency() - )); - summaryMetrics.cleanHttpPushMsgStat(); - - httpLogger.info(String.format(HttpSummaryMetrics.EVENTMESH_MONITOR_FORMAT_BLOCKQ, - eventMeshHTTPServer.getBatchMsgExecutor().getQueue().size(), - eventMeshHTTPServer.getSendMsgExecutor().getQueue().size(), - eventMeshHTTPServer.getPushMsgExecutor().getQueue().size(), - eventMeshHTTPServer.getHttpRetryer().size())); - - httpLogger.info(String.format(HttpSummaryMetrics.EVENTMESH_MONITOR_FORMAT_MQ_CLIENT, - summaryMetrics.avgBatchSendMsgCost(), - summaryMetrics.avgSendMsgCost(), - summaryMetrics.avgReplyMsgCost())); - summaryMetrics.send2MQStatInfoClear(); - } - - public HttpSummaryMetrics getSummaryMetrics() { - return summaryMetrics; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/HttpMetrics.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/HttpMetrics.java new file mode 100644 index 0000000000..5a0e230e4c --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/http/HttpMetrics.java @@ -0,0 +1,827 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.http; + +import org.apache.eventmesh.metrics.api.model.InstrumentFurther; +import org.apache.eventmesh.metrics.api.model.LongCounterMetric; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.metrics.api.model.ObservableDoubleGaugeMetric; +import org.apache.eventmesh.metrics.api.model.ObservableLongGaugeMetric; +import org.apache.eventmesh.runtime.metrics.MetricInstrumentUnit; + +import org.apache.commons.collections4.MapUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicLong; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; + +public class HttpMetrics { + + private static Attributes EMPTY = Attributes.builder().build(); + + private static final int STATIC_PERIOD = 30 * 1000; + + private static final String HTTP_METRICS_NAME_PREFIX = "eventmesh.http."; + + private static final String METRIC_NAME = "HTTP"; + + private float wholeCost = 0f; + + private final AtomicLong wholeRequestNum = new AtomicLong(0); + + //cumulative value + private final AtomicLong httpDiscard = new AtomicLong(0); + + private LongCounterMetric httpDiscardMetric; + + private final AtomicLong maxCost = new AtomicLong(0); + + private final AtomicLong httpRequestPerSecond = new AtomicLong(0); + + private final LinkedList httpRequestTPSSnapshots = new LinkedList<>(); + + private float httpDecodeTimeCost = 0f; + + private final AtomicLong httpDecodeNum = new AtomicLong(0); + + private final AtomicLong sendBatchMsgNumPerSecond = new AtomicLong(0); + + private final AtomicLong sendBatchMsgNumSum = new AtomicLong(0); + + private LongCounterMetric sendBatchMsgNumSumMetric; + + private final AtomicLong sendBatchMsgFailNumSum = new AtomicLong(0); + + private LongCounterMetric sendBatchMsgFailNumSumMetric; + + // This is a cumulative value + private final AtomicLong sendBatchMsgDiscardNumSum = new AtomicLong(0); + + private LongCounterMetric sendBatchMsgDiscardNumSumMetric; + + private final LinkedList sendBatchMsgTPSSnapshots = new LinkedList(); + + private final AtomicLong sendMsgNumSum = new AtomicLong(0); + + private LongCounterMetric sendMsgNumSumMetric; + + private final AtomicLong sendMsgFailNumSum = new AtomicLong(0); + + private LongCounterMetric sendMsgFailNumSumMetric; + + private final AtomicLong replyMsgNumSum = new AtomicLong(0); + + private LongCounterMetric replyMsgNumSumMetric; + + private final AtomicLong replyMsgFailNumSum = new AtomicLong(0); + + private LongCounterMetric replyMsgFailNumSumMetric; + + private final AtomicLong sendMsgNumPerSecond = new AtomicLong(0); + + private final LinkedList sendMsgTPSSnapshots = new LinkedList(); + + private float wholePushCost = 0f; + + private final AtomicLong wholePushRequestNum = new AtomicLong(0); + + private final AtomicLong maxHttpPushLatency = new AtomicLong(0); + + private final AtomicLong pushMsgNumPerSecond = new AtomicLong(0); + + private final LinkedList pushMsgTPSSnapshots = new LinkedList(); + + private final AtomicLong httpPushMsgNumSum = new AtomicLong(0); + + private LongCounterMetric httpPushMsgNumSumMetric; + + private final AtomicLong httpPushFailNumSum = new AtomicLong(0); + + private LongCounterMetric httpPushFailNumSumMetric; + + private float batchSend2MQWholeCost = 0f; + + private final AtomicLong batchSend2MQNum = new AtomicLong(0); + + private float send2MQWholeCost = 0f; + + private final AtomicLong send2MQNum = new AtomicLong(0); + + private float reply2MQWholeCost = 0f; + + private final AtomicLong reply2MQNum = new AtomicLong(0); + + // execute metrics + private final ThreadPoolExecutor batchMsgExecutor; + + private final ThreadPoolExecutor sendMsgExecutor; + + private final ThreadPoolExecutor pushMsgExecutor; + + private final DelayQueue httpFailedQueue; + + private final Map labelMap; + + private final Map metrics = new HashMap<>(32); + + private ObservableDoubleGaugeMetric avgHttpBodyDecodeCostMetric; + + private ObservableDoubleGaugeMetric maxHttpTpsMetric; + + private ObservableDoubleGaugeMetric avgHttpTpsMetric; + + private ObservableLongGaugeMetric maxHttpCostMetric; + + private ObservableDoubleGaugeMetric avgHttpCostMetric; + + private ObservableDoubleGaugeMetric maxBatchSendMsgTpsMetric; + + private ObservableDoubleGaugeMetric avgBatchSendMsgTpsMetric; + + private ObservableDoubleGaugeMetric sumBatchFailRateMetric; + + private ObservableDoubleGaugeMetric maxSendMsgTpsMetric; + + private ObservableDoubleGaugeMetric avgSendMsgTpsMetric; + + private ObservableDoubleGaugeMetric sumFailRateMetric; + + private ObservableDoubleGaugeMetric maxPushMsgTpsMetric; + + private ObservableDoubleGaugeMetric avgPushMsgTpsMetric; + + private ObservableDoubleGaugeMetric pushSumFailRateMetric; + + private ObservableDoubleGaugeMetric maxClientLatencyMetric; + + private ObservableDoubleGaugeMetric avgClientLatencyMetric; + + private ObservableLongGaugeMetric batchMsgQMetric; + + private ObservableLongGaugeMetric sendMsgQMetric; + + private ObservableLongGaugeMetric pushMsgQMetric; + + private ObservableLongGaugeMetric httpRetryQMetric; + + private ObservableDoubleGaugeMetric batchAvgSend2MQCostMetric; + + private ObservableDoubleGaugeMetric avgSend2MQCostMetric; + + private ObservableDoubleGaugeMetric avgReply2MQCostMetric; + + public HttpMetrics(final ThreadPoolExecutor batchMsgExecutor, + final ThreadPoolExecutor sendMsgExecutor, + final ThreadPoolExecutor pushMsgExecutor, + final DelayQueue httpFailedQueue, + final Map labelMap) { + this.batchMsgExecutor = batchMsgExecutor; + this.sendMsgExecutor = sendMsgExecutor; + this.pushMsgExecutor = pushMsgExecutor; + this.httpFailedQueue = httpFailedQueue; + this.labelMap = Optional.ofNullable(labelMap).orElse(new HashMap<>(0)); + initMetrics(); + } + + private void initMetrics() { + + InstrumentFurther furtherHttpDiscard = new InstrumentFurther(); + furtherHttpDiscard.setUnit(MetricInstrumentUnit.SINGLETON); + furtherHttpDiscard.setDescription("Http request discard num."); + furtherHttpDiscard.setName(HTTP_METRICS_NAME_PREFIX + "request.discard.num"); + httpDiscardMetric = new LongCounterMetric(furtherHttpDiscard, METRIC_NAME); + metrics.put("httpDiscardMetric", httpDiscardMetric); + + //sum of batch send message number + InstrumentFurther furtherSendBatchMsgNumSum = new InstrumentFurther(); + furtherSendBatchMsgNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherSendBatchMsgNumSum.setDescription("Sum of batch send message number."); + furtherSendBatchMsgNumSum.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.num"); + sendBatchMsgNumSumMetric = new LongCounterMetric(furtherSendBatchMsgNumSum, METRIC_NAME); + metrics.put("sendBatchMsgNumSumMetric", sendBatchMsgNumSumMetric); + + //sum of batch send message fail message number. + InstrumentFurther furtherSendBatchMsgFailNumSum = new InstrumentFurther(); + furtherSendBatchMsgFailNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherSendBatchMsgFailNumSum.setDescription("Sum of batch send message fail message number."); + furtherSendBatchMsgFailNumSum.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.fail.num"); + sendBatchMsgFailNumSumMetric = new LongCounterMetric(furtherSendBatchMsgFailNumSum, METRIC_NAME); + metrics.put("sendBatchMsgFailNumSumMetric", sendBatchMsgFailNumSumMetric); + + //sum of send batch message discard number. + InstrumentFurther furtherSendBatchMsgDiscardNumSum = new InstrumentFurther(); + furtherSendBatchMsgDiscardNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherSendBatchMsgDiscardNumSum.setDescription("Sum of batch send message fail message number."); + furtherSendBatchMsgDiscardNumSum.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.discard.num"); + sendBatchMsgDiscardNumSumMetric = new LongCounterMetric(furtherSendBatchMsgDiscardNumSum, METRIC_NAME); + metrics.put("sendBatchMsgDiscardNumSumMetric", sendBatchMsgDiscardNumSumMetric); + + //Sum of send message number. + InstrumentFurther furtherSendMsgNumSum = new InstrumentFurther(); + furtherSendMsgNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherSendMsgNumSum.setDescription("Sum of send message number."); + furtherSendMsgNumSum.setName(HTTP_METRICS_NAME_PREFIX + "send.message.num"); + sendMsgNumSumMetric = new LongCounterMetric(furtherSendMsgNumSum, METRIC_NAME); + metrics.put("sendMsgNumSumMetric", sendMsgNumSumMetric); + + //Sum of send message fail number. + InstrumentFurther furtherSendMsgFailNumSum = new InstrumentFurther(); + furtherSendMsgFailNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherSendMsgFailNumSum.setDescription("Sum of send message fail number."); + furtherSendMsgFailNumSum.setName(HTTP_METRICS_NAME_PREFIX + "send.message.fail.num"); + sendMsgFailNumSumMetric = new LongCounterMetric(furtherSendMsgFailNumSum, METRIC_NAME); + metrics.put("sendMsgFailNumSumMetric", sendMsgFailNumSumMetric); + + //Sum of reply message number. + InstrumentFurther furtherReplyMsgNumSum = new InstrumentFurther(); + furtherReplyMsgNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherReplyMsgNumSum.setDescription("Sum of reply message number."); + furtherReplyMsgNumSum.setName(HTTP_METRICS_NAME_PREFIX + "reply.message.num"); + replyMsgNumSumMetric = new LongCounterMetric(furtherReplyMsgNumSum, METRIC_NAME); + metrics.put("replyMsgNumSumMetric", replyMsgNumSumMetric); + + //Sum of reply message fail number. + InstrumentFurther furtherReplyMsgFailNumSum = new InstrumentFurther(); + furtherReplyMsgFailNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherReplyMsgFailNumSum.setDescription("Sum of reply message fail number."); + furtherReplyMsgFailNumSum.setName(HTTP_METRICS_NAME_PREFIX + "reply.message.fail.num"); + replyMsgFailNumSumMetric = new LongCounterMetric(furtherReplyMsgFailNumSum, METRIC_NAME); + metrics.put("replyMsgFailNumSumMetric", replyMsgFailNumSumMetric); + + //Sum of http push message number. + InstrumentFurther furtherHttpPushMsgNumSum = new InstrumentFurther(); + furtherHttpPushMsgNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherHttpPushMsgNumSum.setDescription("Sum of http push message number."); + furtherHttpPushMsgNumSum.setName(HTTP_METRICS_NAME_PREFIX + "push.message.num"); + httpPushMsgNumSumMetric = new LongCounterMetric(furtherHttpPushMsgNumSum, METRIC_NAME); + metrics.put("httpPushMsgNumSumMetric", httpPushMsgNumSumMetric); + + //Sum of http push message fail number. + InstrumentFurther furtherHttpPushFailNumSum = new InstrumentFurther(); + furtherHttpPushFailNumSum.setUnit(MetricInstrumentUnit.SINGLETON); + furtherHttpPushFailNumSum.setDescription("Sum of http push message fail number."); + furtherHttpPushFailNumSum.setName(HTTP_METRICS_NAME_PREFIX + "push.message.fail.num"); + httpPushFailNumSumMetric = new LongCounterMetric(furtherHttpPushFailNumSum, METRIC_NAME); + metrics.put("httpPushFailNumSumMetric", httpPushFailNumSumMetric); + + //avg body decode cost time of http + InstrumentFurther furtherHttpDecode = new InstrumentFurther(); + furtherHttpDecode.setUnit(MetricInstrumentUnit.MILLISECONDS); + furtherHttpDecode.setDescription("Avg body decode cost time of http"); + furtherHttpDecode.setName(HTTP_METRICS_NAME_PREFIX + "body.decode.cost.avg"); + avgHttpBodyDecodeCostMetric = new ObservableDoubleGaugeMetric(furtherHttpDecode, METRIC_NAME, () -> this.avgHTTPBodyDecodeCost()); + avgHttpBodyDecodeCostMetric.putAll(labelMap); + metrics.put("avgHttpBodyDecodeCostMetric", avgHttpBodyDecodeCostMetric); + + //Max TPS of HTTP. + InstrumentFurther furtherMaxHttpTps = new InstrumentFurther(); + furtherMaxHttpTps.setUnit(MetricInstrumentUnit.TPS); + furtherMaxHttpTps.setDescription("Max TPS of HTTP."); + furtherMaxHttpTps.setName(HTTP_METRICS_NAME_PREFIX + "request.tps.max"); + maxHttpTpsMetric = new ObservableDoubleGaugeMetric(furtherMaxHttpTps, METRIC_NAME, () -> this.maxHTTPTPS()); + maxHttpTpsMetric.putAll(labelMap); + metrics.put("maxHttpTpsMetric", maxHttpTpsMetric); + + //Avg TPS of HTTP. + InstrumentFurther furtherAvgHttpTps = new InstrumentFurther(); + furtherAvgHttpTps.setUnit(MetricInstrumentUnit.TPS); + furtherAvgHttpTps.setDescription("Avg TPS of HTTP."); + furtherAvgHttpTps.setName(HTTP_METRICS_NAME_PREFIX + "request.tps.avg"); + avgHttpTpsMetric = new ObservableDoubleGaugeMetric(furtherAvgHttpTps, METRIC_NAME, () -> this.avgHTTPTPS()); + avgHttpTpsMetric.putAll(labelMap); + metrics.put("avgHttpTpsMetric", avgHttpTpsMetric); + + //max cost of HTTP. + InstrumentFurther furtherMaxCostHttpTps = new InstrumentFurther(); + furtherMaxCostHttpTps.setUnit(MetricInstrumentUnit.MILLISECONDS); + furtherMaxCostHttpTps.setDescription("Max cost of HTTP."); + furtherMaxCostHttpTps.setName(HTTP_METRICS_NAME_PREFIX + "request.cost.max"); + maxHttpCostMetric = new ObservableLongGaugeMetric(furtherMaxCostHttpTps, METRIC_NAME, () -> this.maxHTTPCost()); + maxHttpCostMetric.putAll(labelMap); + metrics.put("maxHttpCostMetric", maxHttpCostMetric); + + //Avg cost of HTTP. + InstrumentFurther furtherAvgHttpCost = new InstrumentFurther(); + furtherAvgHttpCost.setUnit(MetricInstrumentUnit.TPS); + furtherAvgHttpCost.setDescription("Avg cost of HTTP."); + furtherAvgHttpCost.setName(HTTP_METRICS_NAME_PREFIX + "request.cost.avg"); + avgHttpCostMetric = new ObservableDoubleGaugeMetric(furtherAvgHttpCost, METRIC_NAME, () -> this.avgHTTPCost()); + avgHttpCostMetric.putAll(labelMap); + metrics.put("avgHttpCostMetric", avgHttpCostMetric); + + //Max of batch send message tps + InstrumentFurther furtherMaxBatchSendMsgTps = new InstrumentFurther(); + furtherMaxBatchSendMsgTps.setUnit(MetricInstrumentUnit.TPS); + furtherMaxBatchSendMsgTps.setDescription("Max of batch send message tps"); + furtherMaxBatchSendMsgTps.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.tps.max"); + maxBatchSendMsgTpsMetric = new ObservableDoubleGaugeMetric(furtherMaxBatchSendMsgTps, METRIC_NAME, () -> this.maxSendBatchMsgTPS()); + maxBatchSendMsgTpsMetric.putAll(labelMap); + metrics.put("maxBatchSendMsgTpsMetric", maxBatchSendMsgTpsMetric); + + //Avg of batch send message tps. + InstrumentFurther furtherAvgBatchSendMsgTps = new InstrumentFurther(); + furtherAvgBatchSendMsgTps.setUnit(MetricInstrumentUnit.TPS); + furtherAvgBatchSendMsgTps.setDescription("Avg of batch send message tps."); + furtherAvgBatchSendMsgTps.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.tps.avg"); + avgBatchSendMsgTpsMetric = new ObservableDoubleGaugeMetric(furtherAvgBatchSendMsgTps, METRIC_NAME, () -> this.avgSendBatchMsgTPS()); + avgBatchSendMsgTpsMetric.putAll(labelMap); + metrics.put("avgBatchSendMsgTpsMetric", avgBatchSendMsgTpsMetric); + + //Send batch message fail rate. + InstrumentFurther furtherSumBatchFailRate = new InstrumentFurther(); + furtherSumBatchFailRate.setUnit(MetricInstrumentUnit.PERCENT); + furtherSumBatchFailRate.setDescription("Send batch message fail rate."); + furtherSumBatchFailRate.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.fail.rate"); + sumBatchFailRateMetric = new ObservableDoubleGaugeMetric(furtherSumBatchFailRate, METRIC_NAME, () -> this.getSendBatchMsgFailRate()); + sumBatchFailRateMetric.putAll(labelMap); + metrics.put("sumBatchFailRateMetric", sumBatchFailRateMetric); + + //Max of send message tps + InstrumentFurther furtherMaxSendMsgTps = new InstrumentFurther(); + furtherMaxSendMsgTps.setUnit(MetricInstrumentUnit.TPS); + furtherMaxSendMsgTps.setDescription("Max of send message tps"); + furtherMaxSendMsgTps.setName(HTTP_METRICS_NAME_PREFIX + "send.message.tps.max"); + maxSendMsgTpsMetric = new ObservableDoubleGaugeMetric(furtherMaxSendMsgTps, METRIC_NAME, () -> this.maxSendMsgTPS()); + maxSendMsgTpsMetric.putAll(labelMap); + metrics.put("maxSendMsgTpsMetric", maxSendMsgTpsMetric); + + //Avg of send message tps + InstrumentFurther furtherAvgSendMsgTps = new InstrumentFurther(); + furtherAvgSendMsgTps.setUnit(MetricInstrumentUnit.TPS); + furtherAvgSendMsgTps.setDescription("Avg of send message tps"); + furtherAvgSendMsgTps.setName(HTTP_METRICS_NAME_PREFIX + "send.message.tps.avg"); + avgSendMsgTpsMetric = new ObservableDoubleGaugeMetric(furtherAvgSendMsgTps, METRIC_NAME, () -> this.avgSendMsgTPS()); + avgSendMsgTpsMetric.putAll(labelMap); + metrics.put("avgSendMsgTpsMetric", avgSendMsgTpsMetric); + + //Send message fail rate. + InstrumentFurther furtherSumFailRate = new InstrumentFurther(); + furtherSumFailRate.setUnit(MetricInstrumentUnit.PERCENT); + furtherSumFailRate.setDescription("Send message fail rate."); + furtherSumFailRate.setName(HTTP_METRICS_NAME_PREFIX + "send.message.fail.rate"); + sumFailRateMetric = new ObservableDoubleGaugeMetric(furtherSumFailRate, METRIC_NAME, () -> this.getSendBatchMsgFailRate()); + sumFailRateMetric.putAll(labelMap); + metrics.put("sumFailRateMetric", sumFailRateMetric); + + //Max of push message tps. + InstrumentFurther furtherMaxPushMsgTps = new InstrumentFurther(); + furtherMaxPushMsgTps.setUnit(MetricInstrumentUnit.TPS); + furtherMaxPushMsgTps.setDescription("Max of push message tps."); + furtherMaxPushMsgTps.setName(HTTP_METRICS_NAME_PREFIX + "push.message.tps.max"); + maxPushMsgTpsMetric = new ObservableDoubleGaugeMetric(furtherMaxPushMsgTps, METRIC_NAME, () -> this.maxPushMsgTPS()); + maxPushMsgTpsMetric.putAll(labelMap); + metrics.put("maxPushMsgTpsMetric", maxPushMsgTpsMetric); + + //Avg of push message tps. + InstrumentFurther furtherAvgPushMsgTps = new InstrumentFurther(); + furtherAvgPushMsgTps.setUnit(MetricInstrumentUnit.TPS); + furtherAvgPushMsgTps.setDescription("Avg of push message tps."); + furtherAvgPushMsgTps.setName(HTTP_METRICS_NAME_PREFIX + "push.message.tps.avg"); + avgPushMsgTpsMetric = new ObservableDoubleGaugeMetric(furtherAvgPushMsgTps, METRIC_NAME, () -> this.avgPushMsgTPS()); + avgPushMsgTpsMetric.putAll(labelMap); + metrics.put("avgPushMsgTpsMetric", avgPushMsgTpsMetric); + + //Http push message fail rate. + InstrumentFurther furtherPushSumFailRate = new InstrumentFurther(); + furtherPushSumFailRate.setUnit(MetricInstrumentUnit.PERCENT); + furtherPushSumFailRate.setDescription("Http push message fail rate."); + furtherPushSumFailRate.setName(HTTP_METRICS_NAME_PREFIX + "push.message.fail.rate"); + pushSumFailRateMetric = new ObservableDoubleGaugeMetric(furtherPushSumFailRate, METRIC_NAME, () -> this.getHttpPushMsgFailRate()); + pushSumFailRateMetric.putAll(labelMap); + metrics.put("pushSumFailRateMetric", pushSumFailRateMetric); + + //Max of http push latency. + InstrumentFurther furtherMaxClientLatency = new InstrumentFurther(); + furtherMaxClientLatency.setUnit(MetricInstrumentUnit.MILLISECONDS); + furtherMaxClientLatency.setDescription("Max of http push latency."); + furtherMaxClientLatency.setName(HTTP_METRICS_NAME_PREFIX + "push.latency.max"); + maxClientLatencyMetric = new ObservableDoubleGaugeMetric(furtherMaxClientLatency, METRIC_NAME, () -> this.maxHTTPPushLatency()); + maxClientLatencyMetric.putAll(labelMap); + metrics.put("maxClientLatencyMetric", maxClientLatencyMetric); + + //Avg of http push latency. + InstrumentFurther furtherAvgClientLatency = new InstrumentFurther(); + furtherAvgClientLatency.setUnit(MetricInstrumentUnit.MILLISECONDS); + furtherAvgClientLatency.setDescription("Avg of http push latency."); + furtherAvgClientLatency.setName(HTTP_METRICS_NAME_PREFIX + "push.latency.avg"); + avgClientLatencyMetric = new ObservableDoubleGaugeMetric(furtherAvgClientLatency, METRIC_NAME, () -> this.avgHTTPPushLatency()); + avgClientLatencyMetric.putAll(labelMap); + metrics.put("avgClientLatencyMetric", avgClientLatencyMetric); + + //Size of batch message queue. + InstrumentFurther furtherBatchMsgQ = new InstrumentFurther(); + furtherBatchMsgQ.setUnit(MetricInstrumentUnit.SINGLETON); + furtherBatchMsgQ.setDescription("Size of batch message queue."); + furtherBatchMsgQ.setName(HTTP_METRICS_NAME_PREFIX + "batch.message.queue.size"); + batchMsgQMetric = new ObservableLongGaugeMetric(furtherBatchMsgQ, METRIC_NAME, () -> this.getBatchMsgQueueSize()); + batchMsgQMetric.putAll(labelMap); + metrics.put("batchMsgQMetric", batchMsgQMetric); + + //Size of send message queue. + InstrumentFurther furtherSendMsgQ = new InstrumentFurther(); + furtherSendMsgQ.setUnit(MetricInstrumentUnit.SINGLETON); + furtherSendMsgQ.setDescription("Size of send message queue."); + furtherSendMsgQ.setName(HTTP_METRICS_NAME_PREFIX + "send.message.queue.size"); + sendMsgQMetric = new ObservableLongGaugeMetric(furtherSendMsgQ, METRIC_NAME, () -> this.getSendMsgQueueSize()); + sendMsgQMetric.putAll(labelMap); + metrics.put("sendMsgQMetric", sendMsgQMetric); + + //Size of push message queue. + InstrumentFurther furtherPushMsgQ = new InstrumentFurther(); + furtherPushMsgQ.setUnit(MetricInstrumentUnit.SINGLETON); + furtherPushMsgQ.setDescription("Size of push message queue."); + furtherPushMsgQ.setName(HTTP_METRICS_NAME_PREFIX + "push.message.queue.size"); + pushMsgQMetric = new ObservableLongGaugeMetric(furtherPushMsgQ, METRIC_NAME, () -> this.getPushMsgQueueSize()); + pushMsgQMetric.putAll(labelMap); + metrics.put("pushMsgQMetric", pushMsgQMetric); + + //Size of http retry queue. + InstrumentFurther furtherHttpRetryQ = new InstrumentFurther(); + furtherHttpRetryQ.setUnit(MetricInstrumentUnit.SINGLETON); + furtherHttpRetryQ.setDescription("Size of http retry queue."); + furtherHttpRetryQ.setName(HTTP_METRICS_NAME_PREFIX + "retry.queue.size"); + httpRetryQMetric = new ObservableLongGaugeMetric(furtherHttpRetryQ, METRIC_NAME, () -> this.getHttpRetryQueueSize()); + httpRetryQMetric.putAll(labelMap); + metrics.put("httpRetryQMetric", httpRetryQMetric); + + + //Avg of batch send message cost. + InstrumentFurther furtherBatchAvgSend2MQCost = new InstrumentFurther(); + furtherBatchAvgSend2MQCost.setUnit(MetricInstrumentUnit.MILLISECONDS); + furtherBatchAvgSend2MQCost.setDescription("Avg of batch send message cost."); + furtherBatchAvgSend2MQCost.setName(HTTP_METRICS_NAME_PREFIX + "batch.send.message.cost.avg"); + batchAvgSend2MQCostMetric = new ObservableDoubleGaugeMetric(furtherBatchAvgSend2MQCost, METRIC_NAME, () -> this.avgBatchSendMsgCost()); + batchAvgSend2MQCostMetric.putAll(labelMap); + metrics.put("avgClientLatencyMetric", batchAvgSend2MQCostMetric); + + //Avg of send message cost. + InstrumentFurther furtherAvgSend2MQCost = new InstrumentFurther(); + furtherAvgSend2MQCost.setUnit(MetricInstrumentUnit.TPS); + furtherAvgSend2MQCost.setDescription("Avg of send message cost."); + furtherAvgSend2MQCost.setName(HTTP_METRICS_NAME_PREFIX + "send.message.cost.avg"); + avgSend2MQCostMetric = new ObservableDoubleGaugeMetric(furtherAvgSend2MQCost, METRIC_NAME, () -> this.avgSendMsgCost()); + avgSend2MQCostMetric.putAll(labelMap); + metrics.put("avgSend2MQCostMetric", avgSend2MQCostMetric); + + //Avg of reply message cost. + InstrumentFurther furtherAvgReply2MQCost = new InstrumentFurther(); + furtherAvgReply2MQCost.setUnit(MetricInstrumentUnit.TPS); + furtherAvgReply2MQCost.setDescription("Avg of reply message cost."); + furtherAvgReply2MQCost.setName(HTTP_METRICS_NAME_PREFIX + "reply.message.cost.avg"); + avgReply2MQCostMetric = new ObservableDoubleGaugeMetric(furtherAvgReply2MQCost, METRIC_NAME, () -> this.avgReplyMsgCost()); + avgReply2MQCostMetric.putAll(labelMap); + metrics.put("avgReply2MQCostMetric", avgReply2MQCostMetric); + } + + public Collection getMetrics() { + return metrics.values(); + } + + public double avgHTTPCost() { + return (wholeRequestNum.longValue() == 0L) ? 0f : wholeCost / wholeRequestNum.longValue(); + } + + public long maxHTTPCost() { + return maxCost.longValue(); + } + + public long getHttpDiscard() { + return httpDiscard.longValue(); + } + + public void recordHTTPRequest() { + httpRequestPerSecond.incrementAndGet(); + } + + public void recordHTTPDiscard() { + httpDiscard.incrementAndGet(); + Map attributes = new HashMap<>(this.labelMap); + httpDiscardMetric.getInstrument().add(1, buildAttributes(attributes)); + } + + private static Attributes buildAttributes(final Map attributes) { + if (MapUtils.isEmpty(attributes)) { + return EMPTY; + } + AttributesBuilder attributesBuilder = Attributes.builder(); + attributes.forEach(attributesBuilder::put); + return attributesBuilder.build(); + } + + public void snapshotHTTPTPS() { + Integer tps = httpRequestPerSecond.intValue(); + httpRequestTPSSnapshots.add(tps); + httpRequestPerSecond.set(0); + if (httpRequestTPSSnapshots.size() > STATIC_PERIOD / 1000) { + httpRequestTPSSnapshots.removeFirst(); + } + } + + public double maxHTTPTPS() { + return Collections.max(httpRequestTPSSnapshots); + } + + public double avgHTTPTPS() { + return avg(httpRequestTPSSnapshots); + } + + public void recordHTTPReqResTimeCost(long cost) { + wholeRequestNum.incrementAndGet(); + wholeCost = wholeCost + cost; + if (cost > maxCost.longValue()) { + maxCost.set(cost); + } + } + + public void httpStatInfoClear() { + wholeRequestNum.set(0L); + wholeCost = 0f; + maxCost.set(0L); + httpDecodeNum.set(0L); + httpDecodeTimeCost = 0f; + } + + + public void recordDecodeTimeCost(long cost) { + httpDecodeNum.incrementAndGet(); + httpDecodeTimeCost = httpDecodeTimeCost + cost; + } + + public double avgHTTPBodyDecodeCost() { + return (httpDecodeNum.longValue() == 0L) ? 0d : (double) httpDecodeTimeCost / httpDecodeNum.longValue(); + } + + + public void recordSendBatchMsgDiscard(long delta) { + sendBatchMsgDiscardNumSum.addAndGet(delta); + sendBatchMsgDiscardNumSumMetric.getInstrument().add(delta, buildAttributes(labelMap)); + } + + public void snapshotSendBatchMsgTPS() { + Integer tps = sendBatchMsgNumPerSecond.intValue(); + sendBatchMsgTPSSnapshots.add(tps); + sendBatchMsgNumPerSecond.set(0); + if (sendBatchMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + sendBatchMsgTPSSnapshots.removeFirst(); + } + } + + public double maxSendBatchMsgTPS() { + return Collections.max(sendBatchMsgTPSSnapshots); + } + + public double avgSendBatchMsgTPS() { + return avg(sendBatchMsgTPSSnapshots); + } + + public void recordSendBatchMsg(long delta) { + sendBatchMsgNumPerSecond.addAndGet(delta); + sendBatchMsgNumSum.addAndGet(delta); + sendBatchMsgNumSumMetric.getInstrument().add(delta, buildAttributes(labelMap)); + } + + public void recordSendBatchMsgFailed(long delta) { + sendBatchMsgFailNumSum.getAndAdd(delta); + sendBatchMsgFailNumSumMetric.getInstrument().add(delta, buildAttributes(labelMap)); + } + + public long getSendBatchMsgNumSum() { + return sendBatchMsgNumSum.longValue(); + } + + public long getSendBatchMsgFailNumSum() { + return sendBatchMsgFailNumSum.longValue(); + } + + public double getSendBatchMsgFailRate() { + return (sendBatchMsgNumSum.longValue() == 0L) ? 0f : sendBatchMsgFailNumSum.floatValue() / sendBatchMsgNumSum.longValue(); + } + + public void cleanSendBatchStat() { + sendBatchMsgNumSum.set(0L); + sendBatchMsgFailNumSum.set(0L); + } + + public long getSendBatchMsgDiscardNumSum() { + return sendBatchMsgDiscardNumSum.longValue(); + } + + + public void snapshotSendMsgTPS() { + Integer tps = sendMsgNumPerSecond.intValue(); + sendMsgTPSSnapshots.add(tps); + sendMsgNumPerSecond.set(0); + if (sendMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + sendMsgTPSSnapshots.removeFirst(); + } + } + + public double maxSendMsgTPS() { + return Collections.max(sendMsgTPSSnapshots); + } + + public double avgSendMsgTPS() { + return avg(sendMsgTPSSnapshots); + } + + public void recordSendMsg() { + sendMsgNumPerSecond.incrementAndGet(); + sendMsgNumSum.incrementAndGet(); + sendMsgNumSumMetric.getInstrument().add(1, buildAttributes(labelMap)); + } + + public void recordReplyMsg() { + replyMsgNumSum.incrementAndGet(); + replyMsgNumSumMetric.getInstrument().add(1, buildAttributes(labelMap)); + } + + public void recordReplyMsgFailed() { + replyMsgFailNumSum.incrementAndGet(); + replyMsgFailNumSumMetric.getInstrument().add(1, buildAttributes(labelMap)); + } + + public long getReplyMsgNumSum() { + return replyMsgNumSum.longValue(); + } + + public long getReplyMsgFailNumSum() { + return replyMsgFailNumSum.longValue(); + } + + public long getSendMsgNumSum() { + return sendMsgNumSum.longValue(); + } + + public long getSendMsgFailNumSum() { + return sendMsgFailNumSum.longValue(); + } + + public float getSendMsgFailRate() { + return (sendMsgNumSum.longValue() == 0L) ? 0f : sendMsgFailNumSum.floatValue() / sendMsgNumSum.longValue(); + } + + public void recordSendMsgFailed() { + sendMsgFailNumSum.incrementAndGet(); + sendMsgFailNumSumMetric.getInstrument().add(1, buildAttributes(labelMap)); + } + + public void cleanSendMsgStat() { + sendMsgNumSum.set(0L); + replyMsgNumSum.set(0L); + sendMsgFailNumSum.set(0L); + replyMsgFailNumSum.set(0L); + } + + + public void snapshotPushMsgTPS() { + Integer tps = pushMsgNumPerSecond.intValue(); + pushMsgTPSSnapshots.add(tps); + pushMsgNumPerSecond.set(0); + if (pushMsgTPSSnapshots.size() > STATIC_PERIOD / 1000) { + pushMsgTPSSnapshots.removeFirst(); + } + } + + public void recordHTTPPushTimeCost(long cost) { + wholePushRequestNum.incrementAndGet(); + wholePushCost = wholePushCost + cost; + if (cost > maxHttpPushLatency.longValue()) { + maxHttpPushLatency.set(cost); + } + } + + public double avgHTTPPushLatency() { + return (wholePushRequestNum.longValue() == 0L) ? 0f : wholePushCost / wholePushRequestNum.longValue(); + } + + public double maxHTTPPushLatency() { + return maxHttpPushLatency.floatValue(); + } + + public double maxPushMsgTPS() { + return Collections.max(pushMsgTPSSnapshots); + } + + public double avgPushMsgTPS() { + return avg(pushMsgTPSSnapshots); + } + + public void recordPushMsg() { + pushMsgNumPerSecond.incrementAndGet(); + httpPushMsgNumSum.incrementAndGet(); + httpPushMsgNumSumMetric.getInstrument().add(1, buildAttributes(labelMap)); + } + + public long getHttpPushMsgNumSum() { + return httpPushMsgNumSum.longValue(); + } + + public long getHttpPushFailNumSum() { + return httpPushFailNumSum.longValue(); + } + + public double getHttpPushMsgFailRate() { + return (httpPushMsgNumSum.longValue() == 0L) ? 0f : httpPushFailNumSum.floatValue() / httpPushMsgNumSum.longValue(); + } + + public void recordHttpPushMsgFailed() { + sendMsgFailNumSum.incrementAndGet(); + sendMsgFailNumSumMetric.getInstrument().add(1, buildAttributes(labelMap)); + } + + public void cleanHttpPushMsgStat() { + httpPushFailNumSum.set(0L); + httpPushMsgNumSum.set(0L); + wholeRequestNum.set(0L); + wholeCost = 0f; + maxCost.set(0L); + } + + + public void recordBatchSendMsgCost(long cost) { + batchSend2MQNum.incrementAndGet(); + batchSend2MQWholeCost = batchSend2MQWholeCost + cost; + } + + public double avgBatchSendMsgCost() { + return (batchSend2MQNum.intValue() == 0) ? 0f : batchSend2MQWholeCost / batchSend2MQNum.intValue(); + } + + public void recordSendMsgCost(long cost) { + send2MQNum.incrementAndGet(); + send2MQWholeCost = send2MQWholeCost + cost; + } + + public double avgSendMsgCost() { + return (send2MQNum.intValue() == 0) ? 0f : send2MQWholeCost / send2MQNum.intValue(); + } + + public void recordReplyMsgCost(long cost) { + reply2MQNum.incrementAndGet(); + reply2MQWholeCost = reply2MQWholeCost + cost; + } + + public double avgReplyMsgCost() { + return (reply2MQNum.intValue() == 0) ? 0f : reply2MQWholeCost / reply2MQNum.intValue(); + } + + public void send2MQStatInfoClear() { + batchSend2MQWholeCost = 0f; + batchSend2MQNum.set(0L); + send2MQWholeCost = 0f; + send2MQNum.set(0L); + reply2MQWholeCost = 0f; + reply2MQNum.set(0L); + } + + + public long getBatchMsgQueueSize() { + return batchMsgExecutor.getQueue().size(); + } + + public long getSendMsgQueueSize() { + return sendMsgExecutor.getQueue().size(); + } + + public long getPushMsgQueueSize() { + return pushMsgExecutor.getQueue().size(); + } + + public long getHttpRetryQueueSize() { + return httpFailedQueue.size(); + } + + + private float avg(LinkedList linkedList) { + if (linkedList.isEmpty()) { + return 0.0f; + } + + int sum = linkedList.stream().reduce(Integer::sum).get(); + return (float) sum / linkedList.size(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/EventMeshTcpMetricsManager.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/EventMeshTcpMetricsManager.java new file mode 100644 index 0000000000..dab6df7118 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/EventMeshTcpMetricsManager.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.tcp; + +import org.apache.eventmesh.common.MetricsConstants; +import org.apache.eventmesh.common.enums.ProtocolType; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.metrics.api.MetricsRegistry; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.metrics.MetricsManager; +import org.apache.eventmesh.runtime.metrics.MetricsUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshTcpMetricsManager implements MetricsManager { + + private final Map labelMap = new HashMap<>(); + + private final EventMeshTCPServer eventMeshTCPServer; + + private final TcpMetrics tcpMetrics; + + private final List metricsRegistries; + + private final TcpMetricsCalculator calculator; + + public EventMeshTcpMetricsManager(EventMeshTCPServer eventMeshTCPServer, List metricsRegistries) { + + this.eventMeshTCPServer = eventMeshTCPServer; + init(); + this.tcpMetrics = new TcpMetrics(eventMeshTCPServer, labelMap); + this.metricsRegistries = Preconditions.checkNotNull(metricsRegistries); + this.calculator = new TcpMetricsCalculator(eventMeshTCPServer, tcpMetrics); + + + } + + private void init() { + String eventMeshServerIp = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshServerIp(); + int eventMeshTcpServerPort = eventMeshTCPServer.getEventMeshTCPConfiguration().getEventMeshTcpServerPort(); + labelMap.put(MetricsConstants.TCP_NET_HOST_NAME, Optional.ofNullable(eventMeshServerIp).orElse(IPUtils.getLocalAddress())); + labelMap.put(MetricsConstants.TCP_NET_HOST_PORT, Integer.toString(eventMeshTcpServerPort)); + labelMap.put(MetricsConstants.RPC_SYSTEM, "TCP"); + labelMap.put(MetricsConstants.RPC_SERVICE, this.eventMeshTCPServer.getClass().getName()); + log.info("EventMeshTcpMetricsManager initialized......"); + } + + public EventMeshTCPServer getEventMeshTCPServer() { + return eventMeshTCPServer; + } + + @Override + public void start() { + this.calculator.start(); + log.info("EventMeshTcpMetricsManager started......"); + } + + public void client2eventMeshMsgNumIncrement(final String clientAddress) { + tcpMetrics.getClient2eventMeshMsgNum().getAndIncrement(); + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.TCP.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementClientToEventMeshMsgNum(attributes); + } + + public void eventMesh2mqMsgNumIncrement() { + tcpMetrics.getEventMesh2mqMsgNum().getAndIncrement(); + Map attributes = new HashMap<>(labelMap); + MetricsUtils.incrementEventMeshToMQMsgNum(attributes); + } + + public void mq2eventMeshMsgNumIncrement() { + tcpMetrics.getMq2eventMeshMsgNum().getAndIncrement(); + Map attributes = new HashMap<>(labelMap); + MetricsUtils.incrementMQToEventMeshMsgNum(attributes); + } + + public void eventMesh2clientMsgNumIncrement(final String clientAddress) { + tcpMetrics.getEventMesh2clientMsgNum().getAndIncrement(); + Map attributes = new HashMap<>(labelMap); + attributes.put(MetricsConstants.CLIENT_PROTOCOL_TYPE, ProtocolType.TCP.name()); + attributes.put(MetricsConstants.CLIENT_ADDRESS, Optional.ofNullable(clientAddress).orElse(MetricsConstants.UNKOWN)); + MetricsUtils.incrementEventMeshToClientMsgNum(attributes); + } + + public TcpMetrics getTcpMetrics() { + return tcpMetrics; + } + + @Override + public void shutdown() { + this.calculator.shutdown(); + log.info("EventMeshTcpMetricsManager shutdown......"); + } + + @Override + public List getMetrics() { + return new ArrayList<>(tcpMetrics.getMetrics()); + } + + @Override + public String getName() { + return this.getClass().getName(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/EventMeshTcpMonitor.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/EventMeshTcpMonitor.java deleted file mode 100644 index 63039a7220..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/EventMeshTcpMonitor.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.metrics.tcp; - -import org.apache.eventmesh.metrics.api.MetricsRegistry; -import org.apache.eventmesh.metrics.api.model.TcpSummaryMetrics; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcpConnectionHandler; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.metrics.MonitorMetricConstants; - -import java.net.InetSocketAddress; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -public class EventMeshTcpMonitor { - - private final EventMeshTCPServer eventMeshTCPServer; - - public EventMeshTCPServer getEventMeshTCPServer() { - return eventMeshTCPServer; - } - - private final Logger tcpLogger = LoggerFactory.getLogger("tcpMonitor"); - - private final Logger appLogger = LoggerFactory.getLogger("appMonitor"); - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static int delay = 60 * 1000; - - private static int period = 60 * 1000; - - private static int PRINT_THREADPOOLSTATE_INTERVAL = 1; - - public ScheduledFuture monitorTpsTask; - - public ScheduledFuture monitorThreadPoolTask; - - private final TcpSummaryMetrics tcpSummaryMetrics; - - private final List metricsRegistries; - - public EventMeshTcpMonitor(EventMeshTCPServer eventMeshTCPServer, List metricsRegistries) { - this.eventMeshTCPServer = eventMeshTCPServer; - this.tcpSummaryMetrics = new TcpSummaryMetrics(); - this.metricsRegistries = Preconditions.checkNotNull(metricsRegistries); - } - - public void init() throws Exception { - metricsRegistries.forEach(MetricsRegistry::start); - logger.info("EventMeshTcpMonitor initialized......"); - } - - public void start() throws Exception { - metricsRegistries.forEach(metricsRegistry -> { - metricsRegistry.register(tcpSummaryMetrics); - logger.info("Register tcpMetrics to " + metricsRegistry.getClass().getName()); - }); - - monitorTpsTask = eventMeshTCPServer.getScheduler().scheduleAtFixedRate((() -> { - int msgNum = tcpSummaryMetrics.client2eventMeshMsgNum(); - tcpSummaryMetrics.setClient2eventMeshTPS(1000 * msgNum / period); - - msgNum = tcpSummaryMetrics.eventMesh2clientMsgNum(); - tcpSummaryMetrics.setEventMesh2clientTPS(1000 * msgNum / period); - - msgNum = tcpSummaryMetrics.eventMesh2mqMsgNum(); - tcpSummaryMetrics.setEventMesh2mqTPS(1000 * msgNum / period); - - msgNum = tcpSummaryMetrics.mq2eventMeshMsgNum(); - tcpSummaryMetrics.setMq2eventMeshTPS(1000 * msgNum / period); - - //count topics subscribed by client in this eventMesh - ConcurrentHashMap sessionMap = - eventMeshTCPServer.getClientSessionGroupMapping().getSessionMap(); - Iterator sessionIterator = sessionMap.values().iterator(); - Set topicSet = new HashSet<>(); - while (sessionIterator.hasNext()) { - Session session = sessionIterator.next(); - AtomicLong deliveredMsgsCount = session.getPusher().getDeliveredMsgsCount(); - AtomicLong deliveredFailCount = session.getPusher().getDeliverFailMsgsCount(); - int unAckMsgsCount = session.getPusher().getTotalUnackMsgs(); - int sendTopics = session.getSessionContext().sendTopics.size(); - int subscribeTopics = session.getSessionContext().subscribeTopics.size(); - - tcpLogger.info("session|deliveredFailCount={}|deliveredMsgsCount={}|unAckMsgsCount={}|sendTopics={}|subscribeTopics={}|user={}", - deliveredFailCount.longValue(), deliveredMsgsCount.longValue(), - unAckMsgsCount, sendTopics, subscribeTopics, session.getClient()); - - topicSet.addAll(session.getSessionContext().subscribeTopics.keySet()); - } - tcpSummaryMetrics.setSubTopicNum(topicSet.size()); - tcpSummaryMetrics.setAllConnections(EventMeshTcpConnectionHandler.connections.get()); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.CLIENT_2_EVENTMESH_TPS, - tcpSummaryMetrics.getClient2eventMeshTPS())); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.EVENTMESH_2_MQ_TPS, - tcpSummaryMetrics.getEventMesh2mqTPS())); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.MQ_2_EVENTMESH_TPS, - tcpSummaryMetrics.getMq2eventMeshTPS())); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.EVENTMESH_2_CLIENT_TPS, - tcpSummaryMetrics.getEventMesh2clientTPS())); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.ALL_TPS, - tcpSummaryMetrics.getAllTPS())); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.CONNECTION, - tcpSummaryMetrics.getAllConnections())); - - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.SUB_TOPIC_NUM, - tcpSummaryMetrics.getSubTopicNum())); - }), delay, period, TimeUnit.MILLISECONDS); - - monitorThreadPoolTask = eventMeshTCPServer.getScheduler().scheduleAtFixedRate(() -> { - eventMeshTCPServer.getEventMeshRebalanceService().printRebalanceThreadPoolState(); - eventMeshTCPServer.getEventMeshTcpRetryer().printRetryThreadPoolState(); - - //monitor retry queue size - tcpSummaryMetrics.setRetrySize(eventMeshTCPServer.getEventMeshTcpRetryer().getRetrySize()); - appLogger.info(String.format( - MonitorMetricConstants.EVENTMESH_MONITOR_FORMAT_COMMON, - EventMeshConstants.PROTOCOL_TCP, - MonitorMetricConstants.RETRY_QUEUE_SIZE, - tcpSummaryMetrics.getRetrySize())); - - }, 10, PRINT_THREADPOOLSTATE_INTERVAL, TimeUnit.SECONDS); - logger.info("EventMeshTcpMonitor started......"); - } - - public TcpSummaryMetrics getTcpSummaryMetrics() { - return tcpSummaryMetrics; - } - - public void shutdown() throws Exception { - monitorTpsTask.cancel(true); - monitorThreadPoolTask.cancel(true); - metricsRegistries.forEach(MetricsRegistry::showdown); - logger.info("EventMeshTcpMonitor shutdown......"); - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/TcpMetrics.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/TcpMetrics.java new file mode 100644 index 0000000000..14ef926b59 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/TcpMetrics.java @@ -0,0 +1,280 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.tcp; + +import org.apache.eventmesh.metrics.api.model.InstrumentFurther; +import org.apache.eventmesh.metrics.api.model.Metric; +import org.apache.eventmesh.metrics.api.model.ObservableDoubleGaugeMetric; +import org.apache.eventmesh.metrics.api.model.ObservableLongGaugeMetric; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.metrics.MetricInstrumentUnit; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Getter +@Setter +@Slf4j +public class TcpMetrics { + + private static final String TPC_METRICS_NAME_PREFIX = "eventmesh.tcp."; + + private static final String METRIC_NAME = "TCP"; + + private final EventMeshTCPServer eventMeshTCPServer; + + private AtomicLong client2eventMeshMsgNum; + private AtomicLong eventMesh2mqMsgNum; + private AtomicLong mq2eventMeshMsgNum; + private AtomicLong eventMesh2clientMsgNum; + + private volatile double client2eventMeshTPS; + private volatile double eventMesh2clientTPS; + private volatile double eventMesh2mqTPS; + private volatile double mq2eventMeshTPS; + + private int subTopicNum; + + private volatile int allConnections; + + private volatile int retrySize; + //TCP connections + private ObservableLongGaugeMetric allConnectionsGauge; + + private ObservableLongGaugeMetric retrySizeGauge; + + private ObservableLongGaugeMetric subTopicGauge; + + private ObservableDoubleGaugeMetric mq2eventMeshTPSGauge; + + private ObservableDoubleGaugeMetric client2eventMeshTPSGauge; + + private ObservableDoubleGaugeMetric eventMesh2clientTPSGauge; + + private ObservableDoubleGaugeMetric eventMesh2mqTPSGauge; + + private final Map labelMap; + + private final Map metrics = new HashMap<>(32); + + public TcpMetrics(final EventMeshTCPServer eventMeshTCPServer, final Map labelMap) { + this.client2eventMeshMsgNum = new AtomicLong(0); + this.eventMesh2mqMsgNum = new AtomicLong(0); + this.mq2eventMeshMsgNum = new AtomicLong(0); + this.eventMesh2clientMsgNum = new AtomicLong(0); + this.eventMeshTCPServer = eventMeshTCPServer; + this.labelMap = labelMap; + initMetric(); + } + + private void initMetric() { + final Map commonAttributes = new HashMap<>(this.labelMap); + + InstrumentFurther furtherConn = new InstrumentFurther(); + furtherConn.setUnit(MetricInstrumentUnit.SINGLETON); + furtherConn.setDescription("Number of TCP client connects to EventMesh runtime"); + furtherConn.setName(TPC_METRICS_NAME_PREFIX + "connection.num"); + allConnectionsGauge = new ObservableLongGaugeMetric(furtherConn, METRIC_NAME, buildAllConnectionSupplier()); + allConnectionsGauge.putAll(commonAttributes); + metrics.put("allConnections", allConnectionsGauge); + + InstrumentFurther furtherTopic = new InstrumentFurther(); + furtherTopic.setUnit(MetricInstrumentUnit.SINGLETON); + furtherTopic.setDescription("Number of TCP client subscribe for topic"); + furtherTopic.setName(TPC_METRICS_NAME_PREFIX + "sub.topic.num"); + subTopicGauge = new ObservableLongGaugeMetric(furtherTopic, METRIC_NAME, buildSubTopicSupplier()); + subTopicGauge.putAll(commonAttributes); + metrics.put("subTopicGauge", subTopicGauge); + + InstrumentFurther furtherCl2Em = new InstrumentFurther(); + furtherCl2Em.setUnit(MetricInstrumentUnit.TPS); + furtherCl2Em.setDescription("Tps of client to EventMesh."); + furtherCl2Em.setName(TPC_METRICS_NAME_PREFIX + "client.eventmesh.tps"); + client2eventMeshTPSGauge = new ObservableDoubleGaugeMetric(furtherCl2Em, METRIC_NAME, () -> TcpMetrics.this.client2eventMeshTPS); + client2eventMeshTPSGauge.putAll(commonAttributes); + metrics.put("client2eventMeshTPSGauge", client2eventMeshTPSGauge); + + InstrumentFurther furtherEm2Cl = new InstrumentFurther(); + furtherEm2Cl.setUnit(MetricInstrumentUnit.TPS); + furtherEm2Cl.setDescription("Tps of EventMesh to client."); + furtherEm2Cl.setName(TPC_METRICS_NAME_PREFIX + "eventmesh.client.tps"); + eventMesh2clientTPSGauge = new ObservableDoubleGaugeMetric(furtherEm2Cl, METRIC_NAME, () -> TcpMetrics.this.eventMesh2clientTPS); + eventMesh2clientTPSGauge.putAll(commonAttributes); + metrics.put("eventMesh2clientTPSGauge", eventMesh2clientTPSGauge); + + InstrumentFurther furtherEm2Mq = new InstrumentFurther(); + furtherEm2Mq.setUnit(MetricInstrumentUnit.TPS); + furtherEm2Mq.setDescription("Tps of EventMesh to MQ."); + furtherEm2Mq.setName(TPC_METRICS_NAME_PREFIX + "eventmesh.mq.tps"); + eventMesh2mqTPSGauge = new ObservableDoubleGaugeMetric(furtherEm2Mq, METRIC_NAME, () -> TcpMetrics.this.eventMesh2mqTPS); + eventMesh2mqTPSGauge.putAll(commonAttributes); + metrics.put("eventMesh2mqTPSGauge", eventMesh2mqTPSGauge); + + InstrumentFurther furtherMq2Em = new InstrumentFurther(); + furtherMq2Em.setUnit(MetricInstrumentUnit.TPS); + furtherMq2Em.setDescription("Tps of MQ to EventMesh."); + furtherMq2Em.setName(TPC_METRICS_NAME_PREFIX + "mq.eventmesh.tps"); + mq2eventMeshTPSGauge = new ObservableDoubleGaugeMetric(furtherMq2Em, METRIC_NAME, () -> TcpMetrics.this.eventMesh2mqTPS); + mq2eventMeshTPSGauge.putAll(commonAttributes); + metrics.put("mq2eventMeshTPSGauge", mq2eventMeshTPSGauge); + } + + /** + * Count the number of TCP clients connected to EventMesh. + * + * @return Supplier + */ + private Supplier buildAllConnectionSupplier() { + return () -> (long) eventMeshTCPServer.getTcpConnectionHandler().getConnectionCount(); + } + + /** + * Count the number of TCP clients subscribed to a topic. + * + * @return Supplier + */ + private Supplier buildSubTopicSupplier() { + return () -> { + //count topics subscribed by client in this eventMesh + ConcurrentHashMap sessionMap = eventMeshTCPServer.getClientSessionGroupMapping().getSessionMap(); + Iterator sessionIterator = sessionMap.values().iterator(); + Set topicSet = new HashSet<>(); + while (sessionIterator.hasNext()) { + Session session = sessionIterator.next(); + AtomicLong deliveredMsgsCount = session.getPusher().getDeliveredMsgsCount(); + AtomicLong deliveredFailCount = session.getPusher().getDeliverFailMsgsCount(); + int unAckMsgsCount = session.getPusher().getTotalUnackMsgs(); + int sendTopics = session.getSessionContext().getSendTopics().size(); + int subscribeTopics = session.getSessionContext().getSubscribeTopics().size(); + + log.info("session|deliveredFailCount={}|deliveredMsgsCount={}|unAckMsgsCount={}|sendTopics={}|subscribeTopics={}|user={}", + deliveredFailCount.longValue(), deliveredMsgsCount.longValue(), + unAckMsgsCount, sendTopics, subscribeTopics, session.getClient()); + topicSet.addAll(session.getSessionContext().getSubscribeTopics().keySet()); + } + return (long) topicSet.size(); + }; + } + + public Collection getMetrics() { + return metrics.values(); + } + + public long client2eventMeshMsgNum() { + return client2eventMeshMsgNum.get(); + } + + public long eventMesh2mqMsgNum() { + return eventMesh2mqMsgNum.get(); + } + + public long mq2eventMeshMsgNum() { + return mq2eventMeshMsgNum.get(); + } + + public long eventMesh2clientMsgNum() { + return eventMesh2clientMsgNum.get(); + } + + public void resetClient2EventMeshMsgNum() { + this.client2eventMeshMsgNum = new AtomicLong(0); + } + + public void resetEventMesh2mqMsgNum() { + this.eventMesh2mqMsgNum = new AtomicLong(0); + } + + public void resetMq2eventMeshMsgNum() { + this.mq2eventMeshMsgNum = new AtomicLong(0); + } + + public void resetEventMesh2ClientMsgNum() { + this.eventMesh2clientMsgNum = new AtomicLong(0); + } + + + public void setClient2eventMeshTPS(double client2eventMeshTPS) { + this.client2eventMeshTPS = client2eventMeshTPS; + } + + public double getEventMesh2clientTPS() { + return eventMesh2clientTPS; + } + + public void setEventMesh2clientTPS(double eventMesh2clientTPS) { + this.eventMesh2clientTPS = eventMesh2clientTPS; + } + + public double getEventMesh2mqTPS() { + return eventMesh2mqTPS; + } + + public void setEventMesh2mqTPS(double eventMesh2mqTPS) { + this.eventMesh2mqTPS = eventMesh2mqTPS; + } + + public double getMq2eventMeshTPS() { + return mq2eventMeshTPS; + } + + public void setMq2eventMeshTPS(double mq2eventMeshTPS) { + this.mq2eventMeshTPS = mq2eventMeshTPS; + } + + public double getAllTPS() { + return client2eventMeshTPS + eventMesh2clientTPS; + } + + public int getSubTopicNum() { + return subTopicNum; + } + + public void setSubTopicNum(int subTopicNum) { + this.subTopicNum = subTopicNum; + } + + public int getAllConnections() { + return allConnections; + } + + public void setAllConnections(int allConnections) { + this.allConnections = allConnections; + } + + public void setRetrySize(int retrySize) { + this.retrySize = retrySize; + } + + public int getRetrySize() { + return retrySize; + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/TcpMetricsCalculator.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/TcpMetricsCalculator.java new file mode 100644 index 0000000000..0281f59bc7 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/metrics/tcp/TcpMetricsCalculator.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.metrics.tcp; + +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; +import org.apache.eventmesh.runtime.metrics.MonitorMetricConstants; + +import java.math.BigDecimal; +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class TcpMetricsCalculator { + + private static final int period = 30 * 1000; + + private static int PRINT_THREADPOOLSTATE_INTERVAL = 1; + + private final EventMeshTCPServer eventMeshTCPServer; + + private final TcpMetrics tcpMetrics; + + private ScheduledFuture monitorTpsTask; + + private ScheduledExecutorService scheduler; + + public TcpMetricsCalculator(EventMeshTCPServer eventMeshTCPServer, TcpMetrics tcpMetrics) { + this.eventMeshTCPServer = eventMeshTCPServer; + this.tcpMetrics = tcpMetrics; + this.scheduler = ThreadPoolFactory.createScheduledExecutor(2, new EventMeshThreadFactory("EventMesh-TcpMetricsCalculator-scheduler", true)); + } + + public void start() { + int delay = 60 * 1000; + monitorTpsTask = this.scheduler.scheduleAtFixedRate((() -> { + long msgNum = tcpMetrics.client2eventMeshMsgNum(); + tcpMetrics.resetClient2EventMeshMsgNum(); + tcpMetrics.setClient2eventMeshTPS( + new BigDecimal(1000 * msgNum).divide(new BigDecimal(period), 2, BigDecimal.ROUND_HALF_UP).doubleValue()); + + msgNum = tcpMetrics.eventMesh2clientMsgNum(); + tcpMetrics.resetEventMesh2ClientMsgNum(); + tcpMetrics.setEventMesh2clientTPS( + new BigDecimal(1000 * msgNum).divide(new BigDecimal(period), 2, BigDecimal.ROUND_HALF_UP).doubleValue()); + + msgNum = tcpMetrics.eventMesh2mqMsgNum(); + tcpMetrics.resetEventMesh2mqMsgNum(); + tcpMetrics.setEventMesh2mqTPS(new BigDecimal(1000 * msgNum).divide(new BigDecimal(period), 2, BigDecimal.ROUND_HALF_UP).doubleValue()); + + msgNum = tcpMetrics.mq2eventMeshMsgNum(); + tcpMetrics.resetMq2eventMeshMsgNum(); + tcpMetrics.setMq2eventMeshTPS(new BigDecimal(1000 * msgNum).divide(new BigDecimal(period), 2, BigDecimal.ROUND_HALF_UP).doubleValue()); + + //count topics subscribed by client in this eventMesh + ConcurrentHashMap sessionMap = eventMeshTCPServer.getClientSessionGroupMapping().getSessionMap(); + Iterator sessionIterator = sessionMap.values().iterator(); + Set topicSet = new HashSet<>(); + while (sessionIterator.hasNext()) { + Session session = sessionIterator.next(); + AtomicLong deliveredMsgsCount = session.getPusher().getDeliveredMsgsCount(); + AtomicLong deliveredFailCount = session.getPusher().getDeliverFailMsgsCount(); + int unAckMsgsCount = session.getPusher().getTotalUnackMsgs(); + int sendTopics = session.getSessionContext().getSendTopics().size(); + int subscribeTopics = session.getSessionContext().getSubscribeTopics().size(); + + log.info("session|deliveredFailCount={}|deliveredMsgsCount={}|unAckMsgsCount={}|sendTopics={}|subscribeTopics={}|user={}", + deliveredFailCount.longValue(), deliveredMsgsCount.longValue(), + unAckMsgsCount, sendTopics, subscribeTopics, session.getClient()); + topicSet.addAll(session.getSessionContext().getSubscribeTopics().keySet()); + } + tcpMetrics.setSubTopicNum(topicSet.size()); + tcpMetrics.setAllConnections(eventMeshTCPServer.getTcpConnectionHandler().getConnectionCount()); + printAppLogger(tcpMetrics); + }), delay, period, TimeUnit.MILLISECONDS); + } + + private void printAppLogger(TcpMetrics tcpSummaryMetrics) { + + log.info("===========================================TCP SERVER METRICS=================================================="); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.CLIENT_2_EVENTMESH_TPS, + tcpSummaryMetrics.getClient2eventMeshTPS()); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.EVENTMESH_2_MQ_TPS, + tcpSummaryMetrics.getEventMesh2mqTPS()); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.MQ_2_EVENTMESH_TPS, + tcpSummaryMetrics.getMq2eventMeshTPS()); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.EVENTMESH_2_CLIENT_TPS, + tcpSummaryMetrics.getEventMesh2clientTPS()); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.ALL_TPS, + tcpSummaryMetrics.getAllTPS()); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.CONNECTION, + tcpSummaryMetrics.getAllConnectionsGauge()); + + log.info("protocol: {}, s: {}, t: {}", EventMeshConstants.PROTOCOL_TCP, MonitorMetricConstants.SUB_TOPIC_NUM, + tcpSummaryMetrics.getSubTopicNum()); + } + + public void shutdown() { + monitorTpsTask.cancel(true); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/registry/Registry.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/registry/Registry.java deleted file mode 100644 index 6deaa5f8ff..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/registry/Registry.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.registry; - -import org.apache.eventmesh.api.registry.RegistryService; -import org.apache.eventmesh.api.registry.dto.EventMeshDataInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshRegisterInfo; -import org.apache.eventmesh.api.registry.dto.EventMeshUnRegisterInfo; -import org.apache.eventmesh.spi.EventMeshExtensionFactory; - -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Registry { - private static final Logger logger = LoggerFactory.getLogger(Registry.class); - - private volatile boolean inited = false; - - private volatile boolean started = false; - - private RegistryService registryService; - - public synchronized void init(String registryPluginType) throws Exception { - if (!inited) { - registryService = EventMeshExtensionFactory.getExtension(RegistryService.class, registryPluginType); - if (registryService == null) { - logger.error("can't load the registryService plugin, please check."); - throw new RuntimeException("doesn't load the registryService plugin, please check."); - } - registryService.init(); - inited = true; - } - } - - public synchronized void start() throws Exception { - if (!started) { - registryService.start(); - started = true; - } - } - - public synchronized void shutdown() throws Exception { - if (started) { - registryService.shutdown(); - started = false; - inited = false; - } - } - - public List findEventMeshInfoByCluster(String clusterName) throws Exception { - return registryService.findEventMeshInfoByCluster(clusterName); - } - - public List findAllEventMeshInfo() throws Exception { - return registryService.findAllEventMeshInfo(); - } - - public Map> findEventMeshClientDistributionData(String clusterName, String group, String purpose) throws Exception { - return registryService.findEventMeshClientDistributionData(clusterName, group, purpose); - } - - public void registerMetadata(Map metadata) { - registryService.registerMetadata(metadata); - } - - public boolean register(EventMeshRegisterInfo eventMeshRegisterInfo) throws Exception { - return registryService.register(eventMeshRegisterInfo); - } - - public boolean unRegister(EventMeshUnRegisterInfo eventMeshUnRegisterInfo) throws Exception { - return registryService.unRegister(eventMeshUnRegisterInfo); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/storage/StorageResource.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/storage/StorageResource.java new file mode 100644 index 0000000000..e84b03b074 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/storage/StorageResource.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.storage; + +import org.apache.eventmesh.api.storage.StorageResourceService; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class StorageResource { + + private static final Map STORAGE_RESOURCE_CACHE = new HashMap<>(16); + + private StorageResourceService storageResourceService; + + private final AtomicBoolean inited = new AtomicBoolean(false); + + private final AtomicBoolean released = new AtomicBoolean(false); + + private StorageResource() { + + } + + public static StorageResource getInstance(String storageResourcePluginType) { + return STORAGE_RESOURCE_CACHE.computeIfAbsent(storageResourcePluginType, StorageResource::storageResourceBuilder); + } + + private static StorageResource storageResourceBuilder(String storageResourcePluginType) { + StorageResourceService storageResourceServiceExt = EventMeshExtensionFactory.getExtension(StorageResourceService.class, + storageResourcePluginType); + if (storageResourceServiceExt == null) { + String errorMsg = "can't load the StorageResourceService plugin, please check."; + log.error(errorMsg); + throw new RuntimeException(errorMsg); + } + StorageResource storageResource = new StorageResource(); + storageResource.storageResourceService = storageResourceServiceExt; + return storageResource; + } + + public void init() throws Exception { + if (!inited.compareAndSet(false, true)) { + return; + } + storageResourceService.init(); + } + + public void release() throws Exception { + if (!released.compareAndSet(false, true)) { + return; + } + inited.compareAndSet(true, false); + storageResourceService.release(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/AttributeKeys.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/AttributeKeys.java index ac151fda89..4c432ac262 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/AttributeKeys.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/AttributeKeys.java @@ -24,6 +24,7 @@ * keys. */ public final class AttributeKeys { + public static final AttributeKey WRITE_CONTEXT = AttributeKey.valueOf(AttributeKeys.class, "passed-context"); diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/LogExporter.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/LogExporter.java index 9bad687353..826dfeb3a8 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/LogExporter.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/LogExporter.java @@ -19,20 +19,18 @@ import java.util.Collection; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; +import lombok.extern.slf4j.Slf4j; + /** - * Because the class 'LoggingSpanExporter' in openTelemetry exported garbled code in eventMesh's startUp, - * I override the 'LoggingSpanExporter'. + * Because the class 'LoggingSpanExporter' in openTelemetry exported garbled code in eventMesh's startUp, I override the 'LoggingSpanExporter'. */ +@Slf4j public class LogExporter implements SpanExporter { - private static final Logger logger = LoggerFactory.getLogger(LogExporter.class); @Override public CompletableResultCode export(Collection spans) { @@ -42,30 +40,29 @@ public CompletableResultCode export(Collection spans) { sb.setLength(0); InstrumentationLibraryInfo instrumentationLibraryInfo = span.getInstrumentationLibraryInfo(); sb.append("'") - .append(span.getName()) - .append("' : ") - .append(span.getTraceId()) - .append(" ") - .append(span.getSpanId()) - .append(" ") - .append(span.getKind()) - .append(" [tracer: ") - .append(instrumentationLibraryInfo.getName()) - .append(":") - .append( - instrumentationLibraryInfo.getVersion() == null - ? "" - : instrumentationLibraryInfo.getVersion()) - .append("] ") - .append(span.getAttributes()); - logger.info(sb.toString()); + .append(span.getName()) + .append("' : ") + .append(span.getTraceId()) + .append(" ") + .append(span.getSpanId()) + .append(" ") + .append(span.getKind()) + .append(" [tracer: ") + .append(instrumentationLibraryInfo.getName()) + .append(":") + .append( + instrumentationLibraryInfo.getVersion() == null + ? "" + : instrumentationLibraryInfo.getVersion()) + .append("] ") + .append(span.getAttributes()); + log.info(sb.toString()); } return CompletableResultCode.ofSuccess(); } /** - * Flushes the data. - * (i guess it is not necessary for slf4j's log) + * Flushes the data. (i guess it is not necessary for slf4j's log) * * @return the result of the operation */ diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/SpanKey.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/SpanKey.java index 3fb285d14d..095e30baa5 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/SpanKey.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/SpanKey.java @@ -24,29 +24,29 @@ * Makes span keys for specific instrumentation accessible to enrich and suppress spans. */ public final class SpanKey { + // server span key public static final ContextKey SERVER_KEY = - ContextKey.named("opentelemetry-traces-span-key-server"); + ContextKey.named("opentelemetry-traces-span-key-server"); // client span keys public static final ContextKey HTTP_CLIENT_KEY = - ContextKey.named("opentelemetry-traces-span-key-http"); + ContextKey.named("opentelemetry-traces-span-key-http"); public static final ContextKey RPC_CLIENT_KEY = - ContextKey.named("opentelemetry-traces-span-key-rpc"); + ContextKey.named("opentelemetry-traces-span-key-rpc"); public static final ContextKey DB_CLIENT_KEY = - ContextKey.named("opentelemetry-traces-span-key-db"); + ContextKey.named("opentelemetry-traces-span-key-db"); // this is used instead of above, depending on the configuration value for // otel.instrumentation.experimental.outgoing-span-suppression-by-type public static final ContextKey CLIENT_KEY = - ContextKey.named("opentelemetry-traces-span-key-client"); + ContextKey.named("opentelemetry-traces-span-key-client"); // producer & consumer (messaging) span keys public static final ContextKey PRODUCER_KEY = - ContextKey.named("opentelemetry-traces-span-key-producer"); + ContextKey.named("opentelemetry-traces-span-key-producer"); public static final ContextKey CONSUMER_RECEIVE_KEY = - ContextKey.named("opentelemetry-traces-span-key-consumer-receive"); + ContextKey.named("opentelemetry-traces-span-key-consumer-receive"); public static final ContextKey CONSUMER_PROCESS_KEY = - ContextKey.named("opentelemetry-traces-span-key-consumer-process"); + ContextKey.named("opentelemetry-traces-span-key-consumer-process"); } - diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/Trace.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/Trace.java index 716577f859..3c7e48ec5b 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/Trace.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/Trace.java @@ -20,11 +20,10 @@ import org.apache.eventmesh.trace.api.EventMeshTraceService; import org.apache.eventmesh.trace.api.TracePluginFactory; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.atomic.AtomicBoolean; import io.cloudevents.CloudEvent; import io.netty.channel.ChannelHandlerContext; @@ -33,25 +32,43 @@ import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.context.Context; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class Trace { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean useTrace; + private static final Map TRACE_CACHE = new HashMap<>(16); + + private final AtomicBoolean inited = new AtomicBoolean(false); + private EventMeshTraceService eventMeshTraceService; - public Trace(boolean useTrace) { - this.useTrace = useTrace; + private boolean useTrace; + + public static Trace getInstance(String tracePluginType, boolean useTrace) { + return TRACE_CACHE.computeIfAbsent(tracePluginType, key -> traceBuilder(tracePluginType, useTrace)); } - public void init(String tracePluginType) throws Exception { - if (useTrace) { - eventMeshTraceService = TracePluginFactory.getEventMeshTraceService(tracePluginType); - eventMeshTraceService.init(); + private static Trace traceBuilder(String tracePluginType, boolean useTrace) { + Trace trace = new Trace(); + trace.useTrace = useTrace; + trace.eventMeshTraceService = TracePluginFactory.getEventMeshTraceService(tracePluginType); + return trace; + } + + private Trace() { + + } + + public void init() throws Exception { + if (!inited.compareAndSet(false, true)) { + return; } + eventMeshTraceService.init(); } public Span createSpan(String spanName, SpanKind spanKind, long startTime, TimeUnit timeUnit, - Context context, boolean isSpanFinishInOtherThread) { + Context context, boolean isSpanFinishInOtherThread) { if (!useTrace) { return Span.getInvalid(); } @@ -60,7 +77,7 @@ public Span createSpan(String spanName, SpanKind spanKind, long startTime, TimeU } public Span createSpan(String spanName, SpanKind spanKind, Context context, - boolean isSpanFinishInOtherThread) { + boolean isSpanFinishInOtherThread) { if (!useTrace) { return Span.getInvalid(); } @@ -94,17 +111,7 @@ public Span addTraceInfoToSpan(ChannelHandlerContext ctx, CloudEvent cloudEvent) } Context context = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get(); Span span = context != null ? context.get(SpanKey.SERVER_KEY) : null; - - if (span == null) { - logger.warn("span is null when finishSpan"); - return null; - } - - //add trace info - for (String entry : cloudEvent.getExtensionNames()) { - span.setAttribute(entry, cloudEvent.getExtension(entry).toString()); - } - return span; + return addTraceInfoToSpan(span, cloudEvent); } public Span addTraceInfoToSpan(Span span, CloudEvent cloudEvent) { @@ -113,7 +120,7 @@ public Span addTraceInfoToSpan(Span span, CloudEvent cloudEvent) { } if (span == null) { - logger.warn("span is null when finishSpan"); + log.warn("span is null when finishSpan"); return null; } @@ -121,8 +128,9 @@ public Span addTraceInfoToSpan(Span span, CloudEvent cloudEvent) { return span; } + // add trace info for (String entry : cloudEvent.getExtensionNames()) { - span.setAttribute(entry, cloudEvent.getExtension(entry).toString()); + span.setAttribute(entry, cloudEvent.getExtension(entry) == null ? "" : cloudEvent.getExtension(entry).toString()); } return span; } @@ -133,7 +141,7 @@ public Span addTraceInfoToSpan(Span span, Map map) { } if (span == null) { - logger.warn("span is null when finishSpan"); + log.warn("span is null when finishSpan"); return null; } @@ -148,22 +156,10 @@ public Span addTraceInfoToSpan(Span span, Map map) { } public void finishSpan(ChannelHandlerContext ctx, StatusCode statusCode) { - try { - if (useTrace) { - Context context = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get(); - Span span = context != null ? context.get(SpanKey.SERVER_KEY) : null; - - if (span == null) { - logger.warn("span is null when finishSpan"); - return; - } - if (statusCode != null) { - span.setStatus(statusCode); - } - span.end(); - } - } catch (Exception e) { - logger.warn("finishSpan occur exception,", e); + if (useTrace) { + Context context = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get(); + Span span = context != null ? context.get(SpanKey.SERVER_KEY) : null; + finishSpan(span, statusCode); } } @@ -171,7 +167,7 @@ public void finishSpan(Span span, StatusCode statusCode) { try { if (useTrace) { if (span == null) { - logger.warn("span is null when finishSpan"); + log.warn("span is null when finishSpan"); return; } if (statusCode != null) { @@ -180,7 +176,7 @@ public void finishSpan(Span span, StatusCode statusCode) { span.end(); } } catch (Exception e) { - logger.warn("finishSpan occur exception,", e); + log.error("finishSpan occur exception,", e); } } @@ -188,7 +184,7 @@ public void finishSpan(Span span, StatusCode statusCode, String errMsg, Throwabl try { if (useTrace) { if (span == null) { - logger.warn("span is null when finishSpan"); + log.warn("span is null when finishSpan"); return; } if (statusCode != null) { @@ -200,36 +196,20 @@ public void finishSpan(Span span, StatusCode statusCode, String errMsg, Throwabl span.end(); } } catch (Exception e) { - logger.warn("finishSpan occur exception,", e); + log.error("finishSpan occur exception,", e); } } - public void finishSpan(ChannelHandlerContext ctx, StatusCode statusCode, String errMsg, - Throwable throwable) { - try { - if (useTrace) { - Context context = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get(); - Span span = context != null ? context.get(SpanKey.SERVER_KEY) : null; - - if (span == null) { - logger.warn("span is null when finishSpan"); - return; - } - if (statusCode != null) { - span.setStatus(statusCode, errMsg); - } - if (throwable != null) { - span.recordException(throwable); - } - span.end(); - } - } catch (Exception e) { - logger.warn("finishSpan occur exception,", e); + public void finishSpan(ChannelHandlerContext ctx, StatusCode statusCode, String errMsg, Throwable throwable) { + if (useTrace) { + Context context = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get(); + Span span = context != null ? context.get(SpanKey.SERVER_KEY) : null; + finishSpan(span, statusCode, errMsg, throwable); } } public void shutdown() throws Exception { - if (useTrace) { + if (useTrace && inited.compareAndSet(true, false)) { eventMeshTraceService.shutdown(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/TraceUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/TraceUtils.java deleted file mode 100644 index b8133c3a19..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/trace/TraceUtils.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.trace; - -import org.apache.eventmesh.runtime.boot.EventMeshServer; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; -import io.netty.channel.ChannelHandlerContext; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Context; - -public class TraceUtils { - private static Logger logger = LoggerFactory.getLogger(TraceUtils.class); - - public static Span prepareClientSpan(Map map, String spanName, - boolean isSpanFinishInOtherThread) { - Span span = null; - try { - span = EventMeshServer.getTrace().createSpan( - spanName, SpanKind.CLIENT, Context.current(), isSpanFinishInOtherThread); - EventMeshServer.getTrace().inject(Context.current(), map); - } catch (Throwable ex) { - logger.warn("upload trace fail when prepareSpan", ex); - } - return span; - } - - public static Span prepareServerSpan(Map map, String spanName, - boolean isSpanFinishInOtherThread) { - Span span = null; - try { - Context traceContext = EventMeshServer.getTrace().extractFrom(Context.current(), map); - span = EventMeshServer.getTrace() - .createSpan(spanName, SpanKind.SERVER, traceContext, isSpanFinishInOtherThread); - } catch (Throwable ex) { - logger.warn("upload trace fail when prepareSpan", ex); - } - return span; - } - - public static Span prepareServerSpan(Map map, String spanName, long startTime, - TimeUnit timeUnit, boolean isSpanFinishInOtherThread) { - Span span = null; - try { - Context traceContext = EventMeshServer.getTrace().extractFrom(Context.current(), map); - if (startTime > 0) { - span = EventMeshServer.getTrace() - .createSpan(spanName, SpanKind.SERVER, startTime, timeUnit, traceContext, - isSpanFinishInOtherThread); - } else { - span = EventMeshServer.getTrace() - .createSpan(spanName, SpanKind.SERVER, traceContext, isSpanFinishInOtherThread); - } - } catch (Throwable ex) { - logger.warn("upload trace fail when prepareSpan", ex); - } - return span; - } - - - public static void finishSpan(Span span, CloudEvent event) { - try { - logger.debug("finishSpan with event:{}", event); - EventMeshServer.getTrace().addTraceInfoToSpan(span, event); - EventMeshServer.getTrace().finishSpan(span, StatusCode.OK); - } catch (Throwable ex) { - logger.warn("upload trace fail when finishSpan", ex); - } - - } - - public static void finishSpan(ChannelHandlerContext ctx, CloudEvent event) { - try { - logger.debug("finishSpan with event:{}", event); - EventMeshServer.getTrace().addTraceInfoToSpan(ctx, event); - EventMeshServer.getTrace().finishSpan(ctx, StatusCode.OK); - } catch (Throwable ex) { - logger.warn("upload trace fail when finishSpan", ex); - } - - } - - public static void finishSpanWithException(ChannelHandlerContext ctx, CloudEvent event, - String errMsg, Throwable e) { - try { - logger.debug("finishSpanWithException with event:{}", event); - EventMeshServer.getTrace().addTraceInfoToSpan(ctx, event); - EventMeshServer.getTrace().finishSpan(ctx, StatusCode.ERROR, errMsg, e); - } catch (Throwable ex) { - logger.warn("upload trace fail when finishSpanWithException", ex); - } - } - - public static void finishSpanWithException(Span span, Map map, String errMsg, - Throwable e) { - try { - logger.debug("finishSpanWithException with map:{}", map); - EventMeshServer.getTrace().addTraceInfoToSpan(span, map); - EventMeshServer.getTrace().finishSpan(span, StatusCode.ERROR, errMsg, e); - } catch (Throwable ex) { - logger.warn("upload trace fail when finishSpanWithException", ex); - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/BannerUtil.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/BannerUtil.java new file mode 100644 index 0000000000..7397c5e913 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/BannerUtil.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import static org.apache.eventmesh.runtime.constants.EventMeshVersion.getCurrentVersionDesc; + +import org.apache.commons.lang3.StringUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * EventMesh banner util + */ +@Slf4j +public class BannerUtil { + + private static final String LOGO = + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEME EMEMEMEME " + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEMEM " + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME " + System.lineSeparator() + + "EMEMEMEMEMEM EMEMEMEMEM EMEMEMEMEMEMEMEME EMEMEMEMEME" + System.lineSeparator() + + "EMEMEMEME EMEMEMEMEM EMEMEMEMEMEME EMEMEMEME" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEME EMEMEMEM" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEME EMEMEMEMEM EMEMEME" + System.lineSeparator() + + "EMEMEMEME EMEMEMEMEM EMEMEMEME" + System.lineSeparator() + + "EMEMEMEMEMEM EMEMEMEMEM EMEMEMEMEMEM" + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM " + System.lineSeparator() + + " EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEM EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME " + System.lineSeparator() + + " MEMEMEMEMEMEMEMEMEMEMEMEMEMEME EMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEMEME"; + + private static final String LOGONAME = + " ____ _ __ __ _ " + System.lineSeparator() + + " / ____|_ _____ _ __ | |_| \\/ | ___ ___| |__ " + System.lineSeparator() + + " | __|\\ \\ / / _ | '_ \\| __| |\\/| |/ _ |/ __| '_ \\ " + System.lineSeparator() + + " | |___ \\ V / __| | | | |_| | | | __|\\__ \\ | | |" + System.lineSeparator() + + " \\ ____| \\_/ \\___|_| |_|\\__|_| |_|\\___||___/_| |_| " + + (StringUtils.isNotBlank(getCurrentVersionDesc()) ? "(" + getCurrentVersionDesc() + ")" : ""); + + public static void generateBanner() { + String banner = + System.lineSeparator() + + System.lineSeparator() + + LOGO + + System.lineSeparator() + + LOGONAME + + System.lineSeparator(); + if (log.isInfoEnabled()) { + log.info(banner); + } else { + System.out.print(banner); + } + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriter.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriter.java index e939ac25e5..cf03cb8f2c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriter.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriter.java @@ -20,18 +20,21 @@ import java.util.HashMap; import java.util.Map; +import javax.annotation.Nonnull; + import io.cloudevents.rw.CloudEventContextWriter; import io.cloudevents.rw.CloudEventRWException; public class EventMeshCloudEventWriter implements CloudEventContextWriter { - private Map extensionMap = null; + + private Map extensionMap; public EventMeshCloudEventWriter() { extensionMap = new HashMap(); } @Override - public CloudEventContextWriter withContextAttribute(String key, String value) + public CloudEventContextWriter withContextAttribute(@Nonnull String key, @Nonnull String value) throws CloudEventRWException { extensionMap.put(key, value); return this; diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImpl.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImpl.java deleted file mode 100644 index cf83904115..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.util; - -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicLong; - -public class EventMeshThreadFactoryImpl implements ThreadFactory { - private final AtomicLong threadIndex = new AtomicLong(0); - private final String threadNamePrefix; - private Boolean isDaemonSpecified = null; - - public EventMeshThreadFactoryImpl(final String threadNamePrefix) { - this.threadNamePrefix = threadNamePrefix; - } - - public EventMeshThreadFactoryImpl(final String threadNamePrefix, final boolean isDaemonSpecified) { - this.threadNamePrefix = threadNamePrefix; - this.isDaemonSpecified = isDaemonSpecified; - } - - public String getThreadNamePrefix() { - return threadNamePrefix; - } - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, threadNamePrefix + '-' + this.threadIndex.incrementAndGet()); - if (isDaemonSpecified != null) { - t.setDaemon(isDaemonSpecified); - } - return t; - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshUtil.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshUtil.java index 7dff967378..dca254a6a5 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshUtil.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/EventMeshUtil.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.runtime.util; +import org.apache.eventmesh.common.EventMeshThreadFactory; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; import org.apache.eventmesh.common.protocol.tcp.UserAgent; import org.apache.eventmesh.common.utils.RandomStringUtils; @@ -37,16 +38,15 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TimeZone; import java.util.concurrent.ThreadPoolExecutor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; import io.cloudevents.core.v03.CloudEventV03; @@ -57,32 +57,39 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -public class EventMeshUtil { - - private static final Logger logger = LoggerFactory.getLogger(EventMeshUtil.class); +import lombok.extern.slf4j.Slf4j; - private static final Logger tcpLogger = LoggerFactory.getLogger("tcpMonitor"); +@Slf4j +public class EventMeshUtil { public static String buildPushMsgSeqNo() { - return StringUtils.rightPad(String.valueOf(System.currentTimeMillis()), 6) + RandomStringUtils.generateNum(4); + return new StringBuilder() + .append(StringUtils.rightPad(String.valueOf(System.currentTimeMillis()), 6)) + .append(RandomStringUtils.generateNum(4)) + .toString(); + } - public static String buildMeshClientID(String clientGroup, String meshCluster) { - return StringUtils.trim(clientGroup) - + "(" + StringUtils.trim(meshCluster) + ")" - + "-" + EventMeshVersion.getCurrentVersionDesc() - + "-" + ThreadUtils.getPID(); + public static String buildMeshClientID(final String clientGroup, final String meshCluster) { + return new StringBuilder() + .append(StringUtils.trim(clientGroup)) + .append('(') + .append(StringUtils.trim(meshCluster)) + .append(')') + .append('-') + .append(EventMeshVersion.getCurrentVersionDesc()) + .append('-') + .append(ThreadUtils.getPID()) + .toString(); } - public static String buildMeshTcpClientID(String clientSysId, String purpose, String meshCluster) { - return StringUtils.trim(clientSysId) - + "-" + StringUtils.trim(purpose) - + "-" + StringUtils.trim(meshCluster) - + "-" + EventMeshVersion.getCurrentVersionDesc() - + "-" + ThreadUtils.getPID(); + public static String buildMeshTcpClientID(final String clientSysId, final String purpose, + final String meshCluster) { + return StringUtils.joinWith("-", StringUtils.trim(clientSysId), StringUtils.trim(purpose), + StringUtils.trim(meshCluster), EventMeshVersion.getCurrentVersionDesc(), ThreadUtils.getPID()); } - public static String buildClientGroup(String systemId) { + public static String buildClientGroup(final String systemId) { return systemId; } @@ -90,25 +97,27 @@ public static String buildClientGroup(String systemId) { * custom fetch stack * * @param e - * @return + * @return stacktrace */ - public static String stackTrace(Throwable e) { + public static String stackTrace(final Throwable e) { return stackTrace(e, 0); } - public static String stackTrace(Throwable e, int level) { + public static String stackTrace(final Throwable e, final int level) { if (e == null) { return null; } - StackTraceElement[] eles = e.getStackTrace(); - level = (level == 0) ? eles.length : level; - StringBuilder sb = new StringBuilder(); + final StackTraceElement[] eles = e.getStackTrace(); + final int localLevel = (level == 0) ? eles.length : level; + final StringBuilder sb = new StringBuilder(); sb.append(e.getMessage()).append(System.lineSeparator()); + int innerLevel = 0; - for (StackTraceElement ele : eles) { - sb.append(ele.toString()).append(System.lineSeparator()); - if (++innerLevel >= level) { + for (final StackTraceElement ele : eles) { + sb.append(ele).append(System.lineSeparator()); + innerLevel++; + if (innerLevel >= localLevel) { break; } } @@ -116,88 +125,82 @@ public static String stackTrace(Throwable e, int level) { } public static ObjectMapper createJsoner() { - ObjectMapper jsonMapper = new ObjectMapper(); - jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - jsonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - jsonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - jsonMapper.setTimeZone(TimeZone.getDefault()); - return jsonMapper; + return new ObjectMapper() + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .setTimeZone(TimeZone.getDefault()); } - /** * print part of the mq message * * @param eventMeshMessage - * @return + * @return message string */ - public static String printMqMessage(EventMeshMessage eventMeshMessage) { - Map properties = eventMeshMessage.getProperties(); + public static String printMqMessage(final EventMeshMessage eventMeshMessage) { + final Map properties = eventMeshMessage.getProperties(); String keys = properties.get(EventMeshConstants.KEYS_UPPERCASE); - if (!StringUtils.isNotBlank(keys)) { + if (StringUtils.isBlank(keys)) { keys = properties.get(EventMeshConstants.KEYS_LOWERCASE); } - String result = String.format("Message [topic=%s,TTL=%s,uniqueId=%s,bizSeq=%s]", eventMeshMessage.getTopic(), + return String.format("Message [topic=%s,TTL=%s,uniqueId=%s,bizSeq=%s]", eventMeshMessage.getTopic(), properties.get(EventMeshConstants.TTL), properties.get(EventMeshConstants.RR_REQUEST_UNIQ_ID), keys); - return result; } - public static String getMessageBizSeq(CloudEvent event) { - + public static String getMessageBizSeq(final CloudEvent event) { String keys = (String) event.getExtension(EventMeshConstants.KEYS_UPPERCASE); - if (!StringUtils.isNotBlank(keys)) { + if (StringUtils.isBlank(keys)) { keys = (String) event.getExtension(EventMeshConstants.KEYS_LOWERCASE); } + return keys; } - public static Map getEventProp(CloudEvent event) { - Set extensionSet = event.getExtensionNames(); - Map prop = new HashMap<>(); - for (String extensionKey : extensionSet) { - prop.put(extensionKey, event.getExtension(extensionKey).toString()); - } - return prop; + public static Map getEventProp(final CloudEvent event) { + final Map propMap = new HashMap<>(); + event.getExtensionNames().forEach((extensionKey) -> { + propMap.put(extensionKey, event.getExtension(extensionKey) == null ? "" + : event.getExtension(extensionKey).toString()); + }); + return propMap; } public static String getLocalAddr() { - //priority of networkInterface when generating client ip - String priority = System.getProperty("networkInterface.priority", "bond1 preferList = new ArrayList(); - for (String eth : priority.split("<")) { - preferList.add(eth); - } + // priority of networkInterface when generating client ip + final String priority = System.getProperty("networkInterface.priority", "bond1 preferList = new ArrayList<>(); + preferList.addAll(Arrays.asList(priority.split("<"))); + NetworkInterface preferNetworkInterface = null; try { - Enumeration enumeration1 = NetworkInterface.getNetworkInterfaces(); + final Enumeration enumeration1 = NetworkInterface.getNetworkInterfaces(); while (enumeration1.hasMoreElements()) { final NetworkInterface networkInterface = enumeration1.nextElement(); if (!preferList.contains(networkInterface.getName())) { continue; - } else if (preferNetworkInterface == null) { - preferNetworkInterface = networkInterface; - } else if (preferList.indexOf(networkInterface.getName()) - > preferList.indexOf(preferNetworkInterface.getName())) { - //get the networkInterface that has higher priority + } else if (preferNetworkInterface == null + || preferList.indexOf(networkInterface.getName()) > preferList.indexOf(preferNetworkInterface.getName())) { preferNetworkInterface = networkInterface; } } // Traversal Network interface to get the first non-loopback and non-private address - ArrayList ipv4Result = new ArrayList(); - ArrayList ipv6Result = new ArrayList(); + final ArrayList ipv4Result = new ArrayList<>(); + final ArrayList ipv6Result = new ArrayList<>(); if (preferNetworkInterface != null) { - logger.debug("use preferNetworkInterface:{}", preferNetworkInterface); + log.debug("use preferNetworkInterface:{}", preferNetworkInterface); final Enumeration en = preferNetworkInterface.getInetAddresses(); getIpResult(ipv4Result, ipv6Result, en); } else { - logger.debug("no preferNetworkInterface"); - Enumeration enumeration = NetworkInterface.getNetworkInterfaces(); + log.debug("no preferNetworkInterface"); + final Enumeration enumeration = NetworkInterface.getNetworkInterfaces(); while (enumeration.hasMoreElements()) { final NetworkInterface networkInterface = enumeration.nextElement(); final Enumeration en = networkInterface.getInetAddresses(); @@ -207,25 +210,20 @@ public static String getLocalAddr() { // prefer ipv4 if (!ipv4Result.isEmpty()) { - for (String ip : ipv4Result) { - if (ip.startsWith("127.0") || ip.startsWith("192.168")) { - continue; + for (final String ip : ipv4Result) { + if (!StringUtils.startsWithAny(ip, "127.0", "192.168")) { + return ip; } - - return ip; } return ipv4Result.get(ipv4Result.size() - 1); } else if (!ipv6Result.isEmpty()) { return ipv6Result.get(0); } - //If failed to find,fall back to localhost - final InetAddress localHost = InetAddress.getLocalHost(); - return normalizeHostAddress(localHost); - } catch (SocketException e) { - e.printStackTrace(); - } catch (UnknownHostException e) { - e.printStackTrace(); + // If failed to find,fall back to localhost + return normalizeHostAddress(InetAddress.getLocalHost()); + } catch (SocketException | UnknownHostException e) { + log.error("failed to get local address", e); } return null; @@ -239,37 +237,44 @@ public static String normalizeHostAddress(final InetAddress localHost) { } } - private static void getIpResult(ArrayList ipv4Result, ArrayList ipv6Result, - Enumeration en) { + private static void getIpResult(final Collection ipv4Result, final Collection ipv6Result, + final Enumeration en) { while (en.hasMoreElements()) { final InetAddress address = en.nextElement(); - if (!address.isLoopbackAddress()) { - if (address instanceof Inet6Address) { - ipv6Result.add(normalizeHostAddress(address)); - } else { - ipv4Result.add(normalizeHostAddress(address)); - } + if (address.isLoopbackAddress()) { + continue; } + + if (address instanceof Inet6Address) { + ipv6Result.add(normalizeHostAddress(address)); + } else { + ipv4Result.add(normalizeHostAddress(address)); + } + } } - public static String buildUserAgentClientId(UserAgent client) { + public static String buildUserAgentClientId(final UserAgent client) { if (client == null) { return null; } - StringBuilder sb = new StringBuilder(); - sb.append(client.getSubsystem()).append("-") - .append("-") - .append(client.getPid()).append("-") - .append(client.getHost()).append(":").append(client.getPort()); - return sb.toString(); + + return new StringBuilder() + .append(client.getSubsystem()) + .append('-') + .append('-') + .append(client.getPid()) + .append('-') + .append(client.getHost()) + .append(':') + .append(client.getPort()) + .toString(); } - public static void printState(ThreadPoolExecutor scheduledExecutorService) { - tcpLogger.info("{} [{} {} {} {}]", ((EventMeshThreadFactoryImpl) scheduledExecutorService.getThreadFactory()) - .getThreadNamePrefix(), scheduledExecutorService.getQueue().size(), scheduledExecutorService - .getPoolSize(), scheduledExecutorService.getActiveCount(), scheduledExecutorService - .getCompletedTaskCount()); + public static void printState(final ThreadPoolExecutor scheduledExecutorService) { + log.info("{} [{} {} {} {}]", ((EventMeshThreadFactory) scheduledExecutorService.getThreadFactory()).getThreadNamePrefix(), + scheduledExecutorService.getQueue().size(), scheduledExecutorService.getPoolSize(), + scheduledExecutorService.getActiveCount(), scheduledExecutorService.getCompletedTaskCount()); } /** @@ -281,29 +286,30 @@ public static void printState(ThreadPoolExecutor scheduledExecutorService) { * @throws ClassNotFoundException */ @SuppressWarnings("unchecked") - public static T cloneObject(T object) throws IOException, ClassNotFoundException { - ByteArrayOutputStream byOut = new ByteArrayOutputStream(); - ObjectOutputStream outputStream = new ObjectOutputStream(byOut); - outputStream.writeObject(object); - - ByteArrayInputStream byIn = new ByteArrayInputStream(byOut.toByteArray()); - ObjectInputStream inputStream = new ObjectInputStream(byIn); - return (T) inputStream.readObject(); - } + public static T cloneObject(final T object) throws IOException, ClassNotFoundException { + try (ByteArrayOutputStream byOut = new ByteArrayOutputStream(); + ObjectOutputStream outputStream = new ObjectOutputStream(byOut)) { - public static Map getCloudEventExtensionMap(String protocolVersion, - CloudEvent cloudEvent) { - try { - EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); - if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion)) { - ((CloudEventV1) cloudEvent).readContext(eventMeshCloudEventWriter); - } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion)) { - ((CloudEventV03) cloudEvent).readContext(eventMeshCloudEventWriter); + outputStream.writeObject(object); + + try (ByteArrayInputStream byIn = new ByteArrayInputStream(byOut.toByteArray()); + ObjectInputStream inputStream = new ObjectInputStream(byIn)) { + return (T) inputStream.readObject(); } - return eventMeshCloudEventWriter.getExtensionMap(); - } catch (Throwable e) { - logger.warn("getCloudEventExtensionMap fail", e); - return null; } + + } + + public static Map getCloudEventExtensionMap(final String protocolVersion, final CloudEvent cloudEvent) { + final EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); + if (StringUtils.equals(SpecVersion.V1.toString(), protocolVersion) + && cloudEvent instanceof CloudEventV1) { + ((CloudEventV1) cloudEvent).readContext(eventMeshCloudEventWriter); + } else if (StringUtils.equals(SpecVersion.V03.toString(), protocolVersion) + && cloudEvent instanceof CloudEventV03) { + ((CloudEventV03) cloudEvent).readContext(eventMeshCloudEventWriter); + } + + return eventMeshCloudEventWriter.getExtensionMap(); } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpRequestUtil.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpRequestUtil.java new file mode 100644 index 0000000000..afa43ba6b4 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpRequestUtil.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.handler.codec.http.multipart.Attribute; +import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; +import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; +import io.netty.handler.codec.http.multipart.InterfaceHttpData; + +public class HttpRequestUtil { + + private static final DefaultHttpDataFactory DEFAULT_HTTP_DATA_FACTORY = new DefaultHttpDataFactory(false); + + public static Map parseHttpRequestBody(final HttpRequest httpRequest, @Nullable Supplier start, @Nullable Consumer end) + throws IOException { + T t = null; + if (!Objects.isNull(start)) { + t = start.get(); + } + final Map httpRequestBody = new HashMap<>(); + if (io.netty.handler.codec.http.HttpMethod.GET.equals(httpRequest.method())) { + new QueryStringDecoder(httpRequest.uri()) + .parameters() + .forEach((key, value) -> httpRequestBody.put(key, value.get(0))); + } else if (io.netty.handler.codec.http.HttpMethod.POST.equals(httpRequest.method())) { + decodeHttpRequestBody(httpRequest, httpRequestBody); + } + if (!Objects.isNull(end)) { + end.accept(t); + } + return httpRequestBody; + } + + public static Map parseHttpRequestBody(final HttpRequest httpRequest) throws IOException { + return parseHttpRequestBody(httpRequest, null, null); + } + + private static void decodeHttpRequestBody(HttpRequest httpRequest, Map httpRequestBody) throws IOException { + final HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(DEFAULT_HTTP_DATA_FACTORY, httpRequest); + for (final InterfaceHttpData param : decoder.getBodyHttpDatas()) { + if (InterfaceHttpData.HttpDataType.Attribute == param.getHttpDataType()) { + final Attribute data = (Attribute) param; + httpRequestBody.put(data.getName(), data.getValue()); + } + } + decoder.destroy(); + } + + /** + * Converts a query string to a map of key-value pairs. + *

+ * This method takes a query string and parses it to create a map of key-value pairs, where each key and value are extracted from the query string + * separated by '='. + *

+ * If the query string is null, an empty map is returned. + * + * @param queryString the query string to convert to a map + * @return a map containing the key-value pairs from the query string + */ + public static Map queryStringToMap(String queryString) { + if (queryString == null) { + return new HashMap<>(); + } + Map result = new HashMap<>(); + for (String param : queryString.split("&")) { + String[] entry = param.split("="); + if (entry.length > 1) { + result.put(entry[0], entry[1]); + } else { + result.put(entry[0], ""); + } + } + return result; + } + + /** + * Get the value of a query parameter in URI query string. + */ + public static String getQueryParam(HttpRequest httpRequest, String key, String defaultValue) { + List values = new QueryStringDecoder(httpRequest.uri()).parameters().get(key); + return values != null ? values.get(0) : defaultValue; + } + + /** + * Get the value of a query parameter in body. + */ + public static String getBodyParam(HttpRequest httpRequest, String key) throws IOException { + HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(httpRequest); + Attribute attribute = (Attribute) decoder.getBodyHttpData(key); + return attribute.getValue(); + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpResponseUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpResponseUtils.java index 6c49c672a6..b24cfeab89 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpResponseUtils.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpResponseUtils.java @@ -17,51 +17,67 @@ package org.apache.eventmesh.runtime.util; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; + import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; +import io.netty.util.AsciiString; public class HttpResponseUtils { - public static final HttpResponse createSuccess() { + /** + * @return Empty response with 200 status code. + */ + public static HttpResponse createSuccess() { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); } - public static final HttpResponse createNotFound() { + /** + * @return Empty response with 404 status code. + */ + public static HttpResponse createNotFound() { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND); } - public static final HttpResponse createInternalServerError() { + /** + * @return Empty response with 500 status code. + */ + public static HttpResponse createInternalServerError() { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR); } - private static final ByteBuf crateByteBuf(ChannelHandlerContext ctx, String body) { - byte[] bytes = body.getBytes(); - ByteBuf byteBuf = ctx.alloc().buffer(bytes.length); - byteBuf.writeBytes(bytes); - return byteBuf; - } - - public static final HttpResponse setResponseJsonBody(String body, ChannelHandlerContext ctx) { + /** + * Only one header is set: {@link HttpHeaderNames#CONTENT_TYPE} with the provided {@code headerValue}. + */ + public static HttpResponse buildHttpResponse(String body, ChannelHandlerContext ctx, AsciiString headerValue, HttpResponseStatus status) { HttpHeaders responseHeaders = new DefaultHttpHeaders(); - responseHeaders.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); - return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, crateByteBuf(ctx, body), - responseHeaders, responseHeaders); + responseHeaders.add(HttpHeaderNames.CONTENT_TYPE, headerValue); + return buildHttpResponse(body, ctx, responseHeaders, status); + } + public static HttpResponse buildHttpResponse(String body, ChannelHandlerContext ctx, HttpHeaders responseHeaders, HttpResponseStatus status) { + return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, createByteBuf(ctx, body), responseHeaders, responseHeaders); } - public static final HttpResponse setResponseTextBody(String body, ChannelHandlerContext ctx) { + public static HttpHeaders buildDefaultHttpHeaders(AsciiString contentType) { HttpHeaders responseHeaders = new DefaultHttpHeaders(); - responseHeaders.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_HTML); - return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, crateByteBuf(ctx, body), - responseHeaders, responseHeaders); + responseHeaders.add(HttpHeaderNames.CONTENT_TYPE, contentType); + responseHeaders.add(EventMeshConstants.HANDLER_ORIGIN, "*"); + return responseHeaders; } + private static ByteBuf createByteBuf(ChannelHandlerContext ctx, String body) { + byte[] bytes = body.getBytes(Constants.DEFAULT_CHARSET); + ByteBuf byteBuf = ctx.alloc().buffer(bytes.length); + byteBuf.writeBytes(bytes); + return byteBuf; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpTinyClient.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpTinyClient.java index e9d904a2c7..24142a6821 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpTinyClient.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/HttpTinyClient.java @@ -17,22 +17,25 @@ package org.apache.eventmesh.runtime.util; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Objects; public class HttpTinyClient { public static HttpResult httpGet(String url, List headers, List paramValues, - String encoding, long readTimeoutMs) throws IOException { + String encoding, long readTimeoutMs) throws IOException { String encodedContent = encodingParams(paramValues, encoding); - url += (null == encodedContent) ? "" : ("?" + encodedContent); + url += (encodedContent == null) ? "" : ("?" + encodedContent); HttpURLConnection conn = null; try { @@ -47,9 +50,9 @@ public static HttpResult httpGet(String url, List headers, List String resp = null; if (HttpURLConnection.HTTP_OK == respCode) { - resp = IOTinyUtils.toString(conn.getInputStream(), encoding); + resp = IOUtils.toString(conn.getInputStream(), encoding); } else { - resp = IOTinyUtils.toString(conn.getErrorStream(), encoding); + resp = IOUtils.toString(conn.getErrorStream(), encoding); } return new HttpResult(respCode, resp); } finally { @@ -59,14 +62,14 @@ public static HttpResult httpGet(String url, List headers, List } } - private static String encodingParams(List paramValues, String encoding) - throws UnsupportedEncodingException { + private static String encodingParams(Collection paramValues, String encoding) + throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); - if (null == paramValues) { + if (paramValues == null) { return null; } - for (Iterator iter = paramValues.iterator(); iter.hasNext(); ) { + for (Iterator iter = paramValues.iterator(); iter.hasNext();) { sb.append(iter.next()).append("="); sb.append(URLEncoder.encode(iter.next(), encoding)); if (iter.hasNext()) { @@ -76,9 +79,9 @@ private static String encodingParams(List paramValues, String encoding) return sb.toString(); } - private static void setHeaders(HttpURLConnection conn, List headers, String encoding) { - if (null != headers) { - for (Iterator iter = headers.iterator(); iter.hasNext(); ) { + private static void setHeaders(HttpURLConnection conn, Collection headers, String encoding) { + if (headers != null) { + for (Iterator iter = headers.iterator(); iter.hasNext();) { conn.addRequestProperty(iter.next(), iter.next()); } } @@ -92,7 +95,7 @@ private static void setHeaders(HttpURLConnection conn, List headers, Str * @return the http response of given http post request */ public static HttpResult httpPost(String url, List headers, List paramValues, - String encoding, long readTimeoutMs) throws IOException { + String encoding, long readTimeoutMs) throws IOException { String encodedContent = encodingParams(paramValues, encoding); HttpURLConnection conn = null; @@ -105,27 +108,24 @@ public static HttpResult httpPost(String url, List headers, List conn.setDoInput(true); setHeaders(conn, headers, encoding); - conn.getOutputStream().write(encodedContent.getBytes(EventMeshConstants.DEFAULT_CHARSET)); + conn.getOutputStream().write(Objects.requireNonNull(encodedContent).getBytes(StandardCharsets.UTF_8)); int respCode = conn.getResponseCode(); - String resp = null; + String resp = HttpURLConnection.HTTP_OK == respCode ? IOUtils.toString(conn.getInputStream(), encoding) + : IOUtils.toString(conn.getErrorStream(), encoding); - if (HttpURLConnection.HTTP_OK == respCode) { - resp = IOTinyUtils.toString(conn.getInputStream(), encoding); - } else { - resp = IOTinyUtils.toString(conn.getErrorStream(), encoding); - } return new HttpResult(respCode, resp); } finally { - if (null != conn) { + if (conn != null) { conn.disconnect(); } } } public static class HttpResult { - private final int code; - private final String content; + + private final transient int code; + private final transient String content; public HttpResult(int code, String content) { this.code = code; diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/IOTinyUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/IOTinyUtils.java deleted file mode 100644 index 5aa3153747..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/IOTinyUtils.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.util; - -import org.apache.eventmesh.runtime.constants.EventMeshConstants; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.List; - -public class IOTinyUtils { - - public static String toString(InputStream input, String encoding) throws IOException { - return (null == encoding) ? toString(new InputStreamReader(input, EventMeshConstants.DEFAULT_CHARSET)) - : toString(new InputStreamReader(input, encoding)); - } - - public static String toString(Reader reader) throws IOException { - CharArrayWriter sw = new CharArrayWriter(); - copy(reader, sw); - return sw.toString(); - } - - public static long copy(Reader input, Writer output) throws IOException { - char[] buffer = new char[1 << 12]; - long count = 0; - for (int n = 0; (n = input.read(buffer)) >= 0; ) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - public static List readLines(Reader input) throws IOException { - BufferedReader reader = toBufferedReader(input); - List list = new ArrayList(); - String line; - for (; ; ) { - line = reader.readLine(); - if (null != line) { - list.add(line); - } else { - break; - } - } - return list; - } - - private static BufferedReader toBufferedReader(Reader reader) { - return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); - } - - public static void copyFile(String source, String target) throws IOException { - File sf = new File(source); - if (!sf.exists()) { - throw new IllegalArgumentException("source file does not exist."); - } - File tf = new File(target); - tf.getParentFile().mkdirs(); - if (!tf.exists() && !tf.createNewFile()) { - throw new RuntimeException("failed to create target file."); - } - - FileChannel sc = null; - FileChannel tc = null; - try { - tc = new FileOutputStream(tf).getChannel(); - sc = new FileInputStream(sf).getChannel(); - sc.transferTo(0, sc.size(), tc); - } finally { - if (null != sc) { - sc.close(); - } - if (null != tc) { - tc.close(); - } - } - } - - public static void delete(File fileOrDir) throws IOException { - if (fileOrDir == null) { - return; - } - - if (fileOrDir.isDirectory()) { - cleanDirectory(fileOrDir); - } - - fileOrDir.delete(); - } - - public static void cleanDirectory(File directory) throws IOException { - if (!directory.exists()) { - String message = directory + " does not exist"; - throw new IllegalArgumentException(message); - } - - if (!directory.isDirectory()) { - String message = directory + " is not a directory"; - throw new IllegalArgumentException(message); - } - - File[] files = directory.listFiles(); - if (files == null) { // null if security restricted - throw new IOException("Failed to list contents of " + directory); - } - - IOException exception = null; - for (File file : files) { - try { - delete(file); - } catch (IOException ioe) { - exception = ioe; - } - } - - if (null != exception) { - throw exception; - } - } - - public static void writeStringToFile(File file, String data, String encoding) throws IOException { - OutputStream os = null; - try { - os = new FileOutputStream(file); - os.write(data.getBytes(encoding)); - } finally { - if (null != os) { - os.close(); - } - } - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/NetUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/NetUtils.java deleted file mode 100644 index 3a1cc8787b..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/NetUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.util; - -import java.io.UnsupportedEncodingException; -import java.net.InetSocketAddress; -import java.net.URLDecoder; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NetUtils { - - private static final Logger logger = LoggerFactory.getLogger(NetUtils.class); - - /** - * Transform the url form string to Map - * - * @param formData - * @return - */ - public static Map formData2Dic(String formData) { - Map result = new HashMap<>(); - if (formData == null || formData.trim().length() == 0) { - return result; - } - final String[] items = formData.split("&"); - Arrays.stream(items).forEach(item -> { - final String[] keyAndVal = item.split("="); - if (keyAndVal.length == 2) { - try { - final String key = URLDecoder.decode(keyAndVal[0], "utf8"); - final String val = URLDecoder.decode(keyAndVal[1], "utf8"); - result.put(key, val); - } catch (UnsupportedEncodingException e) { - logger.warn("formData2Dic:param decode failed...", e); - } - } - }); - return result; - } - - public static String addressToString(List clients) { - if (clients.isEmpty()) { - return "no session had been closed"; - } - StringBuilder sb = new StringBuilder(); - for (InetSocketAddress addr : clients) { - sb.append(addr).append("|"); - } - return sb.toString(); - } -} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/RemotingHelper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/RemotingHelper.java index a2c88dbc71..de20617318 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/RemotingHelper.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/RemotingHelper.java @@ -1,47 +1,39 @@ /* - * Licensed to 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. Apache Software Foundation (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 + * 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. + * 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. */ package org.apache.eventmesh.runtime.util; +import org.apache.commons.lang3.ArrayUtils; + import java.net.InetSocketAddress; import java.net.SocketAddress; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; -public class RemotingHelper { - public static final String DEFAULT_CHARSET = "UTF-8"; - - public static Logger logger = LoggerFactory.getLogger(RemotingHelper.class); +public abstract class RemotingHelper { public static String exceptionSimpleDesc(final Throwable e) { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); if (e != null) { sb.append(e); - StackTraceElement[] stackTrace = e.getStackTrace(); - if (stackTrace != null && stackTrace.length > 0) { - StackTraceElement elment = stackTrace[0]; - sb.append(", "); - sb.append(elment.toString()); + final StackTraceElement[] stackTrace = e.getStackTrace(); + if (ArrayUtils.isNotEmpty(stackTrace)) { + sb.append(", ").append(stackTrace[0]); } } @@ -49,22 +41,21 @@ public static String exceptionSimpleDesc(final Throwable e) { } public static SocketAddress string2SocketAddress(final String addr) { - int split = addr.lastIndexOf(":"); - String host = addr.substring(0, split); - String port = addr.substring(split + 1); - InetSocketAddress isa = new InetSocketAddress(host, Integer.parseInt(port)); - return isa; + final int split = addr.lastIndexOf(':'); + final String host = addr.substring(0, split); + final String port = addr.substring(split + 1); + return new InetSocketAddress(host, Integer.parseInt(port)); } public static String parseChannelRemoteAddr(final Channel channel) { - if (null == channel) { + if (channel == null) { return ""; } - SocketAddress remote = channel.remoteAddress(); - final String addr = remote != null ? remote.toString() : ""; + + final String addr = channel.remoteAddress() != null ? channel.remoteAddress().toString() : ""; if (addr.length() > 0) { - int index = addr.lastIndexOf("/"); + final int index = addr.lastIndexOf('/'); if (index >= 0) { return addr.substring(index + 1); } @@ -75,16 +66,27 @@ public static String parseChannelRemoteAddr(final Channel channel) { return ""; } - public static String parseSocketAddressAddr(SocketAddress socketAddress) { - if (socketAddress != null) { - final String addr = socketAddress.toString(); + public static String parseChannelLocalAddr(final Channel channel) { + if (channel == null) { + return ""; + } - if (addr.length() > 0) { - return addr.substring(1); + final String addr = channel.localAddress() != null ? channel.localAddress().toString() : ""; + + if (addr.length() > 0) { + final int index = addr.lastIndexOf('/'); + if (index >= 0) { + return addr.substring(index + 1); } + + return addr; } + return ""; } -} + public static String parseSocketAddressAddr(final InetSocketAddress socketAddress) { + return socketAddress != null ? socketAddress.getAddress().getHostAddress() + ":" + socketAddress.getPort() : ""; + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ServerGlobal.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ServerGlobal.java index 9ef4422946..9817b15571 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ServerGlobal.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ServerGlobal.java @@ -1,4 +1,3 @@ - /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -23,7 +22,8 @@ public class ServerGlobal { private static class SerGlobalHolder { - private static ServerGlobal singleton = new ServerGlobal(); + + private static final ServerGlobal singleton = new ServerGlobal(); } public static ServerGlobal getInstance() { diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ThreadPoolHelper.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ThreadPoolHelper.java new file mode 100644 index 0000000000..1855a777c2 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ThreadPoolHelper.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ThreadPoolHelper { + + public static void printState(ThreadPoolExecutor threadPool) { + if (threadPool == null) { + log.warn("No thread pool is provided!"); + return; + } + + log.info("The ThreadPool's state=================="); + log.info("Shutdown | Terminating | Terminated: {} | {} | {}", threadPool.isShutdown(), threadPool.isTerminating(), threadPool.isTerminated()); + log.info("Active Threads: " + threadPool.getActiveCount()); + log.info("Completed Tasks / Tasks: {} / {}", threadPool.getCompletedTaskCount(), threadPool.getTaskCount()); + log.info("Queue Size: " + threadPool.getQueue().size()); + log.info("Core Pool Size: " + threadPool.getCorePoolSize()); + log.info("Maximum Pool Size: " + threadPool.getMaximumPoolSize()); + log.info("Keep Alive Time(ms): " + threadPool.getKeepAliveTime(TimeUnit.MILLISECONDS)); + log.info("The rejection policy: " + threadPool.getRejectedExecutionHandler().getClass().getSimpleName()); + log.info("========================================"); + } + +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/TraceUtils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/TraceUtils.java new file mode 100644 index 0000000000..80c9cca962 --- /dev/null +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/TraceUtils.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import org.apache.eventmesh.runtime.boot.EventMeshServer; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; +import io.netty.channel.ChannelHandlerContext; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Context; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TraceUtils { + + public static Span prepareClientSpan(Map map, String spanName, + boolean isSpanFinishInOtherThread) { + Span span = null; + try { + span = EventMeshServer.getTrace().createSpan( + spanName, SpanKind.CLIENT, Context.current(), isSpanFinishInOtherThread); + EventMeshServer.getTrace().inject(Context.current(), map); + } catch (Exception ex) { + log.error("upload trace fail when prepareSpan", ex); + } + return span; + } + + public static Span prepareServerSpan(Map map, String spanName, + boolean isSpanFinishInOtherThread) { + Span span = null; + try { + Context traceContext = EventMeshServer.getTrace().extractFrom(Context.current(), map); + span = EventMeshServer.getTrace() + .createSpan(spanName, SpanKind.SERVER, traceContext, isSpanFinishInOtherThread); + } catch (Exception ex) { + log.error("upload trace fail when prepareSpan", ex); + } + return span; + } + + public static Span prepareServerSpan(Map map, String spanName, long startTime, + TimeUnit timeUnit, boolean isSpanFinishInOtherThread) { + Span span = null; + try { + Context traceContext = EventMeshServer.getTrace().extractFrom(Context.current(), map); + if (startTime > 0) { + span = EventMeshServer.getTrace() + .createSpan(spanName, SpanKind.SERVER, startTime, timeUnit, traceContext, + isSpanFinishInOtherThread); + } else { + span = EventMeshServer.getTrace() + .createSpan(spanName, SpanKind.SERVER, traceContext, isSpanFinishInOtherThread); + } + } catch (Exception ex) { + log.error("upload trace fail when prepareSpan", ex); + } + return span; + } + + public static void finishSpan(Span span, CloudEvent event) { + try { + log.debug("finishSpan with event:{}", event); + EventMeshServer.getTrace().addTraceInfoToSpan(span, event); + EventMeshServer.getTrace().finishSpan(span, StatusCode.OK); + } catch (Throwable ex) { + log.error("upload trace fail when finishSpan", ex); + } + + } + + public static void finishSpan(ChannelHandlerContext ctx, CloudEvent event) { + try { + log.debug("finishSpan with event:{}", event); + EventMeshServer.getTrace().addTraceInfoToSpan(ctx, event); + EventMeshServer.getTrace().finishSpan(ctx, StatusCode.OK); + } catch (Throwable ex) { + log.error("upload trace fail when finishSpan", ex); + } + + } + + public static void finishSpanWithException(ChannelHandlerContext ctx, CloudEvent event, + String errMsg, Throwable e) { + try { + log.debug("finishSpanWithException with event:{}", event); + EventMeshServer.getTrace().addTraceInfoToSpan(ctx, event); + EventMeshServer.getTrace().finishSpan(ctx, StatusCode.ERROR, errMsg, e); + } catch (Throwable ex) { + log.error("upload trace fail when finishSpanWithException", ex); + } + } + + public static void finishSpanWithException(Span span, Map map, String errMsg, + Throwable e) { + try { + log.debug("finishSpanWithException with map:{}", map); + EventMeshServer.getTrace().addTraceInfoToSpan(span, map); + EventMeshServer.getTrace().finishSpan(span, StatusCode.ERROR, errMsg, e); + } catch (Throwable ex) { + log.error("upload trace fail when finishSpanWithException", ex); + } + } +} diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/Utils.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/Utils.java index 0265dc3c3b..8f35c7de25 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/Utils.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/Utils.java @@ -20,13 +20,16 @@ import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.utils.IPUtils; import org.apache.eventmesh.runtime.constants.EventMeshConstants; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.SessionState; import org.apache.commons.lang3.StringUtils; +import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,10 +37,15 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpRequest; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class Utils { - private static final Logger logger = LoggerFactory.getLogger(Utils.class); - private static final Logger messageLogger = LoggerFactory.getLogger("message"); + + private static final Logger MESSAGE_LOGGER = LoggerFactory.getLogger(EventMeshConstants.MESSAGE); /** * used to send messages to the client @@ -48,34 +56,30 @@ public class Utils { * @param session */ public static void writeAndFlush(final Package pkg, long startTime, long taskExecuteTime, ChannelHandlerContext ctx, - Session - session) { + Session session) { try { UserAgent user = session == null ? null : session.getClient(); - if (session != null && session.getSessionState().equals(SessionState.CLOSED)) { + if (session != null && session.getSessionState() == SessionState.CLOSED) { logFailedMessageFlow(pkg, user, startTime, taskExecuteTime, - new Exception("the session has been closed")); + new Exception("the session has been closed")); return; } - ctx.writeAndFlush(pkg).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (!future.isSuccess()) { - logFailedMessageFlow(future, pkg, user, startTime, taskExecuteTime); - } else { - logSucceedMessageFlow(pkg, user, startTime, taskExecuteTime); - - if (session != null) { - session.getClientGroupWrapper().get() - .getEventMeshTcpMonitor().getTcpSummaryMetrics().getEventMesh2clientMsgNum().incrementAndGet(); - } - } + ctx.channel().eventLoop().execute(() -> { + ctx.writeAndFlush(pkg).addListener((ChannelFutureListener) future -> { + if (!future.isSuccess()) { + logFailedMessageFlow(future, pkg, user, startTime, taskExecuteTime); + } else { + logSucceedMessageFlow(pkg, user, startTime, taskExecuteTime); + + if (session != null) { + Objects.requireNonNull(session.getClientGroupWrapper().get()) + .getEventMeshTcpMetricsManager().eventMesh2clientMsgNumIncrement(IPUtils.parseChannelRemoteAddr(ctx.channel())); } } - ); + }); + }); } catch (Exception e) { - logger.error("exception while sending message to client", e); + log.error("exception while sending message to client", e); } } @@ -88,21 +92,21 @@ public void operationComplete(ChannelFuture future) throws Exception { * @param startTime */ public static void logFailedMessageFlow(ChannelFuture future, Package pkg, UserAgent user, long startTime, - long taskExecuteTime) { + long taskExecuteTime) { logFailedMessageFlow(pkg, user, startTime, taskExecuteTime, future.cause()); } private static void logFailedMessageFlow(Package pkg, UserAgent user, long startTime, long taskExecuteTime, - Throwable e) { + Throwable e) { if (pkg.getBody() instanceof EventMeshMessage) { - messageLogger.error("pkg|eventMesh2c|failed|cmd={}|mqMsg={}|user={}|wait={}ms|cost={}ms|errMsg={}", - pkg.getHeader().getCmd(), - printMqMessage((EventMeshMessage) pkg.getBody()), user, taskExecuteTime - startTime, - System.currentTimeMillis() - startTime, e); + final String mqMessage = EventMeshUtil.printMqMessage((EventMeshMessage) pkg.getBody()); + MESSAGE_LOGGER.error("pkg|eventMesh2c|failed|cmd={}|mqMsg={}|user={}|wait={}ms|cost={}ms|errMsg={}", + pkg.getHeader().getCmd(), mqMessage, user, taskExecuteTime - startTime, + System.currentTimeMillis() - startTime, e); } else { - messageLogger.error("pkg|eventMesh2c|failed|cmd={}|pkg={}|user={}|wait={}ms|cost={}ms|errMsg={}", - pkg.getHeader().getCmd(), - pkg, user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime, e); + MESSAGE_LOGGER.error("pkg|eventMesh2c|failed|cmd={}|pkg={}|user={}|wait={}ms|cost={}ms|errMsg={}", + pkg.getHeader().getCmd(), + pkg, user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime, e); } } @@ -115,34 +119,16 @@ private static void logFailedMessageFlow(Package pkg, UserAgent user, long start */ public static void logSucceedMessageFlow(Package pkg, UserAgent user, long startTime, long taskExecuteTime) { if (pkg.getBody() instanceof EventMeshMessage) { - messageLogger.info("pkg|eventMesh2c|cmd={}|mqMsg={}|user={}|wait={}ms|cost={}ms", pkg.getHeader().getCmd(), - printMqMessage((EventMeshMessage) pkg.getBody()), user, taskExecuteTime - startTime, - System.currentTimeMillis() - startTime); + final String mqMessage = EventMeshUtil.printMqMessage((EventMeshMessage) pkg.getBody()); + MESSAGE_LOGGER.info("pkg|eventMesh2c|cmd={}|mqMsg={}|user={}|wait={}ms|cost={}ms", pkg.getHeader().getCmd(), + mqMessage, user, taskExecuteTime - startTime, + System.currentTimeMillis() - startTime); } else { - messageLogger - .info("pkg|eventMesh2c|cmd={}|pkg={}|user={}|wait={}ms|cost={}ms", pkg.getHeader().getCmd(), pkg, - user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime); - } - } - - /** - * print part of the mq message - * - * @param eventMeshMessage - * @return - */ - public static String printMqMessage(EventMeshMessage eventMeshMessage) { - Map properties = eventMeshMessage.getProperties(); + MESSAGE_LOGGER + .info("pkg|eventMesh2c|cmd={}|pkg={}|user={}|wait={}ms|cost={}ms", pkg.getHeader().getCmd(), pkg, + user, taskExecuteTime - startTime, System.currentTimeMillis() - startTime); - String bizSeqNo = properties.get(EventMeshConstants.KEYS_UPPERCASE); - if (!StringUtils.isNotBlank(bizSeqNo)) { - bizSeqNo = properties.get(EventMeshConstants.KEYS_LOWERCASE); } - - String result = String.format("Message [topic=%s,TTL=%s,uniqueId=%s,bizSeq=%s]", eventMeshMessage - .getTopic(), properties.get(EventMeshConstants.TTL), properties.get(EventMeshConstants.RR_REQUEST_UNIQ_ID), - bizSeqNo); - return result; } /** @@ -156,4 +142,23 @@ public static String getServiceId(String topic) { return null; } } + + /** + * parse http header + * + * @param fullReq request parameter + * @return http header + */ + public static Map parseHttpHeader(HttpRequest fullReq) { + Map headerParam = new HashMap<>(); + for (String key : fullReq.headers().names()) { + if (StringUtils.equalsAnyIgnoreCase(key, HttpHeaderNames.CONTENT_TYPE.toString(), + HttpHeaderNames.ACCEPT_ENCODING.toString(), + HttpHeaderNames.CONTENT_LENGTH.toString())) { + continue; + } + headerParam.put(key, fullReq.headers().get(key)); + } + return headerParam; + } } diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ValueComparator.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ValueComparator.java index e3835985f0..8622e6503c 100644 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ValueComparator.java +++ b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/ValueComparator.java @@ -17,10 +17,14 @@ package org.apache.eventmesh.runtime.util; +import java.io.Serializable; import java.util.Comparator; import java.util.Map; -public class ValueComparator implements Comparator> { +public class ValueComparator implements Comparator>, Serializable { + + private static final long serialVersionUID = -8734777387846774249L; + @Override public int compare(Map.Entry x, Map.Entry y) { if (x.getValue().intValue() != y.getValue().intValue()) { diff --git a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/WebhookUtil.java b/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/WebhookUtil.java deleted file mode 100644 index 658a6677c3..0000000000 --- a/eventmesh-runtime/src/main/java/org/apache/eventmesh/runtime/util/WebhookUtil.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.util; - -import org.apache.eventmesh.api.auth.AuthService; -import org.apache.eventmesh.spi.EventMeshExtensionFactory; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpOptions; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.message.BasicHeader; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class for implementing CloudEvents Http Webhook spec - * - * @see CloudEvents Http Webhook - */ -public class WebhookUtil { - - private static final Logger logger = LoggerFactory.getLogger(WebhookUtil.class.getName()); - - private static final String CONTENT_TYPE_HEADER = "Content-Type"; - private static final String REQUEST_ORIGIN_HEADER = "WebHook-Request-Origin"; - private static final String ALLOWED_ORIGIN_HEADER = "WebHook-Allowed-Origin"; - - private static final Map authServices = new ConcurrentHashMap<>(); - - public static boolean obtainDeliveryAgreement(CloseableHttpClient httpClient, String targetUrl, String requestOrigin) { - logger.info("obtain webhook delivery agreement for url: {}", targetUrl); - HttpOptions builder = new HttpOptions(targetUrl); - builder.addHeader(REQUEST_ORIGIN_HEADER, requestOrigin); - - try (CloseableHttpResponse response = httpClient.execute(builder)) { - String allowedOrigin = response.getLastHeader(ALLOWED_ORIGIN_HEADER).getValue(); - return StringUtils.isEmpty(allowedOrigin) - || allowedOrigin.equals("*") || allowedOrigin.equalsIgnoreCase(requestOrigin); - } catch (Exception e) { - logger.warn("HTTP Options Method is not supported at the Delivery Target: {}," - + " unable to obtain the webhook delivery agreement.", targetUrl); - } - return true; - } - - public static void setWebhookHeaders(HttpPost builder, String contentType, String requestOrigin, String urlAuthType) { - builder.setHeader(CONTENT_TYPE_HEADER, contentType); - builder.setHeader(REQUEST_ORIGIN_HEADER, requestOrigin); - - Map authParam = getHttpAuthParam(urlAuthType); - if (authParam != null) { - authParam.forEach((k, v) -> builder.addHeader(new BasicHeader(k, v))); - } - } - - @SuppressWarnings("unchecked") - private static Map getHttpAuthParam(String authType) { - if (StringUtils.isEmpty(authType)) { - return null; - } - AuthService authService = getHttpAuthPlugin(authType); - if (authService != null) { - return authService.getAuthParams(); - } else { - return null; - } - } - - private static AuthService getHttpAuthPlugin(String pluginType) { - if (authServices.containsKey(pluginType)) { - return authServices.get(pluginType); - } - - AuthService authService = EventMeshExtensionFactory.getExtension(AuthService.class, pluginType); - - if (authService == null) { - logger.error("can't load the authService plugin, please check."); - throw new RuntimeException("doesn't load the authService plugin, please check."); - } - try { - authService.init(); - authServices.put(pluginType, authService); - return authService; - } catch (Exception e) { - logger.error("Error in initializing authService", e); - } - return null; - } -} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AClientServerIntegrationTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AClientServerIntegrationTest.java new file mode 100644 index 0000000000..f22d3b2e0b --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AClientServerIntegrationTest.java @@ -0,0 +1,481 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.eventmesh.protocol.a2a.A2AClient; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpOptions; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * True client-server HTTP integration test. + * + *

Starts {@link A2AGatewayServer} on a random port, then uses {@link A2AClient} + * to exercise all A2A functionality over real HTTP: + *

    + *
  • Agent card registration
  • + *
  • Agent listing
  • + *
  • Sync task submission + response
  • + *
  • Task status query
  • + *
  • Async task submission + cancellation
  • + *
  • Heartbeat
  • + *
+ * + *

This test covers the full network path: A2AClient → HTTP → Netty → A2AGatewayHttpHandler → A2AGatewayService. + */ +class A2AClientServerIntegrationTest { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private A2AGatewayServer server; + private String gatewayUrl; + private A2AClient client; + private CloseableHttpClient rawHttpClient; + + @BeforeEach + void setUp() throws Exception { + // Start server on random port + server = new A2AGatewayServer(0); + server.start(); + int port = server.getBoundPort(); + gatewayUrl = "http://localhost:" + port; + + // Create and start client (registers agent card + starts heartbeat) + client = A2AClient.builder() + .gatewayUrl(gatewayUrl) + .namespace("global") + .agentName("default/default/test-client-agent") + .agentCard(AgentCardTestUtils.createValidCard("test-client-agent")) + .heartbeatInterval(60_000L) // long interval so it doesn't interfere with tests + .socketTimeoutMs(30_000) + .build(); + client.start(); + + rawHttpClient = HttpClients.createDefault(); + } + + @AfterEach + void tearDown() throws Exception { + if (client != null) { + client.shutdown(); + } + if (rawHttpClient != null) { + rawHttpClient.close(); + } + if (server != null) { + server.shutdown(); + } + } + + /** + * Registers an agent card via HTTP without subscribing to request topics. + * The agent is "registered" but never responds — useful for testing async/cancel flows. + */ + private void registerSlowAgent(String agentName) throws Exception { + Map card = new HashMap<>(); + card.put("name", agentName); + card.put("version", "1.0.0"); + card.put("description", "A slow agent for testing"); + + // Required fields for schema validation + Map iface = new HashMap<>(); + iface.put("url", "http://localhost/a2a"); + iface.put("protocolBinding", "JSONRPC"); + iface.put("protocolVersion", "0.3"); + java.util.List> interfaces = new java.util.ArrayList<>(); + interfaces.add(iface); + card.put("supportedInterfaces", interfaces); + + Map capabilities = new HashMap<>(); + capabilities.put("streaming", false); + capabilities.put("pushNotifications", false); + card.put("capabilities", capabilities); + + card.put("defaultInputModes", java.util.Collections.singletonList("text/plain")); + card.put("defaultOutputModes", java.util.Collections.singletonList("text/plain")); + + Map skill = new HashMap<>(); + skill.put("id", "slow-skill"); + skill.put("name", "Slow Skill"); + skill.put("description", "Does nothing"); + skill.put("tags", java.util.Collections.singletonList("test")); + java.util.List> skills = new java.util.ArrayList<>(); + skills.add(skill); + card.put("skills", skills); + + HttpPost post = new HttpPost(gatewayUrl + "/a2a/cards/card/default/default/" + agentName); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(objectMapper.writeValueAsString(card), StandardCharsets.UTF_8)); + HttpResponse response = rawHttpClient.execute(post); + int status = response.getStatusLine().getStatusCode(); + if (status >= 400) { + String body = response.getEntity() != null + ? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : ""; + throw new RuntimeException("Failed to register slow agent: " + status + " " + body); + } + } + + // ========================================================================= + // Agent Card Registration & Listing + // ========================================================================= + + @Test + void testPreRegisteredWeatherAgentIsListed() throws Exception { + List agents = client.listAgents(); + assertNotNull(agents); + assertTrue(agents.contains("weather-agent"), + "Pre-registered weather-agent should appear in agent list: " + agents); + } + + @Test + void testClientAgentRegistrationAppearsInList() throws Exception { + List agents = client.listAgents(); + assertNotNull(agents); + assertTrue(agents.contains("test-client-agent"), + "Client-registered test-client-agent should appear in agent list: " + agents); + } + + // ========================================================================= + // Sync Task Submission + // ========================================================================= + + @Test + void testSubmitTaskSyncToWeatherAgent() throws Exception { + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "Beijing", null); + + assertNotNull(result); + assertNotNull(result.getTaskId(), "taskId should be returned in sync response"); + assertEquals("COMPLETED", result.getState()); + assertNotNull(result.getData()); + assertTrue(result.getData().contains("Beijing"), "Response should mention Beijing: " + result.getData()); + assertTrue(result.getData().contains("sunny"), "Response should mention sunny: " + result.getData()); + } + + @Test + void testSubmitTaskSyncReturnsValidTaskId() throws Exception { + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "Shanghai", null); + + assertNotNull(result.getTaskId()); + assertTrue(result.getTaskId().startsWith("task-"), + "Task ID should start with 'task-': " + result.getTaskId()); + } + + // ========================================================================= + // Task Status Query + // ========================================================================= + + @Test + void testGetTaskStatusAfterCompletion() throws Exception { + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "Guangzhou", null); + String taskId = result.getTaskId(); + assertNotNull(taskId); + + // Query status via HTTP GET + A2AClient.TaskResult status = client.getTaskStatus(taskId); + assertNotNull(status); + assertEquals(taskId, status.getTaskId()); + assertEquals("COMPLETED", status.getState()); + assertEquals("weather-agent", status.getTargetAgent()); + assertNotNull(status.getData()); + assertTrue(status.getData().contains("Guangzhou")); + } + + @Test + void testGetTaskStatusNotFound() throws Exception { + A2AClient.TaskResult status = client.getTaskStatus("non-existent-task-id"); + assertNotNull(status); + // Server returns 404 with error JSON; Jackson maps it to TaskResult.error + assertTrue(status.getError() != null || status.getState() == null, + "Should return error for non-existent task"); + } + + // ========================================================================= + // Async Task + Cancellation + // ========================================================================= + + @Test + void testSubmitAsyncTaskAndGetStatus() throws Exception { + // Register a slow agent that doesn't respond (card registered but no request handler) + registerSlowAgent("slow-agent"); + + String taskId = client.sendTaskAsync("slow-agent", "test message", null); + assertNotNull(taskId); + assertTrue(taskId.startsWith("task-")); + + // Query status — should be SUBMITTED + A2AClient.TaskResult status = client.getTaskStatus(taskId); + assertNotNull(status); + assertEquals(taskId, status.getTaskId()); + assertEquals("SUBMITTED", status.getState()); + } + + @Test + void testCancelTask() throws Exception { + // Register a slow agent that doesn't respond + registerSlowAgent("slow-agent"); + + String taskId = client.sendTaskAsync("slow-agent", "cancel me", null); + assertNotNull(taskId); + + // Cancel the task + boolean cancelled = client.cancelTask(taskId); + assertTrue(cancelled, "Task should be cancellable"); + + // Verify state is CANCELLED + A2AClient.TaskResult status = client.getTaskStatus(taskId); + assertNotNull(status); + assertEquals("CANCELLED", status.getState()); + } + + @Test + void testCancelCompletedTaskFails() throws Exception { + // Submit sync to weather-agent (completes immediately) + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "Shenzhen", null); + String taskId = result.getTaskId(); + + // Try to cancel a completed task — should fail + boolean cancelled = client.cancelTask(taskId); + assertFalse(cancelled, "Completed task should not be cancellable"); + } + + @Test + void testCancelNonExistentTaskFails() throws Exception { + boolean cancelled = client.cancelTask("fake-task-id-99999"); + assertFalse(cancelled, "Non-existent task should not be cancellable"); + } + + // ========================================================================= + // Agent Validation + // ========================================================================= + + @Test + void testSubmitTaskToUnregisteredAgentFails() throws Exception { + // Attempt to submit a task to an agent that is not registered + try { + client.sendTaskSync("ghost-agent-not-registered", "hello", null); + org.junit.jupiter.api.Assertions.fail( + "Should throw exception for unregistered agent"); + } catch (Exception e) { + // Expected: server returns 400 because agent is not registered + assertTrue(e.getMessage().contains("not registered") + || e.getMessage().contains("400") + || e.getMessage().contains("Task submission failed"), + "Error should mention unregistered agent: " + e.getMessage()); + } + } + + // ========================================================================= + // Task Listing + // ========================================================================= + + @Test + void testListTasksEndpoint() throws Exception { + // Submit a task that completes + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "ListTest", null); + assertNotNull(result.getTaskId()); + + // List all tasks via HTTP GET /a2a/tasks + HttpGet get = new HttpGet(gatewayUrl + "/a2a/tasks"); + HttpResponse response = rawHttpClient.execute(get); + assertEquals(200, response.getStatusLine().getStatusCode()); + + String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + Map listResponse = objectMapper.readValue(body, Map.class); + assertNotNull(listResponse.get("total")); + assertNotNull(listResponse.get("count")); + assertEquals(100, listResponse.get("limit")); + assertEquals(0, listResponse.get("offset")); + assertNotNull(listResponse.get("hasMore")); + assertNotNull(listResponse.get("tasks")); + } + + @Test + void testListTasksEndpointWithPagination() throws Exception { + client.sendTaskSync("weather-agent", "PageTest-1", null); + client.sendTaskSync("weather-agent", "PageTest-2", null); + client.sendTaskSync("weather-agent", "PageTest-3", null); + + HttpGet get = new HttpGet(gatewayUrl + "/a2a/tasks?state=COMPLETED&limit=2&offset=1"); + HttpResponse response = rawHttpClient.execute(get); + assertEquals(200, response.getStatusLine().getStatusCode()); + + String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + Map listResponse = objectMapper.readValue(body, Map.class); + assertEquals(2, listResponse.get("limit")); + assertEquals(1, listResponse.get("offset")); + assertTrue(((Number) listResponse.get("count")).intValue() <= 2); + assertNotNull(listResponse.get("tasks")); + } + + @Test + void testHealthEndpoint() throws Exception { + HttpGet get = new HttpGet(gatewayUrl + "/a2a/health"); + HttpResponse response = rawHttpClient.execute(get); + assertEquals(200, response.getStatusLine().getStatusCode()); + + String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + Map health = objectMapper.readValue(body, Map.class); + assertEquals("UP", health.get("status")); + assertNotNull(health.get("gatewayId")); + assertNotNull(health.get("namespace")); + assertNotNull(health.get("taskCount")); + assertNotNull(health.get("agentCount")); + assertNotNull(health.get("timestamp")); + } + + @Test + void testCorsPreflightEndpoint() throws Exception { + HttpOptions options = new HttpOptions(gatewayUrl + "/a2a/tasks"); + HttpResponse response = rawHttpClient.execute(options); + assertEquals(200, response.getStatusLine().getStatusCode()); + assertEquals("*", response.getFirstHeader("Access-Control-Allow-Origin").getValue()); + assertTrue(response.getFirstHeader("Access-Control-Allow-Methods").getValue().contains("OPTIONS")); + assertTrue(response.getFirstHeader("Access-Control-Allow-Headers").getValue().contains("Content-Type")); + } + + @Test + void testSseStreamThroughClientSdk() throws Exception { + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", "SSE-City", null); + AtomicInteger eventCount = new AtomicInteger(0); + String[] lastState = new String[1]; + String[] lastData = new String[1]; + + // Build a short-timeout client for this bounded terminal-state SSE test. + try (A2AClient sseClient = A2AClient.builder() + .gatewayUrl(gatewayUrl) + .namespace("global") + .agentName("default/default/test-sse-client-agent") + .agentCard(AgentCardTestUtils.createValidCard("test-sse-client-agent")) + .heartbeatInterval(60_000L) + .socketTimeoutMs(1_000) + .build()) { + sseClient.streamTaskStatus(result.getTaskId(), (taskId, state, data) -> { + eventCount.incrementAndGet(); + lastState[0] = state; + lastData[0] = data; + return true; + }); + } + + assertTrue(eventCount.get() >= 1); + assertEquals("COMPLETED", lastState[0]); + assertTrue(lastData[0].contains("SSE-City")); + } + + // ========================================================================= + // Heartbeat + // ========================================================================= + + @Test + void testHeartbeatForRegisteredAgent() throws Exception { + // Send heartbeat for the pre-registered weather-agent + Map body = new HashMap<>(); + body.put("orgId", "default"); + body.put("unitId", "default"); + body.put("agentId", "weather-agent"); + + HttpPost post = new HttpPost(gatewayUrl + "/a2a/heartbeat"); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(objectMapper.writeValueAsString(body), StandardCharsets.UTF_8)); + + HttpResponse response = rawHttpClient.execute(post); + assertEquals(200, response.getStatusLine().getStatusCode()); + + String respBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + Map result = objectMapper.readValue(respBody, Map.class); + assertEquals(true, result.get("ok"), "Heartbeat for registered agent should succeed: " + respBody); + } + + @Test + void testHeartbeatForUnregisteredAgentFails() throws Exception { + Map body = new HashMap<>(); + body.put("orgId", "default"); + body.put("unitId", "default"); + body.put("agentId", "ghost-agent"); + + HttpPost post = new HttpPost(gatewayUrl + "/a2a/heartbeat"); + post.setHeader("Content-Type", "application/json"); + post.setEntity(new StringEntity(objectMapper.writeValueAsString(body), StandardCharsets.UTF_8)); + + HttpResponse response = rawHttpClient.execute(post); + assertEquals(200, response.getStatusLine().getStatusCode()); + + String respBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + Map result = objectMapper.readValue(respBody, Map.class); + assertEquals(false, result.get("ok"), "Heartbeat for unregistered agent should fail: " + respBody); + } + + // ========================================================================= + // Multiple Tasks / Concurrency + // ========================================================================= + + @Test + void testMultipleSyncTasks() throws Exception { + String[] cities = {"Beijing", "Shanghai", "Guangzhou"}; + for (String city : cities) { + A2AClient.TaskResult result = client.sendTaskSync("weather-agent", city, null); + assertEquals("COMPLETED", result.getState()); + assertTrue(result.getData().contains(city), + "Response for " + city + " should mention the city: " + result.getData()); + } + } + + @Test + void testParentChildTaskViaHttp() throws Exception { + // Submit parent task (sync) + A2AClient.TaskResult parentResult = client.sendTaskSync("weather-agent", "parent", null); + String parentTaskId = parentResult.getTaskId(); + + // Submit child task with parentTaskId (sync) + A2AClient.TaskResult childResult = client.sendTaskSync("weather-agent", "child", parentTaskId); + String childTaskId = childResult.getTaskId(); + + assertNotNull(parentTaskId); + assertNotNull(childTaskId); + assertFalse(parentTaskId.equals(childTaskId), "Parent and child task IDs should differ"); + + // Verify child task has parentTaskId set + A2AClient.TaskResult childStatus = client.getTaskStatus(childTaskId); + assertNotNull(childStatus); + assertEquals(parentTaskId, childStatus.getParentTaskId(), + "Child task should reference parent task ID"); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AGatewayEndToEndTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AGatewayEndToEndTest.java new file mode 100644 index 0000000000..9f0c652137 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AGatewayEndToEndTest.java @@ -0,0 +1,234 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.eventmesh.protocol.a2a.A2AProtocolConstants; +import org.apache.eventmesh.protocol.a2a.A2ATopicFactory; +import org.apache.eventmesh.protocol.a2a.AgentIdentity; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +/** + * End-to-end test for A2A Gateway: task submission, agent response, and task registry. + */ +class A2AGatewayEndToEndTest { + + private InMemoryA2AMessageTransport transport; + private TaskRegistry taskRegistry; + private A2APublishSubscribeService a2aService; + private A2AGatewayService gateway; + + private static final String NAMESPACE = "global"; + private static final String GATEWAY_ID = "test-gateway"; + private static final String AGENT_NAME = "echo-agent"; + + @BeforeEach + void setUp() throws Exception { + transport = new InMemoryA2AMessageTransport(); + taskRegistry = new TaskRegistry(); + a2aService = new A2APublishSubscribeService(null); + a2aService.init(); + a2aService.start(); + gateway = new A2AGatewayService(NAMESPACE, GATEWAY_ID, transport, taskRegistry, a2aService); + gateway.start(); + } + + @AfterEach + void tearDown() throws Exception { + gateway.shutdown(); + a2aService.shutdown(); + } + + @Test + void testTaskSubmissionAndResponse() throws Exception { + // Register agent + AgentCard card = AgentCardTestUtils.createValidCard(AGENT_NAME); + AgentIdentity identity = AgentIdentity.builder() + .orgId("default").unitId("default").agentId(AGENT_NAME).build(); + a2aService.registerCard(identity, card); + + // Agent subscribes to request topic + String requestTopic = A2ATopicFactory.agentRequestTopic(NAMESPACE, AGENT_NAME); + transport.subscribe(requestTopic, (topic, event) -> { + String taskId = event.getId(); + String responseTopic = A2ATopicFactory.gatewayResponseTopic(NAMESPACE, GATEWAY_ID, taskId); + CloudEvent response = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withType(A2AProtocolConstants.CE_TYPE_PREFIX + "task.response") + .withSource(java.net.URI.create("agent/" + AGENT_NAME)) + .withData("echo: hello".getBytes(StandardCharsets.UTF_8)) + .build(); + try { + transport.publish(responseTopic, response); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + // Submit task + java.util.concurrent.CompletableFuture future = + gateway.submitTask(AGENT_NAME, "hello", null); + + A2AGatewayService.TaskResult result = future.get(10, TimeUnit.SECONDS); + + assertNotNull(result); + assertEquals(TaskRegistry.TaskState.COMPLETED, result.getState()); + assertEquals("echo: hello", result.getData()); + } + + @Test + void testTaskRegistryLifecycle() { + String taskId = "test-task-001"; + taskRegistry.createTask(taskId, null, "test-agent", "test-gateway"); + + assertEquals(TaskRegistry.TaskState.SUBMITTED, taskRegistry.getTask(taskId).getState()); + + assertTrue(taskRegistry.markWorking(taskId)); + assertEquals(TaskRegistry.TaskState.WORKING, taskRegistry.getTask(taskId).getState()); + + assertTrue(taskRegistry.markCompleted(taskId, "done")); + assertEquals(TaskRegistry.TaskState.COMPLETED, taskRegistry.getTask(taskId).getState()); + assertEquals("done", taskRegistry.getTask(taskId).getResult()); + } + + @Test + void testTaskCancellation() { + String taskId = "test-task-cancel"; + taskRegistry.createTask(taskId, null, "test-agent", "test-gateway"); + + assertTrue(taskRegistry.markCancelled(taskId)); + assertEquals(TaskRegistry.TaskState.CANCELLED, taskRegistry.getTask(taskId).getState()); + } + + @Test + void testParentChildTaskRelationship() { + String parentId = "parent-task"; + String childId = "child-task"; + + taskRegistry.createTask(parentId, null, "agent-a", "gateway-1"); + taskRegistry.createTask(childId, parentId, "agent-b", "gateway-1"); + + java.util.List children = taskRegistry.getChildTasks(parentId); + assertEquals(1, children.size()); + assertEquals(childId, children.get(0)); + } + + @Test + void testAgentCardTtlExpiry() throws Exception { + // Use a very short TTL for testing + a2aService.shutdown(); + a2aService = new A2APublishSubscribeService(null, 100L, 50L); + a2aService.init(); + a2aService.start(); + + AgentCard card = AgentCardTestUtils.createValidCard("ttl-agent"); + AgentIdentity identity = AgentIdentity.builder() + .orgId("default").unitId("default").agentId("ttl-agent").build(); + + a2aService.registerCard(identity, card); + assertNotNull(a2aService.getCard(identity)); + + // Wait for TTL to expire + Thread.sleep(300); + + // Force cleanup + a2aService.cleanupExpiredCards(); + + // Card should be removed + assertEquals(null, a2aService.getCard(identity)); + } + + @Test + void testHeartbeatRefreshesTtl() throws Exception { + a2aService.shutdown(); + a2aService = new A2APublishSubscribeService(null, 500L, 250L); + a2aService.init(); + a2aService.start(); + + AgentCard card = AgentCardTestUtils.createValidCard("hb-agent"); + AgentIdentity identity = AgentIdentity.builder() + .orgId("default").unitId("default").agentId("hb-agent").build(); + + a2aService.registerCard(identity, card); + + // Heartbeat before TTL expires + Thread.sleep(250); + assertTrue(a2aService.heartbeat(identity), "heartbeat should succeed before TTL"); + + // Should still be registered + Thread.sleep(100); + assertNotNull(a2aService.getCard(identity), "card should still exist after heartbeat refresh"); + } + + @Test + void testTopicFactoryGeneratesCorrectTopics() { + // Agent topics + assertEquals("a2a/v1/agent/request/weather-agent", + A2ATopicFactory.agentRequestTopic("global", "weather-agent")); + assertEquals("a2a/v1/agent/status/weather-agent/task-123", + A2ATopicFactory.agentStatusTopic("global", "weather-agent", "task-123")); + assertEquals("a2a/v1/agent/response/weather-agent/task-123", + A2ATopicFactory.agentResponseTopic("global", "weather-agent", "task-123")); + + // Gateway topics + assertEquals("a2a/v1/gateway/status/gw-1/task-456", + A2ATopicFactory.gatewayStatusTopic("global", "gw-1", "task-456")); + assertEquals("a2a/v1/gateway/response/gw-1/task-456", + A2ATopicFactory.gatewayResponseTopic("global", "gw-1", "task-456")); + + // Discovery topics + assertEquals("a2a/v1/discovery/agentcards", + A2ATopicFactory.discoveryTopic("global")); + + // Namespaced topics + assertEquals("myorg/a2a/v1/agent/request/weather-agent", + A2ATopicFactory.agentRequestTopic("myorg", "weather-agent")); + } + + @Test + void testTopicFactoryParsing() { + A2ATopicFactory.ParsedTopic parsed = A2ATopicFactory.parse("a2a/v1/agent/request/weather-agent"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.AGENT_REQUEST, parsed.getEntityType()); + assertEquals("weather-agent", parsed.getAgentName()); + + parsed = A2ATopicFactory.parse("a2a/v1/gateway/response/gw-1/task-789"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.GATEWAY_RESPONSE, parsed.getEntityType()); + assertEquals("gw-1", parsed.getGatewayId()); + assertEquals("task-789", parsed.getTaskId()); + + parsed = A2ATopicFactory.parse("a2a/v1/discovery/agentcards"); + assertNotNull(parsed); + assertEquals(A2ATopicFactory.EntityType.DISCOVERY_AGENT, parsed.getEntityType()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AGatewayServiceTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AGatewayServiceTest.java new file mode 100644 index 0000000000..42bf71df76 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/A2AGatewayServiceTest.java @@ -0,0 +1,406 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.eventmesh.protocol.a2a.A2AProtocolConstants; +import org.apache.eventmesh.protocol.a2a.A2ATopicFactory; +import org.apache.eventmesh.protocol.a2a.AgentIdentity; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +/** + * Unit tests for {@link A2AGatewayService}. + */ +class A2AGatewayServiceTest { + + private InMemoryA2AMessageTransport transport; + private TaskRegistry taskRegistry; + private A2APublishSubscribeService a2aService; + private A2AGatewayService gateway; + + private static final String NAMESPACE = "global"; + private static final String GATEWAY_ID = "test-gateway"; + + @BeforeEach + void setUp() throws Exception { + transport = new InMemoryA2AMessageTransport(); + taskRegistry = new TaskRegistry(); + a2aService = new A2APublishSubscribeService(null); + a2aService.init(); + a2aService.start(); + gateway = new A2AGatewayService(NAMESPACE, GATEWAY_ID, transport, taskRegistry, a2aService); + gateway.start(); + } + + @AfterEach + void tearDown() throws Exception { + gateway.shutdown(); + a2aService.shutdown(); + } + + // ========================================================================= + // Helpers + // ========================================================================= + + private void registerAgent(String agentName) { + AgentCard card = AgentCardTestUtils.createValidCard(agentName); + AgentIdentity identity = AgentIdentity.builder() + .orgId("default").unitId("default").agentId(agentName).build(); + a2aService.registerCard(identity, card); + } + + private void subscribeEchoAgent(String agentName) throws Exception { + String requestTopic = A2ATopicFactory.agentRequestTopic(NAMESPACE, agentName); + transport.subscribe(requestTopic, (topic, event) -> { + String taskId = event.getId(); + String data = event.getData() != null + ? new String(event.getData().toBytes(), StandardCharsets.UTF_8) : ""; + String responseTopic = A2ATopicFactory.gatewayResponseTopic(NAMESPACE, GATEWAY_ID, taskId); + CloudEvent response = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withType(A2AProtocolConstants.CE_TYPE_PREFIX + "task.response") + .withSource(java.net.URI.create("agent/" + agentName)) + .withData(("echo: " + data).getBytes(StandardCharsets.UTF_8)) + .build(); + try { + transport.publish(responseTopic, response); + } catch (Exception e) { + // ignore + } + }); + } + + // ========================================================================= + // Task submission and response + // ========================================================================= + + @Test + void testSubmitTaskAndReceiveResponse() throws Exception { + registerAgent("echo-agent"); + subscribeEchoAgent("echo-agent"); + + CompletableFuture future = + gateway.submitTask("echo-agent", "hello", null); + + A2AGatewayService.TaskResult result = future.get(10, TimeUnit.SECONDS); + assertNotNull(result); + assertEquals(TaskRegistry.TaskState.COMPLETED, result.getState()); + assertEquals("echo: hello", result.getData()); + } + + @Test + void testTaskRegistryUpdatedAfterResponse() throws Exception { + registerAgent("echo-agent"); + subscribeEchoAgent("echo-agent"); + + CompletableFuture future = + gateway.submitTask("echo-agent", "test", null); + future.get(10, TimeUnit.SECONDS); + + assertEquals(1, taskRegistry.size()); + TaskRegistry.TaskEntry entry = taskRegistry.listTasks().get(0); + assertEquals(TaskRegistry.TaskState.COMPLETED, entry.getState()); + assertEquals("echo: test", entry.getResult()); + assertEquals("echo-agent", entry.getTargetAgent()); + assertEquals(GATEWAY_ID, entry.getGatewayId()); + } + + @Test + void testSubmitTaskWithParentTaskId() throws Exception { + registerAgent("echo-agent"); + subscribeEchoAgent("echo-agent"); + + String parentTaskId = "parent-task-001"; + CompletableFuture future = + gateway.submitTask("echo-agent", "child-msg", parentTaskId); + future.get(10, TimeUnit.SECONDS); + + TaskRegistry.TaskEntry entry = taskRegistry.listTasks().get(0); + assertEquals(parentTaskId, entry.getParentTaskId()); + } + + // ========================================================================= + // Task cancellation + // ========================================================================= + + @Test + void testCancelTask() { + // Register an agent that never responds + registerAgent("slow-agent"); + + CompletableFuture future = + gateway.submitTask("slow-agent", "hello", null); + + // Cancel before response + boolean cancelled = gateway.cancelTask( + taskRegistry.listTasks().get(0).getTaskId()); + + assertTrue(cancelled); + TaskRegistry.TaskEntry entry = taskRegistry.listTasks().get(0); + assertEquals(TaskRegistry.TaskState.CANCELLED, entry.getState()); + + // Future should be completed with CANCELLED + A2AGatewayService.TaskResult result = future.getNow(null); + assertNotNull(result); + assertEquals(TaskRegistry.TaskState.CANCELLED, result.getState()); + } + + @Test + void testCancelNonExistentTask() { + assertFalse(gateway.cancelTask("nonexistent-task")); + } + + // ========================================================================= + // Get task status + // ========================================================================= + + @Test + void testGetTaskStatus() { + registerAgent("echo-agent"); + + gateway.submitTask("echo-agent", "hello", null); + String taskId = taskRegistry.listTasks().get(0).getTaskId(); + + TaskRegistry.TaskEntry entry = gateway.getTaskStatus(taskId); + assertNotNull(entry); + assertEquals(taskId, entry.getTaskId()); + assertEquals(TaskRegistry.TaskState.SUBMITTED, entry.getState()); + } + + @Test + void testGetTaskStatusNonExistent() { + assertNull(gateway.getTaskStatus("nonexistent")); + } + + // ========================================================================= + // Status subscriber (SSE) + // ========================================================================= + + @Test + void testStatusSubscriberNotifiedOnResponse() throws Exception { + registerAgent("echo-agent"); + subscribeEchoAgent("echo-agent"); + + AtomicInteger notifications = new AtomicInteger(0); + String[] lastState = new String[1]; + + // Use a known task ID so we can register subscriber before submitting + String taskId = "status-test-task-001"; + gateway.registerStatusSubscriber(taskId, (tid, state, data) -> { + lastState[0] = state; + notifications.incrementAndGet(); + }); + + // Submit task — InMemory transport is synchronous, so subscriber must be registered first + gateway.submitTask(taskId, "echo-agent", "hello", null); + + // Give async processing time to complete + Thread.sleep(500); + + assertTrue(notifications.get() >= 1); + assertEquals("completed", lastState[0]); + } + + // ========================================================================= + // Agent-to-agent delegation + // ========================================================================= + + @Test + void testAgentDelegation() throws Exception { + // Agent A delegates to Agent B + registerAgent("agent-a"); + registerAgent("agent-b"); + + // Agent B responds + subscribeEchoAgent("agent-b"); + + // Agent A receives request, then delegates to Agent B + String agentARequestTopic = A2ATopicFactory.agentRequestTopic(NAMESPACE, "agent-a"); + transport.subscribe(agentARequestTopic, (topic, event) -> { + String taskId = event.getId(); + // Agent A delegates to Agent B + String delegateTopic = A2ATopicFactory.agentRequestTopic(NAMESPACE, "agent-b"); + CloudEvent delegatedEvent = CloudEventBuilder.v1() + .withId(taskId) // use same task ID for simplicity + .withType(A2AProtocolConstants.CE_TYPE_PREFIX + "task.delegate") + .withSource(java.net.URI.create("agent/agent-a")) + .withData("delegated".getBytes(StandardCharsets.UTF_8)) + .build(); + try { + transport.publish(delegateTopic, delegatedEvent); + } catch (Exception e) { + // ignore + } + }); + + // Also subscribe Agent A to publish response back to gateway + // Actually, Agent B's echo response goes to gateway, not Agent A + // Let's simplify: Agent B's response goes to gateway + CompletableFuture future = + gateway.submitTask("agent-b", "delegation-test", null); + + A2AGatewayService.TaskResult result = future.get(10, TimeUnit.SECONDS); + assertNotNull(result); + assertEquals(TaskRegistry.TaskState.COMPLETED, result.getState()); + assertEquals("echo: delegation-test", result.getData()); + } + + // ========================================================================= + // Gateway not started + // ========================================================================= + + @Test + void testSubmitTaskBeforeStartFails() throws Exception { + gateway.shutdown(); + gateway = new A2AGatewayService(NAMESPACE, GATEWAY_ID, transport, taskRegistry, a2aService); + // Don't start + + CompletableFuture future = + gateway.submitTask("test-agent", "hello", null); + + assertTrue(future.isCompletedExceptionally()); + } + + // ========================================================================= + // Multiple tasks + // ========================================================================= + + @Test + void testMultipleConcurrentTasks() throws Exception { + registerAgent("echo-agent"); + subscribeEchoAgent("echo-agent"); + + CompletableFuture f1 = gateway.submitTask("echo-agent", "msg1", null); + CompletableFuture f2 = gateway.submitTask("echo-agent", "msg2", null); + CompletableFuture f3 = gateway.submitTask("echo-agent", "msg3", null); + + assertEquals("echo: msg1", f1.get(10, TimeUnit.SECONDS).getData()); + assertEquals("echo: msg2", f2.get(10, TimeUnit.SECONDS).getData()); + assertEquals("echo: msg3", f3.get(10, TimeUnit.SECONDS).getData()); + + assertEquals(3, taskRegistry.size()); + } + + // ========================================================================= + // Gateway properties + // ========================================================================= + + @Test + void testGatewayId() { + assertEquals(GATEWAY_ID, gateway.getGatewayId()); + } + + @Test + void testNamespace() { + assertEquals(NAMESPACE, gateway.getNamespace()); + } + + @Test + void testGetA2aService() { + assertNotNull(gateway.getA2aService()); + } + + @Test + void testGetTaskRegistry() { + assertNotNull(gateway.getTaskRegistry()); + } + + // ========================================================================= + // Task Timeout + // ========================================================================= + + @Test + void testTaskTimeoutAutoFails() throws Exception { + // Use a gateway with very short timeout + gateway.shutdown(); + gateway = new A2AGatewayService(NAMESPACE, GATEWAY_ID, transport, taskRegistry, a2aService, 500L); + gateway.start(); + + // Register an agent that never responds + registerAgent("slow-agent"); + + CompletableFuture future = + gateway.submitTask("slow-agent", "hello", null); + + // Wait for timeout + try { + future.get(3, TimeUnit.SECONDS); + org.junit.jupiter.api.Assertions.fail("Future should have timed out"); + } catch (java.util.concurrent.ExecutionException e) { + // Expected: TimeoutException wrapped in ExecutionException + assertTrue(e.getCause() instanceof java.util.concurrent.TimeoutException, + "Cause should be TimeoutException: " + e.getCause()); + } + + // Verify task was marked FAILED + TaskRegistry.TaskEntry entry = taskRegistry.listTasks().get(0); + assertEquals(TaskRegistry.TaskState.FAILED, entry.getState()); + assertTrue(entry.getErrorMessage().contains("timed out")); + } + + @Test + void testCancelTaskNotifiesStatusSubscriber() throws Exception { + registerAgent("slow-agent"); + + CompletableFuture future = + gateway.submitTask("task-cancel-notify", "slow-agent", "hello", null); + AtomicInteger notifications = new AtomicInteger(0); + String[] lastState = new String[1]; + gateway.registerStatusSubscriber("task-cancel-notify", (tid, state, data) -> { + notifications.incrementAndGet(); + lastState[0] = state; + }); + + assertTrue(gateway.cancelTask("task-cancel-notify")); + A2AGatewayService.TaskResult result = future.get(1, TimeUnit.SECONDS); + assertEquals(TaskRegistry.TaskState.CANCELLED, result.getState()); + assertEquals(1, notifications.get()); + assertEquals("cancelled", lastState[0]); + } + + // ========================================================================= + // Agent Validation + // ========================================================================= + + @Test + void testSubmitTaskToUnregisteredAgentFails() { + // Don't register any agent + CompletableFuture future = + gateway.submitTask("ghost-agent", "hello", null); + + assertTrue(future.isCompletedExceptionally()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/AgentCardTestUtils.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/AgentCardTestUtils.java new file mode 100644 index 0000000000..5354d06680 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/AgentCardTestUtils.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import org.apache.eventmesh.protocol.a2a.model.AgentCapabilities; +import org.apache.eventmesh.protocol.a2a.model.AgentCard; +import org.apache.eventmesh.protocol.a2a.model.AgentInterface; +import org.apache.eventmesh.protocol.a2a.model.AgentSkill; + +import java.util.Arrays; +import java.util.Collections; + +/** + * Test utility for creating valid AgentCard instances that pass schema validation. + */ +public final class AgentCardTestUtils { + + private AgentCardTestUtils() { + } + + public static AgentCard createValidCard(String name) { + return AgentCard.builder() + .name(name) + .description("Test agent: " + name) + .version("1.0.0") + .supportedInterfaces(Arrays.asList( + AgentInterface.builder() + .url("http://localhost:10105/a2a") + .protocolBinding("JSONRPC") + .protocolVersion("0.3") + .build() + )) + .capabilities(AgentCapabilities.builder() + .streaming(false) + .pushNotifications(false) + .build()) + .defaultInputModes(Arrays.asList("text/plain")) + .defaultOutputModes(Arrays.asList("text/plain")) + .skills(Arrays.asList( + AgentSkill.builder() + .id("test-skill") + .name("Test Skill") + .description("A test skill") + .tags(Collections.singletonList("test")) + .build() + )) + .build(); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/InMemoryA2AMessageTransportTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/InMemoryA2AMessageTransportTest.java new file mode 100644 index 0000000000..0770a906fb --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/InMemoryA2AMessageTransportTest.java @@ -0,0 +1,194 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +/** + * Unit tests for {@link InMemoryA2AMessageTransport}. + */ +class InMemoryA2AMessageTransportTest { + + private InMemoryA2AMessageTransport transport; + + @BeforeEach + void setUp() { + transport = new InMemoryA2AMessageTransport(); + } + + private CloudEvent createEvent(String data) { + return CloudEventBuilder.v1() + .withId("test-id") + .withType("test-type") + .withSource(java.net.URI.create("test/source")) + .withData(data.getBytes(StandardCharsets.UTF_8)) + .build(); + } + + // ========================================================================= + // Publish / Subscribe direct match + // ========================================================================= + + @Test + void testDirectMatchDelivery() throws Exception { + AtomicInteger received = new AtomicInteger(0); + transport.subscribe("a2a/v1/agent/request/agent-a", (topic, event) -> received.incrementAndGet()); + + transport.publish("a2a/v1/agent/request/agent-a", createEvent("hello")); + assertEquals(1, received.get()); + } + + @Test + void testDirectMatchDataContent() throws Exception { + AtomicInteger received = new AtomicInteger(0); + String[] capturedData = new String[1]; + + transport.subscribe("a2a/v1/agent/request/agent-a", (topic, event) -> { + capturedData[0] = new String(event.getData().toBytes(), StandardCharsets.UTF_8); + received.incrementAndGet(); + }); + + transport.publish("a2a/v1/agent/request/agent-a", createEvent("test-payload")); + assertEquals(1, received.get()); + assertEquals("test-payload", capturedData[0]); + } + + // ========================================================================= + // Wildcard matching + // ========================================================================= + + @Test + void testWildcardPlusMatches() throws Exception { + AtomicInteger received = new AtomicInteger(0); + // Subscribe with wildcard for task ID + transport.subscribe("a2a/v1/gateway/response/gw-1/+", (topic, event) -> received.incrementAndGet()); + + // Publish to specific task IDs + transport.publish("a2a/v1/gateway/response/gw-1/task-1", createEvent("r1")); + transport.publish("a2a/v1/gateway/response/gw-1/task-2", createEvent("r2")); + transport.publish("a2a/v1/gateway/response/gw-1/task-3", createEvent("r3")); + + assertEquals(3, received.get()); + } + + @Test + void testWildcardDoesNotMatchDifferentLevels() throws Exception { + AtomicInteger received = new AtomicInteger(0); + transport.subscribe("a2a/v1/gateway/response/gw-1/+", (topic, event) -> received.incrementAndGet()); + + // Different gateway ID should not match + transport.publish("a2a/v1/gateway/response/gw-2/task-1", createEvent("r1")); + assertEquals(0, received.get()); + } + + @Test + void testWildcardDifferentDepthDoesNotMatch() throws Exception { + AtomicInteger received = new AtomicInteger(0); + transport.subscribe("a2a/v1/agent/request/+", (topic, event) -> received.incrementAndGet()); + + // More levels should not match + transport.publish("a2a/v1/agent/request/agent-a/extra", createEvent("r1")); + assertEquals(0, received.get()); + } + + // ========================================================================= + // No subscribers + // ========================================================================= + + @Test + void testPublishWithNoSubscribersDoesNotThrow() throws Exception { + // Should not throw + transport.publish("a2a/v1/agent/request/unknown-agent", createEvent("hello")); + } + + // ========================================================================= + // Unsubscribe + // ========================================================================= + + @Test + void testUnsubscribeStopsDelivery() throws Exception { + AtomicInteger received = new AtomicInteger(0); + String subId = transport.subscribe("a2a/v1/agent/request/agent-a", + (topic, event) -> received.incrementAndGet()); + + transport.publish("a2a/v1/agent/request/agent-a", createEvent("first")); + assertEquals(1, received.get()); + + transport.unsubscribe(subId); + transport.publish("a2a/v1/agent/request/agent-a", createEvent("second")); + assertEquals(1, received.get()); + } + + // ========================================================================= + // Multiple subscribers + // ========================================================================= + + @Test + void testMultipleSubscribersSameTopic() throws Exception { + AtomicInteger received1 = new AtomicInteger(0); + AtomicInteger received2 = new AtomicInteger(0); + + transport.subscribe("a2a/v1/agent/request/agent-a", (topic, event) -> received1.incrementAndGet()); + transport.subscribe("a2a/v1/agent/request/agent-a", (topic, event) -> received2.incrementAndGet()); + + transport.publish("a2a/v1/agent/request/agent-a", createEvent("hello")); + + // Both should receive + assertEquals(1, received1.get()); + assertEquals(1, received2.get()); + } + + @Test + void testWildcardAndDirectSubscribersBothReceive() throws Exception { + AtomicInteger wildcardReceived = new AtomicInteger(0); + AtomicInteger directReceived = new AtomicInteger(0); + + transport.subscribe("a2a/v1/gateway/response/gw-1/+", (topic, event) -> wildcardReceived.incrementAndGet()); + transport.subscribe("a2a/v1/gateway/response/gw-1/task-1", (topic, event) -> directReceived.incrementAndGet()); + + transport.publish("a2a/v1/gateway/response/gw-1/task-1", createEvent("hello")); + + assertEquals(1, wildcardReceived.get()); + assertEquals(1, directReceived.get()); + } + + // ========================================================================= + // Subscription ID + // ========================================================================= + + @Test + void testSubscriptionIdIsNotNull() throws Exception { + String subId = transport.subscribe("a2a/v1/agent/request/agent-a", (topic, event) -> { }); + assertNotNull(subId); + } + + @Test + void testUnsubscribeNonExistentDoesNotThrow() throws Exception { + transport.unsubscribe("nonexistent-sub-id"); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/TaskRegistryTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/TaskRegistryTest.java new file mode 100644 index 0000000000..4bac7b52be --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/a2a/TaskRegistryTest.java @@ -0,0 +1,297 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.a2a; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link TaskRegistry}. + */ +class TaskRegistryTest { + + private TaskRegistry registry; + + @BeforeEach + void setUp() { + registry = new TaskRegistry(); + } + + // ========================================================================= + // Create + // ========================================================================= + + @Test + void testCreateTask() { + TaskRegistry.TaskEntry entry = registry.createTask("task-1", null, "agent-a", "gw-1"); + assertNotNull(entry); + assertEquals("task-1", entry.getTaskId()); + assertNull(entry.getParentTaskId()); + assertEquals("agent-a", entry.getTargetAgent()); + assertEquals("gw-1", entry.getGatewayId()); + assertEquals(TaskRegistry.TaskState.SUBMITTED, entry.getState()); + assertEquals(1, registry.size()); + } + + @Test + void testCreateTaskWithParent() { + registry.createTask("parent-1", null, "agent-a", "gw-1"); + registry.createTask("child-1", "parent-1", "agent-b", "gw-1"); + + assertEquals(2, registry.size()); + assertEquals(1, registry.getChildTasks("parent-1").size()); + assertEquals("child-1", registry.getChildTasks("parent-1").get(0)); + } + + // ========================================================================= + // State transitions + // ========================================================================= + + @Test + void testSubmittedToWorking() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + assertTrue(registry.markWorking("task-1")); + assertEquals(TaskRegistry.TaskState.WORKING, registry.getTask("task-1").getState()); + } + + @Test + void testWorkingToCompleted() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markWorking("task-1"); + assertTrue(registry.markCompleted("task-1", "result-data")); + assertEquals(TaskRegistry.TaskState.COMPLETED, registry.getTask("task-1").getState()); + assertEquals("result-data", registry.getTask("task-1").getResult()); + } + + @Test + void testWorkingToFailed() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markWorking("task-1"); + assertTrue(registry.markFailed("task-1", "something went wrong")); + assertEquals(TaskRegistry.TaskState.FAILED, registry.getTask("task-1").getState()); + assertEquals("something went wrong", registry.getTask("task-1").getErrorMessage()); + } + + @Test + void testSubmittedDirectlyToCompleted() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + // SUBMITTED -> COMPLETED should be allowed (skip WORKING) + assertTrue(registry.markCompleted("task-1", "fast-result")); + assertEquals(TaskRegistry.TaskState.COMPLETED, registry.getTask("task-1").getState()); + } + + @Test + void testSubmittedToCancelled() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + assertTrue(registry.markCancelled("task-1")); + assertEquals(TaskRegistry.TaskState.CANCELLED, registry.getTask("task-1").getState()); + } + + // ========================================================================= + // Invalid state transitions + // ========================================================================= + + @Test + void testWorkingFromWorkingFails() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markWorking("task-1"); + assertFalse(registry.markWorking("task-1")); + } + + @Test + void testCompletedFromCompletedFails() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markCompleted("task-1", "done"); + assertFalse(registry.markCompleted("task-1", "again")); + } + + @Test + void testCompletedToCancelledFails() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markCompleted("task-1", "done"); + assertFalse(registry.markCancelled("task-1")); + } + + @Test + void testCancelledToCompletedFails() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markCancelled("task-1"); + assertFalse(registry.markCompleted("task-1", "too late")); + } + + @Test + void testCancelledToFailedFails() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.markCancelled("task-1"); + assertFalse(registry.markFailed("task-1", "error")); + } + + @Test + void testWorkingOnNonExistentTaskFails() { + assertFalse(registry.markWorking("nonexistent")); + } + + @Test + void testCompleteOnNonExistentTaskFails() { + assertFalse(registry.markCompleted("nonexistent", "data")); + } + + // ========================================================================= + // Get / List + // ========================================================================= + + @Test + void testGetNonExistentReturnsNull() { + assertNull(registry.getTask("nonexistent")); + } + + @Test + void testListTasks() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.createTask("task-2", null, "agent-b", "gw-1"); + registry.createTask("task-3", null, "agent-c", "gw-1"); + + assertEquals(3, registry.listTasks().size()); + } + + @Test + void testListTasksEmpty() { + assertEquals(0, registry.listTasks().size()); + } + + @Test + void testGetChildTasksNoParent() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + assertEquals(0, registry.getChildTasks("task-1").size()); + } + + @Test + void testGetChildTasksNonExistentParent() { + assertEquals(0, registry.getChildTasks("nonexistent").size()); + } + + @Test + void testMultipleChildren() { + registry.createTask("parent", null, "agent-a", "gw-1"); + registry.createTask("child-1", "parent", "agent-b", "gw-1"); + registry.createTask("child-2", "parent", "agent-c", "gw-1"); + registry.createTask("child-3", "parent", "agent-d", "gw-1"); + + assertEquals(3, registry.getChildTasks("parent").size()); + } + + @Test + void testConcurrentChildTaskCreation() throws Exception { + registry.createTask("parent", null, "agent-a", "gw-1"); + ExecutorService executor = Executors.newCachedThreadPool(); + CountDownLatch ready = new CountDownLatch(50); + CountDownLatch start = new CountDownLatch(1); + List failures = new ArrayList<>(); + + for (int i = 0; i < 50; i++) { + final int index = i; + executor.execute(() -> { + ready.countDown(); + try { + start.await(); + registry.createTask("child-" + index, "parent", "agent-b", "gw-1"); + } catch (Throwable t) { + synchronized (failures) { + failures.add(t); + } + } + }); + } + + assertTrue(ready.await(30, TimeUnit.SECONDS), "Not all threads ready in time"); + start.countDown(); + executor.shutdown(); + assertTrue(executor.awaitTermination(30, TimeUnit.SECONDS), "Executor did not terminate in time"); + assertEquals(0, failures.size()); + assertEquals(50, registry.getChildTasks("parent").size()); + } + + // ========================================================================= + // Remove / Clear + // ========================================================================= + + @Test + void testRemoveTask() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + TaskRegistry.TaskEntry removed = registry.removeTask("task-1"); + assertNotNull(removed); + assertEquals("task-1", removed.getTaskId()); + assertEquals(0, registry.size()); + assertNull(registry.getTask("task-1")); + } + + @Test + void testRemoveNonExistentReturnsNull() { + assertNull(registry.removeTask("nonexistent")); + } + + @Test + void testRemoveChildUpdatesParentChildren() { + registry.createTask("parent", null, "agent-a", "gw-1"); + registry.createTask("child-1", "parent", "agent-b", "gw-1"); + registry.createTask("child-2", "parent", "agent-c", "gw-1"); + + registry.removeTask("child-1"); + assertEquals(1, registry.getChildTasks("parent").size()); + assertEquals("child-2", registry.getChildTasks("parent").get(0)); + } + + @Test + void testClear() { + registry.createTask("task-1", null, "agent-a", "gw-1"); + registry.createTask("task-2", "task-1", "agent-b", "gw-1"); + registry.clear(); + assertEquals(0, registry.size()); + } + + // ========================================================================= + // Timestamps + // ========================================================================= + + @Test + void testTimestampsUpdate() throws InterruptedException { + registry.createTask("task-1", null, "agent-a", "gw-1"); + long createdAt = registry.getTask("task-1").getCreatedAt(); + long updatedAtBefore = registry.getTask("task-1").getUpdatedAt(); + + Thread.sleep(10); + registry.markWorking("task-1"); + long updatedAtAfter = registry.getTask("task-1").getUpdatedAt(); + + assertEquals(createdAt, updatedAtBefore); + assertTrue(updatedAtAfter > updatedAtBefore); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/controller/ClientManageControllerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/controller/ClientManageControllerTest.java deleted file mode 100644 index a7303bf97c..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/controller/ClientManageControllerTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.controller; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.eventmesh.admin.rocketmq.controller.AdminController; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; -import org.apache.eventmesh.webhook.admin.AdminWebHookConfigOperationManage; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; - -import java.io.IOException; - -import org.junit.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import com.sun.net.httpserver.HttpServer; - -public class ClientManageControllerTest { - - @Test - public void testStart() throws IOException { - EventMeshTCPServer eventMeshTCPServer = mock(EventMeshTCPServer.class); - AdminController adminController = mock(AdminController.class); - EventMeshTCPConfiguration tcpConfiguration = mock(EventMeshTCPConfiguration.class); - doNothing().when(tcpConfiguration).init(); - when(eventMeshTCPServer.getEventMeshTCPConfiguration()).thenReturn(tcpConfiguration); - ClientManageController controller = new ClientManageController(eventMeshTCPServer); - - AdminWebHookConfigOperationManage adminWebHookConfigOperationManage = mock(AdminWebHookConfigOperationManage.class); - WebHookConfigOperation webHookConfigOperation = mock(WebHookConfigOperation.class); - when(adminWebHookConfigOperationManage.getWebHookConfigOperation()).thenReturn(webHookConfigOperation); - controller.setAdminWebHookConfigOperationManage(adminWebHookConfigOperationManage); - - try (MockedStatic dummyStatic = Mockito.mockStatic(HttpServer.class)) { - HttpServer server = mock(HttpServer.class); - dummyStatic.when(() -> HttpServer.create(any(), anyInt())).thenReturn(server); - Mockito.doNothing().when(adminController).run(server); - controller.start(); - } - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/EventHandlerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/EventHandlerTest.java new file mode 100644 index 0000000000..1df3386bea --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/EventHandlerTest.java @@ -0,0 +1,151 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.admin.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.runtime.admin.handler.v1.EventHandler; +import org.apache.eventmesh.runtime.boot.EventMeshServer; +import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; +import org.apache.eventmesh.runtime.core.plugin.MQAdminWrapper; +import org.apache.eventmesh.runtime.mock.MockCloudEvent; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import io.cloudevents.CloudEvent; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.codec.http.HttpVersion; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@ExtendWith(MockitoExtension.class) +public class EventHandlerTest { + + public static String storagePlugin = "standalone"; + + EmbeddedChannel embeddedChannel; + + AdminHandlerManager adminHandlerManager; + + @Mock + EventMeshServer eventMeshServer; + + @Mock + EventMeshTCPServer eventMeshTCPServer; + + @Spy + EventHandler eventHandler = new EventHandler(storagePlugin); + + @Mock + MQAdminWrapper mockAdmin; + + List result = new ArrayList<>(); + + Method initHandler; + + @BeforeEach + public void init() throws Exception { + result.add(new MockCloudEvent()); + when(eventMeshServer.getEventMeshTCPServer()).thenReturn(eventMeshTCPServer); + adminHandlerManager = new AdminHandlerManager(eventMeshServer); + Field admin = EventHandler.class.getDeclaredField("admin"); + admin.setAccessible(true); + admin.set(eventHandler, mockAdmin); + embeddedChannel = new EmbeddedChannel( + new HttpRequestDecoder(), + new HttpResponseEncoder(), + new HttpObjectAggregator(Integer.MAX_VALUE), + new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception { + String uriStr = msg.uri(); + URI uri = URI.create(uriStr); + adminHandlerManager.getHttpHandler(uri.getPath()).get().handle(msg, ctx); + } + }); + initHandler = AdminHandlerManager.class.getDeclaredMethod("initHandler", HttpHandler.class); + initHandler.setAccessible(true); + initHandler.invoke(adminHandlerManager, eventHandler); + } + + @Test + public void testGet() throws Exception { + when(mockAdmin.getEvent(anyString(), anyInt(), anyInt())).thenReturn(result); + FullHttpRequest httpRequest = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, HttpMethod.GET, "/event?topicName=123&offset=0&length=1"); + embeddedChannel.writeInbound(httpRequest); + boolean finish = embeddedChannel.finish(); + assertTrue(finish); + ByteBuf byteBuf = null; + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024); + while ((byteBuf = embeddedChannel.readOutbound()) != null) { + byte[] data = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(data); + byteArrayOutputStream.write(data); + } + ; + String response = new String(byteArrayOutputStream.toByteArray(), "UTF-8"); + String responseBody = response.split("\\r?\\n\\r?\\n")[1]; + JsonNode jsonNode = new ObjectMapper().readTree(responseBody); + assertTrue(jsonNode.get(0).asText().contains("mockData")); + } + + @Test + public void testPost() throws IOException { + FullHttpRequest httpRequest = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, HttpMethod.POST, "/event", Unpooled.copiedBuffer( + ("specversion=1.0&id=cd7c0d63-6c7c-4300-9f4e-ceb51f46b1b1&source" + + "=/&type=cloudevents&datacontenttype=application/cloudevents+json&subject=test&ttl=4000").getBytes())); + embeddedChannel.writeInbound(httpRequest); + ByteBuf byteBuf = embeddedChannel.readOutbound(); + byte[] data = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(data); + String response = new String(data, "UTF-8"); + String[] requestMessage = response.split("\r\n"); + assertEquals("HTTP/1.1 200 OK", requestMessage[0].toString()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandlerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandlerTest.java deleted file mode 100644 index 1112cedab7..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/QueryRecommendEventMeshHandlerTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.when; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.recommend.EventMeshRecommendImpl; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; -import java.net.URI; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedConstruction; - -import com.sun.net.httpserver.HttpExchange; - -public class QueryRecommendEventMeshHandlerTest { - - @Test - public void testHandle() throws Exception { - HttpExchange httpExchange = mock(HttpExchange.class); - URI uri = mock(URI.class); - when(uri.getQuery()).thenReturn("group=group&purpose=purpose"); - when(httpExchange.getRequestURI()).thenReturn(uri); - - // mock eventMeshTCPServer - EventMeshTCPServer eventMeshTCPServer = mock(EventMeshTCPServer.class); - EventMeshTCPConfiguration tcpConfiguration = mock(EventMeshTCPConfiguration.class); - doNothing().when(tcpConfiguration).init(); - tcpConfiguration.eventMeshServerRegistryEnable = true; - when(eventMeshTCPServer.getEventMeshTCPConfiguration()).thenReturn(tcpConfiguration); - - OutputStream outputStream = new ByteArrayOutputStream(); - when(httpExchange.getResponseBody()).thenReturn(outputStream); - - QueryRecommendEventMeshHandler handler = new QueryRecommendEventMeshHandler(eventMeshTCPServer); - try (MockedConstruction ignored = mockConstruction(EventMeshRecommendImpl.class, - (mock, context) -> when(mock.calculateRecommendEventMesh(anyString(), anyString())).thenReturn("result"))) { - handler.handle(httpExchange); - String response = outputStream.toString(); - Assert.assertEquals("result", response); - } - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByIpPortHandlerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByIpPortHandlerTest.java deleted file mode 100644 index 7ed08f7db4..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByIpPortHandlerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.URI; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.powermock.api.mockito.PowerMockito; - -import com.sun.net.httpserver.HttpExchange; - -public class RedirectClientByIpPortHandlerTest { - - private RedirectClientByIpPortHandler redirectClientByIpPortHandler; - - @Before - public void init() { - EventMeshTCPServer mockServer = PowerMockito.mock(EventMeshTCPServer.class); - redirectClientByIpPortHandler = new RedirectClientByIpPortHandler(mockServer); - } - - @Test - public void testHandleParamIllegal() throws IOException { - OutputStream outputStream = new ByteArrayOutputStream(); - URI uri = URI.create("ip=127.0.0.1&port=1234&desteventMeshIp=127.0.0.1&desteventMeshPort="); - - HttpExchange mockExchange = PowerMockito.mock(HttpExchange.class); - PowerMockito.when(mockExchange.getResponseBody()).thenReturn(outputStream); - PowerMockito.when(mockExchange.getRequestURI()).thenReturn(uri); - - redirectClientByIpPortHandler.handle(mockExchange); - - String response = outputStream.toString(); - Assert.assertEquals("params illegal!", response); - - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandlerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandlerTest.java deleted file mode 100644 index 0a90172fac..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/admin/handler/RedirectClientByPathHandlerTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.admin.handler; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.runtime.boot.EventMeshTCPServer; -import org.apache.eventmesh.runtime.constants.EventMeshConstants; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.EventMeshTcp2Client; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.group.ClientSessionGroupMapping; -import org.apache.eventmesh.runtime.core.protocol.tcp.client.session.Session; -import org.apache.eventmesh.runtime.util.NetUtils; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import com.sun.net.httpserver.HttpExchange; - -public class RedirectClientByPathHandlerTest { - - @Mock - private EventMeshTCPServer eventMeshTCPServer; - - @Before - public void init() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void testHandle() throws IOException { - final OutputStream outputStream = new ByteArrayOutputStream(); - - ClientSessionGroupMapping mapping = mock(ClientSessionGroupMapping.class); - when(eventMeshTCPServer.getClientSessionGroupMapping()).thenReturn(mapping); - - // mock session map - ConcurrentHashMap sessionMap = new ConcurrentHashMap<>(); - Session session = mock(Session.class); - UserAgent agent = mock(UserAgent.class); - when(agent.getPath()).thenReturn("path"); - when(session.getClient()).thenReturn(agent); - sessionMap.put(new InetSocketAddress(8080), session); - when(mapping.getSessionMap()).thenReturn(sessionMap); - - RedirectClientByPathHandler redirectClientByPathHandler = new RedirectClientByPathHandler(eventMeshTCPServer); - - HttpExchange mockExchange = mock(HttpExchange.class); - when(mockExchange.getResponseBody()).thenReturn(outputStream); - - // mock uri - URI uri = mock(URI.class); - when(uri.getQuery()).thenReturn("path=path&ip=127.0.0.1&port=1234&desteventMeshIp=127.0.0.1&desteventmeshport=8080"); - when(mockExchange.getRequestURI()).thenReturn(uri); - - try (MockedStatic netUtilsMockedStatic = Mockito.mockStatic(NetUtils.class)) { - Map queryStringInfo = new HashMap<>(); - queryStringInfo.put(EventMeshConstants.MANAGE_PATH, EventMeshConstants.MANAGE_PATH); - queryStringInfo.put(EventMeshConstants.MANAGE_DEST_IP, "127.0.0.1"); - queryStringInfo.put(EventMeshConstants.MANAGE_DEST_PORT, "8080"); - netUtilsMockedStatic.when(() -> NetUtils.formData2Dic(anyString())).thenReturn(queryStringInfo); - - try (MockedStatic clientMockedStatic = Mockito.mockStatic(EventMeshTcp2Client.class)) { - clientMockedStatic.when(() -> EventMeshTcp2Client.redirectClient2NewEventMesh(any(), anyString(), anyInt(), any(), - any())).thenReturn("redirectResult"); - redirectClientByPathHandler.handle(mockExchange); - - String response = outputStream.toString(); - Assert.assertTrue(response.contains("redirectClientByPath success")); - } - } - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/EventMeshServerTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/EventMeshServerTest.java new file mode 100644 index 0000000000..cf63ce974c --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/EventMeshServerTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.runtime.configuration.EventMeshTCPConfiguration; +import org.apache.eventmesh.runtime.constants.EventMeshConstants; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class EventMeshServerTest { + + /** + * True Environment variables need to be set during startup + */ + @Test + public void testGetConfigWhenStartup() throws Exception { + + testGetConfigWhenStartup(Boolean.FALSE); + } + + private void testGetConfigWhenStartup(Boolean hasEnv) throws Exception { + String eventMeshConfFile = "configuration.properties"; + + if (hasEnv) { + ConfigService.getInstance() + .setConfigPath(EventMeshConstants.EVENTMESH_CONF_HOME + File.separator) + .setRootConfig(eventMeshConfFile); + } else { + eventMeshConfFile = "classPath://" + eventMeshConfFile; + ConfigService.getInstance().setRootConfig(eventMeshConfFile); + } + + ConfigService configService = ConfigService.getInstance(); + EventMeshTCPConfiguration eventMeshTCPConfiguration = configService.buildConfigInstance(EventMeshTCPConfiguration.class); + + assertCommonConfig(eventMeshTCPConfiguration); + assertTCPConfig(eventMeshTCPConfiguration); + } + + private void assertTCPConfig(EventMeshTCPConfiguration config) { + Assertions.assertEquals(816, config.getEventMeshTcpServerPort()); + Assertions.assertEquals(1816, config.getEventMeshTcpIdleAllSeconds()); + Assertions.assertEquals(2816, config.getEventMeshTcpIdleWriteSeconds()); + Assertions.assertEquals(3816, config.getEventMeshTcpIdleReadSeconds()); + Assertions.assertEquals(Integer.valueOf(4816), config.getEventMeshTcpMsgReqnumPerSecond()); + Assertions.assertEquals(5816, config.getEventMeshTcpClientMaxNum()); + Assertions.assertEquals(6816, config.getEventMeshTcpGlobalScheduler()); + Assertions.assertEquals(7816, config.getEventMeshTcpTaskHandleExecutorPoolSize()); + Assertions.assertEquals(8816, config.getEventMeshTcpMsgDownStreamExecutorPoolSize()); + Assertions.assertEquals(1816, config.getEventMeshTcpSessionExpiredInMills()); + Assertions.assertEquals(11816, config.getEventMeshTcpSessionUpstreamBufferSize()); + Assertions.assertEquals(12816, config.getEventMeshTcpMsgAsyncRetryTimes()); + Assertions.assertEquals(13816, config.getEventMeshTcpMsgSyncRetryTimes()); + Assertions.assertEquals(14816, config.getEventMeshTcpMsgRetrySyncDelayInMills()); + Assertions.assertEquals(15816, config.getEventMeshTcpMsgRetryAsyncDelayInMills()); + Assertions.assertEquals(16816, config.getEventMeshTcpMsgRetryQueueSize()); + Assertions.assertEquals(Integer.valueOf(17816), config.getEventMeshTcpRebalanceIntervalInMills()); + Assertions.assertEquals(Boolean.TRUE, config.isEventMeshTcpSendBackEnabled()); + Assertions.assertEquals(3, config.getEventMeshTcpSendBackMaxTimes()); + Assertions.assertEquals(21816, config.getEventMeshTcpPushFailIsolateTimeInMills()); + Assertions.assertEquals(22816, config.getGracefulShutdownSleepIntervalInMills()); + Assertions.assertEquals(23816, config.getSleepIntervalInRebalanceRedirectMills()); + Assertions.assertEquals(22816, config.getEventMeshEventSize()); + Assertions.assertEquals(23816, config.getEventMeshEventBatchSize()); + } + + private void assertCommonConfig(CommonConfiguration config) { + Assertions.assertEquals("env-succeed!!!", config.getEventMeshEnv()); + Assertions.assertEquals("idc-succeed!!!", config.getEventMeshIDC()); + Assertions.assertEquals("cluster-succeed!!!", config.getEventMeshCluster()); + Assertions.assertEquals("name-succeed!!!", config.getEventMeshName()); + Assertions.assertEquals("816", config.getSysID()); + Assertions.assertEquals("storage-succeed!!!", config.getEventMeshStoragePluginType()); + Assertions.assertEquals("security-succeed!!!", config.getEventMeshSecurityPluginType()); + Assertions.assertEquals("metaStorage-succeed!!!", config.getEventMeshMetaStoragePluginType()); + Assertions.assertEquals("trace-succeed!!!", config.getEventMeshTracePluginType()); + Assertions.assertEquals("hostIp-succeed!!!", config.getEventMeshServerIp()); + + List list = new ArrayList<>(); + list.add("metrics-succeed1!!!"); + list.add("metrics-succeed2!!!"); + list.add("metrics-succeed3!!!"); + Assertions.assertEquals(list, config.getEventMeshMetricsPluginType()); + + Assertions.assertTrue(config.isEventMeshServerSecurityEnable()); + Assertions.assertTrue(config.isEventMeshServerMetaStorageEnable()); + Assertions.assertTrue(config.isEventMeshServerTraceEnable()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/FilterEngineTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/FilterEngineTest.java new file mode 100644 index 0000000000..ccfd994fb3 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/FilterEngineTest.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.function.filter.pattern.Pattern; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class FilterEngineTest { + + @Mock + private MetaStorage metaStorage; + + @Mock + private ProducerManager producerManager; + + @Mock + private ConsumerManager consumerManager; + + @Test + public void testStartAndGetFilter() { + FilterEngine filterEngine = new FilterEngine(metaStorage, producerManager, consumerManager); + + // Mock MetaData + Map filterMetaData = new HashMap<>(); + String group = "testGroup"; + // JSON config for filter + // Condition: source == "testSource" (must be array) + String filterJson = "[{\"topic\":\"testTopic\", \"condition\":{\"source\":[\"testSource\"]}}]"; + filterMetaData.put("filter-" + group, filterJson); + + when(metaStorage.getMetaData(any(String.class), anyBoolean())).thenReturn(filterMetaData); + + // Start Engine + filterEngine.start(); + + // Get Filter + Pattern pattern = filterEngine.getFilterPattern(group + "-testTopic"); + Assertions.assertNotNull(pattern); + + // Verify Filter behavior (optional, depends on Pattern implementation) + // String validEventJson = "{"specversion":"1.0","id":"1","source":"testSource","type":"testType"}"; + // Assertions.assertTrue(pattern.filter(validEventJson)); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/TransformerEngineTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/TransformerEngineTest.java new file mode 100644 index 0000000000..7e436457f0 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/boot/TransformerEngineTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.boot; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.function.transformer.Transformer; +import org.apache.eventmesh.runtime.core.protocol.http.consumer.ConsumerManager; +import org.apache.eventmesh.runtime.core.protocol.producer.ProducerManager; +import org.apache.eventmesh.runtime.meta.MetaStorage; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class TransformerEngineTest { + + @Mock + private MetaStorage metaStorage; + + @Mock + private ProducerManager producerManager; + + @Mock + private ConsumerManager consumerManager; + + @Test + public void testStartAndGetTransformer() throws Exception { + TransformerEngine transformerEngine = new TransformerEngine(metaStorage, producerManager, consumerManager); + + // Mock MetaData + Map transformerMetaData = new HashMap<>(); + String group = "testGroup"; + + // JSON config for transformer + // Use "original" which passes through + String transformerJson = "[{\"topic\":\"testTopic\", \"transformerParam\":{\"transformerType\":\"original\"}}]"; + transformerMetaData.put("transformer-" + group, transformerJson); + + when(metaStorage.getMetaData(any(String.class), anyBoolean())).thenReturn(transformerMetaData); + + // Start Engine + transformerEngine.start(); + + // Get Transformer + Transformer transformer = transformerEngine.getTransformer(group + "-testTopic"); + Assertions.assertNotNull(transformer); + + // Verify transform (original returns content as is) + String content = "testContent"; + Assertions.assertEquals(content, transformer.transform(content)); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/api/SubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/api/SubClient.java index 524b1ba14a..d7c09f2745 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/api/SubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/api/SubClient.java @@ -27,6 +27,7 @@ * SubClient */ public interface SubClient { + void init() throws Exception; void close(); diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientConstants.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientConstants.java index 466e8d1e5e..3f69ca0869 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientConstants.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientConstants.java @@ -20,16 +20,16 @@ /** * ClientConstants */ -public interface ClientConstants { +public class ClientConstants { /** * CLIENT HEART BEAT TIME */ - int HEARTBEAT = 1000 * 60; + public static final int HEARTBEAT = 1000 * 60; - long DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; + public static final long DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; - String SYNC_TOPIC = "TEST-TOPIC-TCP-SYNC"; - String ASYNC_TOPIC = "TEST-TOPIC-TCP-ASYNC"; - String BROADCAST_TOPIC = "TEST-TOPIC-TCP-BROADCAST"; + public static final String SYNC_TOPIC = "TEST-TOPIC-TCP-SYNC"; + public static final String ASYNC_TOPIC = "TEST-TOPIC-TCP-ASYNC"; + public static final String BROADCAST_TOPIC = "TEST-TOPIC-TCP-BROADCAST"; } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientGlobal.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientGlobal.java index 65e14fd2fa..7d88ede523 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientGlobal.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/ClientGlobal.java @@ -19,19 +19,16 @@ import java.util.TimeZone; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class ClientGlobal { - private static Logger logger = LoggerFactory.getLogger(ClientGlobal.class); - public static ClientGlobal INSTANCE = new ClientGlobal(); public static ClientGlobal getInstance() { @@ -51,6 +48,6 @@ public void init() { jsonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); jsonMapper.setTimeZone(TimeZone.getDefault()); this.jsonMapper = jsonMapper; - logger.info("ClientGlobal init success"); + log.info("ClientGlobal init success"); } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Codec.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Codec.java index 1124287c86..26670754df 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Codec.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Codec.java @@ -30,23 +30,23 @@ import java.util.Arrays; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.ReplayingDecoder; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class Codec { - private static final Logger logger = LoggerFactory.getLogger(Codec.class); private static final int FRAME_MAX_LENGTH = 1024 * 1024 * 4; private static final Charset UTF8 = Charset.forName(EventMeshConstants.DEFAULT_CHARSET); private static final byte[] CONSTANT_MAGIC_FLAG = "EventMesh".getBytes(UTF8); private static final byte[] VERSION = "0000".getBytes(UTF8); public static class Encoder extends MessageToByteEncoder { + @Override public void encode(ChannelHandlerContext ctx, Package pkg, ByteBuf out) throws Exception { byte[] headerData; @@ -58,7 +58,7 @@ public void encode(ChannelHandlerContext ctx, Package pkg, ByteBuf out) throws E headerData = headerJson == null ? null : headerJson.getBytes(UTF8); bodyData = bodyJson == null ? null : bodyJson.getBytes(UTF8); - logger.debug("headerJson={}|bodyJson={}", headerJson, bodyJson); + log.debug("headerJson={}|bodyJson={}", headerJson, bodyJson); int headerLength = headerData == null ? 0 : headerData.length; int bodyLength = bodyData == null ? 0 : bodyData.length; @@ -83,6 +83,7 @@ public void encode(ChannelHandlerContext ctx, Package pkg, ByteBuf out) throws E } public static class Decoder extends ReplayingDecoder { + @Override public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { Header header = null; @@ -93,7 +94,7 @@ public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) thro int bodyLength = 0; try { - if (null == in) { + if (in == null) { return; } @@ -104,9 +105,9 @@ public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) thro in.readBytes(versionBytes); if (!Arrays.equals(flagBytes, CONSTANT_MAGIC_FLAG) || !Arrays.equals(versionBytes, VERSION)) { String errorMsg = String.format("invalid magic flag or " - + - "version|flag=%s|version=%s|remoteAddress=%s", new String(flagBytes, UTF8), - new String(versionBytes, UTF8), ctx.channel().remoteAddress()); + + + "version|flag=%s|version=%s|remoteAddress=%s", new String(flagBytes, UTF8), + new String(versionBytes, UTF8), ctx.channel().remoteAddress()); throw new Exception(errorMsg); } @@ -126,13 +127,13 @@ public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) thro body = parseFromJson(header.getCommand(), new String(bodyData, UTF8)); } - logger.debug("headerJson={}|bodyJson={}", new String(headerData, UTF8), new String(bodyData, UTF8)); + log.debug("headerJson={}|bodyJson={}", new String(headerData, UTF8), new String(bodyData, UTF8)); Package pkg = new Package(header, body); out.add(pkg); } catch (Exception e) { - logger.error("decode|length={}|headerLength={}|bodyLength={}|header={}|body={}.", length, - headerLength, bodyLength, header, body); + log.error("decode|length={}|headerLength={}|bodyLength={}|header={}|body={}.", length, + headerLength, bodyLength, header, body); throw e; } } @@ -142,20 +143,20 @@ private static Object parseFromJson(Command cmd, String data) throws Exception { if (cmd == Command.HELLO_REQUEST || cmd == Command.RECOMMEND_REQUEST) { return ClientGlobal.jsonMapper.readValue(data, UserAgent.class); } else if (cmd == Command.SUBSCRIBE_REQUEST - || cmd == Command.UNSUBSCRIBE_REQUEST) { + || cmd == Command.UNSUBSCRIBE_REQUEST) { return ClientGlobal.jsonMapper.readValue(data, Subscription.class); } else if (cmd == Command.REQUEST_TO_SERVER - || cmd == Command.REQUEST_TO_CLIENT - || cmd == Command.RESPONSE_TO_SERVER - || cmd == Command.RESPONSE_TO_CLIENT - || cmd == Command.ASYNC_MESSAGE_TO_SERVER - || cmd == Command.ASYNC_MESSAGE_TO_CLIENT - || cmd == Command.BROADCAST_MESSAGE_TO_SERVER - || cmd == Command.BROADCAST_MESSAGE_TO_CLIENT - || cmd == Command.BROADCAST_MESSAGE_TO_CLIENT_ACK - || cmd == Command.ASYNC_MESSAGE_TO_CLIENT_ACK - || cmd == Command.REQUEST_TO_CLIENT_ACK - || cmd == Command.RESPONSE_TO_CLIENT_ACK) { + || cmd == Command.REQUEST_TO_CLIENT + || cmd == Command.RESPONSE_TO_SERVER + || cmd == Command.RESPONSE_TO_CLIENT + || cmd == Command.ASYNC_MESSAGE_TO_SERVER + || cmd == Command.ASYNC_MESSAGE_TO_CLIENT + || cmd == Command.BROADCAST_MESSAGE_TO_SERVER + || cmd == Command.BROADCAST_MESSAGE_TO_CLIENT + || cmd == Command.BROADCAST_MESSAGE_TO_CLIENT_ACK + || cmd == Command.ASYNC_MESSAGE_TO_CLIENT_ACK + || cmd == Command.REQUEST_TO_CLIENT_ACK + || cmd == Command.RESPONSE_TO_CLIENT_ACK) { return ClientGlobal.jsonMapper.readValue(data, EventMeshMessage.class); } else if (cmd == Command.REDIRECT_TO_CLIENT) { return ClientGlobal.jsonMapper.readValue(data, RedirectInfo.class); diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/MessageUtils.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/MessageUtils.java index 57cde17a68..b20e5d36fd 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/MessageUtils.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/MessageUtils.java @@ -32,11 +32,12 @@ import java.util.concurrent.ThreadLocalRandom; public class MessageUtils { + public static final int seqLength = 10; public static Package hello(UserAgent user) { Package msg = new Package(); - msg.setHeader(new Header(Command.HELLO_REQUEST, 0, "sucess", generateRandomString(seqLength))); + msg.setHeader(new Header(Command.HELLO_REQUEST, 0, "success", generateRandomString(seqLength))); msg.setBody(user); return msg; } @@ -144,7 +145,7 @@ public static Package responseToClientAck(Package in) { public static UserAgent generatePubClient() { UserAgent user = new UserAgent(); - user.setHost("127.0.0.1"); + user.setHost("localhost"); user.setPassword(generateRandomString(8)); user.setUsername("PU4283"); user.setPath("/data/app/umg_proxy"); @@ -158,7 +159,7 @@ public static UserAgent generatePubClient() { public static UserAgent generateSubServer() { UserAgent user = new UserAgent(); - user.setHost("127.0.0.1"); + user.setHost("localhost"); user.setPassword(generateRandomString(8)); user.setUsername("PU4283"); user.setPath("/data/app/umg_proxy"); @@ -229,9 +230,8 @@ public static String generateRandomString(int length) { public static Package askRecommend(UserAgent user) { Package msg = new Package(); - msg.setHeader(new Header(Command.RECOMMEND_REQUEST, 0, "sucess", generateRandomString(seqLength))); + msg.setHeader(new Header(Command.RECOMMEND_REQUEST, 0, "success", generateRandomString(seqLength))); msg.setBody(user); return msg; } } - diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/RequestContext.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/RequestContext.java index 63044dbe79..3991364059 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/RequestContext.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/RequestContext.java @@ -21,13 +21,11 @@ import java.util.concurrent.CountDownLatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class RequestContext { - private static Logger logger = LoggerFactory.getLogger(RequestContext.class); - private Object key; private Package request; private Package response; @@ -78,11 +76,11 @@ public void finish(Package msg) { public static RequestContext context(Object key, Package request, CountDownLatch latch) throws Exception { RequestContext c = new RequestContext(key, request, latch); - logger.info("_RequestContext|create|key=" + key); + log.info("_RequestContext|create|key={}", key); return c; } - public static Object key(Package request) { + public static Object getHeaderSeq(Package request) { return request.getHeader().getSeq(); } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Server.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Server.java index d52eecc830..8c69fd522f 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Server.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/Server.java @@ -18,11 +18,10 @@ package org.apache.eventmesh.runtime.client.common; import org.apache.eventmesh.runtime.boot.EventMeshServer; -import org.apache.eventmesh.runtime.configuration.EventMeshHTTPConfiguration; public class Server { - EventMeshServer server; + private transient EventMeshServer eventMeshServer; static { System.setProperty("proxy.home", "E:\\projects\\external-1\\proxy"); @@ -32,14 +31,11 @@ public class Server { } public void startAccessServer() throws Exception { - EventMeshHTTPConfiguration eventMeshHttpConfiguration = new EventMeshHTTPConfiguration(null); - eventMeshHttpConfiguration.init(); - server = new EventMeshServer(eventMeshHttpConfiguration, null, null); - server.init(); - server.start(); + eventMeshServer = new EventMeshServer(); + eventMeshServer.start(); } public void shutdownAccessServer() throws Exception { - server.shutdown(); + eventMeshServer.shutdown(); } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/TCPClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/TCPClient.java index e3ec52243e..f2f6a01bd6 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/TCPClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/TCPClient.java @@ -17,6 +17,7 @@ package org.apache.eventmesh.runtime.client.common; +import org.apache.eventmesh.common.EventMeshThreadFactory; import org.apache.eventmesh.common.protocol.tcp.Package; import java.io.Closeable; @@ -25,13 +26,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.PooledByteBufAllocator; @@ -48,49 +44,30 @@ import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; +import lombok.extern.slf4j.Slf4j; /** - * one Client connects one ACCESS - * Provides the most basic connection, send capability, and cannot provide disconnected reconnection capability, - * The service is request-dependent. If the disconnection and reconnection capability is provided, - * it will cause business insensitivity, that is, it will not follow the business reconnection logic. + * one Client connects one ACCESS Provides the most basic connection, send capability, and cannot provide disconnected reconnection capability, The + * service is request-dependent. If the disconnection and reconnection capability is provided, it will cause business insensitivity, that is, it will + * not follow the business reconnection logic. */ +@Slf4j public abstract class TCPClient implements Closeable { public int clientNo = (new Random()).nextInt(1000); protected ConcurrentHashMap contexts = new ConcurrentHashMap<>(); - private Logger logger = LoggerFactory.getLogger(this.getClass()); - protected String host = "127.0.0.1"; protected int port = 10000; - private Bootstrap bootstrap = new Bootstrap(); + private final Bootstrap bootstrap = new Bootstrap(); protected static final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(4, - new ThreadFactory() { - AtomicInteger count = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "TCPClientScheduler-" + count.incrementAndGet()); - t.setDaemon(true); - return t; - } - } - ); + new EventMeshThreadFactory("TCPClientScheduler", true)); - private NioEventLoopGroup workers = new NioEventLoopGroup(8, new ThreadFactory() { - AtomicInteger count = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "TCPClientWorker-" + count.incrementAndGet()); - return t; - } - }); + private final NioEventLoopGroup workers = new NioEventLoopGroup(8, new EventMeshThreadFactory("TCPClientWorker")); public Channel channel; @@ -107,7 +84,7 @@ protected void send(Package msg) throws Exception { if (channel.isWritable()) { channel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> { if (!future.isSuccess()) { - logger.warn("send msg failed", future.isSuccess(), future.cause()); + log.warn("send msg failed: {}, {}", future.isSuccess(), future.cause()); } }); } else { @@ -120,13 +97,13 @@ protected Package io(Package msg, long timeout) throws Exception { send(msg); return null; } else { - Object key = RequestContext.key(msg); + Object key = RequestContext.getHeaderSeq(msg); CountDownLatch latch = new CountDownLatch(1); RequestContext c = RequestContext.context(key, msg, latch); if (!contexts.contains(c)) { contexts.put(key, c); } else { - logger.info("duplicate key : {}", key); + log.info("duplicate key : {}", key); } send(msg); if (!c.getLatch().await(timeout, TimeUnit.MILLISECONDS)) { @@ -141,22 +118,23 @@ protected synchronized void open(SimpleChannelInboundHandler handler) t bootstrap.group(workers); bootstrap.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1_000) - .option(ChannelOption.SO_KEEPALIVE, false) - .option(ChannelOption.SO_SNDBUF, 64 * 1024) - .option(ChannelOption.SO_RCVBUF, 64 * 1024) - .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1024, 8192, 65536)) - .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); + .option(ChannelOption.SO_KEEPALIVE, Boolean.FALSE) + .option(ChannelOption.SO_SNDBUF, 64 * 1024) + .option(ChannelOption.SO_RCVBUF, 64 * 1024) + .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1024, 8192, 65536)) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); bootstrap.handler(new ChannelInitializer() { + public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new Codec.Encoder(), new Codec.Decoder()) - .addLast(handler, newExceptionHandler()); + .addLast(handler, newExceptionHandler()); } }); ChannelFuture f = bootstrap.connect(host, port).sync(); InetSocketAddress localAddress = (InetSocketAddress) f.channel().localAddress(); channel = f.channel(); - logger.info("connected|local={}:{}|server={}", localAddress.getAddress().getHostAddress(), localAddress.getPort(), host + ":" + port); + log.info("connected|local={}:{}|server={}", localAddress.getAddress().getHostAddress(), localAddress.getPort(), host + ":" + port); } protected synchronized void reconnect() throws Exception { @@ -166,9 +144,10 @@ protected synchronized void reconnect() throws Exception { private ChannelDuplexHandler newExceptionHandler() { return new ChannelDuplexHandler() { + @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - logger.warn("exceptionCaught, close connection.|remote address={}", ctx.channel().remoteAddress(), cause); + log.warn("exceptionCaught, close connection.|remote address={}", ctx.channel().remoteAddress(), cause); ctx.close(); } }; @@ -179,7 +158,7 @@ public synchronized void close() { try { channel.disconnect().sync(); } catch (InterruptedException e) { - logger.warn("close tcp client failed.|remote address={}", channel.remoteAddress(), e); + log.warn("close tcp client failed.|remote address={}", channel.remoteAddress(), e); } workers.shutdownGracefully(); } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/UserAgentUtils.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/UserAgentUtils.java index a916a91679..500008dd7e 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/UserAgentUtils.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/common/UserAgentUtils.java @@ -23,6 +23,7 @@ import java.util.concurrent.ThreadLocalRandom; public class UserAgentUtils { + public static UserAgent createPubUserAgent() { UserAgent userAgent = new UserAgent(); userAgent.setSubsystem("5023"); @@ -42,8 +43,6 @@ public static UserAgent createPubUserAgent() { public static UserAgent createUserAgent() { UserAgent userAgent = new UserAgent(); userAgent.setSubsystem("5123"); - //userAgent.setPid(UtilAll.getPid()); - //userAgent.setHost(RemotingUtil.getLocalAddress()); userAgent.setVersion("2.0.8"); userAgent.setUsername("username"); userAgent.setPassword("1234"); @@ -53,13 +52,11 @@ public static UserAgent createUserAgent() { public static UserAgent createSubUserAgent() { UserAgent userAgent = new UserAgent(); userAgent.setSubsystem("5243"); - //userAgent.setPid(UtilAll.getPid()); - //userAgent.setHost(RemotingUtil.getLocalAddress()); userAgent.setPort(8888); userAgent.setVersion("2.0.8"); userAgent.setUsername("username"); userAgent.setPassword("1234"); - userAgent.setPath("/data/app/defibus-acl/"); + userAgent.setPath("/data/app/acl/"); userAgent.setPurpose(EventMeshConstants.PURPOSE_SUB); return userAgent; } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java index a3364795dd..a81dc7e566 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/hook/ReceiveMsgHook.java @@ -25,5 +25,6 @@ * Business callback hook, which is a callback for all types of messages */ public interface ReceiveMsgHook { + void handle(Package msg, ChannelHandlerContext ctx); } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java index 5536c2eaf5..25798b4d6e 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/EventMeshClientImpl.java @@ -28,6 +28,7 @@ import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; public class EventMeshClientImpl implements EventMeshClient { + protected UserAgent agent; private String accessHost; private int accessPort; @@ -83,13 +84,13 @@ public Package listen() throws Exception { @Override public Package justSubscribe(String topic, SubscriptionMode subscriptionMode, - SubscriptionType subscriptionType) throws Exception { + SubscriptionType subscriptionType) throws Exception { return this.subClient.justSubscribe(topic, subscriptionMode, subscriptionType); } @Override public Package justUnsubscribe(String topic, SubscriptionMode subscriptionMode, - SubscriptionType subscriptionType) throws Exception { + SubscriptionType subscriptionType) throws Exception { return this.subClient.justUnsubscribe(topic, subscriptionMode, subscriptionType); } @@ -104,36 +105,38 @@ public void registerPubBusiHandler(ReceiveMsgHook handler) throws Exception { @Override public String toString() { return "AccessClientImpl{" - + - "accessHost='" + accessHost + '\'' - + - ", accessPort=" + accessPort - + - ", agent=" + agent - + - '}'; + + + "accessHost='" + accessHost + '\'' + + + ", accessPort=" + accessPort + + + ", agent=" + agent + + + '}'; } @Deprecated public EventMeshClientImpl(String accessServer, String busiTag, String subSystem) { - //this.accessServer = accessServer; - //this.pubClient = new PubClientImpl(StringUtils.split(this.accessServer, ":")[0], - // Integer.parseInt(StringUtils.split(this.accessServer, ":")[1]), OldTestUserAgentFactory.createPubUserAgent - // (busiTag, subSystem)); - //this.subClient = new SubClientImpl(StringUtils.split(this.accessServer, ":")[0], - // Integer.parseInt(StringUtils.split(this.accessServer, ":")[1]), OldTestUserAgentFactory.createSubUserAgent - // (busiTag, subSystem)); - } - - //@Override - //public void sysLog() throws Exception { - // subClient.sysLog(); - //} - // - //@Override - //public void traceLog() throws Exception { - // subClient.traceLog(); - //} + // this.accessServer = accessServer; + // this.pubClient = new PubClientImpl(StringUtils.split(this.accessServer, ":")[0], + // Integer.parseInt(StringUtils.split(this.accessServer, ":")[1]), OldTestUserAgentFactory.createPubUserAgent + // (busiTag, subSystem)); + // this.subClient = new SubClientImpl(StringUtils.split(this.accessServer, ":")[0], + // Integer.parseInt(StringUtils.split(this.accessServer, ":")[1]), OldTestUserAgentFactory.createSubUserAgent + // (busiTag, subSystem)); + } + + /** + * @Override + * public void sysLog() throws Exception { + * subClient.sysLog(); + * } + * + *@Override + *public void traceLog() throws Exception { + * subClient.traceLog(); + *} + */ @Override public void goodbye() throws Exception { diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/PubClientImpl.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/PubClientImpl.java index 2e76d7febe..8735674546 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/PubClientImpl.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/PubClientImpl.java @@ -31,19 +31,18 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.Assertions; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; -public class PubClientImpl extends TCPClient implements PubClient { +import lombok.extern.slf4j.Slf4j; - private Logger publogger = LoggerFactory.getLogger(this.getClass()); +@Slf4j +public class PubClientImpl extends TCPClient implements PubClient { - private UserAgent userAgent; + private final UserAgent userAgent; private ReceiveMsgHook callback; @@ -61,7 +60,7 @@ public void registerBusiHandler(ReceiveMsgHook handler) throws Exception { public void init() throws Exception { open(new Handler()); hello(); - publogger.info("PubClientImpl|{}|started!", clientNo); + log.info("PubClientImpl|{}|started!", clientNo); } public void reconnect() throws Exception { @@ -74,24 +73,21 @@ public void close() { task.cancel(false); super.close(); } catch (Exception e) { - e.printStackTrace(); + log.error("PubClientImpl|{}|close failed!", clientNo, e); } } public void heartbeat() throws Exception { - task = scheduler.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - try { - if (!isActive()) { - PubClientImpl.this.reconnect(); - } - Package msg = MessageUtils.heartBeat(); - publogger.debug("PubClientImpl|{}|send heartbeat|Command={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); - PubClientImpl.this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); - } catch (Exception e) { - //ignore + task = scheduler.scheduleAtFixedRate(() -> { + try { + if (!isActive()) { + PubClientImpl.this.reconnect(); } + Package msg = MessageUtils.heartBeat(); + log.debug("PubClientImpl|{}|send heartbeat|Command={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + PubClientImpl.this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); + } catch (Exception ignored) { + // ignore } }, ClientConstants.HEARTBEAT, ClientConstants.HEARTBEAT, TimeUnit.MILLISECONDS); } @@ -116,7 +112,7 @@ private void hello() throws Exception { */ @Override public Package rr(Package msg, long timeout) throws Exception { - publogger.info("PubClientImpl|{}|rr|send|Command={}|msg={}", clientNo, msg.getHeader().getCommand().REQUEST_TO_SERVER, msg); + log.info("PubClientImpl|{}|rr|send|Command={}|msg={}", clientNo, Command.REQUEST_TO_SERVER, msg); return dispatcher(msg, timeout); } @@ -124,31 +120,31 @@ public Package rr(Package msg, long timeout) throws Exception { * Add test case assertions on the basis of the original IO */ public Package dispatcher(Package request, long timeout) throws Exception { - Assert.assertNotNull(request); + Assertions.assertNotNull(request); Package response = super.io(request, timeout); - Assert.assertNotNull(response); + Assertions.assertNotNull(response); Command cmd = response.getHeader().getCommand(); switch (request.getHeader().getCommand()) { case RECOMMEND_REQUEST: - Assert.assertEquals(cmd, Command.RECOMMEND_RESPONSE); + Assertions.assertEquals(Command.RECOMMEND_RESPONSE, cmd); break; case HELLO_REQUEST: - Assert.assertEquals(cmd, Command.HELLO_RESPONSE); + Assertions.assertEquals(Command.HELLO_RESPONSE, cmd); break; case HEARTBEAT_REQUEST: - Assert.assertEquals(cmd, Command.HEARTBEAT_RESPONSE); + Assertions.assertEquals(Command.HEARTBEAT_RESPONSE, cmd); break; case CLIENT_GOODBYE_REQUEST: - Assert.assertEquals(cmd, Command.CLIENT_GOODBYE_RESPONSE); + Assertions.assertEquals(Command.CLIENT_GOODBYE_RESPONSE, cmd); break; case BROADCAST_MESSAGE_TO_SERVER: - Assert.assertEquals(cmd, Command.BROADCAST_MESSAGE_TO_SERVER_ACK); + Assertions.assertEquals(Command.BROADCAST_MESSAGE_TO_SERVER_ACK, cmd); break; case ASYNC_MESSAGE_TO_SERVER: - Assert.assertEquals(cmd, Command.ASYNC_MESSAGE_TO_SERVER_ACK); + Assertions.assertEquals(Command.ASYNC_MESSAGE_TO_SERVER_ACK, cmd); break; case REQUEST_TO_SERVER: - Assert.assertEquals(cmd, Command.RESPONSE_TO_CLIENT); + Assertions.assertEquals(Command.RESPONSE_TO_CLIENT, cmd); break; default: break; @@ -161,7 +157,7 @@ public Package dispatcher(Package request, long timeout) throws Exception { * Send an event message, the return value is ACCESS and ACK is given */ public Package publish(Package msg, long timeout) throws Exception { - publogger.info("PubClientImpl|{}|publish|send|command={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + log.info("PubClientImpl|{}|publish|send|command={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); return dispatcher(msg, timeout); } @@ -169,7 +165,7 @@ public Package publish(Package msg, long timeout) throws Exception { * send broadcast message */ public Package broadcast(Package msg, long timeout) throws Exception { - publogger.info("PubClientImpl|{}|broadcast|send|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + log.info("PubClientImpl|{}|broadcast|send|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); return dispatcher(msg, timeout); } @@ -180,9 +176,10 @@ public UserAgent getUserAgent() { @ChannelHandler.Sharable private class Handler extends SimpleChannelInboundHandler { + @Override protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Exception { - publogger.info("PubClientImpl|{}|receive|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + log.info("PubClientImpl|{}|receive|type={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); Command cmd = msg.getHeader().getCommand(); if (callback != null) { callback.handle(msg, ctx); @@ -193,27 +190,23 @@ protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Excep if (cmd == Command.RESPONSE_TO_CLIENT) { Package responseToClientAck = MessageUtils.responseToClientAck(msg); send(responseToClientAck); - RequestContext context = contexts.get(RequestContext.key(msg)); + RequestContext context = contexts.get(RequestContext.getHeaderSeq(msg)); if (context != null) { contexts.remove(context.getKey()); context.finish(msg); - return; } else { - publogger.error("msg ignored,context not found .|{}|{}", cmd, msg); - return; + log.warn("msg ignored,context not found.|{}|{}", cmd, msg); } } else if (cmd == Command.SERVER_GOODBYE_REQUEST) { - publogger.error("server goodby request: ---------------------------" + msg); + log.error("server goodbye request: ---------------------------{}", msg); close(); } else { - RequestContext context = contexts.get(RequestContext.key(msg)); + RequestContext context = contexts.get(RequestContext.getHeaderSeq(msg)); if (context != null) { contexts.remove(context.getKey()); context.finish(msg); - return; } else { - publogger.error("msg ignored,context not found .|{}|{}", cmd, msg); - return; + log.warn("msg ignored,context not found.|{}|{}", cmd, msg); } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/SubClientImpl.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/SubClientImpl.java index 6af8b4c0eb..841676f027 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/SubClientImpl.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/client/impl/SubClientImpl.java @@ -38,25 +38,24 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.Assertions; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; -public class SubClientImpl extends TCPClient implements SubClient { +import lombok.extern.slf4j.Slf4j; - private static final Logger logger = LoggerFactory.getLogger(SubClientImpl.class); +@Slf4j +public class SubClientImpl extends TCPClient implements SubClient { - private UserAgent userAgent; + private final transient UserAgent userAgent; - private ReceiveMsgHook callback; + private transient ReceiveMsgHook callback; - private List subscriptionItems = new ArrayList(); + private final transient List subscriptionItems = new ArrayList(); - private ScheduledFuture task; + private transient ScheduledFuture task; public SubClientImpl(String accessIp, int port, UserAgent agent) { super(accessIp, port); @@ -70,7 +69,7 @@ public void registerBusiHandler(ReceiveMsgHook handler) throws Exception { public void init() throws Exception { open(new Handler()); hello(); - logger.info("SubClientImpl|{}|started!", clientNo); + log.info("SubClientImpl|{}|started!", clientNo); } public void reconnect() throws Exception { @@ -90,24 +89,21 @@ public void close() { task.cancel(false); super.close(); } catch (Exception e) { - e.printStackTrace(); + log.error("cancel close err", e); } } public void heartbeat() throws Exception { - task = scheduler.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - try { - if (!isActive()) { - SubClientImpl.this.reconnect(); - } - Package msg = MessageUtils.heartBeat(); - logger.debug("SubClientImpl|{}|send heartbeat|Command={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); - SubClientImpl.this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); - } catch (Exception e) { - //ignore + task = scheduler.scheduleAtFixedRate(() -> { + try { + if (!isActive()) { + SubClientImpl.this.reconnect(); } + Package msg = MessageUtils.heartBeat(); + log.debug("SubClientImpl|{}|send heartbeat|Command={}|msg={}", clientNo, msg.getHeader().getCommand(), msg); + SubClientImpl.this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); + } catch (Exception e) { + // ignore } }, ClientConstants.HEARTBEAT, ClientConstants.HEARTBEAT, TimeUnit.MILLISECONDS); } @@ -122,7 +118,8 @@ private void hello() throws Exception { this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); } - public Package justSubscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) throws Exception { + public Package justSubscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) + throws Exception { subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); Package msg = MessageUtils.subscribe(topic, subscriptionMode, subscriptionType); return this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); @@ -133,19 +130,24 @@ public Package listen() throws Exception { return this.dispatcher(request, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); } - //@Override - //public void traceLog() throws Exception { - // Package msg = MessageUtils.traceLog(); - // this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); - //} - - //public void sysLog() throws Exception { - // Package msg = MessageUtils.sysLog(); - // this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); - //} + /** + * @Override + * public void traceLog() throws Exception { + * Package msg = MessageUtils.traceLog(); + * this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); + * } + */ + + /** + * + * public void sysLog() throws Exception { + * Package msg = MessageUtils.sysLog(); + * this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); + * } + */ public Package justUnsubscribe(String topic, SubscriptionMode subscriptionMode, - SubscriptionType subscriptionType) throws Exception { + SubscriptionType subscriptionType) throws Exception { subscriptionItems.remove(topic); Package msg = MessageUtils.unsubscribe(topic, subscriptionMode, subscriptionType); return this.dispatcher(msg, ClientConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); @@ -156,48 +158,47 @@ public UserAgent getUserAgent() { } public Package dispatcher(Package request, long timeout) throws Exception { - Assert.assertNotNull(request); + Assertions.assertNotNull(request); Package response = super.io(request, timeout); switch (request.getHeader().getCommand()) { case HELLO_REQUEST: - Assert.assertEquals(response.getHeader().getCommand(), Command.HELLO_RESPONSE); + Assertions.assertEquals(Command.HELLO_RESPONSE, response.getHeader().getCommand()); break; case HEARTBEAT_REQUEST: - Assert.assertEquals(response.getHeader().getCommand(), Command.HEARTBEAT_RESPONSE); + Assertions.assertEquals(Command.HEARTBEAT_RESPONSE, response.getHeader().getCommand()); break; case LISTEN_REQUEST: - Assert.assertEquals(response.getHeader().getCommand(), Command.LISTEN_RESPONSE); + Assertions.assertEquals(Command.LISTEN_RESPONSE, response.getHeader().getCommand()); break; case CLIENT_GOODBYE_REQUEST: - Assert.assertEquals(response.getHeader().getCommand(), Command.CLIENT_GOODBYE_RESPONSE); + Assertions.assertEquals(Command.CLIENT_GOODBYE_RESPONSE, response.getHeader().getCommand()); break; case SUBSCRIBE_REQUEST: - Assert.assertEquals(response.getHeader().getCommand(), Command.SUBSCRIBE_RESPONSE); + Assertions.assertEquals(Command.SUBSCRIBE_RESPONSE, response.getHeader().getCommand()); break; case UNSUBSCRIBE_REQUEST: - Assert.assertEquals(response.getHeader().getCommand(), Command.UNSUBSCRIBE_RESPONSE); + Assertions.assertEquals(Command.UNSUBSCRIBE_RESPONSE, response.getHeader().getCommand()); break; case SYS_LOG_TO_LOGSERVER: - Assert.assertNull(response); - break; case TRACE_LOG_TO_LOGSERVER: - Assert.assertNull(response); + Assertions.assertNull(response); break; default: break; } if (response != null) { - assert response.getHeader().getCode() == OPStatus.SUCCESS.getCode(); + Assertions.assertEquals(OPStatus.SUCCESS.getCode(), response.getHeader().getCode()); } return response; } @ChannelHandler.Sharable private class Handler extends SimpleChannelInboundHandler { + @SuppressWarnings("Duplicates") @Override protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Exception { - logger.info(SubClientImpl.class.getSimpleName() + "|receive|command={}|msg={}", msg.getHeader().getCommand(), msg); + log.info(SubClientImpl.class.getSimpleName() + "|receive|command={}|msg={}", msg.getHeader().getCommand(), msg); Command cmd = msg.getHeader().getCommand(); if (callback != null) { callback.handle(msg, ctx); @@ -209,33 +210,33 @@ protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Excep Package responsePKG = MessageUtils.rrResponse(msg); send(responsePKG); } catch (Exception e) { - logger.info("send rr request to client ack failed"); + log.error("send rr request to client ack failed", e); } } else if (cmd == Command.ASYNC_MESSAGE_TO_CLIENT) { Package asyncAck = MessageUtils.asyncMessageAck(msg); try { send(asyncAck); } catch (Exception e) { - logger.info("send async request to client ack failed"); + log.error("send async request to client ack failed", e); } } else if (cmd == Command.BROADCAST_MESSAGE_TO_CLIENT) { Package broadcastAck = MessageUtils.broadcastMessageAck(msg); try { send(broadcastAck); } catch (Exception e) { - logger.info("send broadcast request to client ack failed"); + log.error("send broadcast request to client ack failed", e); } } else if (cmd == Command.SERVER_GOODBYE_REQUEST) { - logger.error("server goodby request: ---------------------------" + msg); + log.info("server goodby request: ---------------------------" + msg); close(); } else { - //control instruction set - RequestContext context = contexts.get(RequestContext.key(msg)); + // control instruction set + RequestContext context = contexts.get(RequestContext.getHeaderSeq(msg)); if (context != null) { contexts.remove(context.getKey()); context.finish(msg); } else { - logger.error("msg ignored,context not found.|{}|{}", cmd, msg); + log.warn("msg ignored,context not found.|{}|{}", cmd, msg); } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfigurationTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfigurationTest.java new file mode 100644 index 0000000000..799c0a37cd --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshGrpcConfigurationTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.configuration; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class EventMeshGrpcConfigurationTest { + + @Test + public void testGetConfigForEventMeshGrpcConfiguration() throws Exception { + + ConfigService configService = ConfigService.getInstance(); + configService.setRootConfig("classPath://configuration.properties"); + + EventMeshGrpcConfiguration config = configService.buildConfigInstance(EventMeshGrpcConfiguration.class); + + assertCommonConfig(config); + assertGrpcConfig(config); + } + + private void assertGrpcConfig(EventMeshGrpcConfiguration config) { + Assertions.assertEquals(816, config.getGrpcServerPort()); + Assertions.assertEquals(1816, config.getEventMeshSessionExpiredInMills()); + Assertions.assertEquals(Boolean.FALSE, config.isEventMeshServerBatchMsgBatchEnabled()); + Assertions.assertEquals(2816, config.getEventMeshServerBatchMsgThreadNum()); + Assertions.assertEquals(3816, config.getEventMeshServerSendMsgThreadNum()); + Assertions.assertEquals(4816, config.getEventMeshServerPushMsgThreadNum()); + Assertions.assertEquals(5816, config.getEventMeshServerReplyMsgThreadNum()); + Assertions.assertEquals(6816, config.getEventMeshServerSubscribeMsgThreadNum()); + Assertions.assertEquals(7816, config.getEventMeshServerMetaStorageThreadNum()); + Assertions.assertEquals(9816, config.getEventMeshServerRetryThreadNum()); + Assertions.assertEquals(11816, config.getEventMeshServerPullMetaStorageInterval()); + Assertions.assertEquals(12816, config.getEventMeshServerAsyncAccumulationThreshold()); + Assertions.assertEquals(13816, config.getEventMeshServerRetryBlockQueueSize()); + Assertions.assertEquals(14816, config.getEventMeshServerBatchBlockQueueSize()); + Assertions.assertEquals(15816, config.getEventMeshServerSendMsgBlockQueueSize()); + Assertions.assertEquals(16816, config.getEventMeshServerPushMsgBlockQueueSize()); + Assertions.assertEquals(17816, config.getEventMeshServerSubscribeMsgBlockQueueSize()); + Assertions.assertEquals(18816, config.getEventMeshServerBusyCheckInterval()); + Assertions.assertEquals(Boolean.TRUE, config.isEventMeshServerConsumerEnabled()); + Assertions.assertEquals(Boolean.TRUE, config.isEventMeshServerUseTls()); + Assertions.assertEquals(21816, config.getEventMeshBatchMsgRequestNumPerSecond()); + Assertions.assertEquals(19816, config.getEventMeshMsgReqNumPerSecond()); + } + + private void assertCommonConfig(CommonConfiguration config) { + Assertions.assertEquals("env-succeed!!!", config.getEventMeshEnv()); + Assertions.assertEquals("idc-succeed!!!", config.getEventMeshIDC()); + Assertions.assertEquals("cluster-succeed!!!", config.getEventMeshCluster()); + Assertions.assertEquals("name-succeed!!!", config.getEventMeshName()); + Assertions.assertEquals("816", config.getSysID()); + Assertions.assertEquals("storage-succeed!!!", config.getEventMeshStoragePluginType()); + Assertions.assertEquals("security-succeed!!!", config.getEventMeshSecurityPluginType()); + Assertions.assertEquals("metaStorage-succeed!!!", config.getEventMeshMetaStoragePluginType()); + Assertions.assertEquals("trace-succeed!!!", config.getEventMeshTracePluginType()); + Assertions.assertEquals("hostIp-succeed!!!", config.getEventMeshServerIp()); + + List list = new ArrayList<>(); + list.add("metrics-succeed1!!!"); + list.add("metrics-succeed2!!!"); + list.add("metrics-succeed3!!!"); + Assertions.assertEquals(list, config.getEventMeshMetricsPluginType()); + + Assertions.assertTrue(config.isEventMeshServerSecurityEnable()); + Assertions.assertTrue(config.isEventMeshServerMetaStorageEnable()); + Assertions.assertTrue(config.isEventMeshServerTraceEnable()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfigurationTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfigurationTest.java new file mode 100644 index 0000000000..4c167a82c1 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshHTTPConfigurationTest.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.configuration; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import inet.ipaddr.AddressStringException; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; + +public class EventMeshHTTPConfigurationTest { + + @Test + public void testGetEventMeshHTTPConfiguration() throws Exception { + + ConfigService configService = ConfigService.getInstance(); + configService.setRootConfig("classPath://configuration.properties"); + + EventMeshHTTPConfiguration config = configService.buildConfigInstance(EventMeshHTTPConfiguration.class); + + assertCommonConfig(config); + assertHTTPConfig(config); + } + + private void assertHTTPConfig(EventMeshHTTPConfiguration config) throws AddressStringException { + Assertions.assertEquals(1816, config.getHttpServerPort()); + Assertions.assertEquals(Boolean.FALSE, config.isEventMeshServerBatchMsgBatchEnabled()); + Assertions.assertEquals(2816, config.getEventMeshServerBatchMsgThreadNum()); + Assertions.assertEquals(3816, config.getEventMeshServerSendMsgThreadNum()); + Assertions.assertEquals(4816, config.getEventMeshServerPushMsgThreadNum()); + Assertions.assertEquals(5816, config.getEventMeshServerReplyMsgThreadNum()); + Assertions.assertEquals(6816, config.getEventMeshServerClientManageThreadNum()); + Assertions.assertEquals(7816, config.getEventMeshServerMetaStorageThreadNum()); + + Assertions.assertEquals(9816, config.getEventMeshServerRetryThreadNum()); + Assertions.assertEquals(11816, config.getEventMeshServerPullMetaStorageInterval()); + Assertions.assertEquals(12816, config.getEventMeshServerAsyncAccumulationThreshold()); + Assertions.assertEquals(13816, config.getEventMeshServerRetryBlockQSize()); + Assertions.assertEquals(14816, config.getEventMeshServerBatchBlockQSize()); + Assertions.assertEquals(15816, config.getEventMeshServerSendMsgBlockQSize()); + Assertions.assertEquals(16816, config.getEventMeshServerPushMsgBlockQSize()); + Assertions.assertEquals(17816, config.getEventMeshServerClientManageBlockQSize()); + Assertions.assertEquals(18816, config.getEventMeshServerBusyCheckInterval()); + Assertions.assertEquals(Boolean.TRUE, config.isEventMeshServerConsumerEnabled()); + Assertions.assertEquals(Boolean.TRUE, config.isEventMeshServerUseTls()); + Assertions.assertEquals(19816, config.getEventMeshHttpMsgReqNumPerSecond()); + Assertions.assertEquals(21816, config.getEventMeshBatchMsgRequestNumPerSecond()); + Assertions.assertEquals(22816, config.getEventMeshEventSize()); + Assertions.assertEquals(23816, config.getEventMeshEventBatchSize()); + + List list4 = new ArrayList<>(); + list4.add(new IPAddressString("127.0.0.1").toAddress()); + list4.add(new IPAddressString("127.0.0.2").toAddress()); + Assertions.assertEquals(list4, config.getEventMeshIpv4BlackList()); + List list6 = new ArrayList<>(); + list6.add(new IPAddressString("0:0:0:0:0:0:7f00:01").toAddress()); + list6.add(new IPAddressString("0:0:0:0:0:0:7f00:02").toAddress()); + Assertions.assertEquals(list6, config.getEventMeshIpv6BlackList()); + } + + private void assertCommonConfig(CommonConfiguration config) { + Assertions.assertEquals("env-succeed!!!", config.getEventMeshEnv()); + Assertions.assertEquals("idc-succeed!!!", config.getEventMeshIDC()); + Assertions.assertEquals("cluster-succeed!!!", config.getEventMeshCluster()); + Assertions.assertEquals("name-succeed!!!", config.getEventMeshName()); + Assertions.assertEquals("816", config.getSysID()); + Assertions.assertEquals("storage-succeed!!!", config.getEventMeshStoragePluginType()); + Assertions.assertEquals("security-succeed!!!", config.getEventMeshSecurityPluginType()); + Assertions.assertEquals("metaStorage-succeed!!!", config.getEventMeshMetaStoragePluginType()); + Assertions.assertEquals("trace-succeed!!!", config.getEventMeshTracePluginType()); + Assertions.assertEquals("hostIp-succeed!!!", config.getEventMeshServerIp()); + + List list = new ArrayList<>(); + list.add("metrics-succeed1!!!"); + list.add("metrics-succeed2!!!"); + list.add("metrics-succeed3!!!"); + Assertions.assertEquals(list, config.getEventMeshMetricsPluginType()); + + Assertions.assertTrue(config.isEventMeshServerSecurityEnable()); + Assertions.assertTrue(config.isEventMeshServerMetaStorageEnable()); + Assertions.assertTrue(config.isEventMeshServerTraceEnable()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfigurationTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfigurationTest.java new file mode 100644 index 0000000000..9669adf0d7 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/configuration/EventMeshTCPConfigurationTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.configuration; + +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.config.ConfigService; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class EventMeshTCPConfigurationTest { + + @Test + public void testGetEventMeshTCPConfiguration() throws Exception { + + ConfigService configService = ConfigService.getInstance(); + configService.setRootConfig("classPath://configuration.properties"); + + EventMeshTCPConfiguration config = configService.buildConfigInstance(EventMeshTCPConfiguration.class); + + assertCommonConfig(config); + assertTCPConfig(config); + } + + private void assertTCPConfig(EventMeshTCPConfiguration config) { + Assertions.assertEquals(816, config.getEventMeshTcpServerPort()); + Assertions.assertEquals(1816, config.getEventMeshTcpIdleAllSeconds()); + Assertions.assertEquals(2816, config.getEventMeshTcpIdleWriteSeconds()); + Assertions.assertEquals(3816, config.getEventMeshTcpIdleReadSeconds()); + Assertions.assertEquals(Integer.valueOf(4816), config.getEventMeshTcpMsgReqnumPerSecond()); + Assertions.assertEquals(5816, config.getEventMeshTcpClientMaxNum()); + Assertions.assertEquals(6816, config.getEventMeshTcpGlobalScheduler()); + Assertions.assertEquals(7816, config.getEventMeshTcpTaskHandleExecutorPoolSize()); + Assertions.assertEquals(8816, config.getEventMeshTcpMsgDownStreamExecutorPoolSize()); + Assertions.assertEquals(1816, config.getEventMeshTcpSessionExpiredInMills()); + Assertions.assertEquals(11816, config.getEventMeshTcpSessionUpstreamBufferSize()); + Assertions.assertEquals(12816, config.getEventMeshTcpMsgAsyncRetryTimes()); + Assertions.assertEquals(13816, config.getEventMeshTcpMsgSyncRetryTimes()); + Assertions.assertEquals(14816, config.getEventMeshTcpMsgRetrySyncDelayInMills()); + Assertions.assertEquals(15816, config.getEventMeshTcpMsgRetryAsyncDelayInMills()); + Assertions.assertEquals(16816, config.getEventMeshTcpMsgRetryQueueSize()); + Assertions.assertEquals(Integer.valueOf(17816), config.getEventMeshTcpRebalanceIntervalInMills()); + Assertions.assertEquals(Boolean.TRUE, config.isEventMeshTcpSendBackEnabled()); + Assertions.assertEquals(3, config.getEventMeshTcpSendBackMaxTimes()); + Assertions.assertEquals(21816, config.getEventMeshTcpPushFailIsolateTimeInMills()); + Assertions.assertEquals(22816, config.getGracefulShutdownSleepIntervalInMills()); + Assertions.assertEquals(23816, config.getSleepIntervalInRebalanceRedirectMills()); + Assertions.assertEquals(22816, config.getEventMeshEventSize()); + Assertions.assertEquals(23816, config.getEventMeshEventBatchSize()); + } + + private void assertCommonConfig(CommonConfiguration config) { + Assertions.assertEquals("env-succeed!!!", config.getEventMeshEnv()); + Assertions.assertEquals("idc-succeed!!!", config.getEventMeshIDC()); + Assertions.assertEquals("cluster-succeed!!!", config.getEventMeshCluster()); + Assertions.assertEquals("name-succeed!!!", config.getEventMeshName()); + Assertions.assertEquals("816", config.getSysID()); + Assertions.assertEquals("storage-succeed!!!", config.getEventMeshStoragePluginType()); + Assertions.assertEquals("security-succeed!!!", config.getEventMeshSecurityPluginType()); + Assertions.assertEquals("metaStorage-succeed!!!", config.getEventMeshMetaStoragePluginType()); + Assertions.assertEquals("trace-succeed!!!", config.getEventMeshTracePluginType()); + Assertions.assertEquals("hostIp-succeed!!!", config.getEventMeshServerIp()); + + List list = new ArrayList<>(); + list.add("metrics-succeed1!!!"); + list.add("metrics-succeed2!!!"); + list.add("metrics-succeed3!!!"); + Assertions.assertEquals(list, config.getEventMeshMetricsPluginType()); + + Assertions.assertTrue(config.isEventMeshServerSecurityEnable()); + Assertions.assertTrue(config.isEventMeshServerMetaStorageEnable()); + Assertions.assertTrue(config.isEventMeshServerTraceEnable()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncPubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncPubClient.java index a2dd1d904d..98f1114eac 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncPubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncPubClient.java @@ -17,37 +17,30 @@ package org.apache.eventmesh.runtime.demo; -import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.common.utils.ThreadUtils; import org.apache.eventmesh.runtime.client.common.ClientConstants; import org.apache.eventmesh.runtime.client.common.MessageUtils; import org.apache.eventmesh.runtime.client.common.UserAgentUtils; -import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; import org.apache.eventmesh.runtime.client.impl.PubClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class AsyncPubClient { - private static final Logger logger = LoggerFactory.getLogger(AsyncPubClient.class); - public static void main(String[] args) throws Exception { - PubClientImpl pubClient = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createUserAgent()); - pubClient.init(); - pubClient.heartbeat(); - pubClient.registerBusiHandler(new ReceiveMsgHook() { - @Override - public void handle(Package msg, ChannelHandlerContext ctx) { - logger.error("receive msg-----------------------------" + msg.toString()); + try (PubClientImpl pubClient = + new PubClientImpl("localhost", 10000, UserAgentUtils.createUserAgent())) { + pubClient.init(); + pubClient.heartbeat(); + pubClient.registerBusiHandler((msg, ctx) -> { + log.info("server good by request: {}", msg); + }); + + for (int i = 0; i < 1; i++) { + ThreadUtils.randomPause(0, 500); + pubClient.broadcast(MessageUtils.asyncMessage(ClientConstants.ASYNC_TOPIC, i), 5000); } - }); - - for (int i = 0; i < 1; i++) { - ThreadUtils.randomSleep(0, 500); - pubClient.broadcast(MessageUtils.asyncMessage(ClientConstants.ASYNC_TOPIC, i), 5000); } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncSubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncSubClient.java index 2783e136ed..355d94f71d 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncSubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/AsyncSubClient.java @@ -20,34 +20,27 @@ import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.runtime.client.common.ClientConstants; import org.apache.eventmesh.runtime.client.common.MessageUtils; -import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; import org.apache.eventmesh.runtime.client.impl.SubClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class AsyncSubClient { - private static final Logger logger = LoggerFactory.getLogger(AsyncSubClient.class); - public static void main(String[] args) throws Exception { - SubClientImpl client = new SubClientImpl("127.0.0.1", 10002, MessageUtils.generateSubServer()); - client.init(); - client.heartbeat(); - client.justSubscribe(ClientConstants.ASYNC_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC); - client.registerBusiHandler(new ReceiveMsgHook() { - @Override - public void handle(Package msg, ChannelHandlerContext ctx) { + try (SubClientImpl client = + new SubClientImpl("localhost", 10002, MessageUtils.generateSubServer())) { + client.init(); + client.heartbeat(); + client.justSubscribe(ClientConstants.ASYNC_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC); + client.registerBusiHandler((msg, ctx) -> { if (msg.getBody() instanceof EventMeshMessage) { String body = ((EventMeshMessage) msg.getBody()).getBody(); - logger.error("receive message -------------------------------" + body); + log.info("receive message : {}", body); } - } - }); + }); + } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastPubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastPubClient.java index 5f3fa158bd..805d8ba292 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastPubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastPubClient.java @@ -24,13 +24,16 @@ import org.apache.eventmesh.runtime.client.impl.PubClientImpl; public class BroadCastPubClient { + public static void main(String[] args) throws Exception { - PubClientImpl pubClient = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createUserAgent()); - pubClient.init(); - pubClient.heartbeat(); - for (int i = 0; i < 10000; i++) { - ThreadUtils.randomSleep(0, 500); - pubClient.broadcast(MessageUtils.broadcastMessage(ClientConstants.BROADCAST_TOPIC, i), 5000); + try (PubClientImpl pubClient = + new PubClientImpl("localhost", 10000, UserAgentUtils.createUserAgent())) { + pubClient.init(); + pubClient.heartbeat(); + for (int i = 0; i < 10000; i++) { + ThreadUtils.randomPause(0, 500); + pubClient.broadcast(MessageUtils.broadcastMessage(ClientConstants.BROADCAST_TOPIC, i), 5000); + } } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastSubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastSubClient.java index 8e00541dc0..72ac6d98e2 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastSubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/BroadCastSubClient.java @@ -21,36 +21,28 @@ import org.apache.eventmesh.common.protocol.SubscriptionType; import org.apache.eventmesh.common.protocol.tcp.Command; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.runtime.client.common.ClientConstants; import org.apache.eventmesh.runtime.client.common.MessageUtils; -import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; import org.apache.eventmesh.runtime.client.impl.SubClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class BroadCastSubClient { - private static final Logger logger = LoggerFactory.getLogger(BroadCastSubClient.class); - public static void main(String[] args) throws Exception { - SubClientImpl client = new SubClientImpl("127.0.0.1", 10000, MessageUtils.generateSubServer()); - client.init(); - client.heartbeat(); - client.justSubscribe(ClientConstants.BROADCAST_TOPIC, SubscriptionMode.BROADCASTING, SubscriptionType.ASYNC); - client.registerBusiHandler(new ReceiveMsgHook() { - @Override - public void handle(Package msg, ChannelHandlerContext ctx) { + try (SubClientImpl client = new SubClientImpl("localhost", 10000, MessageUtils.generateSubServer())) { + client.init(); + client.heartbeat(); + client.justSubscribe(ClientConstants.BROADCAST_TOPIC, SubscriptionMode.BROADCASTING, SubscriptionType.ASYNC); + client.registerBusiHandler((msg, ctx) -> { if (msg.getHeader().getCommand() == Command.BROADCAST_MESSAGE_TO_CLIENT) { if (msg.getBody() instanceof EventMeshMessage) { String body = ((EventMeshMessage) msg.getBody()).getBody(); - logger.error("receive message -------------------------------" + body); + log.info("receive message : {}", body); } } - } - }); + }); + } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCPubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCPubClient.java index a05a24ab31..e87f89469d 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCPubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCPubClient.java @@ -25,11 +25,13 @@ public class CCPubClient { public static void main(String[] args) throws Exception { - PubClientImpl pubClient = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createUserAgent()); - pubClient.init(); - pubClient.heartbeat(); + try (PubClientImpl pubClient = + new PubClientImpl("localhost", 10000, UserAgentUtils.createUserAgent())) { + pubClient.init(); + pubClient.heartbeat(); - pubClient.broadcast(MessageUtils.rrMesssage(ClientConstants.ASYNC_TOPIC, 0), 5000); + pubClient.broadcast(MessageUtils.rrMesssage(ClientConstants.ASYNC_TOPIC, 0), 5000); + } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCSubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCSubClient.java index 9e60011fa5..a604bd8b5e 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCSubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CCSubClient.java @@ -23,33 +23,27 @@ import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.runtime.client.common.MessageUtils; import org.apache.eventmesh.runtime.client.common.UserAgentUtils; -import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; import org.apache.eventmesh.runtime.client.impl.SubClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class CCSubClient { - private static final Logger logger = LoggerFactory.getLogger(CCSubClient.class); - public static void main(String[] args) throws Exception { - SubClientImpl subClient = new SubClientImpl("127.0.0.1", 10000, UserAgentUtils.createUserAgent()); - subClient.init(); - subClient.heartbeat(); - subClient.listen(); - subClient.justSubscribe("TEST-TOPIC-TCP-SYNC", SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); - subClient.registerBusiHandler(new ReceiveMsgHook() { - @Override - public void handle(Package msg, ChannelHandlerContext ctx) { - logger.error("Received message: -----------------------------------------" + msg.toString()); + try (SubClientImpl subClient = + new SubClientImpl("localhost", 10000, UserAgentUtils.createUserAgent())) { + subClient.init(); + subClient.heartbeat(); + subClient.listen(); + subClient.justSubscribe("TEST-TOPIC-TCP-SYNC", SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); + subClient.registerBusiHandler((msg, ctx) -> { + log.info("Received message: {}", msg); if (msg.getHeader().getCommand() == Command.REQUEST_TO_CLIENT) { Package rrResponse = MessageUtils.rrResponse(msg); ctx.writeAndFlush(rrResponse); } - } - }); + }); + } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CClientDemo.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CClientDemo.java index 0b53764c8a..59599a11ad 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CClientDemo.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/CClientDemo.java @@ -20,53 +20,37 @@ import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.runtime.client.common.MessageUtils; -import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; import org.apache.eventmesh.runtime.client.impl.EventMeshClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; /** * simple client usage example */ +@Slf4j public class CClientDemo { - public static Logger logger = LoggerFactory.getLogger(CClientDemo.class); - - private static final String SYNC_TOPIC = "TEST-TOPIC-TCP-SYNC"; private static final String ASYNC_TOPIC = "TEST-TOPIC-TCP-ASYNC"; private static final String BROADCAST_TOPIC = "TEST-TOPIC-TCP-BROADCAST"; public static void main(String[] args) throws Exception { - EventMeshClientImpl client = new EventMeshClientImpl("127.0.0.1", 10000); + EventMeshClientImpl client = new EventMeshClientImpl("localhost", 10000); client.init(); client.heartbeat(); client.justSubscribe(ASYNC_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.ASYNC); client.justSubscribe(BROADCAST_TOPIC, SubscriptionMode.BROADCASTING, SubscriptionType.ASYNC); client.listen(); - client.registerSubBusiHandler(new ReceiveMsgHook() { - @Override - public void handle(Package msg, ChannelHandlerContext ctx) { - if (msg.getHeader().getCmd() == Command.ASYNC_MESSAGE_TO_CLIENT || msg.getHeader().getCmd() == Command.BROADCAST_MESSAGE_TO_CLIENT) { - logger.error("receive message-------------------------------------" + msg); - } + client.registerSubBusiHandler((msg, ctx) -> { + if (msg.getHeader().getCmd() == Command.ASYNC_MESSAGE_TO_CLIENT || msg.getHeader().getCmd() == Command.BROADCAST_MESSAGE_TO_CLIENT) { + log.info("receive message: {}", msg); } }); for (int i = 0; i < 10000; i++) { - //ThreadUtil.randomSleep(0,200); - //broadcast message + // broadcast message client.broadcast(MessageUtils.broadcastMessage("TEST-TOPIC-TCP-BROADCAST", i), 5000); - //asynchronous message + // asynchronous message client.publish(MessageUtils.asyncMessage(ASYNC_TOPIC, i), 5000); } - // - //Thread.sleep(10000); - //client.close(); - - } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncPubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncPubClient.java index 172c7a269b..8b23d2a829 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncPubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncPubClient.java @@ -23,23 +23,23 @@ import org.apache.eventmesh.runtime.client.common.UserAgentUtils; import org.apache.eventmesh.runtime.client.impl.PubClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class SyncPubClient { - private static final Logger logger = LoggerFactory.getLogger(SyncPubClient.class); - public static void main(String[] args) throws Exception { - PubClientImpl pubClient = new PubClientImpl("127.0.0.1", 10000, UserAgentUtils.createUserAgent()); - pubClient.init(); - pubClient.heartbeat(); + try (PubClientImpl pubClient = + new PubClientImpl("localhost", 10000, UserAgentUtils.createUserAgent())) { + pubClient.init(); + pubClient.heartbeat(); - for (int i = 0; i < 100; i++) { - Package rr = pubClient.rr(MessageUtils.rrMesssage("TEST-TOPIC-TCP-SYNC", i), 3000); - if (rr.getBody() instanceof EventMeshMessage) { - String body = ((EventMeshMessage) rr.getBody()).getBody(); - logger.error("rrMessage: " + body + " " + "rr-reply-------------------------------------------------" + rr); + for (int i = 0; i < 100; i++) { + Package rr = pubClient.rr(MessageUtils.rrMesssage("TEST-TOPIC-TCP-SYNC", i), 3000); + if (rr.getBody() instanceof EventMeshMessage) { + String body = ((EventMeshMessage) rr.getBody()).getBody(); + log.info("rrMessage: " + body + " " + "rr-reply-------------------------------------------------" + rr); + } } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncSubClient.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncSubClient.java index f7d2f12df5..c64f6ac570 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncSubClient.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/demo/SyncSubClient.java @@ -20,33 +20,26 @@ import org.apache.eventmesh.common.protocol.SubscriptionMode; import org.apache.eventmesh.common.protocol.SubscriptionType; import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.Package; import org.apache.eventmesh.runtime.client.common.ClientConstants; import org.apache.eventmesh.runtime.client.common.MessageUtils; -import org.apache.eventmesh.runtime.client.hook.ReceiveMsgHook; import org.apache.eventmesh.runtime.client.impl.SubClientImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class SyncSubClient { - private static final Logger logger = LoggerFactory.getLogger(SyncSubClient.class); - public static void main(String[] args) throws Exception { - SubClientImpl client = new SubClientImpl("127.0.0.1", 10000, MessageUtils.generateSubServer()); - client.init(); - client.heartbeat(); - client.justSubscribe(ClientConstants.SYNC_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); - client.registerBusiHandler(new ReceiveMsgHook() { - @Override - public void handle(Package msg, ChannelHandlerContext ctx) { + try (SubClientImpl client = + new SubClientImpl("localhost", 10000, MessageUtils.generateSubServer())) { + client.init(); + client.heartbeat(); + client.justSubscribe(ClientConstants.SYNC_TOPIC, SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); + client.registerBusiHandler((msg, ctx) -> { if (msg.getHeader().getCommand() == Command.REQUEST_TO_CLIENT) { - logger.error("receive message -------------------------------" + msg); + log.info("receive message:{}", msg); } - } - }); + }); + } } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/mock/MockCloudEvent.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/mock/MockCloudEvent.java new file mode 100644 index 0000000000..ff114d18c6 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/mock/MockCloudEvent.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.mock; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.Set; + +import io.cloudevents.CloudEvent; +import io.cloudevents.CloudEventData; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.data.BytesCloudEventData; + +public class MockCloudEvent implements CloudEvent { + + @Override + public CloudEventData getData() { + return BytesCloudEventData.wrap("mockData".getBytes(StandardCharsets.UTF_8)); + } + + @Override + public SpecVersion getSpecVersion() { + return SpecVersion.V1; + } + + @Override + public String getId() { + return "mockId"; + } + + @Override + public String getType() { + return "mockType"; + } + + @Override + public URI getSource() { + return URI.create("mockSource"); + } + + @Override + public String getDataContentType() { + return null; + } + + @Override + public URI getDataSchema() { + return URI.create("mockDataSchema"); + } + + @Override + public String getSubject() { + return "mockSubject"; + } + + @Override + public OffsetDateTime getTime() { + return null; + } + + @Override + public Object getAttribute(String attributeName) throws IllegalArgumentException { + return null; + } + + @Override + public Object getExtension(String extensionName) { + return null; + } + + @Override + public Set getExtensionNames() { + return Collections.emptySet(); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/BannerUtilTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/BannerUtilTest.java new file mode 100644 index 0000000000..96dd4ec099 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/BannerUtilTest.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class BannerUtilTest { + + @Test + public void testGenerateBanner() { + Assertions.assertDoesNotThrow(BannerUtil::generateBanner); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriterTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriterTest.java new file mode 100644 index 0000000000..e7f5cfcebe --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshCloudEventWriterTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class EventMeshCloudEventWriterTest { + + @Test + public void testURIAsValueWithContextAttribute() throws URISyntaxException { + String key = "testKey"; + EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); + + eventMeshCloudEventWriter.withContextAttribute(key, new URI("file://foo/bars")); + + Map extensionMap = eventMeshCloudEventWriter.getExtensionMap(); + Assertions.assertEquals(extensionMap.get(key), "file://foo/bars"); + } + + @Test + public void testOffsetDateTimeAsValueWithContextAttribute() { + String key = "testKey"; + EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); + + eventMeshCloudEventWriter.withContextAttribute(key, OffsetDateTime.of(LocalDateTime.of( + LocalDate.of(2023, 6, 17), LocalTime.MIDNIGHT), ZoneOffset.ofTotalSeconds(32400))); + + Map extensionMap = eventMeshCloudEventWriter.getExtensionMap(); + Assertions.assertEquals(extensionMap.get(key), "2023-06-17T00:00:00+09:00"); + } + + @Test + public void testIntegerAsValueWithContextAttribute() { + String key = "testKey"; + EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); + + eventMeshCloudEventWriter.withContextAttribute(key, 123); + + Map extensionMap = eventMeshCloudEventWriter.getExtensionMap(); + Assertions.assertEquals(extensionMap.get(key), "123"); + } + + @Test + public void testBooleanAsValueWithContextAttribute() { + String key = "testKey"; + EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); + + eventMeshCloudEventWriter.withContextAttribute(key, Boolean.FALSE); + + Map extensionMap = eventMeshCloudEventWriter.getExtensionMap(); + Assertions.assertEquals(extensionMap.get(key), "false"); + } + + @Test + public void testByteArrayAsValueWithContextAttribute() { + String key = "testKey"; + EventMeshCloudEventWriter eventMeshCloudEventWriter = new EventMeshCloudEventWriter(); + + eventMeshCloudEventWriter.withContextAttribute(key, "bytesArray".getBytes(StandardCharsets.UTF_8)); + + Map extensionMap = eventMeshCloudEventWriter.getExtensionMap(); + String base64EncodedValue = "Ynl0ZXNBcnJheQ=="; + Assertions.assertEquals(extensionMap.get(key), base64EncodedValue); + } + +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImplTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImplTest.java deleted file mode 100644 index f9b4821852..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshThreadFactoryImplTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.util; - -import org.junit.Assert; -import org.junit.Test; - -public class EventMeshThreadFactoryImplTest { - - @Test - public void testGetThreadNamePrefix() { - final String threadNamePrefix = "threadNamePrefix"; - EventMeshThreadFactoryImpl factory = new EventMeshThreadFactoryImpl(threadNamePrefix, false); - Assert.assertEquals(threadNamePrefix, factory.getThreadNamePrefix()); - } - - @Test - public void testNewThread() { - final String threadNamePrefix = "threadNamePrefix"; - EventMeshThreadFactoryImpl factory = new EventMeshThreadFactoryImpl(threadNamePrefix, true); - Thread t = factory.newThread(() -> {}); - Assert.assertNotNull(t); - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshUtilTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshUtilTest.java index d70424eed7..16fb42a25f 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshUtilTest.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/EventMeshUtilTest.java @@ -17,76 +17,92 @@ package org.apache.eventmesh.runtime.util; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.ThreadPoolFactory; import org.apache.eventmesh.common.exception.EventMeshException; import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; import org.apache.eventmesh.common.protocol.tcp.UserAgent; import org.apache.eventmesh.runtime.constants.EventMeshConstants; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; import org.apache.http.client.utils.URIBuilder; +import java.io.IOException; import java.net.InetAddress; +import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; import java.util.regex.Pattern; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import io.cloudevents.CloudEvent; +import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.v03.CloudEventV03; +import io.cloudevents.core.v1.CloudEventV1; import com.fasterxml.jackson.databind.ObjectMapper; public class EventMeshUtilTest { + private static final String TYPE = "type"; + private static final String V03 = "V03"; + @Test public void testBuildPushMsgSeqNo() { String seq = EventMeshUtil.buildPushMsgSeqNo(); - Assert.assertTrue(Pattern.compile("\\d{17}").matcher(seq).matches()); - Assert.assertEquals(17, seq.length()); + Assertions.assertTrue(Pattern.compile("\\d{17}").matcher(seq).matches()); + Assertions.assertEquals(17, seq.length()); } @Test public void testBuildMeshClientID() { String clientGroup = "clientGroup"; String clientID = EventMeshUtil.buildMeshClientID(clientGroup, "LS"); - Assert.assertTrue(clientID.contains(clientGroup)); + Assertions.assertTrue(clientID.contains(clientGroup)); } @Test public void testBuildMeshTcpClientID() { String clientSysId = "clientSysId"; String clientID = EventMeshUtil.buildMeshTcpClientID(clientSysId, "purpose", "meshCluster"); - Assert.assertTrue(clientID.contains(clientSysId)); + Assertions.assertTrue(clientID.contains(clientSysId)); } @Test public void testBuildClientGroup() { String systemId = "systemId"; String clientGroup = EventMeshUtil.buildClientGroup(systemId); - Assert.assertEquals(clientGroup, systemId); + Assertions.assertEquals(clientGroup, systemId); } @Test public void testStackTrace() { Throwable e = new EventMeshException("error"); String exception = EventMeshUtil.stackTrace(e); - Assert.assertTrue(exception.contains(e.getMessage())); + Assertions.assertTrue(exception.contains(e.getMessage())); + + exception = EventMeshUtil.stackTrace(null); + Assertions.assertNull(exception); } @Test public void testCreateJsoner() { ObjectMapper mapper = EventMeshUtil.createJsoner(); - Assert.assertNotNull(mapper); + Assertions.assertNotNull(mapper); } @Test public void testPrintMqMessage() { EventMeshMessage meshMessage = new EventMeshMessage(); String result = EventMeshUtil.printMqMessage(meshMessage); - Assert.assertTrue(result.contains("Message")); + Assertions.assertTrue(result.contains("Message")); } @Test @@ -95,10 +111,10 @@ public void testGetMessageBizSeq() throws URISyntaxException { CloudEvent cloudEvent = CloudEventBuilder.v03().withExtension(EventMeshConstants.KEYS_LOWERCASE, value) .withId(UUID.randomUUID().toString()) .withSource(new URIBuilder().build()) - .withType("type") + .withType(TYPE) .build(); String result = EventMeshUtil.getMessageBizSeq(cloudEvent); - Assert.assertEquals(result, value); + Assertions.assertEquals(result, value); } @Test @@ -107,34 +123,71 @@ public void testGetEventProp() throws URISyntaxException { CloudEvent cloudEvent = CloudEventBuilder.v03().withExtension(EventMeshConstants.KEYS_LOWERCASE, value) .withId(UUID.randomUUID().toString()) .withSource(new URIBuilder().build()) - .withType("type") + .withType(TYPE) .build(); Map result = EventMeshUtil.getEventProp(cloudEvent); - Assert.assertEquals(result.get(EventMeshConstants.KEYS_LOWERCASE), value); + Assertions.assertEquals(result.get(EventMeshConstants.KEYS_LOWERCASE), value); } @Test public void testGetLocalAddr() { String addr = EventMeshUtil.getLocalAddr(); - Assert.assertNotNull(addr); + Assertions.assertNotNull(addr); } @Test public void testNormalizeHostAddress() throws UnknownHostException { InetAddress localAddress = InetAddress.getLocalHost(); String result = EventMeshUtil.normalizeHostAddress(localAddress); - Assert.assertNotNull(result); + Assertions.assertNotNull(result); } @Test public void testBuildUserAgentClientId() { String subSystem = "subsystem"; - String host = "127.0.0.1"; + String host = "localhost"; int pid = 1; int port = 8080; UserAgent agent = UserAgent.builder().subsystem(subSystem).host(host) .pid(pid).port(port).build(); String result = EventMeshUtil.buildUserAgentClientId(agent); - Assert.assertEquals(result, String.format("%s--%d-%s:%d", subSystem, pid, host, port)); + Assertions.assertEquals(result, String.format("%s--%d-%s:%d", subSystem, pid, host, port)); + + result = EventMeshUtil.buildUserAgentClientId(null); + Assertions.assertNull(result); + } + + @Test + public void testCloneObject() throws IOException, ClassNotFoundException { + TopicMetadata topicMetadata = new TopicMetadata("topicName"); + TopicMetadata topicMetadata2 = EventMeshUtil.cloneObject(topicMetadata); + Assertions.assertNotEquals(System.identityHashCode(topicMetadata), System.identityHashCode(topicMetadata2)); + Assertions.assertEquals(topicMetadata, topicMetadata2); + } + + @Test + public void testPrintState() { + ScheduledExecutorService serviceRebalanceScheduler = ThreadPoolFactory + .createScheduledExecutor(5, new EventMeshThreadFactory("proxy-rebalance-sch", true)); + Assertions.assertDoesNotThrow(() -> EventMeshUtil.printState((ThreadPoolExecutor) serviceRebalanceScheduler)); + } + + @Test + public void testGetCloudEventExtensionMap() { + URI source = URI.create("uri"); + CloudEventV03 cloudEventV03 = CloudEventBuilder.v03().withId(V03).withSource(source).withType(V03).build(); + Map extMapV03 = EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V03.toString(), cloudEventV03); + Assertions.assertNotNull(extMapV03); + Assertions.assertEquals(V03, extMapV03.get("id")); + Assertions.assertEquals(V03, extMapV03.get(TYPE)); + + CloudEventV1 cloudEventV1 = (CloudEventV1) CloudEventBuilder.v1().withId("V1").withSource(source).withType("V1").build(); + Map extMapV1 = EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), cloudEventV1); + Assertions.assertNotNull(extMapV1); + Assertions.assertEquals("V1", extMapV1.get("id")); + Assertions.assertEquals("V1", extMapV1.get(TYPE)); + + Map map = EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V03.toString(), cloudEventV1); + Assertions.assertTrue(map.isEmpty()); } } diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpRequestUtilTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpRequestUtilTest.java new file mode 100644 index 0000000000..3d4c868dad --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpRequestUtilTest.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpVersion; + +public class HttpRequestUtilTest { + + @Test + public void testShouldParseHttpGETRequestBody() throws IOException { + HttpRequest httpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/some-path?q1=xyz"); + Map expected = new HashMap<>(); + expected.put("q1", "xyz"); + Assertions.assertEquals(expected, HttpRequestUtil.parseHttpRequestBody(httpRequest)); + } + + @Test + public void testShouldParseHttpPOSTRequestBody() throws IOException { + HttpRequest httpRequest = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, HttpMethod.POST, + "/some-path", + Unpooled.copiedBuffer(("q1=xyz").getBytes()) + ); + Map expected = new HashMap<>(); + expected.put("q1", "xyz"); + Assertions.assertEquals(expected, HttpRequestUtil.parseHttpRequestBody(httpRequest)); + } + + @Test + public void testQueryStringToMap() { + Map expected = new HashMap<>(); + expected.put("q1", "xyz"); + expected.put("q2", "abc"); + Assertions.assertEquals(expected, HttpRequestUtil.queryStringToMap("q1=xyz&q2=abc")); + } + + @Test + public void testGetQueryParam() { + HttpRequest httpRequest = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, + HttpMethod.GET, + "/some-path?q1=xyz" + ); + Assertions.assertEquals("xyz", HttpRequestUtil.getQueryParam(httpRequest, "q1", "")); + } + + @Test + public void testGetBodyParam() throws IOException { + HttpRequest httpRequest = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, + HttpMethod.POST, + "/some-path", + Unpooled.copiedBuffer(("q1=xyz").getBytes()) + ); + Assertions.assertEquals("xyz", HttpRequestUtil.getBodyParam(httpRequest, "q1")); + } + +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpResponseUtilsTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpResponseUtilsTest.java new file mode 100644 index 0000000000..3a6d0bccc0 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpResponseUtilsTest.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +/** + * HttpResponseUtils test cases. + */ +public class HttpResponseUtilsTest { + + @Test + public void testCreateSuccess() { + Assertions.assertEquals(HttpVersion.HTTP_1_1, HttpResponseUtils.createSuccess().protocolVersion()); + Assertions.assertEquals(HttpResponseStatus.OK, HttpResponseUtils.createSuccess().status()); + } + + @Test + public void testCreateNotFound() { + Assertions.assertEquals(HttpVersion.HTTP_1_1, HttpResponseUtils.createNotFound().protocolVersion()); + Assertions.assertEquals(HttpResponseStatus.NOT_FOUND, HttpResponseUtils.createNotFound().status()); + } + + @Test + public void testCreateInternalServerError() { + Assertions.assertEquals(HttpVersion.HTTP_1_1, HttpResponseUtils.createInternalServerError().protocolVersion()); + Assertions.assertEquals(HttpResponseStatus.INTERNAL_SERVER_ERROR, HttpResponseUtils.createInternalServerError().status()); + } + +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpTinyClientTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpTinyClientTest.java index 6bfdc82041..30c2e65a68 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpTinyClientTest.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/HttpTinyClientTest.java @@ -19,19 +19,19 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import org.apache.eventmesh.runtime.util.HttpTinyClient.HttpResult; +import org.apache.commons.io.IOUtils; + import java.io.IOException; -import java.io.OutputStream; +import java.io.InputStream; import java.net.HttpURLConnection; -import java.net.URL; +import java.util.ArrayList; +import java.util.List; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -40,38 +40,40 @@ public class HttpTinyClientTest { @Test public void testHttpGet() throws IOException { String content = "http mock response"; - HttpURLConnection conn = mock(HttpURLConnection.class); - URL url = mock(URL.class); - doNothing().when(conn).connect(); - when(url.openConnection()).thenReturn(conn); - when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - try (MockedStatic dummyStatic = Mockito.mockStatic(IOTinyUtils.class)) { - dummyStatic.when(() -> IOTinyUtils.toString(any(), any())).thenReturn(content); + try (MockedStatic dummyStatic = Mockito.mockStatic(IOUtils.class)) { + dummyStatic.when(() -> IOUtils.toString(any(InputStream.class), any(String.class))).thenReturn(content); String requestUrl = "https://eventmesh.apache.org"; HttpResult result = HttpTinyClient.httpGet(requestUrl, null, null, "utf-8", 0); - Assert.assertEquals(result.getContent(), content); - Assert.assertEquals(result.getCode(), HttpURLConnection.HTTP_OK); + Assertions.assertEquals(content, result.getContent()); + Assertions.assertEquals(HttpURLConnection.HTTP_OK, result.getCode()); + } + + List paramValues = new ArrayList<>(); + paramValues.add("mock-key-1"); + paramValues.add("mock-value-1"); + paramValues.add("mock-key-2"); + paramValues.add("mock-value-2"); + List headers = new ArrayList<>(); + headers.add("mock-key"); + headers.add("mock-value"); + try (MockedStatic dummyStatic = Mockito.mockStatic(IOUtils.class)) { + dummyStatic.when(() -> IOUtils.toString(any(InputStream.class), any(String.class))).thenReturn(content); + String requestUrl = "https://eventmesh.apache.org"; + HttpResult result = HttpTinyClient.httpGet(requestUrl, headers, paramValues, "utf-8", 0); + Assertions.assertEquals(content, result.getContent()); + Assertions.assertEquals(HttpURLConnection.HTTP_OK, result.getCode()); } } @Test public void testHttpPost() throws IOException { String content = "http mock response"; - HttpURLConnection conn = mock(HttpURLConnection.class); - URL url = mock(URL.class); - doNothing().when(conn).connect(); - when(url.openConnection()).thenReturn(conn); - when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - - OutputStream outputStream = mock(OutputStream.class); - doNothing().when(outputStream).write(new byte[0]); - when(conn.getOutputStream()).thenReturn(outputStream); - try (MockedStatic dummyStatic = Mockito.mockStatic(IOTinyUtils.class)) { - dummyStatic.when(() -> IOTinyUtils.toString(any(), any())).thenReturn(content); + try (MockedStatic dummyStatic = Mockito.mockStatic(IOUtils.class)) { + dummyStatic.when(() -> IOUtils.toString(any(InputStream.class), any(String.class))).thenReturn(content); String requestUrl = "https://eventmesh.apache.org"; HttpResult result = HttpTinyClient.httpPost(requestUrl, anyList(), anyList(), "utf-8", 0); - Assert.assertEquals(result.getContent(), content); - Assert.assertEquals(result.getCode(), HttpURLConnection.HTTP_OK); + Assertions.assertEquals(content, result.getContent()); + Assertions.assertEquals(HttpURLConnection.HTTP_OK, result.getCode()); } } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/IOTinyUtilsTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/IOTinyUtilsTest.java deleted file mode 100644 index 05888a2b7f..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/IOTinyUtilsTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.runtime.util; - - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.when; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedConstruction; - -public class IOTinyUtilsTest { - - @Test - public void testCopy() throws Exception { - BufferedReader input = mock(BufferedReader.class); - BufferedWriter output = mock(BufferedWriter.class); - int count = 10; - char[] buffer = new char[1 << 12]; - doNothing().when(output).write(buffer, 0, count); - when(input.read(buffer)).thenReturn(10, 10, -1); - long result = IOTinyUtils.copy(input, output); - Assert.assertEquals(result, count * 2); - } - - @Test - public void testReadLines() throws IOException { - BufferedReader input = mock(BufferedReader.class); - when(input.readLine()).thenReturn("hello", "world", null); - List result = IOTinyUtils.readLines(input); - Assert.assertEquals(result.get(0), "hello"); - } - - @Test - public void testCopyFile() { - } - - @Test - public void testCleanDirectory() throws IOException { - File dirFile = mock(File.class); - when(dirFile.exists()).thenReturn(true); - when(dirFile.isDirectory()).thenReturn(true); - - File normalFile = mock(File.class); - when(normalFile.exists()).thenReturn(true); - when(normalFile.isDirectory()).thenReturn(false); - when(normalFile.delete()).thenReturn(true); - - File[] files = {normalFile}; - when(dirFile.listFiles()).thenReturn(files); - IOTinyUtils.cleanDirectory(dirFile); - } - - @Test - public void testWriteStringToFile() throws IOException { - File file = mock(File.class); - try (MockedConstruction ignored = mockConstruction(FileOutputStream.class, - (mock, context) -> doNothing().when(mock).write(any()))) { - IOTinyUtils.writeStringToFile(file, "data", "utf-8"); - } - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/RemotingHelperTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/RemotingHelperTest.java index 0e78b981f1..b3498a80b2 100644 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/RemotingHelperTest.java +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/RemotingHelperTest.java @@ -20,8 +20,8 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import io.netty.channel.Channel; @@ -31,29 +31,30 @@ public class RemotingHelperTest { @Test public void testExceptionSimpleDesc() { String result = RemotingHelper.exceptionSimpleDesc(new NullPointerException()); - Assert.assertNotNull(result); + Assertions.assertNotNull(result); } @Test public void testString2SocketAddress() { - String addr = "127.0.0.1:11002"; - SocketAddress address = RemotingHelper.string2SocketAddress(addr); - Assert.assertNotNull(address); + String addr = "127.0.0.1:8080"; + InetSocketAddress address = (InetSocketAddress) RemotingHelper.string2SocketAddress(addr); + Assertions.assertNotNull(address); + Assertions.assertEquals("127.0.0.1:8080", address.getHostString() + ":" + address.getPort()); } @Test public void testParseChannelRemoteAddr() { - SocketAddress address = new InetSocketAddress("127.0.0.1", 80); + SocketAddress address = new InetSocketAddress("localhost", 80); Channel channel = Mockito.mock(Channel.class); Mockito.when(channel.remoteAddress()).thenReturn(address); String addr = RemotingHelper.parseChannelRemoteAddr(channel); - Assert.assertEquals(addr, "127.0.0.1:80"); + Assertions.assertEquals(addr, "127.0.0.1:80"); } @Test public void testParseSocketAddressAddr() { - SocketAddress address = new InetSocketAddress("127.0.0.1", 80); + InetSocketAddress address = new InetSocketAddress("localhost", 80); String addr = RemotingHelper.parseSocketAddressAddr(address); - Assert.assertEquals(addr, "127.0.0.1:80"); + Assertions.assertEquals("127.0.0.1:80", addr); } -} \ No newline at end of file +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ServerGlobalTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ServerGlobalTest.java new file mode 100644 index 0000000000..6e51012f62 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ServerGlobalTest.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * ServerGlobal test cases. + */ +public class ServerGlobalTest { + + @Test + public void testGetMsgCounter() { + ServerGlobal.getInstance().setMsgCounter(new AtomicLong(1L)); + Assertions.assertEquals(1L, ServerGlobal.getInstance().getMsgCounter().get()); + } + + @Test + public void testSetMsgCounter() { + ServerGlobal.getInstance().setMsgCounter(new AtomicLong(1L)); + Assertions.assertEquals(1L, ServerGlobal.getInstance().getMsgCounter().get()); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ThreadPoolHelperTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ThreadPoolHelperTest.java new file mode 100644 index 0000000000..d04712eef4 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ThreadPoolHelperTest.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class ThreadPoolHelperTest { + + @Mock + private ThreadPoolExecutor mockThreadPool; + + @Mock + private RejectedExecutionHandler mockRejectionPolicy; + + @Test + public void testPrintState() { + when(mockThreadPool.isShutdown()).thenReturn(false); + when(mockThreadPool.isTerminating()).thenReturn(false); + when(mockThreadPool.isTerminated()).thenReturn(false); + when(mockThreadPool.getActiveCount()).thenReturn(2); + when(mockThreadPool.getCompletedTaskCount()).thenReturn(10L); + when(mockThreadPool.getTaskCount()).thenReturn(15L); + when(mockThreadPool.getQueue()).thenReturn(new LinkedBlockingDeque<>(5)); + when(mockThreadPool.getCorePoolSize()).thenReturn(5); + when(mockThreadPool.getMaximumPoolSize()).thenReturn(10); + when(mockThreadPool.getKeepAliveTime(any(TimeUnit.class))).thenReturn(1000L); + when(mockThreadPool.getRejectedExecutionHandler()).thenReturn(mockRejectionPolicy); + + ThreadPoolHelper.printState(mockThreadPool); + + verify(mockThreadPool).isShutdown(); + verify(mockThreadPool).isTerminating(); + verify(mockThreadPool).isTerminated(); + verify(mockThreadPool).getActiveCount(); + verify(mockThreadPool).getCompletedTaskCount(); + verify(mockThreadPool).getTaskCount(); + verify(mockThreadPool).getQueue(); + verify(mockThreadPool).getCorePoolSize(); + verify(mockThreadPool).getMaximumPoolSize(); + verify(mockThreadPool).getKeepAliveTime(any(TimeUnit.class)); + verify(mockThreadPool).getRejectedExecutionHandler(); + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/TraceUtilsTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/TraceUtilsTest.java new file mode 100644 index 0000000000..34989b6442 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/TraceUtilsTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import org.apache.eventmesh.runtime.boot.EventMeshServer; +import org.apache.eventmesh.runtime.mock.MockCloudEvent; +import org.apache.eventmesh.runtime.trace.Trace; + +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import io.cloudevents.SpecVersion; +import io.opentelemetry.api.trace.Span; + +public class TraceUtilsTest { + @Test + public void testShouldPrepareClientSpan() throws Exception { + Map cloudEventExtensionMap = EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), new MockCloudEvent()); + try (MockedStatic dummyStatic = Mockito.mockStatic(EventMeshServer.class)) { + Trace trace = Trace.getInstance("zipkin", true); + trace.init(); + dummyStatic.when(EventMeshServer::getTrace).thenReturn(trace); + Span testClientSpan = TraceUtils.prepareClientSpan( + cloudEventExtensionMap, + "test client span", + false + ); + Assertions.assertNotNull(testClientSpan); + } + } + + @Test + public void testShouldPrepareServerSpan() throws Exception { + Map cloudEventExtensionMap = EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), new MockCloudEvent()); + try (MockedStatic dummyStatic = Mockito.mockStatic(EventMeshServer.class)) { + Trace trace = Trace.getInstance("zipkin", true); + trace.init(); + dummyStatic.when(EventMeshServer::getTrace).thenReturn(trace); + TraceUtils.prepareClientSpan( + cloudEventExtensionMap, + "test client span", + false + ); + Span testServerSpan = TraceUtils.prepareServerSpan( + cloudEventExtensionMap, + "test server span", + false + ); + Assertions.assertNotNull(testServerSpan); + } + } + + @Test + public void testShouldFinishSpan() throws Exception { + MockCloudEvent cloudEvent = new MockCloudEvent(); + Map cloudEventExtensionMap = EventMeshUtil.getCloudEventExtensionMap(SpecVersion.V1.toString(), cloudEvent); + try (MockedStatic dummyStatic = Mockito.mockStatic(EventMeshServer.class)) { + Trace trace = Trace.getInstance("zipkin", true); + trace.init(); + dummyStatic.when(EventMeshServer::getTrace).thenReturn(trace); + Span testClientSpan = TraceUtils.prepareClientSpan( + cloudEventExtensionMap, + "test client span", + false + ); + + TraceUtils.finishSpan(testClientSpan, cloudEvent); + Assertions.assertFalse(testClientSpan.isRecording()); + } + } +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ValueComparatorTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ValueComparatorTest.java new file mode 100644 index 0000000000..e647a52152 --- /dev/null +++ b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/ValueComparatorTest.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.runtime.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.util.Map; +import java.util.TreeMap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ValueComparatorTest { + + @Test + public void testSerializeOrderedCollection() throws IOException { + Map, Integer> map = new TreeMap<>(new ValueComparator()); + try (OutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos)) { + Assertions.assertDoesNotThrow(() -> oos.writeObject(map)); + } + } + +} diff --git a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/WebhookUtilTest.java b/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/WebhookUtilTest.java deleted file mode 100644 index 6dd5bcedb1..0000000000 --- a/eventmesh-runtime/src/test/java/org/apache/eventmesh/runtime/util/WebhookUtilTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - @Test - * 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. - */ - -package org.apache.eventmesh.runtime.util; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; - -import org.apache.eventmesh.api.auth.AuthService; -import org.apache.eventmesh.spi.EventMeshExtensionFactory; - -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.message.BasicHeader; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -public class WebhookUtilTest { - - @Test - public void testObtainDeliveryAgreement() throws Exception { - CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); - CloseableHttpResponse response = Mockito.mock(CloseableHttpResponse.class); - Mockito.when(response.getLastHeader("WebHook-Allowed-Origin")).thenReturn(new BasicHeader("WebHook-Allowed-Origin", "*")); - Mockito.when(httpClient.execute(any())).thenReturn(response); - Assert.assertTrue(WebhookUtil.obtainDeliveryAgreement(httpClient, "https://eventmesh.apache.org", "*")); - } - - @Test - public void testSetWebhookHeaders() { - String authType = "auth-http-basic"; - AuthService authService = mock(AuthService.class); - doNothing().when(authService).init(); - Map authParams = new HashMap<>(); - String key = "Authorization"; - String value = "Basic ****"; - authParams.put(key, value); - Mockito.when(authService.getAuthParams()).thenReturn(authParams); - - try (MockedStatic dummyStatic = Mockito.mockStatic(EventMeshExtensionFactory.class)) { - dummyStatic.when(() -> EventMeshExtensionFactory.getExtension(AuthService.class, authType)).thenReturn(authService); - HttpPost post = new HttpPost(); - WebhookUtil.setWebhookHeaders(post, "application/json", "eventmesh.FT", authType); - Assert.assertEquals(post.getLastHeader(key).getValue(), value); - } - } -} \ No newline at end of file diff --git a/eventmesh-runtime/src/test/resources/configuration.properties b/eventmesh-runtime/src/test/resources/configuration.properties new file mode 100644 index 0000000000..836fc9c981 --- /dev/null +++ b/eventmesh-runtime/src/test/resources/configuration.properties @@ -0,0 +1,103 @@ +# +# 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. +# + +# CommonConfiguration config +eventMesh.server.env=env-succeed!!! +eventMesh.server.idc=idc-succeed!!! +eventMesh.sysid=816 +eventMesh.server.cluster=cluster-succeed!!! +eventMesh.server.name=name-succeed!!! +eventMesh.server.hostIp=hostIp-succeed!!! +eventMesh.storage.plugin.type=storage-succeed!!! +eventMesh.security.plugin.type=security-succeed!!! +eventMesh.trace.plugin=trace-succeed!!! + +eventMesh.metrics.plugin=metrics-succeed1!!!,metrics-succeed2!!!,metrics-succeed3!!! +eventMesh.metaStorage.plugin.type=metaStorage-succeed!!! +eventMesh.metaStorage.plugin.server-addr=server-addr-succeed1!!! +eventMesh.metaStorage.plugin.enabled=true +eventMesh.metaStorage.plugin.username=username-succeed!!! +eventMesh.metaStorage.plugin.password=password-succeed!!! + +eventMesh.server.security.enabled=true +eventMesh.server.trace.enabled=true + +eventMesh.server.provide.protocols=TCP,HTTP,GRPC + +# EventMeshHTTPConfiguration config +eventMesh.server.http.port=1816 +eventMesh.server.batchmsg.batch.enabled=false +eventMesh.server.batchmsg.threads.num=2816 +eventMesh.server.sendmsg.threads.num=3816 +eventMesh.server.pushmsg.threads.num=4816 +eventMesh.server.replymsg.threads.num=5816 +eventMesh.server.clientmanage.threads.num=6816 +eventMesh.server.metaStorage.threads.num=7816 +eventMesh.server.admin.threads.num=8816 +eventMesh.server.retry.threads.num=9816 +eventMesh.server.pull.metaStorage.interval=11816 +eventMesh.server.async.accumulation.threshold=12816 +eventMesh.server.retry.blockQ.size=13816 +eventMesh.server.batchmsg.blockQ.size=14816 +eventMesh.server.sendmsg.blockQ.size=15816 +eventMesh.server.pushmsg.blockQ.size=16816 +eventMesh.server.clientM.blockQ.size=17816 +eventMesh.server.busy.check.interval=18816 +eventMesh.server.consumer.enabled=true +eventMesh.server.useTls.enabled=true +eventMesh.server.http.msgReqnumPerSecond=19816 +eventMesh.server.batchmsg.reqNumPerSecond=21816 +eventMesh.server.maxEventSize=22816 +eventMesh.server.maxEventBatchSize=23816 +eventMesh.server.blacklist.ipv4=127.0.0.1,127.0.0.2 +eventMesh.server.blacklist.ipv6=0:0:0:0:0:0:7f00:01,0:0:0:0:0:0:7f00:02 + +# EventMeshGrpcConfiguration config +eventMesh.server.grpc.port=816 +eventMesh.server.session.expiredInMills=1816 + + +# EventMeshTCPConfiguration config +eventMesh.server.tcp.port=816 +eventMesh.server.tcp.allIdleSeconds=1816 +eventMesh.server.tcp.writerIdleSeconds=2816 +eventMesh.server.tcp.readerIdleSeconds=3816 +eventMesh.server.tcp.msgReqnumPerSecond=4816 +eventMesh.server.tcp.clientMaxNum=5816 +eventMesh.server.global.scheduler=6816 +eventMesh.server.tcp.taskHandleExecutorPoolSize=7816 +eventMesh.server.tcp.msgDownStreamExecutorPoolSize=8816 +eventMesh.server.session.upstreamBufferSize=11816 +eventMesh.server.retry.async.pushRetryTimes=12816 +eventMesh.server.retry.sync.pushRetryTimes=13816 +eventMesh.server.retry.sync.pushRetryDelayInMills=14816 +eventMesh.server.retry.async.pushRetryDelayInMills=15816 +eventMesh.server.retry.pushRetryQueueSize=16816 +eventMesh.server.tcp.RebalanceIntervalInMills=17816 +eventMesh.server.tcp.sendBack.enabled=true +eventMesh.server.tcp.pushFailIsolateTimeInMills=21816 +eventMesh.server.gracefulShutdown.sleepIntervalInMills=22816 +eventMesh.server.rebalanceRedirect.sleepIntervalInM=23816 + + + + + + + + + diff --git a/eventmesh-sdk-go/README.md b/eventmesh-sdk-go/README.md deleted file mode 100644 index efdb1cef74..0000000000 --- a/eventmesh-sdk-go/README.md +++ /dev/null @@ -1,6 +0,0 @@ -EventMesh Go SDK ---- -support api -1. gRPC -2. HTTP -3. TCP \ No newline at end of file diff --git a/eventmesh-sdk-go/common/id/api.go b/eventmesh-sdk-go/common/id/api.go deleted file mode 100644 index 379b5457c5..0000000000 --- a/eventmesh-sdk-go/common/id/api.go +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -package id - -// Interface api to generate uniq id -type Interface interface { - // Next create uniq ID - Next() string -} diff --git a/eventmesh-sdk-go/common/id/id_snake.go b/eventmesh-sdk-go/common/id/id_snake.go deleted file mode 100644 index 675669a55e..0000000000 --- a/eventmesh-sdk-go/common/id/id_snake.go +++ /dev/null @@ -1,79 +0,0 @@ -// 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. - -package id - -import ( - "bytes" - "fmt" - "net" - "strconv" - "strings" - - "github.com/sony/sonyflake" -) - -// flake generate uid by flake -type flake struct { - sf *sonyflake.Sonyflake -} - -func NewFlake() Interface { - macAddr := getMacAddr() - st := sonyflake.Settings{ - MachineID: func() (uint16, error) { - ma := strings.Split(macAddr, ":") - mid, err := strconv.ParseInt(ma[0]+ma[1], 16, 16) - return uint16(mid), err - }, - } - return &flake{ - sf: sonyflake.NewSonyflake(st), - } -} - -// getMacAddr return the current machine mac address -func getMacAddr() (addr string) { - interfaces, err := net.Interfaces() - if err == nil { - for _, i := range interfaces { - if i.Flags&net.FlagUp != 0 && bytes.Compare(i.HardwareAddr, nil) != 0 { - // Don't use random as we have a real address - addr = i.HardwareAddr.String() - break - } - } - } - return -} - -// Nextv generates next id as an uint64 -func (f *flake) Nextv() (id uint64, err error) { - var i uint64 - if f.sf != nil { - i, err = f.sf.NextID() - if err == nil { - id = i - } - } - return -} - -// Next generates next id as a string -func (f *flake) Next() string { - var i uint64 - i, _ = f.Nextv() - return fmt.Sprintf("%d", i) -} diff --git a/eventmesh-sdk-go/common/id/id_uuid.go b/eventmesh-sdk-go/common/id/id_uuid.go deleted file mode 100644 index fb1c36a5ef..0000000000 --- a/eventmesh-sdk-go/common/id/id_uuid.go +++ /dev/null @@ -1,34 +0,0 @@ -// 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. - -package id - -import ( - "github.com/google/uuid" - "strings" -) - -// UUID generate id by uuid -type UUID struct { -} - -// NewUUID uuid instance -func NewUUID() Interface { - return &UUID{} -} - -func (u *UUID) Next() string { - return strings.ReplaceAll(uuid.New().String(), "-", "") -} diff --git a/eventmesh-sdk-go/common/seq/num.go b/eventmesh-sdk-go/common/seq/num.go deleted file mode 100644 index c962ea8731..0000000000 --- a/eventmesh-sdk-go/common/seq/num.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -package seq - -import ( - "fmt" - "go.uber.org/atomic" -) - -// Interface to generate sequence number -type Interface interface { - Next() string -} - -// AtomicSeq use atomic.Int64 to create seq number -type AtomicSeq struct { - *atomic.Uint64 -} - -// NewAtomicSeq new atomic sequence instance -func NewAtomicSeq() Interface { - return &AtomicSeq{ - Uint64: atomic.NewUint64(0), - } -} - -func (a *AtomicSeq) Next() string { - return fmt.Sprintf("%v", a.Inc()) -} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go b/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go deleted file mode 100644 index 28f26a7b54..0000000000 --- a/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go +++ /dev/null @@ -1,77 +0,0 @@ -// 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. - -package main - -import ( - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "io/ioutil" - "net/http" - "time" -) - -func main() { - cli, err := grpc.New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-async-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - if err != nil { - panic(err) - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - err = cli.SubscribeWebhook(conf.SubscribeItem{ - SubscribeMode: conf.CLUSTERING, - SubscribeType: conf.ASYNC, - Topic: "async-sub-grpc-topic", - }, "http://localhost:8080/onmessage") - if err != nil { - fmt.Println(err.Error()) - return - } - http.HandleFunc("/onmessage", func(writer http.ResponseWriter, request *http.Request) { - buf, err := ioutil.ReadAll(request.Body) - if err != nil { - return - } - defer request.Body.Close() - fmt.Println(string(buf)) - }) - http.ListenAndServe(":8080", nil) -} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go b/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go deleted file mode 100644 index 6d5c518820..0000000000 --- a/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go +++ /dev/null @@ -1,67 +0,0 @@ -// 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. - -package main - -import ( - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "time" -) - -func main() { - cli, err := grpc.New(&conf.GRPCConfig{ - Host: "101.43.84.47", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-broadcast-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - if err != nil { - panic(err) - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - err = cli.SubscribeWebhook(conf.SubscribeItem{ - SubscribeMode: conf.BROADCASTING, - SubscribeType: conf.ASYNC, - Topic: "grpc-broadcast-topic", - }, "") - if err != nil { - fmt.Println(err.Error()) - return - } - time.Sleep(time.Hour) -} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go b/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go deleted file mode 100644 index 47973c5e70..0000000000 --- a/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go +++ /dev/null @@ -1,67 +0,0 @@ -// 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. - -package main - -import ( - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "time" -) - -func main() { - cli, err := grpc.New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-broadcast-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - if err != nil { - panic(err) - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - err = cli.SubscribeWebhook(conf.SubscribeItem{ - SubscribeMode: conf.BROADCASTING, - SubscribeType: conf.ASYNC, - Topic: "grpc-broadcast-topic", - }, "http://localhost:18080/onmessage") - if err != nil { - fmt.Println(err.Error()) - return - } - time.Sleep(time.Hour) -} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go b/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go deleted file mode 100644 index d95b44ef81..0000000000 --- a/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go +++ /dev/null @@ -1,67 +0,0 @@ -// 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. - -package main - -import ( - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "time" -) - -func main() { - cli, err := grpc.New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-sync-consumer-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - if err != nil { - panic(err) - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - err = cli.SubscribeWebhook(conf.SubscribeItem{ - SubscribeMode: conf.CLUSTERING, - SubscribeType: conf.SYNC, - Topic: "grpc-topic", - }, "") - if err != nil { - fmt.Println(err.Error()) - return - } - time.Sleep(time.Hour) -} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go b/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go deleted file mode 100644 index 32303feb7d..0000000000 --- a/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go +++ /dev/null @@ -1,71 +0,0 @@ -// 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. - -package main - -import ( - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "time" -) - -func main() { - cli, err := grpc.New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-sync-consumer-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - if err != nil { - panic(err) - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - err = cli.SubscribeStream(conf.SubscribeItem{ - SubscribeMode: conf.CLUSTERING, - SubscribeType: conf.ASYNC, - Topic: "grpc-topic", - }, func(msg *proto.SimpleMessage) interface{} { - fmt.Println("receive msg: " + msg.String()) - return nil - }) - if err != nil { - fmt.Println(err.Error()) - return - } - time.Sleep(time.Hour) -} diff --git a/eventmesh-sdk-go/examples/grpc/producer/bp/main.go b/eventmesh-sdk-go/examples/grpc/producer/bp/main.go deleted file mode 100644 index fe3cb55607..0000000000 --- a/eventmesh-sdk-go/examples/grpc/producer/bp/main.go +++ /dev/null @@ -1,88 +0,0 @@ -// 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. - -package main - -import ( - "context" - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" -) - -func main() { - cfg := &conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-batch-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: false, - }, - } - cli, err := grpc.New(cfg) - if err != nil { - fmt.Println("create publish client err:" + err.Error()) - return - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - batchMsg := &proto.BatchMessage{ - Header: grpc.CreateHeader(cfg), - ProducerGroup: "grpc-producergroup", - Topic: "grpc-batch-topic", - MessageItem: []*proto.BatchMessage_MessageItem{ - { - Content: "test for batch publish go grpc -1", - Ttl: "1024", - UniqueId: "110", - SeqNum: "111", - Tag: "batch publish tag 1", - Properties: map[string]string{ - "from": "grpc", - "type": "batch publish", - }, - }, - { - Content: "test for batch publish go grpc", - Ttl: "1024", - UniqueId: "210", - SeqNum: "211", - Tag: "batch publish tag 2", - Properties: map[string]string{ - "from": "grpc", - "type": "batch publish", - }, - }, - }, - } - resp, err := cli.BatchPublish(context.TODO(), batchMsg) - if err != nil { - panic(err) - } - fmt.Println(resp.String()) -} diff --git a/eventmesh-sdk-go/examples/grpc/producer/publish/main.go b/eventmesh-sdk-go/examples/grpc/producer/publish/main.go deleted file mode 100644 index c86fcedc8e..0000000000 --- a/eventmesh-sdk-go/examples/grpc/producer/publish/main.go +++ /dev/null @@ -1,74 +0,0 @@ -// 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. - -package main - -import ( - "context" - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/google/uuid" - "time" -) - -func main() { - cfg := &conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: false, - }, - } - cli, err := grpc.New(cfg) - if err != nil { - fmt.Println("create publish client err:" + err.Error()) - return - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - for i := 0; i < 10; i++ { - builder := grpc.NewMessageBuilder() - builder.WithHeader(grpc.CreateHeader(cfg)). - WithContent("test for publish go grpc"). - WithProperties(map[string]string{ - "from": "grpc", - "for": "test"}). - WithProducerGroup("grpc-publish-producergroup"). - WithTag("grpc publish tag"). - WithTopic("grpc-topic"). - WithTTL(time.Hour). - WithSeqNO(uuid.New().String()). - WithUniqueID(uuid.New().String()) - resp, err := cli.Publish(context.TODO(), builder.SimpleMessage) - if err != nil { - panic(err) - } - fmt.Println(resp.String()) - } -} diff --git a/eventmesh-sdk-go/examples/grpc/producer/rr/main.go b/eventmesh-sdk-go/examples/grpc/producer/rr/main.go deleted file mode 100644 index 70e486bf09..0000000000 --- a/eventmesh-sdk-go/examples/grpc/producer/rr/main.go +++ /dev/null @@ -1,73 +0,0 @@ -// 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. - -package main - -import ( - "context" - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "time" -) - -func main() { - cfg := &conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 10205, - ENV: "go-grpc-test-env", - Region: "sh", - IDC: "pd", - SYS: "grpc-go", - Username: "grpc-go-username", - Password: "grpc-go-passwd", - ProtocolType: grpc.EventmeshMessage, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-rr-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: false, - }, - } - cli, err := grpc.New(cfg) - if err != nil { - panic(err) - } - defer func() { - if err := cli.Close(); err != nil { - panic(err) - } - }() - builder := grpc.NewMessageBuilder() - builder.WithHeader(grpc.CreateHeader(cfg)). - WithContent("test for rr go grpc"). - WithProperties(map[string]string{ - "from": "grpc", - "for": "test"}). - WithProducerGroup("grpc-rr-producergroup"). - WithTag("grpc rr tag"). - WithTopic("grpc-topic"). - WithTTL(time.Hour). - WithSeqNO("1"). - WithUniqueID("1") - - msg, err := cli.RequestReply(context.TODO(), builder.SimpleMessage) - if err != nil { - fmt.Println("send rr msg err:" + err.Error()) - return - } - fmt.Println(msg.String()) - -} diff --git a/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go b/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go deleted file mode 100644 index 5ca6362ae5..0000000000 --- a/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go +++ /dev/null @@ -1,69 +0,0 @@ -// 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. - -package http - -import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/producer" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - - cloudevents "github.com/cloudevents/sdk-go/v2" - "github.com/google/uuid" - - "os" - "strconv" -) - -func AsyncPubCloudEvents() { - eventMeshIPPort := "127.0.0.1" + ":" + "10105" - producerGroup := "EventMeshTest-producerGroup" - topic := "TEST-TOPIC-HTTP-ASYNC" - env := "P" - idc := "FT" - subSys := "1234" - // FIXME Get ip dynamically - localIp := "127.0.0.1" - - // (Deep) Copy of default config - eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig - eventMeshClientConfig.SetLiteEventMeshAddr(eventMeshIPPort) - eventMeshClientConfig.SetProducerGroup(producerGroup) - eventMeshClientConfig.SetEnv(env) - eventMeshClientConfig.SetIdc(idc) - eventMeshClientConfig.SetSys(subSys) - eventMeshClientConfig.SetIp(localIp) - eventMeshClientConfig.SetPid(strconv.Itoa(os.Getpid())) - - // Make event to send - event := cloudevents.NewEvent() - event.SetID(uuid.New().String()) - event.SetSubject(topic) - event.SetSource("example/uri") - event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) - event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) - event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) - data := map[string]string{"hello": "EventMesh"} - err := event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) - if err != nil { - log.Fatalf("Failed to set cloud event data, error: %v", err) - } - - // Publish event - httpProducer := producer.NewEventMeshHttpProducer(eventMeshClientConfig) - httpProducer.Publish(event) -} diff --git a/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go b/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go deleted file mode 100644 index 0af60d5f53..0000000000 --- a/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -package tcp - -import ( - "time" - - "github.com/google/uuid" - "strconv" - - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" - gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" - cloudevents "github.com/cloudevents/sdk-go/v2" -) - -func AsyncPubCloudEvents() { - eventMeshIp := "127.0.0.1" - eventMeshTcpPort := 10000 - topic := "TEST-TOPIC-TCP-ASYNC" - - // Init client - userAgent := gtcp.UserAgent{Env: "test", Subsystem: "5023", Path: "/data/app/umg_proxy", Pid: 32893, - Host: "127.0.0.1", Port: 8362, Version: "2.0.11", Username: "PU4283", Password: "PUPASS", Idc: "FT", - Group: "EventmeshTestGroup", Purpose: "pub"} - config := conf.NewEventMeshTCPClientConfig(eventMeshIp, eventMeshTcpPort, userAgent) - client := tcp.CreateEventMeshTCPClient(*config, protocol.DefaultMessageType.CloudEvent) - client.Init() - - // Make event to send - event := cloudevents.NewEvent() - event.SetID(uuid.New().String()) - event.SetSubject(topic) - event.SetSource("example/uri") - event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) - event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) - event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) - data := map[string]string{"hello": "EventMesh"} - event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) - - // Publish event - client.Publish(event, 10000) - time.Sleep(10 * time.Second) -} diff --git a/eventmesh-sdk-go/go.mod b/eventmesh-sdk-go/go.mod deleted file mode 100644 index 2ae6bd6c9a..0000000000 --- a/eventmesh-sdk-go/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -module github.com/apache/incubator-eventmesh/eventmesh-sdk-go - -go 1.16 - -require ( - github.com/cespare/xxhash v1.1.0 - github.com/cloudevents/sdk-go/v2 v2.6.0 - github.com/google/uuid v1.3.0 - github.com/json-iterator/go v1.1.10 - github.com/panjf2000/ants v1.3.0 - github.com/sony/sonyflake v1.0.0 - github.com/stretchr/testify v1.7.0 - go.uber.org/atomic v1.4.0 - go.uber.org/zap v1.10.0 - google.golang.org/grpc v1.45.0 - google.golang.org/protobuf v1.28.0 -) diff --git a/eventmesh-sdk-go/go.sum b/eventmesh-sdk-go/go.sum deleted file mode 100644 index 80f6b9c21c..0000000000 --- a/eventmesh-sdk-go/go.sum +++ /dev/null @@ -1,172 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudevents/sdk-go/v2 v2.6.0 h1:yp6zLEvhXSi6P25zzfgORgFI0quG2/NXoH9QoHzvKn8= -github.com/cloudevents/sdk-go/v2 v2.6.0/go.mod h1:nlXhgFkf0uTopxmRXalyMwS2LG70cRGPrxzmjJgSG0U= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= -github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M= -github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= -github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/eventmesh-sdk-go/grpc/api.go b/eventmesh-sdk-go/grpc/api.go deleted file mode 100644 index b6568e6d6f..0000000000 --- a/eventmesh-sdk-go/grpc/api.go +++ /dev/null @@ -1,51 +0,0 @@ -// 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. - -package grpc - -import ( - "context" - - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "google.golang.org/grpc" -) - -// OnMessage on receive message from eventmesh, used in subscribe message -type OnMessage func(*proto.SimpleMessage) interface{} - -// Interface grpc client to producer and consumer message -type Interface interface { - // Publish send message to eventmesh, without wait the response from other client - Publish(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.Response, error) - - // RequestReply send message to eventmesh, and wait for the response - RequestReply(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.SimpleMessage, error) - - // BatchPublish send batch message to eventmesh - BatchPublish(ctx context.Context, msg *proto.BatchMessage, opts ...grpc.CallOption) (*proto.Response, error) - - // SubscribeWebhook consumer message in webhook, and OnMessage invoked when new message arrived - SubscribeWebhook(item conf.SubscribeItem, callbackURL string) error - - // SubscribeStream stream subscribe the message - SubscribeStream(item conf.SubscribeItem, handler OnMessage) error - - // UnSubscribe unsubcribe topic, and don't subscribe msg anymore - UnSubscribe() error - - // Close release all resources in the client - Close() error -} diff --git a/eventmesh-sdk-go/grpc/client_test.go b/eventmesh-sdk-go/grpc/client_test.go deleted file mode 100644 index f3ebf3b8ec..0000000000 --- a/eventmesh-sdk-go/grpc/client_test.go +++ /dev/null @@ -1,464 +0,0 @@ -// 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. - -package grpc - -import ( - "context" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc" - "testing" - "time" -) - -func Test_newEventMeshGRPCClient(t *testing.T) { - type args struct { - cfg *conf.GRPCConfig - } - tests := []struct { - name string - args args - want *eventMeshGRPCClient - wantErr bool - }{ - { - name: "host is empty", - args: args{cfg: &conf.GRPCConfig{ - Host: "", - }}, - wantErr: true, - want: nil, - }, - { - name: "producer wrong", - args: args{cfg: &conf.GRPCConfig{ - Host: "1.1.1.1", - ProducerConfig: conf.ProducerConfig{}, - }}, - wantErr: true, - want: nil, - }, - { - name: "client with send msg", - args: args{cfg: &conf.GRPCConfig{ - Host: "101.43.84.47", - Port: 10205, - ENV: "sendmsgenv", - Region: "sh", - IDC: "idc01", - SYS: "test-system", - ProtocolType: "grpc", - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-producer-group", - }, - Username: "user", - Password: "passwd", - }}, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cli, err := newEventMeshGRPCClient(tt.args.cfg) - if (err != nil) != tt.wantErr { - t.Errorf("newEventMeshGRPCClient() error = %v, wantErr %v", err, tt.wantErr) - return - } - if err == nil { - assert.NoError(t, cli.Close()) - } - }) - } -} - -func Test_multiple_set_context(t *testing.T) { - root := context.Background() - onec, cancel := context.WithTimeout(root, time.Second*5) - defer cancel() - valc := context.WithValue(onec, "test", "got") - - select { - case <-valc.Done(): - val := valc.Value("test") - t.Logf("5 s reached, value in context:%v", val) - case <-time.After(time.Second * 10): - t.Logf("ooor, 10s timeout") - } - -} - -func Test_eventMeshGRPCClient_Publish(t *testing.T) { - // run fake server - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: false, - }, - }) - assert.NoError(t, err, "create grpc client") - type args struct { - ctx context.Context - msg *proto.SimpleMessage - opts []grpc.CallOption - } - tests := []struct { - name string - args args - want *proto.Response - wantErr assert.ErrorAssertionFunc - }{ - { - name: "publish msg", - args: args{ - ctx: context.TODO(), - msg: &proto.SimpleMessage{ - Header: &proto.RequestHeader{}, - Topic: "test-publish-topic", - }, - }, - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { - return true - }, - }, - { - name: "publish with timeout", - args: args{ - ctx: func() context.Context { - ctx, _ := context.WithTimeout(context.Background(), time.Second*10) - return ctx - }(), - msg: &proto.SimpleMessage{ - Header: &proto.RequestHeader{}, - Topic: "test-timeout-topic", - }, - }, - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { - return true - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := cli.Publish(tt.args.ctx, tt.args.msg, tt.args.opts...) - assert.NoError(t, err) - t.Logf("receive publish response:%v", got.String()) - assert.NoError(t, cli.Close()) - }) - } -} - -func Test_eventMeshGRPCClient_RequestReply(t *testing.T) { - // run fake server - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: false, - }, - }) - assert.NoError(t, err, "create grpc client") - type args struct { - ctx context.Context - msg *proto.SimpleMessage - opts []grpc.CallOption - } - tests := []struct { - name string - args args - want *proto.SimpleMessage - wantErr assert.ErrorAssertionFunc - }{ - { - name: "test-request-reply", - args: args{ - ctx: context.TODO(), - msg: &proto.SimpleMessage{ - Header: &proto.RequestHeader{}, - Topic: "test-request-reply-topic", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := cli.RequestReply(tt.args.ctx, tt.args.msg, tt.args.opts...) - assert.NoError(t, err) - t.Logf("receive request reply response:%v", got.String()) - assert.NoError(t, cli.Close()) - }) - } -} - -func Test_eventMeshGRPCClient_BatchPublish(t *testing.T) { - // run fake server - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: false, - }, - }) - assert.NoError(t, err, "create grpc client") - type args struct { - ctx context.Context - msg *proto.BatchMessage - opts []grpc.CallOption - } - tests := []struct { - name string - args args - want *proto.Response - wantErr assert.ErrorAssertionFunc - }{ - { - name: "test batch publish", - args: args{ - ctx: context.TODO(), - msg: &proto.BatchMessage{ - Header: &proto.RequestHeader{}, - ProducerGroup: "fake-batch-group", - Topic: "fake-batch-topic", - MessageItem: []*proto.BatchMessage_MessageItem{ - { - Content: "batch-1", - Ttl: "1", - UniqueId: "batch-id", - SeqNum: "1", - Tag: "tag", - Properties: map[string]string{ - "from": "test", - "type": "batch-msg", - }, - }, - { - Content: "batch-2", - Ttl: "2", - UniqueId: "batch-id", - SeqNum: "2", - Tag: "tag", - Properties: map[string]string{ - "from": "test", - "type": "batch-msg", - }, - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := cli.BatchPublish(tt.args.ctx, tt.args.msg, tt.args.opts...) - assert.NoError(t, err) - t.Logf("receive request reply response:%v", got.String()) - assert.NoError(t, cli.Close()) - }) - } -} - -func Test_eventMeshGRPCClient_webhook_subscribe(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) - defer cancel() - go runWebhookServer(ctx) - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - assert.NoError(t, err, "create grpc client") - assert.NoError(t, cli.SubscribeWebhook(conf.SubscribeItem{ - SubscribeMode: 1, - SubscribeType: 1, - Topic: "topic-1", - }, "http://localhost:8080/onmessage")) - time.Sleep(time.Second * 5) -} - -func Test_eventMeshGRPCClient_Subscribe(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - assert.NoError(t, err, "create grpc client") - type args struct { - item conf.SubscribeItem - handler OnMessage - } - tests := []struct { - name string - args args - wantErr assert.ErrorAssertionFunc - }{ - { - name: "subcribe one", - args: args{ - item: conf.SubscribeItem{ - SubscribeMode: 1, - SubscribeType: 1, - Topic: "topic-1", - }, - handler: func(message *proto.SimpleMessage) interface{} { - t.Logf("receive subscribe response:%s", message.String()) - return nil - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := cli.SubscribeStream(tt.args.item, tt.args.handler) - assert.NoError(t, err) - assert.NoError(t, cli.Close()) - }) - } -} - -func Test_eventMeshGRPCClient_UnSubscribe(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "test-consumer-group-subscribe", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - assert.NoError(t, err, "create grpc client") - err = cli.SubscribeStream(conf.SubscribeItem{ - SubscribeMode: 1, - SubscribeType: 1, - Topic: "topic-1", - }, func(message *proto.SimpleMessage) interface{} { - t.Logf("receive subscribe response:%s", message.String()) - return nil - }) - assert.NoError(t, err, "subscribe err") - tests := []struct { - name string - wantErr assert.ErrorAssertionFunc - }{ - { - name: "unsubcribe", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.NoError(t, cli.UnSubscribe()) - assert.NoError(t, cli.Close()) - }) - } -} - -type fakeidg struct { -} - -func (f *fakeidg) Next() string { - return "fake" -} - -func Test_eventMeshGRPCClient_setupContext(t *testing.T) { - type args struct { - ctx context.Context - } - - cli := &eventMeshGRPCClient{ - idg: &fakeidg{}, - } - tests := []struct { - name string - args args - want string - }{ - { - name: "setup with uid", - args: args{ - ctx: context.WithValue(context.Background(), GRPC_ID_KEY, "value"), - }, - want: "value", - }, - { - name: "setup without uid", - args: args{ - ctx: context.TODO(), - }, - want: "fake", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx := cli.setupContext(tt.args.ctx) - assert.Equal(t, ctx.Value(GRPC_ID_KEY).(string), tt.want) - }) - } -} diff --git a/eventmesh-sdk-go/grpc/dispatcher_test.go b/eventmesh-sdk-go/grpc/dispatcher_test.go deleted file mode 100644 index 49392057fb..0000000000 --- a/eventmesh-sdk-go/grpc/dispatcher_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// 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. - -package grpc - -import ( - "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/stretchr/testify/assert" - "sync" - "testing" -) - -func Test_messageDispatcher_addHandler(t *testing.T) { - type fields struct { - topicMap *sync.Map - poolsize int - } - type args struct { - topic string - hdl OnMessage - } - tests := []struct { - name string - fields fields - args args - wantErr assert.ErrorAssertionFunc - }{ - { - name: "test add handler", - fields: fields{ - topicMap: new(sync.Map), - poolsize: 5, - }, - args: args{ - topic: "handler-1", - hdl: func(message *proto.SimpleMessage) interface{} { - t.Logf("handle message") - return nil - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &messageDispatcher{ - topicMap: tt.fields.topicMap, - poolsize: tt.fields.poolsize, - } - tt.wantErr(t, m.addHandler(tt.args.topic, tt.args.hdl), fmt.Sprintf("addHandler(%v, %v)", tt.args.topic, tt.args.hdl)) - }) - } -} diff --git a/eventmesh-sdk-go/grpc/heartbeat_test.go b/eventmesh-sdk-go/grpc/heartbeat_test.go deleted file mode 100644 index 45f6ed1610..0000000000 --- a/eventmesh-sdk-go/grpc/heartbeat_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// 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. - -package grpc - -import ( - "context" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/stretchr/testify/assert" - "testing" - "time" -) - -func Test_eventMeshHeartbeat_sendMsg(t *testing.T) { - // run fake server - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go runFakeServer(ctx) - cli, err := New(&conf.GRPCConfig{ - Host: "127.0.0.1", - Port: 8086, - ProducerConfig: conf.ProducerConfig{ - ProducerGroup: "test-publish-group", - LoadBalancerType: conf.Random, - }, - ConsumerConfig: conf.ConsumerConfig{ - Enabled: true, - ConsumerGroup: "fake-consumer", - PoolSize: 5, - }, - HeartbeatConfig: conf.HeartbeatConfig{ - Period: time.Second * 5, - Timeout: time.Second * 3, - }, - }) - topic := "fake-topic" - assert.NoError(t, cli.SubscribeStream(conf.SubscribeItem{ - SubscribeType: 1, - SubscribeMode: 1, - Topic: topic, - }, func(message *proto.SimpleMessage) interface{} { - t.Logf("receive sub msg:%v", message.String()) - return nil - })) - rcli := cli.(*eventMeshGRPCClient) - beat := rcli.heartbeat - assert.NoError(t, err, "create grpc client") - defer assert.NoError(t, cli.Close()) - tests := []struct { - name string - want error - }{ - { - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := beat.sendMsg(beat.client) - assert.NoError(t, err) - }) - } -} diff --git a/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go b/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go deleted file mode 100644 index cbb26df6f6..0000000000 --- a/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go +++ /dev/null @@ -1,110 +0,0 @@ -// 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. - -package consumer - -import ( - gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/body/client" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/common" - gutils "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/model" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - nethttp "net/http" - "strconv" - "time" -) - -type EventMeshHttpConsumer struct { - *http.AbstractHttpClient - subscriptions []protocol.SubscriptionItem -} - -func NewEventMeshHttpConsumer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshHttpConsumer { - c := &EventMeshHttpConsumer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} - c.subscriptions = make([]protocol.SubscriptionItem, 1000) - return c -} - -func (e *EventMeshHttpConsumer) HeartBeat(topicList []protocol.SubscriptionItem, subscribeUrl string) { - - // FIXME check topicList, subscribeUrl is not blank - - for range time.Tick(time.Duration(gcommon.Constants.HEARTBEAT) * time.Millisecond) { - - var heartbeatEntities []client.HeartbeatEntity - for _, item := range topicList { - entity := client.HeartbeatEntity{Topic: item.Topic, Url: subscribeUrl} - heartbeatEntities = append(heartbeatEntities, entity) - } - - requestParam := e.buildCommonRequestParam() - requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.HEARTBEAT.RequestCode)) - // FIXME Java is name of SUB name - //requestParam.AddBody(client.HeartbeatRequestBodyKey.CLIENTTYPE, common.DefaultClientType.SUB.name()) - requestParam.AddBody(client.HeartbeatRequestBodyKey.CLIENTTYPE, "SUB") - requestParam.AddBody(client.HeartbeatRequestBodyKey.HEARTBEATENTITIES, gutils.MarshalJsonString(heartbeatEntities)) - - target := e.SelectEventMesh() - resp := utils.HttpPost(e.HttpClient, target, requestParam) - var ret http.EventMeshRetObj - gutils.UnMarshalJsonString(resp, &ret) - if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { - log.Fatalf("Request failed, error code: %d", ret.RetCode) - } - - } - -} - -func (e *EventMeshHttpConsumer) Subscribe(topicList []protocol.SubscriptionItem, subscribeUrl string) { - - // FIXME check topicList, subscribeUrl is not blank - - requestParam := e.buildCommonRequestParam() - requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.SUBSCRIBE.RequestCode)) - requestParam.AddBody(client.SubscribeRequestBodyKey.TOPIC, gutils.MarshalJsonString(topicList)) - requestParam.AddBody(client.SubscribeRequestBodyKey.URL, subscribeUrl) - requestParam.AddBody(client.SubscribeRequestBodyKey.CONSUMERGROUP, e.EventMeshHttpClientConfig.ConsumerGroup()) - - target := e.SelectEventMesh() - resp := utils.HttpPost(e.HttpClient, target, requestParam) - var ret http.EventMeshRetObj - gutils.UnMarshalJsonString(resp, &ret) - if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { - log.Fatalf("Request failed, error code: %d", ret.RetCode) - } - e.subscriptions = append(e.subscriptions, topicList...) -} - -func (e *EventMeshHttpConsumer) buildCommonRequestParam() *model.RequestParam { - param := model.NewRequestParam(nethttp.MethodPost) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, e.EventMeshHttpClientConfig.Env()) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, e.EventMeshHttpClientConfig.Idc()) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, e.EventMeshHttpClientConfig.Ip()) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, e.EventMeshHttpClientConfig.Pid()) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, e.EventMeshHttpClientConfig.Sys()) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, e.EventMeshHttpClientConfig.UserName()) - param.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, e.EventMeshHttpClientConfig.Password()) - param.AddHeader(common.ProtocolKey.VERSION, common.DefaultProtocolVersion.V1.Version()) - param.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) - param.SetTimeout(gcommon.Constants.DEFAULT_HTTP_TIME_OUT) - param.AddBody(client.HeartbeatRequestBodyKey.CONSUMERGROUP, e.EventMeshHttpClientConfig.ConsumerGroup()) - return param -} diff --git a/eventmesh-sdk-go/http/producer/cloudevent_producer.go b/eventmesh-sdk-go/http/producer/cloudevent_producer.go deleted file mode 100644 index 815e665875..0000000000 --- a/eventmesh-sdk-go/http/producer/cloudevent_producer.go +++ /dev/null @@ -1,101 +0,0 @@ -// 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. - -package producer - -import ( - gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/message" - gutils "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/model" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - cloudevents "github.com/cloudevents/sdk-go/v2" - - nethttp "net/http" - "strconv" -) - -type CloudEventProducer struct { - *http.AbstractHttpClient -} - -func NewCloudEventProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *CloudEventProducer { - c := &CloudEventProducer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} - return c -} - -func (c *CloudEventProducer) Publish(event cloudevents.Event) { - enhancedEvent := c.enhanceCloudEvent(event) - requestParam := c.buildCommonPostParam(enhancedEvent) - requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.MSG_SEND_ASYNC.RequestCode)) - - target := c.SelectEventMesh() - resp := utils.HttpPost(c.HttpClient, target, requestParam) - var ret http.EventMeshRetObj - gutils.UnMarshalJsonString(resp, &ret) - if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { - log.Fatalf("Request failed, error code: %d", ret.RetCode) - } -} - -func (c *CloudEventProducer) buildCommonPostParam(event cloudevents.Event) *model.RequestParam { - - eventBytes, err := event.MarshalJSON() - if err != nil { - log.Fatalf("Failed to marshal cloudevent") - } - content := string(eventBytes) - - requestParam := model.NewRequestParam(nethttp.MethodPost) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, c.EventMeshHttpClientConfig.UserName()) - requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, c.EventMeshHttpClientConfig.Password()) - requestParam.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) - // FIXME Improve constants - requestParam.AddHeader(common.ProtocolKey.PROTOCOL_TYPE, "cloudevents") - requestParam.AddHeader(common.ProtocolKey.PROTOCOL_DESC, "http") - requestParam.AddHeader(common.ProtocolKey.PROTOCOL_VERSION, event.SpecVersion()) - - // todo: move producerGroup tp header - requestParam.AddBody(message.SendMessageRequestBodyKey.PRODUCERGROUP, c.EventMeshHttpClientConfig.ProducerGroup()) - requestParam.AddBody(message.SendMessageRequestBodyKey.CONTENT, content) - - return requestParam -} - -func (c *CloudEventProducer) enhanceCloudEvent(event cloudevents.Event) cloudevents.Event { - event.SetExtension(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) - event.SetExtension(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) - event.SetExtension(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) - event.SetExtension(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) - event.SetExtension(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) - // FIXME Random string - event.SetExtension(common.ProtocolKey.ClientInstanceKey.BIZSEQNO, "333333") - event.SetExtension(common.ProtocolKey.ClientInstanceKey.UNIQUEID, "444444") - event.SetExtension(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) - // FIXME Java is name of spec version name - //event.SetExtension(common.ProtocolKey.PROTOCOL_DESC, event.SpecVersion()) - event.SetExtension(common.ProtocolKey.PROTOCOL_VERSION, event.SpecVersion()) - - return event -} diff --git a/eventmesh-sdk-go/http/producer/eventmesh_http_producer.go b/eventmesh-sdk-go/http/producer/eventmesh_http_producer.go deleted file mode 100644 index e4eb3c43dd..0000000000 --- a/eventmesh-sdk-go/http/producer/eventmesh_http_producer.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -package producer - -import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" - cloudevents "github.com/cloudevents/sdk-go/v2" -) - -type EventMeshHttpProducer struct { - cloudEventProducer *CloudEventProducer -} - -func NewEventMeshHttpProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshHttpProducer { - return &EventMeshHttpProducer{ - cloudEventProducer: NewCloudEventProducer(eventMeshHttpClientConfig), - } -} - -func (e *EventMeshHttpProducer) Publish(eventMeshMessage interface{}) { - - // FIXME Check eventMeshMessage is not nil - - // CloudEvent - if _, ok := eventMeshMessage.(cloudevents.Event); ok { - event := eventMeshMessage.(cloudevents.Event) - e.cloudEventProducer.Publish(event) - } -} diff --git a/eventmesh-sdk-go/http/producer/eventmesh_protocol_producer.go b/eventmesh-sdk-go/http/producer/eventmesh_protocol_producer.go deleted file mode 100644 index de56476b75..0000000000 --- a/eventmesh-sdk-go/http/producer/eventmesh_protocol_producer.go +++ /dev/null @@ -1,20 +0,0 @@ -// 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. - -package producer - -type EventMeshProtocolProducer interface { - Publish(eventMeshMessage interface{}) -} diff --git a/eventmesh-sdk-go/log/logger.go b/eventmesh-sdk-go/log/logger.go deleted file mode 100644 index e500511dcf..0000000000 --- a/eventmesh-sdk-go/log/logger.go +++ /dev/null @@ -1,163 +0,0 @@ -// 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. - -package log - -import ( - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - "time" -) - -var ( - // _defaultLogger global log instance, default to zap.log - _defaultLogger Logger = &DefaultLogger{ - SugaredLogger: func() *zap.SugaredLogger { - encoder := zapcore.EncoderConfig{ - TimeKey: "ts", - LevelKey: "level", - NameKey: "logger", - CallerKey: "caller", - MessageKey: "msg", - StacktraceKey: "stacktrace", - LineEnding: zapcore.DefaultLineEnding, - EncodeLevel: zapcore.CapitalLevelEncoder, - EncodeTime: func(time time.Time, encoder zapcore.PrimitiveArrayEncoder) { - encoder.AppendString(time.Format("2006-01-02 15:04:05.000")) - }, - EncodeDuration: zapcore.SecondsDurationEncoder, - EncodeCaller: zapcore.ShortCallerEncoder, - } - l, _ := zap.Config{ - Level: zap.NewAtomicLevelAt(zap.InfoLevel), - Development: false, - Sampling: &zap.SamplingConfig{ - Initial: 100, - Thereafter: 100, - }, - Encoding: "console", - EncoderConfig: encoder, - OutputPaths: []string{"stderr"}, - ErrorOutputPaths: []string{"stderr"}, - }.Build([]zap.Option{zap.AddCallerSkip(2)}...) - return l.Sugar() - }(), - } -) - -// SetLogger set the log -func SetLogger(l Logger) { - _defaultLogger = l -} - -func Debugf(template string, args ...interface{}) { - _defaultLogger.Debugf(template, args...) -} - -func Infof(template string, args ...interface{}) { - _defaultLogger.Infof(template, args...) -} - -// Warnf uses fmt.Sprintf to log a templated message. -func Warnf(template string, args ...interface{}) { - _defaultLogger.Warnf(template, args...) -} - -// Errorf uses fmt.Sprintf to log a templated message. -func Errorf(template string, args ...interface{}) { - _defaultLogger.Errorf(template, args...) -} - -// DPanicf uses fmt.Sprintf to log a templated message. In development, the -// log then panics. (See DPanicLevel for details.) -func DPanicf(template string, args ...interface{}) { - _defaultLogger.DPanicf(template, args...) -} - -// Panicf uses fmt.Sprintf to log a templated message, then panics. -func Panicf(template string, args ...interface{}) { - _defaultLogger.Panicf(template, args...) -} - -// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. -func Fatalf(template string, args ...interface{}) { - _defaultLogger.Fatalf(template, args...) -} - -// Logger define the log api for eventmesh -type Logger interface { - // Debugf uses fmt.Sprintf to log a templated message. - // DebugLevel logs are typically voluminous, and are usually disabled in - // production. - Debugf(template string, args ...interface{}) - - // Infof uses fmt.Sprintf to log a templated message. - // InfoLevel is the default logging priority. - Infof(template string, args ...interface{}) - - // Warnf uses fmt.Sprintf to log a templated message. - // WarnLevel logs are more important than Info, but don't need individual - // human review. - Warnf(template string, args ...interface{}) - - // Errorf uses fmt.Sprintf to log a templated message. - // ErrorLevel logs are high-priority. If an application is running smoothly, - // it shouldn't generate any error-level logs. - Errorf(template string, args ...interface{}) - - // DPanicf uses fmt.Sprintf to log a templated message. In development, the - // DPanicLevel logs are particularly important errors. In development the - // log panics after writing the message. - DPanicf(template string, args ...interface{}) - - // Panicf uses fmt.Sprintf to log a templated message, then panics. - Panicf(template string, args ...interface{}) - - // Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. - Fatalf(template string, args ...interface{}) -} - -// DefaultLogger write log by zap log -type DefaultLogger struct { - *zap.SugaredLogger -} - -func (s *DefaultLogger) Debugf(template string, args ...interface{}) { - s.SugaredLogger.Debugf(template, args...) -} - -func (s *DefaultLogger) Infof(template string, args ...interface{}) { - s.SugaredLogger.Infof(template, args...) -} - -func (s *DefaultLogger) Warnf(template string, args ...interface{}) { - s.SugaredLogger.Warnf(template, args...) -} - -func (s *DefaultLogger) Errorf(template string, args ...interface{}) { - s.SugaredLogger.Errorf(template, args...) -} - -func (s *DefaultLogger) DPanicf(template string, args ...interface{}) { - s.SugaredLogger.DPanicf(template, args...) -} - -func (s *DefaultLogger) Panicf(template string, args ...interface{}) { - s.SugaredLogger.Panicf(template, args...) -} - -func (s *DefaultLogger) Fatalf(template string, args ...interface{}) { - s.SugaredLogger.Fatalf(template, args...) -} diff --git a/eventmesh-sdk-java/build.gradle b/eventmesh-sdk-java/build.gradle deleted file mode 100644 index ee9e2b1222..0000000000 --- a/eventmesh-sdk-java/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -def grpcVersion = '1.17.1' - -dependencies { - api project(":eventmesh-common") - - implementation "com.fasterxml.jackson.core:jackson-databind" - implementation "com.fasterxml.jackson.core:jackson-core" - implementation "com.fasterxml.jackson.core:jackson-annotations" - implementation "org.apache.commons:commons-collections4" - - implementation "io.netty:netty-all" - implementation "org.apache.httpcomponents:httpclient" - - implementation "io.grpc:grpc-protobuf:${grpcVersion}" - implementation "io.grpc:grpc-stub:${grpcVersion}" - implementation "io.grpc:grpc-netty:${grpcVersion}" - implementation "io.grpc:grpc-netty-shaded:${grpcVersion}" - - // protocol - api "io.cloudevents:cloudevents-core" - api "io.cloudevents:cloudevents-json-jackson" - api "io.openmessaging:openmessaging-api" - - testImplementation project(":eventmesh-common") - - testImplementation "com.fasterxml.jackson.core:jackson-databind" - testImplementation "com.fasterxml.jackson.core:jackson-core" - testImplementation "com.fasterxml.jackson.core:jackson-annotations" - - testImplementation "io.netty:netty-all" - testImplementation "org.apache.httpcomponents:httpclient" - - implementation "io.grpc:grpc-protobuf:1.17.1" - implementation "io.grpc:grpc-stub:1.17.1" - implementation "com.google.protobuf:protobuf-java-util:3.5.1" - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' - - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' - - testImplementation "org.assertj:assertj-core" - - testImplementation "org.mockito:mockito-core" - testImplementation "org.powermock:powermock-module-junit4" - testImplementation "org.powermock:powermock-api-mockito2" -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/config/EventMeshGrpcClientConfig.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/config/EventMeshGrpcClientConfig.java deleted file mode 100644 index 79a67f55b4..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/config/EventMeshGrpcClientConfig.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.config; - -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class EventMeshGrpcClientConfig { - - @Builder.Default - private String serverAddr = "127.0.0.1"; - - @Builder.Default - private int serverPort = 10205; - - @Builder.Default - private String env = "env"; - - @Builder.Default - private String consumerGroup = "DefaultConsumerGroup"; - - @Builder.Default - private String producerGroup = "DefaultProducerGroup"; - - @Builder.Default - private String idc = "default"; - - @Builder.Default - private String sys = "sys123"; - - @Builder.Default - private String userName = "username"; - - @Builder.Default - private String password = "passwd"; - - @Builder.Default - private String language = "JAVA"; - - @Builder.Default - private boolean useTls = false; - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("ClientConfig={") - .append("ServerAddr=").append(serverAddr).append(",") - .append("ServerPort=").append(serverPort).append(",") - .append("env=").append(env).append(",") - .append("idc=").append(idc).append(",") - .append("producerGroup=").append(producerGroup).append(",") - .append("consumerGroup=").append(consumerGroup).append(",") - .append("sys=").append(sys).append(",") - .append("userName=").append(userName).append(",") - .append("password=").append("***").append(",") - .append("useTls=").append(useTls).append("}"); - return sb.toString(); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumer.java deleted file mode 100644 index f181f6559b..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumer.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.consumer; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.util.EventMeshClientUtil; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc.ConsumerServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc.ConsumerServiceStub; -import org.apache.eventmesh.common.protocol.grpc.protos.Heartbeat; -import org.apache.eventmesh.common.protocol.grpc.protos.HeartbeatServiceGrpc; -import org.apache.eventmesh.common.protocol.grpc.protos.HeartbeatServiceGrpc.HeartbeatServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; - -import org.apache.commons.lang3.StringUtils; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -public class EventMeshGrpcConsumer implements AutoCloseable { - - private static final Logger logger = LoggerFactory.getLogger(EventMeshGrpcConsumer.class); - - private static final String SDK_STREAM_URL = "grpc_stream"; - - private final EventMeshGrpcClientConfig clientConfig; - - private final Map subscriptionMap = new ConcurrentHashMap<>(); - private final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor( - Runtime.getRuntime().availableProcessors(), - new ThreadFactoryBuilder().setNameFormat("GRPCClientScheduler").setDaemon(true).build()); - - private ManagedChannel channel; - ConsumerServiceBlockingStub consumerClient; - ConsumerServiceStub consumerAsyncClient; - HeartbeatServiceBlockingStub heartbeatClient; - - private ReceiveMsgHook listener; - private SubStreamHandler subStreamHandler; - - public EventMeshGrpcConsumer(EventMeshGrpcClientConfig clientConfig) { - this.clientConfig = clientConfig; - } - - public void init() { - channel = ManagedChannelBuilder.forAddress(clientConfig.getServerAddr(), clientConfig.getServerPort()) - .usePlaintext().build(); - - consumerClient = ConsumerServiceGrpc.newBlockingStub(channel); - consumerAsyncClient = ConsumerServiceGrpc.newStub(channel); - heartbeatClient = HeartbeatServiceGrpc.newBlockingStub(channel); - - heartBeat(); - } - - public Response subscribe(List subscriptionItems, String url) { - logger.info("Create subscription: " + subscriptionItems + ", url: " + url); - - addSubscription(subscriptionItems, url); - - Subscription subscription = buildSubscription(subscriptionItems, url); - try { - Response response = consumerClient.subscribe(subscription); - logger.info("Received response " + response.toString()); - return response; - } catch (Exception e) { - logger.error("Error in subscribe. error {}", e.getMessage()); - return null; - } - } - - public void subscribe(List subscriptionItems) { - logger.info("Create streaming subscription: " + subscriptionItems); - - if (listener == null) { - logger.error("Error in subscriber, no Event Listener is registered."); - return; - } - - addSubscription(subscriptionItems, SDK_STREAM_URL); - - Subscription subscription = buildSubscription(subscriptionItems, null); - - synchronized (this) { - if (subStreamHandler == null) { - subStreamHandler = new SubStreamHandler<>(consumerAsyncClient, clientConfig, listener); - subStreamHandler.start(); - } - } - subStreamHandler.sendSubscription(subscription); - } - - private void addSubscription(List subscriptionItems, String url) { - for (SubscriptionItem item : subscriptionItems) { - subscriptionMap.put(item.getTopic(), url); - } - } - - private void removeSubscription(List subscriptionItems) { - for (SubscriptionItem item : subscriptionItems) { - subscriptionMap.remove(item.getTopic()); - } - } - - public Response unsubscribe(List subscriptionItems, String url) { - logger.info("Removing subscription: " + subscriptionItems + ", url: " + url); - - removeSubscription(subscriptionItems); - - Subscription subscription = buildSubscription(subscriptionItems, url); - - try { - Response response = consumerClient.unsubscribe(subscription); - logger.info("Received response " + response.toString()); - return response; - } catch (Exception e) { - logger.error("Error in unsubscribe. error {}", e.getMessage()); - return null; - } - } - - public Response unsubscribe(List subscriptionItems) { - logger.info("Removing subscription stream: " + subscriptionItems); - - removeSubscription(subscriptionItems); - - Subscription subscription = buildSubscription(subscriptionItems, null); - - try { - Response response = consumerClient.unsubscribe(subscription); - logger.info("Received response " + response.toString()); - - // there is no stream subscriptions, stop the subscription stream handler - synchronized (this) { - if (!subscriptionMap.containsValue(SDK_STREAM_URL) && subStreamHandler != null) { - subStreamHandler.close(); - subStreamHandler = null; - } - } - return response; - } catch (Exception e) { - logger.error("Error in unsubscribe. error {}", e.getMessage()); - return null; - } - } - - private Subscription buildSubscription(List subscriptionItems, String url) { - Subscription.Builder builder = Subscription.newBuilder() - .setHeader(EventMeshClientUtil.buildHeader(clientConfig, EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME)) - .setConsumerGroup(clientConfig.getConsumerGroup()); - - if (StringUtils.isNotEmpty(url)) { - builder.setUrl(url); - } - - for (SubscriptionItem subscriptionItem : subscriptionItems) { - Subscription.SubscriptionItem.SubscriptionMode mode; - if (SubscriptionMode.CLUSTERING.equals(subscriptionItem.getMode())) { - mode = Subscription.SubscriptionItem.SubscriptionMode.CLUSTERING; - } else if (SubscriptionMode.BROADCASTING.equals(subscriptionItem.getMode())) { - mode = Subscription.SubscriptionItem.SubscriptionMode.BROADCASTING; - } else { - mode = Subscription.SubscriptionItem.SubscriptionMode.UNRECOGNIZED; - } - - Subscription.SubscriptionItem.SubscriptionType type; - if (SubscriptionType.ASYNC.equals(subscriptionItem.getType())) { - type = Subscription.SubscriptionItem.SubscriptionType.ASYNC; - } else if (SubscriptionType.SYNC.equals(subscriptionItem.getType())) { - type = Subscription.SubscriptionItem.SubscriptionType.SYNC; - } else { - type = Subscription.SubscriptionItem.SubscriptionType.UNRECOGNIZED; - } - - Subscription.SubscriptionItem item = Subscription.SubscriptionItem.newBuilder() - .setTopic(subscriptionItem.getTopic()) - .setMode(mode) - .setType(type) - .build(); - builder.addSubscriptionItems(item); - } - return builder.build(); - } - - public synchronized void registerListener(ReceiveMsgHook listener) { - if (this.listener == null) { - this.listener = listener; - } - } - - private void heartBeat() { - RequestHeader header = EventMeshClientUtil.buildHeader(clientConfig, EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME); - scheduler.scheduleAtFixedRate(() -> { - if (subscriptionMap.isEmpty()) { - return; - } - Heartbeat.Builder heartbeatBuilder = Heartbeat.newBuilder() - .setHeader(header) - .setConsumerGroup(clientConfig.getConsumerGroup()) - .setClientType(Heartbeat.ClientType.SUB); - - for (Map.Entry entry : subscriptionMap.entrySet()) { - Heartbeat.HeartbeatItem heartbeatItem = Heartbeat.HeartbeatItem - .newBuilder() - .setTopic(entry.getKey()).setUrl(entry.getValue()) - .build(); - heartbeatBuilder.addHeartbeatItems(heartbeatItem); - } - Heartbeat heartbeat = heartbeatBuilder.build(); - - try { - Response response = heartbeatClient.heartbeat(heartbeat); - if (logger.isDebugEnabled()) { - logger.debug("Grpc Consumer Heartbeat response: {}", response); - } - } catch (Exception e) { - logger.error("Error in sending out heartbeat. error {}", e.getMessage()); - } - }, 10000, EventMeshCommon.HEARTBEAT, TimeUnit.MILLISECONDS); - - logger.info("Grpc Consumer Heartbeat started."); - } - - @Override - public void close() { - if (this.subStreamHandler != null) { - this.subStreamHandler.close(); - } - channel.shutdown(); - scheduler.shutdown(); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/SubStreamHandler.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/SubStreamHandler.java deleted file mode 100644 index ed3654cc91..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/SubStreamHandler.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.consumer; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.util.EventMeshClientUtil; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc.ConsumerServiceStub; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; - -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CountDownLatch; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.grpc.stub.StreamObserver; - -public class SubStreamHandler extends Thread { - - private static final Logger logger = LoggerFactory.getLogger(SubStreamHandler.class); - - private final CountDownLatch latch = new CountDownLatch(1); - - private final ConsumerServiceStub consumerAsyncClient; - - private final EventMeshGrpcClientConfig clientConfig; - - private StreamObserver sender; - - private final ReceiveMsgHook listener; - - public SubStreamHandler(ConsumerServiceStub consumerAsyncClient, EventMeshGrpcClientConfig clientConfig, - ReceiveMsgHook listener) { - this.consumerAsyncClient = consumerAsyncClient; - this.clientConfig = clientConfig; - this.listener = listener; - } - - public void sendSubscription(Subscription subscription) { - synchronized (this) { - if (this.sender == null) { - this.sender = consumerAsyncClient.subscribeStream(createReceiver()); - } - } - senderOnNext(subscription); - } - - private StreamObserver createReceiver() { - return new StreamObserver() { - @Override - public void onNext(SimpleMessage message) { - T msg = EventMeshClientUtil.buildMessage(message, listener.getProtocolType()); - - if (msg instanceof Map) { - logger.info("Received message from Server." + message); - } else { - logger.info("Received message from Server.|seq={}|uniqueId={}|", message.getSeqNum(), message.getUniqueId()); - Subscription streamReply = null; - try { - Optional reply = listener.handle(msg); - if (reply.isPresent()) { - streamReply = buildReplyMessage(message, reply.get()); - } - } catch (Throwable t) { - logger.error("Error in handling reply message.|seq={}|uniqueId={}|", message.getSeqNum(), message.getUniqueId(), t); - } - if (streamReply != null) { - logger.info("Sending reply message to Server.|seq={}|uniqueId={}|", streamReply.getReply().getSeqNum(), - streamReply.getReply().getUniqueId()); - senderOnNext(streamReply); - } - } - } - - @Override - public void onError(Throwable t) { - logger.error("Received Server side error: " + t.getMessage()); - close(); - } - - @Override - public void onCompleted() { - logger.info("Finished receiving messages from server."); - close(); - } - }; - } - - private Subscription buildReplyMessage(SimpleMessage reqMessage, T replyMessage) { - SimpleMessage simpleMessage = EventMeshClientUtil.buildSimpleMessage(replyMessage, clientConfig, listener.getProtocolType()); - - Subscription.Reply reply = Subscription.Reply.newBuilder() - .setProducerGroup(clientConfig.getConsumerGroup()) - .setTopic(simpleMessage.getTopic()) - .setContent(simpleMessage.getContent()) - .setSeqNum(simpleMessage.getSeqNum()) - .setUniqueId(simpleMessage.getUniqueId()) - .setTtl(simpleMessage.getTtl()) - .putAllProperties(reqMessage.getPropertiesMap()) - .putAllProperties(simpleMessage.getPropertiesMap()) - .build(); - - return Subscription.newBuilder() - .setHeader(simpleMessage.getHeader()) - .setReply(reply).build(); - } - - @Override - public void run() { - try { - latch.await(); - } catch (InterruptedException e) { - logger.error("SubStreamHandler Thread interrupted." + e.getMessage()); - } - } - - public void close() { - if (this.sender != null) { - senderOnComplete(); - this.sender = null; - } - latch.countDown(); - logger.info("SubStreamHandler closed."); - } - - private void senderOnNext(Subscription subscription) { - try { - synchronized (sender) { - sender.onNext(subscription); - } - } catch (Throwable t) { - logger.warn("StreamObserver Error onNext {}", t.getMessage()); - } - } - - private void senderOnComplete() { - try { - synchronized (sender) { - sender.onCompleted(); - } - } catch (Throwable t) { - logger.warn("StreamObserver Error onComplete {}", t.getMessage()); - } - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducer.java deleted file mode 100644 index 99118f1d64..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducer.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.producer; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.util.EventMeshClientUtil; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.PublisherServiceGrpc.PublisherServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -import java.util.List; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; - -public class CloudEventProducer { - private static final Logger logger = LoggerFactory.getLogger(EventMeshGrpcProducer.class); - - private static final String PROTOCOL_TYPE = EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME; - - private final EventMeshGrpcClientConfig clientConfig; - - private final PublisherServiceBlockingStub publisherClient; - - public CloudEventProducer(EventMeshGrpcClientConfig clientConfig, PublisherServiceBlockingStub publisherClient) { - this.clientConfig = clientConfig; - this.publisherClient = publisherClient; - } - - public Response publish(List events) { - logger.info("BatchPublish message, batch size=" + events.size()); - - if (events.size() == 0) { - return null; - } - List enhancedEvents = events.stream() - .map(event -> enhanceCloudEvent(event, null)) - .collect(Collectors.toList()); - - BatchMessage enhancedMessage = EventMeshClientUtil.buildBatchMessages(enhancedEvents, clientConfig, PROTOCOL_TYPE); - try { - Response response = publisherClient.batchPublish(enhancedMessage); - logger.info("Received response " + response.toString()); - return response; - } catch (Exception e) { - logger.error("Error in BatchPublish message {}, error {}", events, e.getMessage()); - return null; - } - } - - public Response publish(CloudEvent cloudEvent) { - logger.info("Publish message " + cloudEvent.toString()); - CloudEvent enhanceEvent = enhanceCloudEvent(cloudEvent, null); - - SimpleMessage enhancedMessage = EventMeshClientUtil.buildSimpleMessage(enhanceEvent, clientConfig, PROTOCOL_TYPE); - - try { - Response response = publisherClient.publish(enhancedMessage); - logger.info("Received response " + response.toString()); - return response; - } catch (Exception e) { - logger.error("Error in publishing message {}, error {}", cloudEvent, e.getMessage()); - return null; - } - } - - public CloudEvent requestReply(CloudEvent cloudEvent, int timeout) { - logger.info("RequestReply message " + cloudEvent.toString()); - CloudEvent enhanceEvent = enhanceCloudEvent(cloudEvent, String.valueOf(timeout)); - - SimpleMessage enhancedMessage = EventMeshClientUtil.buildSimpleMessage(enhanceEvent, clientConfig, PROTOCOL_TYPE); - try { - SimpleMessage reply = publisherClient.requestReply(enhancedMessage); - logger.info("Received reply message" + reply.toString()); - - Object msg = EventMeshClientUtil.buildMessage(reply, PROTOCOL_TYPE); - if (msg instanceof CloudEvent) { - return (CloudEvent) msg; - } else { - return null; - } - } catch (Exception e) { - logger.error("Error in RequestReply message {}, error {}", cloudEvent, e.getMessage()); - return null; - } - } - - private CloudEvent enhanceCloudEvent(final CloudEvent cloudEvent, String timeout) { - CloudEventBuilder builder = CloudEventBuilder.from(cloudEvent) - .withExtension(ProtocolKey.ENV, clientConfig.getEnv()) - .withExtension(ProtocolKey.IDC, clientConfig.getIdc()) - .withExtension(ProtocolKey.IP, IPUtils.getLocalAddress()) - .withExtension(ProtocolKey.PID, Long.toString(ThreadUtils.getPID())) - .withExtension(ProtocolKey.SYS, clientConfig.getSys()) - .withExtension(ProtocolKey.LANGUAGE, "JAVA") - .withExtension(ProtocolKey.PROTOCOL_TYPE, PROTOCOL_TYPE) - .withExtension(ProtocolKey.PROTOCOL_DESC, "grpc") - .withExtension(ProtocolKey.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()) - .withExtension(ProtocolKey.UNIQUE_ID, RandomStringUtils.generateNum(30)) - .withExtension(ProtocolKey.SEQ_NUM, RandomStringUtils.generateNum(30)) - .withExtension(ProtocolKey.USERNAME, clientConfig.getUserName()) - .withExtension(ProtocolKey.PASSWD, clientConfig.getPassword()) - .withExtension(ProtocolKey.PRODUCERGROUP, clientConfig.getProducerGroup()); - - if (timeout != null) { - builder.withExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL, timeout); - } - return builder.build(); - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducer.java deleted file mode 100644 index 804d3341b8..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducer.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.producer; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.grpc.util.EventMeshClientUtil; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.PublisherServiceGrpc; -import org.apache.eventmesh.common.protocol.grpc.protos.PublisherServiceGrpc.PublisherServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; - -public class EventMeshGrpcProducer implements AutoCloseable { - - private static final Logger logger = LoggerFactory.getLogger(EventMeshGrpcProducer.class); - - private static final String PROTOCOL_TYPE = EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME; - - private final EventMeshGrpcClientConfig clientConfig; - - private ManagedChannel channel; - - PublisherServiceBlockingStub publisherClient; - - CloudEventProducer cloudEventProducer; - - public EventMeshGrpcProducer(EventMeshGrpcClientConfig clientConfig) { - this.clientConfig = clientConfig; - } - - public void init() { - channel = ManagedChannelBuilder.forAddress(clientConfig.getServerAddr(), clientConfig.getServerPort()) - .usePlaintext().build(); - publisherClient = PublisherServiceGrpc.newBlockingStub(channel); - - cloudEventProducer = new CloudEventProducer(clientConfig, publisherClient); - } - - public Response publish(EventMeshMessage message) { - logger.info("Publish message " + message.toString()); - - SimpleMessage simpleMessage = EventMeshClientUtil.buildSimpleMessage(message, clientConfig, PROTOCOL_TYPE); - try { - Response response = publisherClient.publish(simpleMessage); - logger.info("Received response " + response.toString()); - return response; - } catch (Exception e) { - logger.error("Error in publishing message {}, error {}", message, e.getMessage()); - return null; - } - } - - @SuppressWarnings("unchecked") - public Response publish(List messageList) { - logger.info("BatchPublish message " + messageList.toString()); - - if (messageList.size() == 0) { - return null; - } - if (messageList.get(0) instanceof CloudEvent) { - return cloudEventProducer.publish((List) messageList); - } - BatchMessage batchMessage = EventMeshClientUtil.buildBatchMessages(messageList, clientConfig, PROTOCOL_TYPE); - try { - Response response = publisherClient.batchPublish(batchMessage); - logger.info("Received response " + response.toString()); - return response; - } catch (Exception e) { - logger.error("Error in BatchPublish message {}, error {}", messageList, e.getMessage()); - return null; - } - } - - public Response publish(CloudEvent cloudEvent) { - return cloudEventProducer.publish(cloudEvent); - } - - public CloudEvent requestReply(CloudEvent cloudEvent, int timeout) { - return cloudEventProducer.requestReply(cloudEvent, timeout); - } - - public EventMeshMessage requestReply(EventMeshMessage message, int timeout) { - logger.info("RequestReply message " + message.toString()); - - SimpleMessage simpleMessage = EventMeshClientUtil.buildSimpleMessage(message, clientConfig, PROTOCOL_TYPE); - try { - SimpleMessage reply = publisherClient.withDeadlineAfter(timeout, TimeUnit.MILLISECONDS).requestReply(simpleMessage); - logger.info("Received reply message" + reply.toString()); - - Object msg = EventMeshClientUtil.buildMessage(reply, PROTOCOL_TYPE); - if (msg instanceof EventMeshMessage) { - return (EventMeshMessage) msg; - } else { - return null; - } - } catch (Exception e) { - logger.error("Error in RequestReply message {}, error {}", message, e.getMessage()); - return null; - } - } - - @Override - public void close() { - channel.shutdown(); - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/util/EventMeshClientUtil.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/util/EventMeshClientUtil.java deleted file mode 100644 index 71b0e2aa59..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/util/EventMeshClientUtil.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.util; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.RequestHeader; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -import org.apache.commons.lang3.StringUtils; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.jackson.JsonFormat; - -import com.fasterxml.jackson.core.type.TypeReference; - -public class EventMeshClientUtil { - - private static final Logger logger = LoggerFactory.getLogger(EventMeshClientUtil.class); - - public static RequestHeader buildHeader(EventMeshGrpcClientConfig clientConfig, String protocolType) { - return RequestHeader.newBuilder() - .setEnv(clientConfig.getEnv()) - .setIdc(clientConfig.getIdc()) - .setIp(IPUtils.getLocalAddress()) - .setPid(Long.toString(ThreadUtils.getPID())) - .setSys(clientConfig.getSys()) - .setLanguage(clientConfig.getLanguage()) - .setUsername(clientConfig.getUserName()) - .setPassword(clientConfig.getPassword()) - .setProtocolType(protocolType) - .setProtocolDesc("grpc") - // default CloudEvents version is V1 - .setProtocolVersion(SpecVersion.V1.toString()) - .build(); - } - - @SuppressWarnings("unchecked") - public static T buildMessage(SimpleMessage message, String protocolType) { - String seq = message.getSeqNum(); - String uniqueId = message.getUniqueId(); - String content = message.getContent(); - - // This is GRPC response message - if (StringUtils.isEmpty(seq) && StringUtils.isEmpty(uniqueId)) { - HashMap response = JsonUtils.deserialize(content, new TypeReference>() { - }); - return (T) response; - } - - if (EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME.equals(protocolType)) { - String contentType = message.getPropertiesOrDefault(ProtocolKey.CONTENT_TYPE, JsonFormat.CONTENT_TYPE); - try { - CloudEvent cloudEvent = EventFormatProvider.getInstance().resolveFormat(contentType) - .deserialize(content.getBytes(StandardCharsets.UTF_8)); - - CloudEventBuilder cloudEventBuilder = CloudEventBuilder.from(cloudEvent) - .withSubject(message.getTopic()) - .withExtension(ProtocolKey.SEQ_NUM, message.getSeqNum()) - .withExtension(ProtocolKey.UNIQUE_ID, message.getUniqueId()); - - message.getPropertiesMap().forEach(cloudEventBuilder::withExtension); - - return (T) cloudEventBuilder.build(); - } catch (Throwable t) { - logger.warn("Error in building message. {}", t.getMessage()); - return null; - } - } else { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .content(content) - .topic(message.getTopic()) - .bizSeqNo(seq) - .uniqueId(uniqueId) - .prop(message.getPropertiesMap()) - .build(); - return (T) eventMeshMessage; - } - } - - public static SimpleMessage buildSimpleMessage(T message, EventMeshGrpcClientConfig clientConfig, - String protocolType) { - if (EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME.equals(protocolType)) { - CloudEvent cloudEvent = (CloudEvent) message; - String contentType = StringUtils.isEmpty(cloudEvent.getDataContentType()) ? "application/cloudevents+json" - : cloudEvent.getDataContentType(); - byte[] bodyByte = EventFormatProvider.getInstance().resolveFormat(contentType) - .serialize(cloudEvent); - String content = new String(bodyByte, StandardCharsets.UTF_8); - String ttl = cloudEvent.getExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL) == null ? Constants.DEFAULT_EVENTMESH_MESSAGE_TTL - : cloudEvent.getExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL).toString(); - - String seqNum = cloudEvent.getExtension(ProtocolKey.SEQ_NUM) == null ? RandomStringUtils.generateNum(30) - : cloudEvent.getExtension(ProtocolKey.SEQ_NUM).toString(); - - String uniqueId = cloudEvent.getExtension(ProtocolKey.UNIQUE_ID) == null ? RandomStringUtils.generateNum(30) - : cloudEvent.getExtension(ProtocolKey.UNIQUE_ID).toString(); - - SimpleMessage.Builder builder = SimpleMessage.newBuilder() - .setHeader(EventMeshClientUtil.buildHeader(clientConfig, protocolType)) - .setProducerGroup(clientConfig.getProducerGroup()) - .setTopic(cloudEvent.getSubject()) - .setTtl(ttl) - .setSeqNum(seqNum) - .setUniqueId(uniqueId) - .setContent(content) - .putProperties(ProtocolKey.CONTENT_TYPE, contentType); - - for (String extName : cloudEvent.getExtensionNames()) { - builder.putProperties(extName, cloudEvent.getExtension(extName).toString()); - } - - return builder.build(); - } else { - EventMeshMessage eventMeshMessage = (EventMeshMessage) message; - - String ttl = eventMeshMessage.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL) == null ? Constants.DEFAULT_EVENTMESH_MESSAGE_TTL - : eventMeshMessage.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL); - Map props = eventMeshMessage.getProp() == null ? new HashMap<>() : eventMeshMessage.getProp(); - - String seqNum = eventMeshMessage.getBizSeqNo() == null ? RandomStringUtils.generateNum(30) - : eventMeshMessage.getBizSeqNo(); - - String uniqueId = eventMeshMessage.getUniqueId() == null ? RandomStringUtils.generateNum(30) - : eventMeshMessage.getUniqueId(); - - return SimpleMessage.newBuilder() - .setHeader(EventMeshClientUtil.buildHeader(clientConfig, protocolType)) - .setProducerGroup(clientConfig.getProducerGroup()) - .setTopic(eventMeshMessage.getTopic()) - .setContent(eventMeshMessage.getContent()) - .setSeqNum(seqNum) - .setUniqueId(uniqueId) - .setTtl(ttl) - .putAllProperties(props) - .build(); - } - } - - @SuppressWarnings("unchecked") - public static BatchMessage buildBatchMessages(List messageList, EventMeshGrpcClientConfig clientConfig, - String protocolType) { - if (EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME.equals(protocolType)) { - List events = (List) messageList; - BatchMessage.Builder messageBuilder = BatchMessage.newBuilder() - .setHeader(EventMeshClientUtil.buildHeader(clientConfig, protocolType)) - .setProducerGroup(clientConfig.getProducerGroup()) - .setTopic(events.get(0).getSubject()); - - for (CloudEvent event : events) { - String contentType = StringUtils.isEmpty(event.getDataContentType()) ? "application/cloudevents+json" - : event.getDataContentType(); - byte[] bodyByte = EventFormatProvider.getInstance().resolveFormat(contentType) - .serialize(event); - String content = new String(bodyByte, StandardCharsets.UTF_8); - - String ttl = event.getExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL) == null ? Constants.DEFAULT_EVENTMESH_MESSAGE_TTL - : event.getExtension(Constants.EVENTMESH_MESSAGE_CONST_TTL).toString(); - - BatchMessage.MessageItem messageItem = BatchMessage.MessageItem.newBuilder() - .setContent(content) - .setTtl(ttl) - .setSeqNum(event.getExtension(ProtocolKey.SEQ_NUM).toString()) - .setUniqueId(event.getExtension(ProtocolKey.UNIQUE_ID).toString()) - .putProperties(ProtocolKey.CONTENT_TYPE, contentType) - .build(); - - messageBuilder.addMessageItem(messageItem); - } - return messageBuilder.build(); - } else { - List eventMeshMessages = (List) messageList; - BatchMessage.Builder messageBuilder = BatchMessage.newBuilder() - .setHeader(EventMeshClientUtil.buildHeader(clientConfig, protocolType)) - .setProducerGroup(clientConfig.getProducerGroup()) - .setTopic(eventMeshMessages.get(0).getTopic()); - - for (EventMeshMessage message : eventMeshMessages) { - BatchMessage.MessageItem item = BatchMessage.MessageItem.newBuilder() - .setContent(message.getContent()) - .setUniqueId(message.getUniqueId()) - .setSeqNum(message.getBizSeqNo()) - .setTtl( - Optional.ofNullable(message.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL)).orElse(Constants.DEFAULT_EVENTMESH_MESSAGE_TTL)) - .putAllProperties(message.getProp()) - .build(); - messageBuilder.addMessageItem(item); - } - return messageBuilder.build(); - } - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractHttpClient.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractHttpClient.java deleted file mode 100644 index 58ebb0b386..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractHttpClient.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http; - -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.ssl.MyX509TrustManager; -import org.apache.eventmesh.client.http.util.HttpLoadBalanceUtils; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.loadbalance.LoadBalanceSelector; - -import org.apache.http.conn.ssl.DefaultHostnameVerifier; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; - -import java.io.IOException; -import java.security.SecureRandom; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public abstract class AbstractHttpClient implements AutoCloseable { - - protected EventMeshHttpClientConfig eventMeshHttpClientConfig; - - protected LoadBalanceSelector eventMeshServerSelector; - - protected final CloseableHttpClient httpClient; - - public AbstractHttpClient(EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { - Preconditions.checkNotNull(eventMeshHttpClientConfig, "liteClientConfig can't be null"); - Preconditions.checkNotNull(eventMeshHttpClientConfig.getLiteEventMeshAddr(), "liteServerAddr can't be null"); - - this.eventMeshHttpClientConfig = eventMeshHttpClientConfig; - this.eventMeshServerSelector = HttpLoadBalanceUtils.createEventMeshServerLoadBalanceSelector( - eventMeshHttpClientConfig); - this.httpClient = setHttpClient(); - } - - @Override - public void close() throws EventMeshException { - try (final CloseableHttpClient ignore = this.httpClient) { - // ignore - } catch (IOException e) { - throw new EventMeshException("Close http client error", e); - } - } - - private CloseableHttpClient setHttpClient() throws EventMeshException { - if (!eventMeshHttpClientConfig.isUseTls()) { - return HttpClients.createDefault(); - } - SSLContext sslContext; - try { - // todo: config in properties file? - String protocol = System.getProperty("ssl.client.protocol", "TLSv1.2"); - TrustManager[] tm = new TrustManager[]{new MyX509TrustManager()}; - sslContext = SSLContext.getInstance(protocol); - sslContext.init(null, tm, new SecureRandom()); - // todo: custom client pool - return HttpClients.custom() - .setSSLContext(sslContext) - .setSSLHostnameVerifier(new DefaultHostnameVerifier()) - .build(); - } catch (Exception e) { - log.error("Error in creating HttpClient.", e); - throw new EventMeshException(e); - } - } - - protected String selectEventMesh() { - // todo: target endpoint maybe destroy, should remove the bad endpoint - if (eventMeshHttpClientConfig.isUseTls()) { - return Constants.HTTPS_PROTOCOL_PREFIX + eventMeshServerSelector.select(); - } else { - return Constants.HTTP_PROTOCOL_PREFIX + eventMeshServerSelector.select(); - } - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/EventMeshHttpClientConfig.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/EventMeshHttpClientConfig.java deleted file mode 100644 index 24dfd0fee4..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/EventMeshHttpClientConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.conf; - -import org.apache.eventmesh.common.loadbalance.LoadBalanceType; - -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class EventMeshHttpClientConfig { - - /** - * The event server address list - *

- * If it's a cluster, please use ; to split, and the address format is related to loadBalanceType. - *

- * E.g. - *

If you use Random strategy, the format like: 127.0.0.1:10105;127.0.0.2:10105 - *

If you use weighted round robin or weighted random strategy, the format like: 127.0.0.1:10105:1;127.0.0.2:10105:2 - */ - @Builder.Default - private String liteEventMeshAddr = "127.0.0.1:10105"; - - @Builder.Default - private LoadBalanceType loadBalanceType = LoadBalanceType.RANDOM; - - @Builder.Default - private int consumeThreadCore = 2; - - @Builder.Default - private int consumeThreadMax = 5; - - @Builder.Default - private String env = ""; - - @Builder.Default - private String consumerGroup = "DefaultConsumerGroup"; - - @Builder.Default - private String producerGroup = "DefaultProducerGroup"; - - @Builder.Default - private String idc = ""; - - @Builder.Default - private String ip = "127.0.0.1"; - - @Builder.Default - private String pid = ""; - - @Builder.Default - private String sys = ""; - - @Builder.Default - private String userName = ""; - - @Builder.Default - private String password = ""; - - @Builder.Default - private boolean useTls = false; - -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/EventMeshHttpConsumer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/EventMeshHttpConsumer.java deleted file mode 100644 index a891bdf177..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/EventMeshHttpConsumer.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.consumer; - -import org.apache.eventmesh.client.http.AbstractHttpClient; -import org.apache.eventmesh.client.http.EventMeshRetObj; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.model.RequestParam; -import org.apache.eventmesh.client.http.util.HttpUtils; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.ThreadPoolFactory; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.http.body.client.HeartbeatRequestBody; -import org.apache.eventmesh.common.protocol.http.body.client.SubscribeRequestBody; -import org.apache.eventmesh.common.protocol.http.body.client.UnSubscribeRequestBody; -import org.apache.eventmesh.common.protocol.http.common.ClientType; -import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; -import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.common.utils.JsonUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import io.netty.handler.codec.http.HttpMethod; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class EventMeshHttpConsumer extends AbstractHttpClient implements AutoCloseable { - - private final ThreadPoolExecutor consumeExecutor; - - private static final List SUBSCRIPTIONS = Collections.synchronizedList(new ArrayList<>()); - - private final ScheduledThreadPoolExecutor scheduler; - - public EventMeshHttpConsumer(EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { - this(eventMeshHttpClientConfig, null); - } - - public EventMeshHttpConsumer(EventMeshHttpClientConfig eventMeshHttpClientConfig, ThreadPoolExecutor customExecutor) - throws EventMeshException { - super(eventMeshHttpClientConfig); - this.consumeExecutor = Optional.ofNullable(customExecutor).orElseGet( - () -> ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpClientConfig.getConsumeThreadCore(), - eventMeshHttpClientConfig.getConsumeThreadMax(), "EventMesh-client-consume-") - ); - this.scheduler = new ScheduledThreadPoolExecutor( - Runtime.getRuntime().availableProcessors(), - new ThreadFactoryBuilder().setNameFormat("HTTPClientScheduler").setDaemon(true).build() - ); - } - - /** - * When receive message will callback the url. - * - * @param topicList topic that be subscribed - * @param subscribeUrl url will be trigger - * @throws EventMeshException if subscribe failed - */ - public void subscribe(List topicList, String subscribeUrl) throws EventMeshException { - Preconditions.checkNotNull(topicList, "Subscribe item cannot be null"); - Preconditions.checkNotNull(subscribeUrl, "SubscribeUrl cannot be null"); - RequestParam subscribeParam = buildCommonRequestParam() - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.SUBSCRIBE.getRequestCode()) - .addBody(SubscribeRequestBody.TOPIC, JsonUtils.serialize(topicList)) - .addBody(SubscribeRequestBody.CONSUMERGROUP, eventMeshHttpClientConfig.getConsumerGroup()) - .addBody(SubscribeRequestBody.URL, subscribeUrl); - - String target = selectEventMesh(); - try { - String subRes = HttpUtils.post(httpClient, target, subscribeParam); - EventMeshRetObj ret = JsonUtils.deserialize(subRes, EventMeshRetObj.class); - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } - SUBSCRIPTIONS.addAll(topicList); - } catch (Exception ex) { - throw new EventMeshException(String.format("Subscribe topic error, target:%s", target), ex); - } - } - - // todo: remove http heartBeat? - public void heartBeat(List topicList, String subscribeUrl) { - Preconditions.checkNotNull(topicList, "Subscribe item cannot be null"); - Preconditions.checkNotNull(subscribeUrl, "SubscribeUrl cannot be null"); - scheduler.scheduleAtFixedRate(() -> { - try { - List heartbeatEntities = topicList.stream().map(subscriptionItem - -> { - HeartbeatRequestBody.HeartbeatEntity heartbeatEntity = new HeartbeatRequestBody.HeartbeatEntity(); - heartbeatEntity.topic = subscriptionItem.getTopic(); - heartbeatEntity.url = subscribeUrl; - return heartbeatEntity; - }).collect(Collectors.toList()); - RequestParam requestParam = buildCommonRequestParam() - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.HEARTBEAT.getRequestCode()) - .addBody(HeartbeatRequestBody.CLIENTTYPE, ClientType.SUB.name()) - .addBody(HeartbeatRequestBody.HEARTBEATENTITIES, JsonUtils.serialize(heartbeatEntities)); - String target = selectEventMesh(); - String res = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(res, EventMeshRetObj.class); - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } - } catch (Exception e) { - log.error("send heartBeat error", e); - } - }, EventMeshCommon.HEARTBEAT, EventMeshCommon.HEARTBEAT, TimeUnit.MILLISECONDS); - } - - /** - * @param topicList subscribe topic - * @param unSubscribeUrl subscribeUrl - * @throws EventMeshException if unsubscribe failed - */ - public void unsubscribe(List topicList, String unSubscribeUrl) throws EventMeshException { - Preconditions.checkNotNull(topicList, "Topics cannot be null"); - Preconditions.checkNotNull(unSubscribeUrl, "unSubscribeUrl cannot be null"); - RequestParam unSubscribeParam = buildCommonRequestParam() - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.UNSUBSCRIBE.getRequestCode()) - .addBody(UnSubscribeRequestBody.TOPIC, JsonUtils.serialize(topicList)) - .addBody(UnSubscribeRequestBody.URL, unSubscribeUrl); - String target = selectEventMesh(); - try { - String unSubRes = HttpUtils.post(httpClient, target, unSubscribeParam); - EventMeshRetObj ret = JsonUtils.deserialize(unSubRes, EventMeshRetObj.class); - - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } - // todo: avoid concurrentModifiedException - SUBSCRIPTIONS.removeIf(item -> topicList.contains(item.getTopic())); - } catch (Exception ex) { - throw new EventMeshException(String.format("Unsubscribe topic error, target:%s", target), ex); - } - } - - @Override - public void close() throws EventMeshException { - log.info("LiteConsumer shutting down"); - super.close(); - if (consumeExecutor != null) { - consumeExecutor.shutdown(); - } - scheduler.shutdown(); - log.info("LiteConsumer shutdown"); - } - - private RequestParam buildCommonRequestParam() { - return new RequestParam(HttpMethod.POST) - .addHeader(ProtocolKey.ClientInstanceKey.ENV, eventMeshHttpClientConfig.getEnv()) - .addHeader(ProtocolKey.ClientInstanceKey.IDC, eventMeshHttpClientConfig.getIdc()) - .addHeader(ProtocolKey.ClientInstanceKey.IP, eventMeshHttpClientConfig.getIp()) - .addHeader(ProtocolKey.ClientInstanceKey.PID, eventMeshHttpClientConfig.getPid()) - .addHeader(ProtocolKey.ClientInstanceKey.SYS, eventMeshHttpClientConfig.getSys()) - .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, eventMeshHttpClientConfig.getUserName()) - .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, eventMeshHttpClientConfig.getPassword()) - // add protocol version? - .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) - .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) - .setTimeout(Constants.DEFAULT_HTTP_TIME_OUT) - .addBody(HeartbeatRequestBody.CONSUMERGROUP, eventMeshHttpClientConfig.getConsumerGroup()); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/model/RequestParam.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/model/RequestParam.java deleted file mode 100644 index 97f4c95cb6..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/model/RequestParam.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.model; - -import org.apache.eventmesh.common.Constants; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import io.netty.handler.codec.http.HttpMethod; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class RequestParam { - - private Map queryParams; - - private final HttpMethod httpMethod; - - private Map body; - - private Map headers; - - private long timeout = Constants.DEFAULT_HTTP_TIME_OUT; - - public RequestParam(HttpMethod httpMethod) { - this.httpMethod = httpMethod; - } - - public HttpMethod getHttpMethod() { - return httpMethod; - } - - public Map getHeaders() { - return headers; - } - - public RequestParam setHeaders(Map headers) { - this.headers = headers; - return this; - } - - public Map getBody() { - return body; - } - - public RequestParam setBody(Map body) { - this.body = body; - return this; - } - - public Map getQueryParamsMap() { - return queryParams; - } - - public String getQueryParams() { - if (queryParams == null || queryParams.size() == 0) { - return ""; - } - StringBuilder stringBuilder = new StringBuilder(); - try { - for (Map.Entry query : queryParams.entrySet()) { - for (String val : query.getValue()) { - stringBuilder.append("&") - .append(URLEncoder.encode(query.getKey(), "UTF-8")); - - if (val != null && !val.isEmpty()) { - stringBuilder.append("=") - .append(URLEncoder.encode(val, "UTF-8")); - } - } - } - } catch (UnsupportedEncodingException e) { - log.error("get query params failed.", e); - return ""; - } - return stringBuilder.substring(1); - } - - public RequestParam setQueryParams(Map queryParams) { - this.queryParams = queryParams; - return this; - } - - public RequestParam addQueryParam(String key, String value) { - if (queryParams == null) { - queryParams = new HashMap<>(); - } - if (!queryParams.containsKey(key)) { - queryParams.put(key, new String[]{value}); - } else { - queryParams.put(key, (String[]) Arrays.asList(queryParams.get(key), value).toArray()); - } - return this; - } - - public RequestParam addHeader(String key, Object value) { - if (headers == null) { - headers = new HashMap<>(); - } - headers.put(key, value.toString()); - return this; - } - - public RequestParam addBody(String key, String value) { - if (body == null) { - body = new HashMap<>(); - } - body.put(key, value); - return this; - } - - public long getTimeout() { - return timeout; - } - - public RequestParam setTimeout(long timeout) { - this.timeout = timeout; - return this; - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/CloudEventProducer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/CloudEventProducer.java deleted file mode 100644 index 995e267be0..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/CloudEventProducer.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.producer; - -import org.apache.eventmesh.client.http.AbstractHttpClient; -import org.apache.eventmesh.client.http.EventMeshRetObj; -import org.apache.eventmesh.client.http.ProtocolConstant; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.model.RequestParam; -import org.apache.eventmesh.client.http.util.HttpUtils; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; -import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; -import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.provider.EventFormatProvider; -import io.netty.handler.codec.http.HttpMethod; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -class CloudEventProducer extends AbstractHttpClient implements EventMeshProtocolProducer { - - public CloudEventProducer(EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { - super(eventMeshHttpClientConfig); - } - - @Override - public void publish(CloudEvent cloudEvent) throws EventMeshException { - validateCloudEvent(cloudEvent); - CloudEvent enhanceCloudEvent = enhanceCloudEvent(cloudEvent); - // todo: Can put to abstract class, all protocol use the same send method? This can be a template method - RequestParam requestParam = buildCommonPostParam(enhanceCloudEvent) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_ASYNC.getRequestCode()); - String target = selectEventMesh(); - try { - String response = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(response, EventMeshRetObj.class); - - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } - } catch (Exception exception) { - throw new EventMeshException(String.format("Publish message error, target:%s", target), exception); - } - - } - - @Override - public CloudEvent request(CloudEvent cloudEvent, long timeout) throws EventMeshException { - validateCloudEvent(cloudEvent); - CloudEvent enhanceCloudEvent = enhanceCloudEvent(cloudEvent); - RequestParam requestParam = buildCommonPostParam(enhanceCloudEvent) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) - .setTimeout(timeout); - String target = selectEventMesh(); - - try { - String response = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(response, EventMeshRetObj.class); - if (ret.getRetCode() == EventMeshRetCode.SUCCESS.getRetCode()) { - return transformMessage(ret); - } - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } catch (Exception e) { - throw new EventMeshException(String.format("Request message error, target:%s", target), e); - } - } - - @Override - public void request(final CloudEvent cloudEvent, final RRCallback rrCallback, long timeout) - throws EventMeshException { - validateCloudEvent(cloudEvent); - CloudEvent enhanceCloudEvent = enhanceCloudEvent(cloudEvent); - RequestParam requestParam = buildCommonPostParam(enhanceCloudEvent) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) - .setTimeout(timeout); - String target = selectEventMesh(); - RRCallbackResponseHandlerAdapter adapter = new RRCallbackResponseHandlerAdapter<>( - enhanceCloudEvent, rrCallback, timeout); - try { - HttpUtils.post(httpClient, null, target, requestParam, adapter); - } catch (IOException e) { - throw new EventMeshException(String.format("Request message error, target:%s", target), e); - } - - } - - private void validateCloudEvent(CloudEvent cloudEvent) { - Preconditions.checkNotNull(cloudEvent, "CloudEvent cannot be null"); - } - - private RequestParam buildCommonPostParam(CloudEvent cloudEvent) { - byte[] bodyByte = EventFormatProvider.getInstance().resolveFormat(cloudEvent.getDataContentType()) - .serialize(cloudEvent); - String content = new String(bodyByte, StandardCharsets.UTF_8); - - RequestParam requestParam = new RequestParam(HttpMethod.POST); - requestParam - .addHeader(ProtocolKey.ClientInstanceKey.ENV, eventMeshHttpClientConfig.getEnv()) - .addHeader(ProtocolKey.ClientInstanceKey.IDC, eventMeshHttpClientConfig.getIdc()) - .addHeader(ProtocolKey.ClientInstanceKey.IP, eventMeshHttpClientConfig.getIp()) - .addHeader(ProtocolKey.ClientInstanceKey.PID, eventMeshHttpClientConfig.getPid()) - .addHeader(ProtocolKey.ClientInstanceKey.SYS, eventMeshHttpClientConfig.getSys()) - .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, eventMeshHttpClientConfig.getUserName()) - .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, eventMeshHttpClientConfig.getPassword()) - .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) - .addHeader(ProtocolKey.PROTOCOL_TYPE, ProtocolConstant.CE_PROTOCOL) - .addHeader(ProtocolKey.PROTOCOL_DESC, ProtocolConstant.PROTOCOL_DESC) - .addHeader(ProtocolKey.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()) - - // todo: move producerGroup tp header - .addBody(SendMessageRequestBody.PRODUCERGROUP, eventMeshHttpClientConfig.getProducerGroup()) - .addBody(SendMessageRequestBody.CONTENT, content); - return requestParam; - } - - private CloudEvent enhanceCloudEvent(final CloudEvent cloudEvent) { - return CloudEventBuilder.from(cloudEvent) - .withExtension(ProtocolKey.ClientInstanceKey.ENV, eventMeshHttpClientConfig.getEnv()) - .withExtension(ProtocolKey.ClientInstanceKey.IDC, eventMeshHttpClientConfig.getIdc()) - .withExtension(ProtocolKey.ClientInstanceKey.IP, eventMeshHttpClientConfig.getIp()) - .withExtension(ProtocolKey.ClientInstanceKey.PID, eventMeshHttpClientConfig.getPid()) - .withExtension(ProtocolKey.ClientInstanceKey.SYS, eventMeshHttpClientConfig.getSys()) - .withExtension(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) - .withExtension(ProtocolKey.PROTOCOL_DESC, cloudEvent.getSpecVersion().name()) - .withExtension(ProtocolKey.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()) - .withExtension(ProtocolKey.ClientInstanceKey.BIZSEQNO, RandomStringUtils.generateNum(30)) - .withExtension(ProtocolKey.ClientInstanceKey.UNIQUEID, RandomStringUtils.generateNum(30)) - .build(); - } - - private CloudEvent transformMessage(EventMeshRetObj retObj) { - SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.deserialize(retObj.getRetMsg(), - SendMessageResponseBody.ReplyMessage.class); - // todo: deserialize message - return null; - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshMessageProducer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshMessageProducer.java deleted file mode 100644 index d4fcf505e5..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshMessageProducer.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.producer; - -import org.apache.eventmesh.client.http.AbstractHttpClient; -import org.apache.eventmesh.client.http.EventMeshRetObj; -import org.apache.eventmesh.client.http.ProtocolConstant; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.model.RequestParam; -import org.apache.eventmesh.client.http.util.HttpUtils; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; -import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; -import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.common.utils.JsonUtils; - -import java.io.IOException; - -import io.cloudevents.SpecVersion; -import io.netty.handler.codec.http.HttpMethod; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -class EventMeshMessageProducer extends AbstractHttpClient implements EventMeshProtocolProducer { - - public EventMeshMessageProducer(EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { - super(eventMeshHttpClientConfig); - } - - @Override - public void publish(EventMeshMessage message) throws EventMeshException { - validateEventMeshMessage(message); - RequestParam requestParam = buildCommonPostParam(message) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_ASYNC.getRequestCode()); - - String target = selectEventMesh(); - try { - String response = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(response, EventMeshRetObj.class); - - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } - } catch (Exception exception) { - throw new EventMeshException(String.format("Publish message error, target:%s", target), exception); - } - } - - @Override - public EventMeshMessage request(EventMeshMessage message, long timeout) throws EventMeshException { - validateEventMeshMessage(message); - RequestParam requestParam = buildCommonPostParam(message) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) - .setTimeout(timeout); - - String target = selectEventMesh(); - - try { - String response = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(response, EventMeshRetObj.class); - if (ret.getRetCode() == EventMeshRetCode.SUCCESS.getRetCode()) { - return transformMessage(ret); - } - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } catch (Exception e) { - throw new EventMeshException(String.format("Request message error, target:%s", target), e); - } - } - - @Override - public void request(EventMeshMessage message, RRCallback rrCallback, long timeout) - throws EventMeshException { - validateEventMeshMessage(message); - - RequestParam requestParam = buildCommonPostParam(message) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) - .setTimeout(timeout); - - String target = selectEventMesh(); - RRCallbackResponseHandlerAdapter adapter = - new RRCallbackResponseHandlerAdapter<>(message, rrCallback, timeout); - try { - HttpUtils.post(httpClient, null, target, requestParam, adapter); - } catch (IOException e) { - throw new EventMeshException(String.format("Request message error, target:%s", target), e); - } - } - - private void validateEventMeshMessage(EventMeshMessage message) { - Preconditions.checkNotNull(message, "eventMeshMessage invalid"); - Preconditions.checkNotNull(message.getTopic(), "eventMeshMessage[topic] invalid"); - Preconditions.checkNotNull(message.getContent(), "eventMeshMessage[content] invalid"); - } - - private RequestParam buildCommonPostParam(EventMeshMessage message) { - RequestParam requestParam = new RequestParam(HttpMethod.POST); - requestParam - .addHeader(ProtocolKey.ClientInstanceKey.ENV, eventMeshHttpClientConfig.getEnv()) - .addHeader(ProtocolKey.ClientInstanceKey.IDC, eventMeshHttpClientConfig.getIdc()) - .addHeader(ProtocolKey.ClientInstanceKey.IP, eventMeshHttpClientConfig.getIp()) - .addHeader(ProtocolKey.ClientInstanceKey.PID, eventMeshHttpClientConfig.getPid()) - .addHeader(ProtocolKey.ClientInstanceKey.SYS, eventMeshHttpClientConfig.getSys()) - .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, eventMeshHttpClientConfig.getUserName()) - .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, eventMeshHttpClientConfig.getPassword()) - .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) - .addHeader(ProtocolKey.PROTOCOL_TYPE, ProtocolConstant.EM_MESSAGE_PROTOCOL) - .addHeader(ProtocolKey.PROTOCOL_DESC, ProtocolConstant.PROTOCOL_DESC) - //default ce version is 1.0 - .addHeader(ProtocolKey.PROTOCOL_VERSION, SpecVersion.V1.toString()) - .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) - .addBody(SendMessageRequestBody.PRODUCERGROUP, eventMeshHttpClientConfig.getProducerGroup()) - // todo: set message to content is better - .addBody(SendMessageRequestBody.TOPIC, message.getTopic()) - .addBody(SendMessageRequestBody.CONTENT, message.getContent()) - .addBody(SendMessageRequestBody.TTL, message.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL)) - .addBody(SendMessageRequestBody.BIZSEQNO, message.getBizSeqNo()) - .addBody(SendMessageRequestBody.UNIQUEID, message.getUniqueId()); - return requestParam; - } - - private EventMeshMessage transformMessage(EventMeshRetObj retObj) { - SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.deserialize(retObj.getRetMsg(), - SendMessageResponseBody.ReplyMessage.class); - return EventMeshMessage.builder() - .content(replyMessage.body) - .prop(replyMessage.properties) - .topic(replyMessage.topic).build(); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/OpenMessageProducer.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/OpenMessageProducer.java deleted file mode 100644 index b817158cdc..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/OpenMessageProducer.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.producer; - -import org.apache.eventmesh.client.http.AbstractHttpClient; -import org.apache.eventmesh.client.http.EventMeshRetObj; -import org.apache.eventmesh.client.http.ProtocolConstant; -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.model.RequestParam; -import org.apache.eventmesh.client.http.util.HttpUtils; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; -import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; -import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.http.common.RequestCode; -import org.apache.eventmesh.common.utils.JsonUtils; - -import java.io.IOException; - -import io.netty.handler.codec.http.HttpMethod; -import io.openmessaging.api.Message; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -class OpenMessageProducer extends AbstractHttpClient implements EventMeshProtocolProducer { - - public OpenMessageProducer(EventMeshHttpClientConfig eventMeshHttpClientConfig) - throws EventMeshException { - super(eventMeshHttpClientConfig); - } - - @Override - public void publish(Message openMessage) throws EventMeshException { - validateOpenMessage(openMessage); - RequestParam requestParam = buildCommonPostParam(openMessage) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_ASYNC.getRequestCode()); - String target = selectEventMesh(); - try { - String response = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(response, EventMeshRetObj.class); - - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } - } catch (Exception exception) { - throw new EventMeshException(String.format("Publish message error, target:%s", target), exception); - } - } - - @Override - public Message request(Message message, long timeout) throws EventMeshException { - validateOpenMessage(message); - RequestParam requestParam = buildCommonPostParam(message) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) - .setTimeout(timeout); - String target = selectEventMesh(); - - try { - String response = HttpUtils.post(httpClient, target, requestParam); - EventMeshRetObj ret = JsonUtils.deserialize(response, EventMeshRetObj.class); - if (ret.getRetCode() == EventMeshRetCode.SUCCESS.getRetCode()) { - return transformMessage(ret); - } - throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); - } catch (Exception e) { - throw new EventMeshException(String.format("Request message error, target:%s", target), e); - } - } - - @Override - public void request(Message message, RRCallback rrCallback, long timeout) throws EventMeshException { - validateOpenMessage(message); - RequestParam requestParam = buildCommonPostParam(message) - .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) - .setTimeout(timeout); - String target = selectEventMesh(); - RRCallbackResponseHandlerAdapter adapter = - new RRCallbackResponseHandlerAdapter<>(message, rrCallback, timeout); - try { - HttpUtils.post(httpClient, null, target, requestParam, adapter); - } catch (IOException e) { - throw new EventMeshException(String.format("Request message error, target:%s", target), e); - } - } - - private void validateOpenMessage(Message openMessage) { - Preconditions.checkNotNull(openMessage, "Message cannot be null"); - } - - private RequestParam buildCommonPostParam(Message openMessage) { - RequestParam requestParam = new RequestParam(HttpMethod.POST); - requestParam - .addHeader(ProtocolKey.ClientInstanceKey.USERNAME, eventMeshHttpClientConfig.getUserName()) - .addHeader(ProtocolKey.ClientInstanceKey.PASSWD, eventMeshHttpClientConfig.getPassword()) - .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) - .addHeader(ProtocolKey.PROTOCOL_TYPE, ProtocolConstant.OP_MESSAGE_PROTOCOL) - .addHeader(ProtocolKey.PROTOCOL_DESC, ProtocolConstant.PROTOCOL_DESC) - // todo: add producerGroup to header, set protocol type, protocol version - .addBody(SendMessageRequestBody.PRODUCERGROUP, eventMeshHttpClientConfig.getProducerGroup()) - .addBody(SendMessageRequestBody.CONTENT, JsonUtils.serialize(openMessage)); - return requestParam; - } - - private Message transformMessage(EventMeshRetObj retObj) { - SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.deserialize(retObj.getRetMsg(), - SendMessageResponseBody.ReplyMessage.class); - // todo: deserialize message - return null; - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java deleted file mode 100644 index e3c2229b7a..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.producer; - -import org.apache.eventmesh.client.http.EventMeshRetObj; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; -import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; -import org.apache.eventmesh.common.utils.JsonUtils; - -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.ResponseHandler; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.nio.charset.Charset; - -import io.cloudevents.CloudEvent; -import io.openmessaging.api.Message; - -import com.google.common.base.Preconditions; - -import lombok.extern.slf4j.Slf4j; - -/** - * RRCallbackResponseHandlerAdapter. - */ -@Slf4j -public class RRCallbackResponseHandlerAdapter implements ResponseHandler { - - private final long createTime; - - private final ProtocolMessage protocolMessage; - - private final RRCallback rrCallback; - - private final long timeout; - - public RRCallbackResponseHandlerAdapter(ProtocolMessage protocolMessage, RRCallback rrCallback, - long timeout) { - Preconditions.checkNotNull(rrCallback, "rrCallback invalid"); - Preconditions.checkNotNull(protocolMessage, "message invalid"); - if (!(protocolMessage instanceof EventMeshMessage) - && !(protocolMessage instanceof CloudEvent) - && !(protocolMessage instanceof Message)) { - throw new IllegalArgumentException(String.format("ProtocolMessage: %s is not supported", protocolMessage)); - } - this.protocolMessage = protocolMessage; - this.rrCallback = rrCallback; - this.timeout = timeout; - this.createTime = System.currentTimeMillis(); - } - - @Override - public String handleResponse(HttpResponse response) throws IOException { - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - rrCallback.onException(new EventMeshException(response.toString())); - return response.toString(); - } - - if (System.currentTimeMillis() - createTime > timeout) { - String err = String.format("response too late, message: %s", protocolMessage); - rrCallback.onException(new EventMeshException(err)); - return err; - } - - String res = EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); - EventMeshRetObj ret = JsonUtils.deserialize(res, EventMeshRetObj.class); - if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { - rrCallback.onException(new EventMeshException(ret.getRetCode(), ret.getRetMsg())); - return res; - } - - // todo: constructor protocol message - ProtocolMessage protocolMessage = transformToProtocolMessage(ret); - rrCallback.onSuccess(protocolMessage); - - return protocolMessage.toString(); - } - - @SuppressWarnings("unchecked") - private ProtocolMessage transformToProtocolMessage(EventMeshRetObj ret) { - SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.deserialize(ret.getRetMsg(), SendMessageResponseBody.ReplyMessage.class); - if (protocolMessage instanceof EventMeshMessage) { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .content(replyMessage.body) - .prop(replyMessage.properties) - .topic(replyMessage.topic) - .build(); - return (ProtocolMessage) eventMeshMessage; - } - // todo: constructor other protocol message - throw new RuntimeException("Unsupported callback message type"); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ssl/MyX509TrustManager.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ssl/MyX509TrustManager.java deleted file mode 100644 index 1a50038cab..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ssl/MyX509TrustManager.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.ssl; - -import org.apache.commons.lang3.StringUtils; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.security.KeyStore; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -public class MyX509TrustManager implements X509TrustManager { - X509TrustManager myTrustManager; - - public MyX509TrustManager() throws Exception { - KeyStore keyStore = KeyStore.getInstance("JKS"); - String fileName = System.getProperty("ssl.client.cer", ""); - String pass = System.getProperty("ssl.client.pass", ""); - char[] filePass = null; - if (StringUtils.isNotBlank(pass)) { - filePass = pass.toCharArray(); - } - keyStore.load(Files.newInputStream(Paths.get(System.getProperty("confPath", System.getenv("confPath")) - + File.separator - + fileName), StandardOpenOption.READ), filePass); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(keyStore); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509TrustManager) { - myTrustManager = (X509TrustManager) trustManager; - return; - } - } - throw new Exception("Couldn't initialize"); - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - } - - @Override - public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException { - if ((certificates != null) && (certificates.length == 1)) { - certificates[0].checkValidity(); - } else { - myTrustManager.checkServerTrusted(certificates, authType); - } - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return myTrustManager.getAcceptedIssuers(); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtils.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtils.java deleted file mode 100644 index 0b17d01ca8..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtils.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.util; - -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.loadbalance.LoadBalanceSelector; -import org.apache.eventmesh.common.loadbalance.RandomLoadBalanceSelector; -import org.apache.eventmesh.common.loadbalance.Weight; -import org.apache.eventmesh.common.loadbalance.WeightRandomLoadBalanceSelector; -import org.apache.eventmesh.common.loadbalance.WeightRoundRobinLoadBalanceSelector; - -import org.apache.commons.collections4.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import com.google.common.base.Splitter; - -public class HttpLoadBalanceUtils { - - private static final Pattern IP_PORT_PATTERN = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5}"); - private static final Pattern IP_PORT_WEIGHT_PATTERN = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5}:\\d{1,6}"); - - public static LoadBalanceSelector createEventMeshServerLoadBalanceSelector( - EventMeshHttpClientConfig eventMeshHttpClientConfig) - throws EventMeshException { - LoadBalanceSelector eventMeshServerSelector = null; - switch (eventMeshHttpClientConfig.getLoadBalanceType()) { - case RANDOM: - eventMeshServerSelector = new RandomLoadBalanceSelector<>(buildClusterGroupFromConfig( - eventMeshHttpClientConfig)); - break; - case WEIGHT_RANDOM: - eventMeshServerSelector = new WeightRandomLoadBalanceSelector<>(buildWeightedClusterGroupFromConfig( - eventMeshHttpClientConfig)); - break; - case WEIGHT_ROUND_ROBIN: - eventMeshServerSelector = new WeightRoundRobinLoadBalanceSelector<>(buildWeightedClusterGroupFromConfig( - eventMeshHttpClientConfig)); - break; - default: - // ignore - } - if (eventMeshServerSelector == null) { - throw new EventMeshException("liteEventMeshAddr param illegal,please check"); - } - return eventMeshServerSelector; - } - - private static List> buildWeightedClusterGroupFromConfig( - EventMeshHttpClientConfig eventMeshHttpClientConfig) - throws EventMeshException { - List eventMeshAddrs = Splitter.on(";").trimResults().splitToList(eventMeshHttpClientConfig.getLiteEventMeshAddr()); - if (CollectionUtils.isEmpty(eventMeshAddrs)) { - throw new EventMeshException("liteEventMeshAddr can not be empty"); - } - - List> eventMeshAddrWeightList = new ArrayList<>(); - for (String eventMeshAddrWight : eventMeshAddrs) { - if (!IP_PORT_WEIGHT_PATTERN.matcher(eventMeshAddrWight).matches()) { - throw new EventMeshException( - String.format("liteEventMeshAddr:%s is not illegal", eventMeshHttpClientConfig.getLiteEventMeshAddr())); - } - int splitIndex = eventMeshAddrWight.lastIndexOf(":"); - Weight weight = new Weight<>( - eventMeshAddrWight.substring(0, splitIndex), - Integer.parseInt(eventMeshAddrWight.substring(splitIndex + 1)) - ); - eventMeshAddrWeightList.add(weight); - } - return eventMeshAddrWeightList; - } - - private static List buildClusterGroupFromConfig(EventMeshHttpClientConfig eventMeshHttpClientConfig) - throws EventMeshException { - List eventMeshAddrs = Splitter.on(";").trimResults().splitToList(eventMeshHttpClientConfig.getLiteEventMeshAddr()); - if (CollectionUtils.isEmpty(eventMeshAddrs)) { - throw new EventMeshException("liteEventMeshAddr can not be empty"); - } - - List eventMeshAddrList = new ArrayList<>(); - for (String eventMeshAddr : eventMeshAddrs) { - if (!IP_PORT_PATTERN.matcher(eventMeshAddr).matches()) { - throw new EventMeshException( - String.format("liteEventMeshAddr:%s is not illegal", eventMeshHttpClientConfig.getLiteEventMeshAddr())); - } - eventMeshAddrList.add(eventMeshAddr); - } - return eventMeshAddrList; - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpUtils.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpUtils.java deleted file mode 100644 index 23e1546dd3..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpUtils.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.util; - -import org.apache.eventmesh.client.http.model.RequestParam; -import org.apache.eventmesh.common.Constants; - -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpHost; -import org.apache.http.NameValuePair; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.netty.handler.codec.http.HttpMethod; - -import com.google.common.base.Preconditions; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class HttpUtils { - - public static String post(CloseableHttpClient client, - String uri, - RequestParam requestParam) throws Exception { - final ResponseHolder responseHolder = new ResponseHolder(); - final CountDownLatch countDownLatch = new CountDownLatch(1); - post(client, null, uri, requestParam, response -> { - responseHolder.response = - EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); - countDownLatch.countDown(); - if (log.isDebugEnabled()) { - log.debug("{}", responseHolder); - } - return responseHolder.response; - }); - - try { - countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); - } catch (InterruptedException ie) { - //ignore - } - - return responseHolder.response; - } - - public static String post(CloseableHttpClient client, - HttpHost forwardAgent, - String uri, - RequestParam requestParam) throws Exception { - final ResponseHolder responseHolder = new ResponseHolder(); - final CountDownLatch countDownLatch = new CountDownLatch(1); - post(client, forwardAgent, uri, requestParam, response -> { - responseHolder.response = - EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); - countDownLatch.countDown(); - if (log.isDebugEnabled()) { - log.debug("{}", responseHolder); - } - return responseHolder.response; - }); - - try { - countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); - } catch (InterruptedException ie) { - // ignore - } - - return responseHolder.response; - } - - public static void post(CloseableHttpClient client, - HttpHost forwardAgent, - String uri, - RequestParam requestParam, - ResponseHandler responseHandler) throws IOException { - Preconditions.checkState(client != null, "client can't be null"); - Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); - Preconditions.checkState(requestParam != null, "requestParam can't be null"); - Preconditions.checkState(responseHandler != null, "responseHandler can't be null"); - Preconditions.checkState(requestParam.getHttpMethod() == HttpMethod.POST, "invalid requestParam httpMethod"); - - HttpPost httpPost = new HttpPost(uri); - - //header - if (MapUtils.isNotEmpty(requestParam.getHeaders())) { - for (Map.Entry entry : requestParam.getHeaders().entrySet()) { - httpPost.addHeader(entry.getKey(), entry.getValue()); - } - } - - //body - if (MapUtils.isNotEmpty(requestParam.getBody())) { - List pairs = new ArrayList<>(); - for (Map.Entry entry : requestParam.getBody().entrySet()) { - pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); - } - httpPost.setEntity(new UrlEncodedFormEntity(pairs, Constants.DEFAULT_CHARSET)); - } - - //ttl - RequestConfig.Builder configBuilder = RequestConfig.custom(); - configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) - .setConnectTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) - .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))); - - if (forwardAgent != null) { - configBuilder.setProxy(forwardAgent); - } - - httpPost.setConfig(configBuilder.build()); - - if (log.isDebugEnabled()) { - log.debug("{}", httpPost); - } - - client.execute(httpPost, responseHandler); - } - - public static void get(CloseableHttpClient client, - HttpHost forwardAgent, - String uri, - RequestParam requestParam, - ResponseHandler responseHandler) throws Exception { - Preconditions.checkState(client != null, "client can't be null"); - Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); - Preconditions.checkState(requestParam != null, "requestParam can't be null"); - Preconditions.checkState(requestParam.getHttpMethod() == HttpMethod.GET, "invalid requestParam httpMethod"); - - //body - if (MapUtils.isNotEmpty(requestParam.getQueryParamsMap())) { - uri = uri + "?" + requestParam.getQueryParams(); - } - - HttpGet httpGet = new HttpGet(uri); - - //header - if (MapUtils.isNotEmpty(requestParam.getHeaders())) { - for (Map.Entry entry : requestParam.getHeaders().entrySet()) { - httpGet.addHeader(entry.getKey(), entry.getValue()); - } - } - - //ttl - RequestConfig.Builder configBuilder = RequestConfig.custom(); - configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) - .setConnectTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) - .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))); - - if (forwardAgent != null) { - configBuilder.setProxy(forwardAgent); - } - - httpGet.setConfig(configBuilder.build()); - - if (log.isDebugEnabled()) { - log.debug("{}", httpGet); - } - - client.execute(httpGet, responseHandler); - } - - public static String get(CloseableHttpClient client, - String url, - RequestParam requestParam) throws Exception { - final ResponseHolder responseHolder = new ResponseHolder(); - final CountDownLatch countDownLatch = new CountDownLatch(1); - get(client, null, url, requestParam, response -> { - responseHolder.response = - EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); - countDownLatch.countDown(); - if (log.isDebugEnabled()) { - log.debug("{}", responseHolder); - } - return responseHolder.response; - }); - - try { - countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); - } catch (InterruptedException ie) { - //ignore - } - - return responseHolder.response; - } - - public static String get(CloseableHttpClient client, - HttpHost forwardAgent, - String url, - RequestParam requestParam) throws Exception { - final ResponseHolder responseHolder = new ResponseHolder(); - final CountDownLatch countDownLatch = new CountDownLatch(1); - get(client, forwardAgent, url, requestParam, response -> { - responseHolder.response = - EntityUtils.toString(response.getEntity(), Charset.forName(Constants.DEFAULT_CHARSET)); - countDownLatch.countDown(); - if (log.isDebugEnabled()) { - log.debug("{}", responseHolder); - } - return responseHolder.response; - }); - - try { - countDownLatch.await(requestParam.getTimeout(), TimeUnit.MILLISECONDS); - } catch (InterruptedException ie) { - //ignore - } - - return responseHolder.response; - } - - @Data - public static class ResponseHolder { - public String response; - - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java deleted file mode 100644 index e006fa84bf..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.tcp.common; - -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.tcp.Command; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Header; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.protocol.tcp.Subscription; -import org.apache.eventmesh.common.protocol.tcp.UserAgent; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; - -import org.assertj.core.util.Preconditions; - -import io.cloudevents.CloudEvent; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.provider.EventFormatProvider; -import io.openmessaging.api.Message; - -public class MessageUtils { - private static final int seqLength = 10; - - public static Package hello(UserAgent user) { - Package msg = new Package(); - msg.setHeader(new Header(Command.HELLO_REQUEST, 0, null, generateRandomString(seqLength))); - msg.setBody(user); - return msg; - } - - public static Package heartBeat() { - Package msg = new Package(); - msg.setHeader(new Header(Command.HEARTBEAT_REQUEST, 0, null, generateRandomString(seqLength))); - return msg; - } - - public static Package goodbye() { - Package msg = new Package(); - msg.setHeader(new Header(Command.CLIENT_GOODBYE_REQUEST, 0, null, generateRandomString(seqLength))); - return msg; - } - - public static Package listen() { - Package msg = new Package(); - msg.setHeader(new Header(Command.LISTEN_REQUEST, 0, null, generateRandomString(seqLength))); - return msg; - } - - public static Package subscribe(String topic, SubscriptionMode subscriptionMode, - SubscriptionType subscriptionType) { - Package msg = new Package(); - msg.setHeader(new Header(Command.SUBSCRIBE_REQUEST, 0, null, generateRandomString(seqLength))); - msg.setBody(generateSubscription(topic, subscriptionMode, subscriptionType)); - return msg; - } - - public static Package unsubscribe() { - Package msg = new Package(); - msg.setHeader(new Header(Command.UNSUBSCRIBE_REQUEST, 0, null, generateRandomString(seqLength))); - return msg; - } - - public static Package asyncMessageAck(Package in) { - Package msg = new Package(); - msg.setHeader(new Header(Command.ASYNC_MESSAGE_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); - msg.setBody(in.getBody()); - return msg; - } - - public static Package buildPackage(Object message, Command command) { - Package msg = new Package(); - msg.setHeader(new Header(command, 0, null, generateRandomString(seqLength))); - if (message instanceof CloudEvent) { - CloudEvent cloudEvent = (CloudEvent) message; - Preconditions.checkNotNull(cloudEvent.getDataContentType(), "DateContentType cannot be null"); - msg.getHeader().putProperty(Constants.PROTOCOL_TYPE, EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME); - msg.getHeader().putProperty(Constants.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()); - msg.getHeader().putProperty(Constants.PROTOCOL_DESC, "tcp"); - byte[] bodyByte = EventFormatProvider.getInstance().resolveFormat(cloudEvent.getDataContentType()) - .serialize((CloudEvent) message); - msg.setBody(bodyByte); - } else if (message instanceof EventMeshMessage) { - msg.getHeader().putProperty(Constants.PROTOCOL_TYPE, EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME); - msg.getHeader().putProperty(Constants.PROTOCOL_VERSION, SpecVersion.V1.toString()); - msg.getHeader().putProperty(Constants.PROTOCOL_DESC, "tcp"); - msg.setBody(message); - } else if (message instanceof Message) { - msg.getHeader().putProperty(Constants.PROTOCOL_TYPE, EventMeshCommon.OPEN_MESSAGE_PROTOCOL_NAME); - // todo: this version need to be confirmed. - msg.getHeader().putProperty(Constants.PROTOCOL_VERSION, SpecVersion.V1.toString()); - } else { - // unsupported protocol for server - throw new IllegalArgumentException("Unsupported message protocol"); - } - - return msg; - } - - public static Package broadcastMessageAck(Package in) { - Package msg = new Package(); - msg.setHeader(new Header(Command.BROADCAST_MESSAGE_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); - msg.setBody(in.getBody()); - return msg; - } - - public static Package requestToClientAck(Package in) { - Package msg = new Package(); - msg.setHeader(new Header(Command.REQUEST_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); - msg.setBody(in.getBody()); - return msg; - } - - public static Package responseToClientAck(Package in) { - Package msg = new Package(); - msg.setHeader(new Header(Command.RESPONSE_TO_CLIENT_ACK, 0, null, in.getHeader().getSeq())); - msg.setBody(in.getBody()); - return msg; - } - - public static UserAgent generateSubClient(UserAgent agent) { - return UserAgent.builder() - .env(agent.getEnv()) - .host(agent.getHost()) - .password(agent.getPassword()) - .username(agent.getUsername()) - .path(agent.getPath()) - .port(agent.getPort()) - .subsystem(agent.getSubsystem()) - .pid(agent.getPid()) - .version(agent.getVersion()) - .idc(agent.getIdc()) - .group(agent.getGroup()) - .purpose(EventMeshCommon.USER_AGENT_PURPOSE_SUB) - .build(); - } - - public static UserAgent generatePubClient(UserAgent agent) { - return UserAgent.builder() - .env(agent.getEnv()) - .host(agent.getHost()) - .password(agent.getPassword()) - .username(agent.getUsername()) - .path(agent.getPath()) - .port(agent.getPort()) - .subsystem(agent.getSubsystem()) - .pid(agent.getPid()) - .version(agent.getVersion()) - .idc(agent.getIdc()) - .group(agent.getGroup()) - .purpose(EventMeshCommon.USER_AGENT_PURPOSE_PUB) - .build(); - } - - private static Subscription generateSubscription(String topic, SubscriptionMode subscriptionMode, - SubscriptionType subscriptionType) { - Subscription subscription = new Subscription(); - List subscriptionItems = new ArrayList<>(); - subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); - subscription.setTopicList(subscriptionItems); - return subscription; - } - - private static String generateRandomString(int length) { - StringBuilder builder = new StringBuilder(length); - for (int i = 0; i < length; i++) { - builder.append((char) ThreadLocalRandom.current().nextInt(48, 57)); - } - return builder.toString(); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java deleted file mode 100644 index 3021754949..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.tcp.common; - -import org.apache.eventmesh.common.protocol.tcp.Package; - -import java.util.concurrent.CountDownLatch; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RequestContext { - - private static final Logger logger = LoggerFactory.getLogger(RequestContext.class); - - private Object key; - private Package request; - private Package response; - private CountDownLatch latch; - - public RequestContext(Object key, Package request, CountDownLatch latch) { - this.key = key; - this.request = request; - this.latch = latch; - } - - public Object getKey() { - return key; - } - - public void setKey(Object key) { - this.key = key; - } - - public Package getRequest() { - return request; - } - - public void setRequest(Package request) { - this.request = request; - } - - public Package getResponse() { - return response; - } - - public void setResponse(Package response) { - this.response = response; - } - - public CountDownLatch getLatch() { - return latch; - } - - public void setLatch(CountDownLatch latch) { - this.latch = latch; - } - - public void finish(Package msg) { - this.response = msg; - latch.countDown(); - } - - public static RequestContext context(Object key, Package request, CountDownLatch latch) throws Exception { - RequestContext c = new RequestContext(key, request, latch); - logger.info("_RequestContext|create|key=" + key); - return c; - } - - - public static Object key(Package request) { - return request.getHeader().getSeq(); - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java deleted file mode 100644 index 7f37b73a8d..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.tcp.common; - -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.common.protocol.tcp.Package; -import org.apache.eventmesh.common.protocol.tcp.UserAgent; -import org.apache.eventmesh.common.protocol.tcp.codec.Codec; - -import java.io.Closeable; -import java.net.InetSocketAddress; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.channel.AdaptiveRecvByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public abstract class TcpClient implements Closeable { - - public final int clientNo = (new Random()).nextInt(1000); - - protected final ConcurrentHashMap contexts = new ConcurrentHashMap<>(); - - protected final String host; - protected final int port; - protected final UserAgent userAgent; - - private final Bootstrap bootstrap = new Bootstrap(); - - private final EventLoopGroup workers = new NioEventLoopGroup(); - - private Channel channel; - - private ScheduledFuture heartTask; - - protected static final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor( - Runtime.getRuntime().availableProcessors(), - new ThreadFactoryBuilder().setNameFormat("TCPClientScheduler").setDaemon(true).build()); - - public TcpClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - Preconditions.checkNotNull(eventMeshTcpClientConfig, "EventMeshTcpClientConfig cannot be null"); - Preconditions.checkNotNull(eventMeshTcpClientConfig.getHost(), "Host cannot be null"); - Preconditions.checkState(eventMeshTcpClientConfig.getPort() > 0, "port is not validated"); - this.host = eventMeshTcpClientConfig.getHost(); - this.port = eventMeshTcpClientConfig.getPort(); - this.userAgent = eventMeshTcpClientConfig.getUserAgent(); - } - - protected synchronized void open(SimpleChannelInboundHandler handler) throws Exception { - bootstrap.group(workers); - bootstrap.channel(NioSocketChannel.class); - bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1_000) - .option(ChannelOption.SO_KEEPALIVE, true) - .option(ChannelOption.SO_SNDBUF, 64 * 1024) - .option(ChannelOption.SO_RCVBUF, 64 * 1024) - .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1024, 8192, 65536)) - .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); - bootstrap.handler(new ChannelInitializer() { - public void initChannel(SocketChannel ch) { - ch.pipeline().addLast(new Codec.Encoder(), new Codec.Decoder()) - .addLast(handler, newExceptionHandler()); - } - }); - - ChannelFuture f = bootstrap.connect(host, port).sync(); - InetSocketAddress localAddress = (InetSocketAddress) f.channel().localAddress(); - channel = f.channel(); - log - .info("connected|local={}:{}|server={}", localAddress.getAddress().getHostAddress(), localAddress.getPort(), - host + ":" + port); - } - - @Override - public void close() { - try { - channel.disconnect().sync(); - workers.shutdownGracefully(); - if (heartTask != null) { - heartTask.cancel(false); - } - goodbye(); - } catch (Exception e) { - Thread.currentThread().interrupt(); - log.warn("close tcp client failed.|remote address={}", channel.remoteAddress(), e); - } - } - - protected void heartbeat() { - if (heartTask == null) { - synchronized (TcpClient.class) { - heartTask = scheduler.scheduleAtFixedRate(() -> { - try { - if (!isActive()) { - reconnect(); - } - Package msg = MessageUtils.heartBeat(); - io(msg, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - log.debug("heart beat start {}", msg); - } catch (Exception ignore) { - // ignore - } - }, EventMeshCommon.HEARTBEAT, EventMeshCommon.HEARTBEAT, TimeUnit.MILLISECONDS); - } - } - } - - protected synchronized void reconnect() throws Exception { - ChannelFuture f = bootstrap.connect(host, port).sync(); - channel = f.channel(); - } - - protected boolean isActive() { - return (channel != null) && (channel.isActive()); - } - - protected void send(Package msg) throws Exception { - if (channel.isWritable()) { - channel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> { - if (!future.isSuccess()) { - log.warn("send msg failed", future.cause()); - } - }); - } else { - channel.writeAndFlush(msg).sync(); - } - } - - protected Package io(Package msg, long timeout) throws Exception { - Object key = RequestContext.key(msg); - CountDownLatch latch = new CountDownLatch(1); - RequestContext c = RequestContext.context(key, msg, latch); - if (!contexts.contains(c)) { - contexts.put(key, c); - } else { - log.info("duplicate key : {}", key); - } - send(msg); - if (!c.getLatch().await(timeout, TimeUnit.MILLISECONDS)) { - throw new TimeoutException("operation timeout, context.key=" + c.getKey()); - } - return c.getResponse(); - } - - // todo: remove hello - protected void hello() throws Exception { - Package msg = MessageUtils.hello(userAgent); - this.io(msg, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } - - // todo: remove goodbye - protected void goodbye() throws Exception { - Package msg = MessageUtils.goodbye(); - this.io(msg, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); - } - - private ChannelDuplexHandler newExceptionHandler() { - return new ChannelDuplexHandler() { - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - log - .info("exceptionCaught, close connection.|remote address={}", ctx.channel().remoteAddress(), cause); - ctx.close(); - } - }; - } -} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java b/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java deleted file mode 100644 index a7412daa1b..0000000000 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.tcp.impl.eventmeshmessage; - -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -import org.apache.eventmesh.client.tcp.EventMeshTCPClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPPubClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPSubClient; -import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; -import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; -import org.apache.eventmesh.common.protocol.tcp.Package; - -import com.google.common.base.Preconditions; - -public class EventMeshMessageTCPClient implements EventMeshTCPClient { - - private final EventMeshTCPPubClient eventMeshMessageTCPPubClient; - private final EventMeshTCPSubClient eventMeshMessageTCPSubClient; - - public EventMeshMessageTCPClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { - eventMeshMessageTCPPubClient = new EventMeshMessageTCPPubClient(eventMeshTcpClientConfig); - eventMeshMessageTCPSubClient = new EventMeshMessageTCPSubClient(eventMeshTcpClientConfig); - } - - @Override - public void init() throws EventMeshException { - eventMeshMessageTCPPubClient.init(); - eventMeshMessageTCPSubClient.init(); - } - - @Override - public Package rr(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { - validateMessage(eventMeshMessage); - return eventMeshMessageTCPPubClient.rr(eventMeshMessage, timeout); - } - - @Override - public void asyncRR(EventMeshMessage eventMeshMessage, AsyncRRCallback callback, long timeout) - throws EventMeshException { - validateMessage(eventMeshMessage); - eventMeshMessageTCPPubClient.asyncRR(eventMeshMessage, callback, timeout); - } - - @Override - public Package publish(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { - validateMessage(eventMeshMessage); - return eventMeshMessageTCPPubClient.publish(eventMeshMessage, timeout); - } - - @Override - public void broadcast(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { - validateMessage(eventMeshMessage); - eventMeshMessageTCPPubClient.broadcast(eventMeshMessage, timeout); - } - - @Override - public void listen() throws EventMeshException { - eventMeshMessageTCPSubClient.listen(); - } - - @Override - public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { - eventMeshMessageTCPSubClient.subscribe(topic, subscriptionMode, subscriptionType); - } - - @Override - public void unsubscribe() throws EventMeshException { - eventMeshMessageTCPSubClient.unsubscribe(); - } - - @Override - public void registerPubBusiHandler(ReceiveMsgHook handler) throws EventMeshException { - eventMeshMessageTCPPubClient.registerBusiHandler(handler); - } - - @Override - public void registerSubBusiHandler(ReceiveMsgHook handler) throws EventMeshException { - eventMeshMessageTCPSubClient.registerBusiHandler(handler); - } - - @Override - public void close() throws EventMeshException { - try (final EventMeshTCPPubClient eventMeshTCPPubClient = eventMeshMessageTCPPubClient; - final EventMeshTCPSubClient eventMeshTCPSubClient = eventMeshMessageTCPSubClient) { - // close client - } - } - - @Override - public EventMeshTCPPubClient getPubClient() { - return eventMeshMessageTCPPubClient; - } - - @Override - public EventMeshTCPSubClient getSubClient() { - return eventMeshMessageTCPSubClient; - } - - private void validateMessage(EventMeshMessage message) { - Preconditions.checkNotNull(message, "Message cannot be null"); - Preconditions.checkArgument(isNotBlank(message.getTopic()), "Message's topic cannot be null and blank"); - Preconditions.checkArgument(isNotBlank(message.getBody()), "Message's body cannot be null and blank"); - } -} diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumerTest.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumerTest.java deleted file mode 100644 index 68378937f5..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumerTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.consumer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.protocol.SubscriptionItem; -import org.apache.eventmesh.common.protocol.SubscriptionMode; -import org.apache.eventmesh.common.protocol.SubscriptionType; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc.ConsumerServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.ConsumerServiceGrpc.ConsumerServiceStub; -import org.apache.eventmesh.common.protocol.grpc.protos.HeartbeatServiceGrpc.HeartbeatServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.Subscription; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import io.grpc.stub.StreamObserver; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ConsumerServiceBlockingStub.class, ConsumerServiceStub.class, HeartbeatServiceBlockingStub.class}) -@PowerMockIgnore({"javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*"}) -public class EventMeshGrpcConsumerTest { - - @Mock - private ConsumerServiceBlockingStub consumerClient; - @Mock - private ConsumerServiceStub consumerAsyncClient; - @Mock - private HeartbeatServiceBlockingStub heartbeatClient; - private EventMeshGrpcConsumer eventMeshGrpcConsumer; - - @Before - public void setUp() throws Exception { - eventMeshGrpcConsumer = new EventMeshGrpcConsumer(EventMeshGrpcClientConfig.builder().build()); - eventMeshGrpcConsumer.init(); - eventMeshGrpcConsumer.consumerClient = consumerClient; - eventMeshGrpcConsumer.consumerAsyncClient = consumerAsyncClient; - eventMeshGrpcConsumer.heartbeatClient = heartbeatClient; - when(consumerClient.subscribe(any())).thenReturn(Response.getDefaultInstance()); - when(consumerClient.unsubscribe(any())).thenReturn(Response.getDefaultInstance()); - when(heartbeatClient.heartbeat(any())).thenReturn(Response.getDefaultInstance()); - when(consumerAsyncClient.subscribeStream(any())).thenAnswer(invocation -> { - StreamObserver receiver = invocation.getArgument(0); - return new StreamObserver() { - @Override - public void onNext(Subscription value) { - receiver.onNext( - SimpleMessage.newBuilder().setUniqueId("uniqueId").setSeqNum("1").setContent("mockContent") - .setTopic("mockTopic").build()); - receiver.onCompleted(); - } - - @Override - public void onError(Throwable t) { - receiver.onError(t); - } - - @Override - public void onCompleted() { - } - }; - }); - } - - @Test - public void testSubscribeWithUrl() { - assertThat(eventMeshGrpcConsumer.subscribe(Collections.singletonList(buildMockSubscriptionItem()), - "customUrl")).isEqualTo(Response.getDefaultInstance()); - verify(consumerClient, times(1)).subscribe(any()); - verify(heartbeatClient, Mockito.after(10000L).times(1)).heartbeat(any()); - assertThat(eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(buildMockSubscriptionItem()), - "customUrl")).isEqualTo(Response.getDefaultInstance()); - verify(consumerClient, times(1)).unsubscribe(any()); - } - - @Test - public void testSubscribeStreamWithoutListener() { - eventMeshGrpcConsumer.subscribe(Collections.singletonList(buildMockSubscriptionItem())); - verifyZeroInteractions(consumerAsyncClient); - } - - @Test - public void testSubscribeStream() { - List result = new ArrayList<>(); - eventMeshGrpcConsumer.registerListener(new ReceiveMsgHook() { - @Override - public Optional handle(Object msg) throws Throwable { - result.add(msg); - return Optional.empty(); - } - - @Override - public String getProtocolType() { - return null; - } - }); - eventMeshGrpcConsumer.subscribe(Collections.singletonList(buildMockSubscriptionItem())); - assertThat(result).hasSize(1).first().isInstanceOf(EventMeshMessage.class) - .hasFieldOrPropertyWithValue("bizSeqNo", "1").hasFieldOrPropertyWithValue("uniqueId", "uniqueId") - .hasFieldOrPropertyWithValue("topic", "mockTopic") - .hasFieldOrPropertyWithValue("content", "mockContent"); - verify(consumerAsyncClient, times(1)).subscribeStream(any()); - assertThat(eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(buildMockSubscriptionItem()))).isEqualTo( - Response.getDefaultInstance()); - verify(consumerClient, times(1)).unsubscribe(any()); - } - - private SubscriptionItem buildMockSubscriptionItem() { - SubscriptionItem subscriptionItem = new SubscriptionItem(); - subscriptionItem.setType(SubscriptionType.SYNC); - subscriptionItem.setMode(SubscriptionMode.CLUSTERING); - subscriptionItem.setTopic("topic"); - return subscriptionItem; - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducerTest.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducerTest.java deleted file mode 100644 index 6ed0b57850..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducerTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.producer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.PublisherServiceGrpc.PublisherServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; - -import java.util.Collections; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.reflect.Whitebox; - -import io.cloudevents.core.v1.CloudEventV1; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({PublisherServiceBlockingStub.class, Response.class}) -@PowerMockIgnore({"javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*"}) -public class CloudEventProducerTest { - - private CloudEventProducer cloudEventProducer; - @Mock - private PublisherServiceBlockingStub blockingStub; - @Mock - private Response mockResponse; - - @Before - public void setUp() throws Exception { - cloudEventProducer = new CloudEventProducer(EventMeshGrpcClientConfig.builder().build(), blockingStub); - when(blockingStub.batchPublish(Mockito.isA(BatchMessage.class))).thenReturn(mockResponse); - when(blockingStub.publish(Mockito.isA(SimpleMessage.class))).thenReturn(mockResponse); - } - - @Test - public void testEnhanceCloudEvent() { - MockCloudEvent mockCloudEvent = new MockCloudEvent(); - Object enhanceCloudEvent; - try { - enhanceCloudEvent = Whitebox.invokeMethod(cloudEventProducer, "enhanceCloudEvent", mockCloudEvent, - null); - } catch (Exception e) { - enhanceCloudEvent = null; - } - assertThat(enhanceCloudEvent).isNotNull().isInstanceOf(CloudEventV1.class) - .hasFieldOrPropertyWithValue("id", mockCloudEvent.getId()) - .hasFieldOrPropertyWithValue("source", mockCloudEvent.getSource()) - .hasFieldOrPropertyWithValue("type", mockCloudEvent.getType()) - .hasFieldOrPropertyWithValue("dataschema", mockCloudEvent.getDataSchema()) - .hasFieldOrPropertyWithValue("subject", mockCloudEvent.getSubject()) - .hasFieldOrPropertyWithValue("data", mockCloudEvent.getData()); - } - - @Test - public void testPublishMultiWithEmpty() { - assertThat(cloudEventProducer.publish(Collections.emptyList())).isNull(); - } - - @Test - public void testPublishMulti() { - assertThat(cloudEventProducer.publish(Collections.singletonList(new MockCloudEvent()))).isEqualTo(mockResponse); - } - - @Test - public void testPublishSingle() { - assertThat(cloudEventProducer.publish(new MockCloudEvent())).isEqualTo(mockResponse); - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducerTest.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducerTest.java deleted file mode 100644 index 8d60fb1166..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducerTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.producer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.when; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.EventMeshMessage.EventMeshMessageBuilder; -import org.apache.eventmesh.common.protocol.grpc.protos.PublisherServiceGrpc.PublisherServiceBlockingStub; -import org.apache.eventmesh.common.protocol.grpc.protos.Response; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; - -import org.apache.commons.lang3.StringUtils; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@PrepareForTest(PublisherServiceBlockingStub.class) -@PowerMockIgnore({"javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*"}) -public class EventMeshGrpcProducerTest { - - private EventMeshGrpcProducer producer; - @Mock - private CloudEventProducer cloudEventProducer; - @Mock - private PublisherServiceBlockingStub stub; - - @Before - public void setUp() throws Exception { - producer = new EventMeshGrpcProducer(EventMeshGrpcClientConfig.builder().build()); - producer.cloudEventProducer = cloudEventProducer; - producer.publisherClient = stub; - doThrow(RuntimeException.class).when(stub).publish( - argThat(argument -> argument != null && StringUtils.equals(argument.getContent(), - "mockExceptionContent"))); - doReturn(Response.getDefaultInstance()).when(stub).publish( - argThat(argument -> argument != null && StringUtils.equals(argument.getContent(), "mockContent"))); - doReturn(Response.getDefaultInstance()).when(stub).batchPublish( - argThat(argument -> argument != null && StringUtils.equals(argument.getTopic(), "mockTopic"))); - doAnswer(invocation -> { - SimpleMessage simpleMessage = invocation.getArgument(0); - if (StringUtils.isEmpty(simpleMessage.getContent())) { - return SimpleMessage.getDefaultInstance(); - } - return SimpleMessage.newBuilder(simpleMessage).build(); - }).when(stub).requestReply(any()); - doReturn(stub).when(stub).withDeadlineAfter(1000, TimeUnit.MILLISECONDS); - when(cloudEventProducer.publish(anyList())).thenReturn(Response.getDefaultInstance()); - } - - @Test - public void testPublishWithException() { - assertThat(producer.publish(defaultEventMeshMessageBuilder().content("mockExceptionContent").build())).isNull(); - } - - @Test - public void testPublishEventMeshMessage() { - assertThat(producer.publish(defaultEventMeshMessageBuilder().build())).isEqualTo(Response.getDefaultInstance()); - } - - @Test - public void testPublishEmptyList() { - assertThat(producer.publish(Collections.emptyList())).isNull(); - } - - @Test - public void testPublishGenericMessageList() { - assertThat(producer.publish(Collections.singletonList(new MockCloudEvent()))).isEqualTo( - Response.getDefaultInstance()); - EventMeshMessageBuilder eventMeshMessageBuilder = defaultEventMeshMessageBuilder(); - eventMeshMessageBuilder.prop(Collections.singletonMap(Constants.EVENTMESH_MESSAGE_CONST_TTL, "1000")); - assertThat(producer.publish(Collections.singletonList(eventMeshMessageBuilder.build()))).isEqualTo( - Response.getDefaultInstance()); - } - - @Test - public void testRequestReply() { - assertThat(producer.requestReply(defaultEventMeshMessageBuilder().content(StringUtils.EMPTY).build(), - 1000)).isNull(); - EventMeshMessage eventMeshMessage = defaultEventMeshMessageBuilder().build(); - assertThat(producer.requestReply(eventMeshMessage, 1000)).hasFieldOrPropertyWithValue("content", - eventMeshMessage.getContent()).hasFieldOrPropertyWithValue("topic", eventMeshMessage.getTopic()); - } - - private EventMeshMessage.EventMeshMessageBuilder defaultEventMeshMessageBuilder() { - return EventMeshMessage.builder().bizSeqNo("bizSeqNo").content("mockContent") - .createTime(System.currentTimeMillis()).uniqueId("mockUniqueId").topic("mockTopic") - .prop(Collections.emptyMap()); - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/util/EventMeshClientUtilTest.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/util/EventMeshClientUtilTest.java deleted file mode 100644 index 4b54314e07..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/util/EventMeshClientUtilTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.grpc.util; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; -import org.apache.eventmesh.client.tcp.common.EventMeshCommon; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; -import org.apache.eventmesh.common.protocol.grpc.protos.BatchMessage; -import org.apache.eventmesh.common.protocol.grpc.protos.SimpleMessage; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -import org.junit.Test; - -import io.cloudevents.CloudEvent; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.jackson.JsonFormat; - -public class EventMeshClientUtilTest { - - @Test - public void testBuildHeader() { - EventMeshGrpcClientConfig clientConfig = EventMeshGrpcClientConfig.builder().build(); - assertThat(EventMeshClientUtil.buildHeader(clientConfig, "protocolType")).hasFieldOrPropertyWithValue("env", - clientConfig.getEnv()).hasFieldOrPropertyWithValue("idc", clientConfig.getIdc()) - .hasFieldOrPropertyWithValue("ip", IPUtils.getLocalAddress()) - .hasFieldOrPropertyWithValue("pid", Long.toString(ThreadUtils.getPID())) - .hasFieldOrPropertyWithValue("sys", clientConfig.getSys()) - .hasFieldOrPropertyWithValue("language", clientConfig.getLanguage()) - .hasFieldOrPropertyWithValue("username", clientConfig.getUserName()) - .hasFieldOrPropertyWithValue("password", clientConfig.getPassword()) - .hasFieldOrPropertyWithValue("protocolType", "protocolType") - .hasFieldOrPropertyWithValue("protocolDesc", "grpc") - .hasFieldOrPropertyWithValue("protocolVersion", SpecVersion.V1.toString()); - } - - @Test - public void testBuildMessageWithEmptySeq() { - SimpleMessage message = SimpleMessage.newBuilder().setContent("{}").build(); - Object buildMessage = EventMeshClientUtil.buildMessage(message, null); - assertThat(buildMessage).isInstanceOf(HashMap.class); - assertThat(((HashMap) buildMessage)).isEmpty(); - } - - @Test - public void testBuildMessageWithCloudEventProto() { - SimpleMessage message = SimpleMessage.newBuilder().setSeqNum("1").setUniqueId(RandomStringUtils.generateNum(5)) - .setTopic("mockTopic") - .setContent("{\"specversion\":\"1.0\",\"id\":\"id\",\"source\":\"source\",\"type\":\"type\"}").build(); - Object buildMessage = EventMeshClientUtil.buildMessage(message, EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME); - assertThat(buildMessage).isInstanceOf(CloudEvent.class); - CloudEvent cloudEvent = (CloudEvent) buildMessage; - assertThat(cloudEvent).isNotNull().hasFieldOrPropertyWithValue("subject", message.getTopic()); - assertThat(cloudEvent.getExtension(ProtocolKey.SEQ_NUM)).isEqualTo(message.getSeqNum()); - assertThat(cloudEvent.getExtension(ProtocolKey.UNIQUE_ID)).isEqualTo(message.getUniqueId()); - } - - @Test - public void testBuildMessageWithDefaultProto() { - SimpleMessage message = SimpleMessage.newBuilder().setSeqNum("1").setUniqueId(RandomStringUtils.generateNum(5)) - .setTopic("mockTopic").setContent("mockContent").build(); - Object buildMessage = EventMeshClientUtil.buildMessage(message, null); - assertThat(buildMessage).isInstanceOf(EventMeshMessage.class) - .hasFieldOrPropertyWithValue("content", message.getContent()) - .hasFieldOrPropertyWithValue("topic", message.getTopic()) - .hasFieldOrPropertyWithValue("bizSeqNo", message.getSeqNum()) - .hasFieldOrPropertyWithValue("uniqueId", message.getUniqueId()); - } - - @Test - public void buildSimpleMessageWithCloudEventProto() { - CloudEvent cloudEvent = CloudEventBuilder.v1().withSubject("mockSubject").withId("mockId") - .withSource(URI.create("mockSource")).withType("mockType").withExtension(ProtocolKey.SEQ_NUM, "1") - .withExtension(ProtocolKey.UNIQUE_ID, "uniqueId").build(); - EventMeshGrpcClientConfig clientConfig = EventMeshGrpcClientConfig.builder().build(); - assertThat(EventMeshClientUtil.buildSimpleMessage(cloudEvent, clientConfig, - EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME)).hasFieldOrPropertyWithValue("header", - EventMeshClientUtil.buildHeader(clientConfig, EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME)) - .hasFieldOrPropertyWithValue("producerGroup", clientConfig.getProducerGroup()) - .hasFieldOrPropertyWithValue("topic", cloudEvent.getSubject()) - .hasFieldOrPropertyWithValue("ttl", "4000") - .hasFieldOrPropertyWithValue("seqNum", cloudEvent.getExtension(ProtocolKey.SEQ_NUM)) - .hasFieldOrPropertyWithValue("uniqueId", cloudEvent.getExtension(ProtocolKey.UNIQUE_ID)) - .hasFieldOrPropertyWithValue("content", new String( - EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE).serialize(cloudEvent), - StandardCharsets.UTF_8)); - } - - @Test - public void buildSimpleMessageWithDefaultProto() { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder().content("mockContent").topic("mockTopic") - .uniqueId("mockUniqueId").bizSeqNo("mockBizSeqNo").build(); - EventMeshGrpcClientConfig clientConfig = EventMeshGrpcClientConfig.builder().build(); - assertThat( - EventMeshClientUtil.buildSimpleMessage(eventMeshMessage, clientConfig, "")).hasFieldOrPropertyWithValue( - "header", EventMeshClientUtil.buildHeader(clientConfig, "")) - .hasFieldOrPropertyWithValue("producerGroup", clientConfig.getProducerGroup()) - .hasFieldOrPropertyWithValue("topic", eventMeshMessage.getTopic()) - .hasFieldOrPropertyWithValue("ttl", "4000") - .hasFieldOrPropertyWithValue("seqNum", eventMeshMessage.getBizSeqNo()) - .hasFieldOrPropertyWithValue("uniqueId", eventMeshMessage.getUniqueId()) - .hasFieldOrPropertyWithValue("content", eventMeshMessage.getContent()); - } - - @Test - public void buildBatchMessagesWithCloudEventProto() { - List cloudEvents = Collections.singletonList( - CloudEventBuilder.v1().withSubject("mockSubject").withId("mockId").withSource(URI.create("mockSource")) - .withType("mockType").withExtension(ProtocolKey.SEQ_NUM, "1") - .withExtension(ProtocolKey.UNIQUE_ID, "uniqueId").build()); - EventMeshGrpcClientConfig clientConfig = EventMeshGrpcClientConfig.builder().build(); - BatchMessage batchMessage = EventMeshClientUtil.buildBatchMessages(cloudEvents, clientConfig, - EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME); - assertThat(batchMessage).hasFieldOrPropertyWithValue("header", - EventMeshClientUtil.buildHeader(clientConfig, EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME)) - .hasFieldOrPropertyWithValue("topic", cloudEvents.get(0).getSubject()) - .hasFieldOrPropertyWithValue("producerGroup", clientConfig.getProducerGroup()); - assertThat(batchMessage.getMessageItemList()).hasSize(1).first().hasFieldOrPropertyWithValue("content", - new String(EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE) - .serialize(cloudEvents.get(0)), StandardCharsets.UTF_8)) - .hasFieldOrPropertyWithValue("ttl", "4000") - .hasFieldOrPropertyWithValue("seqNum", cloudEvents.get(0).getExtension(ProtocolKey.SEQ_NUM)) - .hasFieldOrPropertyWithValue("uniqueId", cloudEvents.get(0).getExtension(ProtocolKey.UNIQUE_ID)); - assertThat(batchMessage.getMessageItem(0).getPropertiesMap()).containsEntry(ProtocolKey.CONTENT_TYPE, - JsonFormat.CONTENT_TYPE); - } - - @Test - public void buildBatchMessagesWithDefaultProto() { - List eventMeshMessages = Collections.singletonList( - EventMeshMessage.builder().content("mockContent").topic("mockTopic").uniqueId("mockUniqueId") - .bizSeqNo("mockBizSeqNo") - .prop(Collections.singletonMap(Constants.EVENTMESH_MESSAGE_CONST_TTL, "4000")).build()); - EventMeshGrpcClientConfig clientConfig = EventMeshGrpcClientConfig.builder().build(); - BatchMessage batchMessage = EventMeshClientUtil.buildBatchMessages(eventMeshMessages, clientConfig, ""); - assertThat(batchMessage).hasFieldOrPropertyWithValue("header", - EventMeshClientUtil.buildHeader(clientConfig, "")) - .hasFieldOrPropertyWithValue("topic", eventMeshMessages.get(0).getTopic()) - .hasFieldOrPropertyWithValue("producerGroup", clientConfig.getProducerGroup()); - EventMeshMessage firstMeshMessage = eventMeshMessages.get(0); - assertThat(batchMessage.getMessageItemList()).hasSize(1).first() - .hasFieldOrPropertyWithValue("content", firstMeshMessage.getContent()) - .hasFieldOrPropertyWithValue("uniqueId", firstMeshMessage.getUniqueId()) - .hasFieldOrPropertyWithValue("seqNum", firstMeshMessage.getBizSeqNo()) - .hasFieldOrPropertyWithValue("ttl", firstMeshMessage.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL)); - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncPublishInstance.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncPublishInstance.java deleted file mode 100644 index 0e74b3030d..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncPublishInstance.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.demo; - -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class AsyncPublishInstance { - - public static void main(String[] args) throws Exception { - - String eventMeshIPPort = "127.0.0.1:10105"; - final String topic = "TEST-TOPIC-HTTP-ASYNC"; - - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup("EventMeshTest-producerGroup") - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())).build(); - - EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); - for (int i = 0; i < 1; i++) { - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .bizSeqNo(RandomStringUtils.generateNum(30)) - .content("testPublishMessage") - .topic(topic) - .uniqueId(RandomStringUtils.generateNum(30)) - .build() - .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); - - eventMeshHttpProducer.publish(eventMeshMessage); - Thread.sleep(1000); - } - Thread.sleep(30000); - try (EventMeshHttpProducer ignore = eventMeshHttpProducer) { - // ignore - } - } -} diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncSyncRequestInstance.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncSyncRequestInstance.java deleted file mode 100644 index 9f84cb6ae6..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncSyncRequestInstance.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.demo; - - -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; -import org.apache.eventmesh.client.http.producer.RRCallback; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -import org.apache.commons.lang3.StringUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AsyncSyncRequestInstance { - - public static Logger logger = LoggerFactory.getLogger(AsyncSyncRequestInstance.class); - - public static void main(String[] args) throws Exception { - - EventMeshHttpProducer eventMeshHttpProducer = null; - try { - //String eventMeshIPPort = args[0]; - String eventMeshIPPort = ""; - //final String topic = args[1]; - final String topic = "TEST-TOPIC-HTTP-ASYNC"; - if (StringUtils.isBlank(eventMeshIPPort)) { - // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 - eventMeshIPPort = "127.0.0.1:10105"; - } - - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup("EventMeshTest-producerGroup") - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())).build(); - - eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); - - final long startTime = System.currentTimeMillis(); - final EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .bizSeqNo(RandomStringUtils.generateNum(30)) - .content("testAsyncMessage") - .topic(topic) - .uniqueId(RandomStringUtils.generateNum(30)).build(); - - eventMeshHttpProducer.request(eventMeshMessage, new RRCallback() { - @Override - public void onSuccess(EventMeshMessage o) { - logger.debug("sendmsg : {}, return : {}, cost:{}ms", eventMeshMessage.getContent(), o.getContent(), - System.currentTimeMillis() - startTime); - } - - @Override - public void onException(Throwable e) { - logger.debug("sendmsg failed", e); - } - }, 3000); - - Thread.sleep(2000); - } catch (Exception e) { - logger.warn("async send msg failed", e); - } - - Thread.sleep(30000); - try (final EventMeshHttpProducer ignore = eventMeshHttpProducer) { - // close producer - } catch (Exception e1) { - logger.warn("producer shutdown exception", e1); - } - } -} diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/SyncRequestInstance.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/SyncRequestInstance.java deleted file mode 100644 index 6096438a97..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/SyncRequestInstance.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.demo; - -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; -import org.apache.eventmesh.common.EventMeshMessage; -import org.apache.eventmesh.common.utils.IPUtils; -import org.apache.eventmesh.common.utils.RandomStringUtils; -import org.apache.eventmesh.common.utils.ThreadUtils; - -import org.apache.commons.lang3.StringUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SyncRequestInstance { - - public static Logger logger = LoggerFactory.getLogger(SyncRequestInstance.class); - - public static void main(String[] args) throws Exception { - - EventMeshHttpProducer eventMeshHttpProducer = null; - try { - String eventMeshIPPort = args[0]; - - final String topic = args[1]; - - if (StringUtils.isBlank(eventMeshIPPort)) { - // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 - eventMeshIPPort = "127.0.0.1:10105"; - } - - EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr(eventMeshIPPort) - .producerGroup("EventMeshTest-producerGroup") - .env("env") - .idc("idc") - .ip(IPUtils.getLocalAddress()) - .sys("1234") - .pid(String.valueOf(ThreadUtils.getPID())).build(); - - eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); - - long startTime = System.currentTimeMillis(); - EventMeshMessage eventMeshMessage = EventMeshMessage.builder() - .bizSeqNo(RandomStringUtils.generateNum(30)) - .content("contentStr with special protocal") - .topic(topic) - .uniqueId(RandomStringUtils.generateNum(30)).build(); - - EventMeshMessage rsp = eventMeshHttpProducer.request(eventMeshMessage, 10000); - if (logger.isDebugEnabled()) { - logger.debug("sendmsg : {}, return : {}, cost:{}ms", eventMeshMessage.getContent(), rsp.getContent(), - System.currentTimeMillis() - startTime); - } - } catch (Exception e) { - logger.warn("send msg failed", e); - } - - Thread.sleep(30000); - try (final EventMeshHttpProducer closed = eventMeshHttpProducer) { - // close producer - } catch (Exception e1) { - logger.warn("producer shutdown exception", e1); - } - } -} diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtilsTest.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtilsTest.java deleted file mode 100644 index f97c2d81eb..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtilsTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.http.util; - -import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; -import org.apache.eventmesh.common.exception.EventMeshException; -import org.apache.eventmesh.common.loadbalance.LoadBalanceSelector; -import org.apache.eventmesh.common.loadbalance.LoadBalanceType; - -import org.junit.Assert; -import org.junit.Test; - -public class HttpLoadBalanceUtilsTest { - - @Test - public void testCreateRandomSelector() throws EventMeshException { - EventMeshHttpClientConfig eventMeshHttpClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr("127.0.0.1:1001;127.0.0.2:1002") - .build(); - LoadBalanceSelector randomSelector = HttpLoadBalanceUtils - .createEventMeshServerLoadBalanceSelector(eventMeshHttpClientConfig); - Assert.assertEquals(LoadBalanceType.RANDOM, randomSelector.getType()); - } - - @Test - public void testCreateWeightRoundRobinSelector() throws EventMeshException { - EventMeshHttpClientConfig eventMeshHttpClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr("127.0.0.1:1001:1;127.0.0.2:1001:2") - .loadBalanceType(LoadBalanceType.WEIGHT_ROUND_ROBIN).build(); - LoadBalanceSelector weightRoundRobinSelector = HttpLoadBalanceUtils - .createEventMeshServerLoadBalanceSelector(eventMeshHttpClientConfig); - Assert.assertEquals(LoadBalanceType.WEIGHT_ROUND_ROBIN, weightRoundRobinSelector.getType()); - } - - @Test - public void testCreateWeightRandomSelector() throws EventMeshException { - EventMeshHttpClientConfig eventMeshHttpClientConfig = EventMeshHttpClientConfig.builder() - .liteEventMeshAddr("127.0.0.1:1001:1;127.0.0.2:1001:2") - .loadBalanceType(LoadBalanceType.WEIGHT_RANDOM).build(); - LoadBalanceSelector weightRoundRobinSelector = HttpLoadBalanceUtils - .createEventMeshServerLoadBalanceSelector(eventMeshHttpClientConfig); - Assert.assertEquals(LoadBalanceType.WEIGHT_RANDOM, weightRoundRobinSelector.getType()); - } -} \ No newline at end of file diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/impl/EventMeshTCPClientFactoryTest.java b/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/impl/EventMeshTCPClientFactoryTest.java deleted file mode 100644 index 3467a9e42a..0000000000 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/impl/EventMeshTCPClientFactoryTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.client.tcp.impl; - -import org.apache.eventmesh.client.tcp.EventMeshTCPClient; -import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory; -import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; -import org.apache.eventmesh.client.tcp.impl.cloudevent.CloudEventTCPClient; -import org.apache.eventmesh.client.tcp.impl.eventmeshmessage.EventMeshMessageTCPClient; -import org.apache.eventmesh.client.tcp.impl.openmessage.OpenMessageTCPClient; -import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; - -import org.junit.Assert; -import org.junit.Test; - -import io.cloudevents.CloudEvent; -import io.openmessaging.api.Message; - -public class EventMeshTCPClientFactoryTest { - - @Test - public void createEventMeshTCPClient() { - EventMeshTCPClientConfig meshTCPClientConfig = EventMeshTCPClientConfig.builder() - .host("localhost") - .port(1234) - .build(); - - - EventMeshTCPClient eventMeshMessageTCPClient = - EventMeshTCPClientFactory.createEventMeshTCPClient(meshTCPClientConfig, EventMeshMessage.class); - Assert.assertEquals(EventMeshMessageTCPClient.class, eventMeshMessageTCPClient.getClass()); - - EventMeshTCPClient cloudEventTCPClient = - EventMeshTCPClientFactory.createEventMeshTCPClient(meshTCPClientConfig, CloudEvent.class); - Assert.assertEquals(CloudEventTCPClient.class, cloudEventTCPClient.getClass()); - - EventMeshTCPClient openMessageTCPClient = - EventMeshTCPClientFactory.createEventMeshTCPClient(meshTCPClientConfig, Message.class); - Assert.assertEquals(OpenMessageTCPClient.class, openMessageTCPClient.getClass()); - } -} \ No newline at end of file diff --git a/eventmesh-sdks/build.gradle b/eventmesh-sdks/build.gradle new file mode 100644 index 0000000000..d973dcedae --- /dev/null +++ b/eventmesh-sdks/build.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-c/README.md b/eventmesh-sdks/eventmesh-sdk-c/README.md new file mode 100644 index 0000000000..25a4ddabea --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/README.md @@ -0,0 +1,20 @@ +## EventMesh C/C++ SDK + +### Support api + +1. **TCP** + +### Build +1. **build lib** +``` +git submodule init +git submodule update +make +``` + +2. **build example** +``` +git submodule init +git submodule update +make demo +``` \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-c/configs/rmb.conf b/eventmesh-sdks/eventmesh-sdk-c/configs/rmb.conf new file mode 100644 index 0000000000..8295ebf163 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/configs/rmb.conf @@ -0,0 +1,61 @@ +# 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. + +consumerSysId 1000 +consumerSysVersion 1.0.0 +consumerSvrId 10.199.199.199 +consumerDcn A00 +orgId 99996 +localIdc A +wemq_user wemq +wemq_passwd default + +#log configure +logFile sub +logLevel 5 +logFileNums 10 +logFileSize 100000000 +logSwiftType 1 + +#receive message +reqFifoPath ./tmp_req.fifo +reqShmKey 0x27151203 +reqShmSize 20000000 +#receive rr-async reply message +ayncRspFifoPath ./tmp_aync_rsp.fifo +ayncRspShmKey 0x77151204 +ayncRspShmSize 20000000 +#receive broadcast message +broadcastFifoPath ./tmp_broadcast.fifo +broadcastShmKey 0x77151205 +broadcastShmSize 20000000 + +#message log control +logserverSwitch 0 +#req gsl +ReqGslSwitch 0 + +#wemq cc configure +wemqUseHttpCfg 1 +configCenterIp 10.255.34.57 +configCenterPort 8090 +configCenterAddrMulti 127.0.0.1:8090 +#connect directly to access when: wemqUseHttpCfg 0 +wemqProxyIp 127.0.0.1 +wemqProxyPort 10000 +# tlsOnoff:控制与eventmesh的tcp连接是否开启tls +# 0: 不开启(默认) +# 1: 开启 +tlsOnoff 0 diff --git a/eventmesh-sdks/eventmesh-sdk-c/examples/demo.c b/eventmesh-sdks/eventmesh-sdk-c/examples/demo.c new file mode 100644 index 0000000000..f6b7f4f55a --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/examples/demo.c @@ -0,0 +1,1715 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rmb_sub.h" +#include "rmb_pub.h" +#include "rmb_msg.h" +#include "rmb_udp.h" +#include "rmb_cfg.h" +#include "rmb_log.h" +#include "rmb_errno.h" + +#define LOG_PRINT(loglevel,fmt, args...) {log_print(loglevel, "[%s:%d(%s)]: "fmt"", __FILE__, __LINE__, __FUNCTION__, ## args);} + +#define UNIX_DOMAIN "unix.domain" + +typedef struct tMessage +{ + int type; //0:pub 1:sub + pid_t pid; + unsigned int process_num; + unsigned int process_status; + unsigned int has_send; + unsigned int send_msg_num; + unsigned int recv_msg_num; +} tMessage; + +#define MAX_MSG_LEN (1024*1024*3+1) + +static const char *version_test = "RMB_C_API_V2.2.0"; + +static const char *send_msg = "pubSendMsg"; + +pthread_mutex_t test_mutex; + +StRmbSub *pRmbSub; +StRmbPub *pRmbPub; + +static char StatLogLevel[6][10] = + { "FATAL", "ERROR", "WARN ", "INFO", "DEBUG", "ALL" }; + +int log_print (int logLevel, const char *format, ...) +{ + va_list ap; + struct timeval stLogTv; + + va_start (ap, format); + gettimeofday (&stLogTv, NULL); + fprintf (stdout, "[%s][%s %03d][%d]", StatLogLevel[logLevel], + RmbGetDateTimeStr ((const time_t *) &(stLogTv.tv_sec)), + (int) ((stLogTv.tv_usec) / 1000), getpid ()); + //fprintf(stdout, "[%s][%d]", StatLogLevel[logLevel],getpid()); + vfprintf (stdout, format, ap); + va_end (ap); + fprintf (stdout, "\n"); + + return 0; +} + +void printfUsage (const char *name) +{ + printf ("%s: version:%s\n\n", name, version_test); + + printf ("%s: sub server端(非广播)\n", name); + printf + (" %s sub sleep_time log_control process_nums topic1 topic2 ...\n", + name); + printf + (" sleep_time:睡眠时间,通常为0, log_control:测试内容大小时使用,1:打印,其他值为不打印 process_nums:进程数量,最小为1\n"); + printf ("\n"); + + printf ("%s: sub server端(广播)\n", name); + printf + (" %s sub_broadcast process_nums log_control topic1 topic2 ...\n", name); + printf ("\n"); + + printf + ("%s: pub client端(RR同步消息/单播/多播/广播消息发送):\n", + name); + printf + (" %s pub pthread_nums log_control msg_nums msg_len ttl_time sleep_time topic1 topic2 ...\n", + name); + printf + (" pthread_nums:线程数量,最小为1, log_control:测试内容大小时使用,1:打印,其他值为不打印 msg_nums:每个线程发送消息数量 msg:消息内容 msg_len:消息内容大小\n"); + printf ("\n"); + + printf ("%s: pub端(RR异步):\n", name); + printf + (" %s rr_async_pub process_nums log_control msg_nums msg_len sleep_time topic\n", + name); + printf + (" process_nums:进程数量,最小为1, msg_nums:每个进程发送消息数量 msg:消息内容\n"); + printf ("\n"); + + printf ("////////////////////////////////////////////////////////\n"); + + exit (0); +} + +typedef struct StDemoArgv +{ + //建议字段 + StRmbPub *pRmbPub; + StRmbSub *pRmbSub; + StRmbMsg *pReceiveMsg; + StRmbMsg *pReplyMsg; + //其他字段 + unsigned int uiLog; + unsigned long ulMsgTotal; + unsigned int uiSleepTime; + unsigned int uiLogServer; + unsigned int uiFlag; +} StDemoArgv; + +typedef struct tThreadArgs +{ + StRmbPub *pRmbPub; + enum EVENT_OR_SERVICE_CALL event_or_service; + unsigned int times; + int iContent; + char cDcn[100]; + char cServiceId[100]; + char cSenaId[100]; + /////////////// + unsigned long ulMsgSucc; + /////////////// + int iLogNum; + unsigned long ttl; + const char *pMsg; +} tThreadArgs; + +/** + * return value: + * 0: success + * 1: topic check failed + * <0: send error + */ +int pubOwnMessage (StRmbPub * pRmbPub, int iEventOrService, + unsigned long ttl_time, const char *cDcn, + const char *cServiceId, const char *cSenaId, + unsigned int log_control, const char *strMsg) +{ + int iRet = 0; + StRmbMsg *pSendMsg = rmb_msg_malloc (); + rmb_msg_clear (pSendMsg); + static unsigned int uiSeq = 1; + struct timeval tv; + gettimeofday (&tv, NULL); + unsigned long ulNowTime = tv.tv_sec * 1000 + tv.tv_usec / 1000; + char cSeqNo[33]; + snprintf (cSeqNo, sizeof (cSeqNo), "%013lu%019u", ulNowTime, uiSeq++); +// rmb_msg_set_bizSeqNo(pSendMsg, "12345678901234567890123456789012"); + rmb_msg_set_bizSeqNo (pSendMsg, cSeqNo); +// rmb_msg_set_consumerSeqNo(pSendMsg, "22222678901234567890123456799999"); + rmb_msg_set_consumerSeqNo (pSendMsg, cSeqNo); + rmb_msg_set_orgSysId (pSendMsg, "9999"); + //set ttl, millisecond(hao s) +// printf("ttl = %lu\n", ttl_time); + if (ttl_time > 0) + { + rmb_msg_set_live_time (pSendMsg, ttl_time); + } + if (iEventOrService == 0) + { + iRet = + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, RMB_EVENT_CALL, + cServiceId, cSenaId); + } + else + { + iRet = + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, RMB_SERVICE_CALL, + cServiceId, cSenaId); + } +/* if (iRet < 0) + return 1;*/ + + rmb_msg_set_content (pSendMsg, strMsg, strlen (strMsg)); + char appHeader[100] = "{}"; + rmb_msg_set_app_header (pSendMsg, appHeader, strlen (appHeader)); + + if (iEventOrService == 0) + { + iRet = rmb_pub_send_msg (pRmbPub, pSendMsg); + if (log_control & 2) + { + if (iRet == 0) + { + LOG_PRINT (RMB_LOG_INFO, "send msg=%s OK", pSendMsg->cContent); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_msg error!iRet = %d", iRet); + } + } + } + else + { + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + iRet = rmb_pub_send_and_receive (pRmbPub, pSendMsg, pReceiveMsg, 50000); + if (iRet == 0) + { + char receiveBuf[MAX_MSG_LEN]; + unsigned int receiveLen = sizeof (receiveBuf); + rmb_msg_get_content (pReceiveMsg, receiveBuf, &receiveLen); + + if (log_control == 1) + { + LOG_PRINT (RMB_LOG_INFO, "receive reply:len=%u, %s", receiveLen, + receiveBuf); + } + } + else + { + LOG_PRINT (RMB_LOG_INFO, + "rmb_pub_send_and_receive error!iRet = %d,msg=%s", iRet, + strMsg); + } + + //sleep(1); + rmb_msg_free (pReceiveMsg); + } + + rmb_msg_free (pSendMsg); + return iRet; +} + +////////////////////////////////////////////////// + +int pub_message (StRmbPub * pRmbPub, int iEventOrService, int first_msg_nums, + int second_msg_nums, const char *cDcn, + const char *cServiceId, const char *cSenaId) +{ + int iRet = 0; + StRmbMsg *pSendMsg = rmb_msg_malloc (); + + rmb_msg_set_bizSeqNo (pSendMsg, "12345678901234567890123456789012"); + rmb_msg_set_consumerSeqNo (pSendMsg, "22222678901234567890123456799999"); + rmb_msg_set_orgSysId (pSendMsg, "9999"); + if (iEventOrService == 0) + { + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, RMB_EVENT_CALL, + cServiceId, cSenaId); + } + else + { + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, RMB_SERVICE_CALL, + cServiceId, cSenaId); + } + rmb_msg_set_content (pSendMsg, send_msg, strlen (send_msg)); + char appHeader[100] = "{}"; + rmb_msg_set_app_header (pSendMsg, appHeader, strlen (appHeader)); + + unsigned long ulNowTime = 0; + unsigned long ulSleepTime = 0; + struct timeval tv; + + if (iEventOrService == 0) + { + gettimeofday (&tv, NULL); + ulNowTime = tv.tv_sec * 1000000 + tv.tv_usec; + int i; + for (i = 0; i < first_msg_nums; i++) + { + iRet = rmb_pub_send_msg (pRmbPub, pSendMsg); +#ifdef DEBUG + if (iRet == 0) + { + LOG_PRINT (RMB_LOG_INFO, "send msg=%s OK", pSendMsg->cContent); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_msg error!iRet = %d", iRet); + } +#endif + } + + gettimeofday (&tv, NULL); + ulSleepTime = tv.tv_sec * 1000000 + tv.tv_usec - ulNowTime; + printf ("ulSleepTime = %lu\n", ulSleepTime); + if (ulSleepTime < 1000000) + usleep (ulSleepTime); + + for (i = 0; i < second_msg_nums; i++) + { + iRet = rmb_pub_send_msg (pRmbPub, pSendMsg); +#ifdef DEBUG + if (iRet == 0) + { + LOG_PRINT (RMB_LOG_INFO, "send msg=%s OK", pSendMsg->cContent); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_msg error!iRet = %d", iRet); + } +#endif + } + } + else + { + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + gettimeofday (&tv, NULL); + ulNowTime = tv.tv_sec * 1000000 + tv.tv_usec; + int i; + for (i = 0; i < first_msg_nums; i++) + { + iRet = rmb_pub_send_and_receive (pRmbPub, pSendMsg, pReceiveMsg, 5000); + if (iRet == 0) + { + char receiveBuf[1024]; + unsigned int receiveLen = sizeof (receiveBuf); + rmb_msg_get_content (pReceiveMsg, receiveBuf, &receiveLen); +#ifdef DEBUG + LOG_PRINT (RMB_LOG_INFO, "receive reply pkg=%s", receiveBuf); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, + "rmb_pub_send_and_receive error!iRet = %d,msg=%s", iRet, + strMsg); + } +#else + } +#endif + } + gettimeofday (&tv, NULL); + ulSleepTime = tv.tv_sec * 1000000 + tv.tv_usec - ulNowTime; + printf ("ulSleepTime = %lu\n", ulSleepTime); + if (ulSleepTime < 1000000) + usleep (ulSleepTime); + + for (i = 0; i < second_msg_nums; i++) + { + iRet = rmb_pub_send_and_receive (pRmbPub, pSendMsg, pReceiveMsg, 5000); + if (iRet == 0) + { + char receiveBuf[1024]; + unsigned int receiveLen = sizeof (receiveBuf); + rmb_msg_get_content (pReceiveMsg, receiveBuf, &receiveLen); +#ifdef DEBUG + LOG_PRINT (RMB_LOG_INFO, "receive reply pkg=%s", receiveBuf); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, + "rmb_pub_send_and_receive error!iRet = %d,msg=%s", iRet, + strMsg); + } +#else + } +#endif + } + + rmb_msg_free (pReceiveMsg); + } + printf ("%s: send msg:%d\n", __func__, first_msg_nums + second_msg_nums); + + rmb_msg_free (pSendMsg); + return iRet; +} + +static int pub_board_message (StRmbPub * pRmbPub, int iEventOrService, + unsigned long ttl_time, const char *cDcn, + const char *cServiceId, const char *cSenaId, + const char *cOrgId, unsigned int log_control, + const char *strMsg) +{ + int iRet = 0; + StRmbMsg *pSendMsg = rmb_msg_malloc (); + rmb_msg_clear (pSendMsg); + rmb_msg_set_bizSeqNo (pSendMsg, "12345678901234567890123456789012"); + rmb_msg_set_consumerSeqNo (pSendMsg, "22222678901234567890123456799999"); + rmb_msg_set_orgSysId (pSendMsg, "9999"); + //set ttl, millisecond(hao s) + //printf("ttl = %lu\n", ttl_time); + if (ttl_time > 0) + rmb_msg_set_live_time (pSendMsg, ttl_time); + + if (iEventOrService != RMB_EVENT_CALL) + { + printf ("type:%d is not event call\n", iEventOrService); + return -1; + } + + iRet = rmb_msg_set_dest_v2_1 (pRmbPub, cDcn, cServiceId, cSenaId, cOrgId); + if (iRet < 0) + { + printf ("rmb_msg_set_dest_v2_1 return: %d\n", iRet); + return iRet; + } + + rmb_msg_set_content (pSendMsg, strMsg, strlen (strMsg)); + char appHeader[100] = "{}"; + rmb_msg_set_app_header (pSendMsg, appHeader, strlen (appHeader)); + if (iEventOrService == 0) + { + iRet = rmb_pub_send_msg (pRmbPub, pSendMsg); + if (log_control & 2) + { + if (iRet == 0) + { + LOG_PRINT (RMB_LOG_INFO, "send msg=%s OK", pSendMsg->cContent); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_msg error!iRet = %d", iRet); + } + } + } + + rmb_msg_free (pSendMsg); + return iRet; +} + +int mutil_thread_pub_message (StRmbPub * pRmbPub, int iEventOrService, + unsigned long ttl, int iContentBase, + int iOffset, const char *cDcn, + const char *cServiceId, const char *cSenaId, + const char *strMsg) +{ + int iRet = 0; + StRmbMsg *pSendMsg = rmb_msg_malloc (); + + rmb_msg_set_bizSeqNo (pSendMsg, "12345678901234567890123456789012"); + rmb_msg_set_consumerSeqNo (pSendMsg, "22222678901234567890123456799999"); + rmb_msg_set_orgSysId (pSendMsg, "9999"); +// printf("ttl = %lu\n", ttl); + if (ttl > 0) + { + rmb_msg_set_live_time (pSendMsg, ttl); + } + if (iEventOrService == 0) + { + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, RMB_EVENT_CALL, + cServiceId, cSenaId); + } + else + { + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, RMB_SERVICE_CALL, + cServiceId, cSenaId); + } + +// char cContent[100]; +// snprintf(cContent, sizeof(cContent), "thread%d--%dth:%s", iContentBase, iOffset, strMsg); +// rmb_msg_set_content(pSendMsg, cContent, strlen(cContent)); + rmb_msg_set_content (pSendMsg, strMsg, strlen (strMsg)); + char appHeader[100] = "{}"; + rmb_msg_set_app_header (pSendMsg, appHeader, strlen (appHeader)); + + if (iEventOrService == 0) + { + iRet = rmb_pub_send_msg (pRmbPub, pSendMsg); +#ifdef DEBUG + if (iRet == 0) + { + LOG_PRINT (RMB_LOG_INFO, "send msg=%s OK", pSendMsg->cContent); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_msg error!iRet = %d", iRet); + } +#endif + } + else + { + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + iRet = rmb_pub_send_and_receive (pRmbPub, pSendMsg, pReceiveMsg, 5000); + if (iRet == 0) + { +// char receiveBuf[1024]; + char receiveBuf[MAX_MSG_LEN]; + unsigned int receiveLen = sizeof (receiveBuf); + rmb_msg_get_content (pReceiveMsg, receiveBuf, &receiveLen); +#ifdef DEBUG + LOG_PRINT (RMB_LOG_INFO, "receive reply pkg=%s", receiveBuf); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, + "rmb_pub_send_and_receive error!iRet = %d,msg=%s", iRet, + strMsg); + } +#else + } +#endif + rmb_msg_free (pReceiveMsg); + } + + rmb_msg_free (pSendMsg); + return iRet; +} + +void mutil_thread_for_pub (void *pArgs) +{ + tThreadArgs *pTmp = (tThreadArgs *) pArgs; + + int iRet = 0; + unsigned int message_times = 0; + int i; + for (i = 0; i < pTmp->times; ++i) + { + iRet = + mutil_thread_pub_message (pTmp->pRmbPub, pTmp->event_or_service, + pTmp->ttl, pTmp->iContent, i, pTmp->cDcn, + pTmp->cServiceId, pTmp->cSenaId, pTmp->pMsg); + if (iRet == 0) + { + message_times++; + pTmp->ulMsgSucc++; + } + } + if (pTmp->event_or_service == RMB_SERVICE_CALL) + { + LOG_PRINT (RMB_LOG_INFO, "threadid:%d -- pub send %u and recv msg:%u\n", + (int) pthread_self (), pTmp->times, message_times); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "threadid:%d -- pub send %u and succ msg:%u\n", + (int) pthread_self (), pTmp->times, message_times); + } +} + +//sub回调函数 +void func_with_req (const char *buf, const int len, void *pAgv) +//void func_with_req(void *pRevMsg, void *pAgv) +{ + if (pAgv == NULL) + { + printf ("%s:%d-%s pAgv or pRevMsg is null\n", __FILE__, __LINE__, + __func__); + return; + } + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + if (pReceiveMsg == NULL) + { + printf ("rmb_msg_malloc failed"); + return; + } + + StDemoArgv *p = (StDemoArgv *) pAgv; + + shift_buf_2_msg (pReceiveMsg, buf, len); + + if (p->uiSleepTime > 0) + sleep (p->uiSleepTime); + +// //test for get dest +// const char *pDest = NULL; +// if ((pDest = rmb_msg_get_dest_ptr(pReceiveMsg)) != NULL) { +// printf("get dest name is:%s\n", pDest); +// } +// +// //test for get ConsumerSysId +// const char *pConsumerSysId = NULL; +// if ((pConsumerSysId = rmb_msg_get_consumerSysId_ptr(pReceiveMsg)) != NULL) { +// printf("get consumer sys id is:%s\n", pConsumerSysId); +// } +// +// //test for get cConsumerSvrId +// const char *pConsumerSvrId = NULL; +// if ((pConsumerSvrId = rmb_msg_get_consumerSvrId_ptr(pReceiveMsg)) != NULL) { +// printf("get consumer svr id is:%s\n", pConsumerSvrId); +// } +// +// printf("get consumerSysVersion version:%s\n", pReceiveMsg->sysHeader.cConsumerSysVersion); + +// printf("ulTranTimeStamp=%lu\n", pReceiveMsg->sysHeader.ulTranTimeStamp); + + p->uiFlag = 1; + p->ulMsgTotal++; + const char *pContent = NULL; + unsigned int uiContentLen = 0; + if ((pContent = + rmb_msg_get_content_ptr (pReceiveMsg, &uiContentLen)) != NULL) + { + if (p->uiLog == 1) + { + printf ("***get message len=%d,%s\n", uiContentLen, pContent); + } +// if (pReceiveMsg->iEventOrService == RMB_EVENT_CALL) { + if (strlen (pReceiveMsg->replyTo.cDestName) > 0) + { + char replyContent[MAX_MSG_LEN] = { 0 }; + unsigned int uiReplyLen = 0; + memcpy (replyContent, pContent, uiContentLen); + uiReplyLen += uiContentLen; + memcpy (&replyContent[uiReplyLen], "_reply", strlen ("_reply")); + uiReplyLen += strlen ("_reply"); + replyContent[uiReplyLen] = '\0'; + + rmb_msg_set_content (p->pReplyMsg, replyContent, uiReplyLen); + + char appHeader[10] = "{}"; + rmb_msg_set_app_header (p->pReplyMsg, appHeader, strlen (appHeader)); + rmb_sub_reply_msg (p->pRmbSub, pReceiveMsg, p->pReplyMsg); + } + rmb_sub_ack_msg (p->pRmbSub, pReceiveMsg); + } + + rmb_msg_free (pReceiveMsg); + + return; +} + +//sub回调函数 +void func_with_req_pub_reply (const char *buf, const int len, void *pAgv) +{ + if (pAgv == NULL) + { + printf ("%s:%d-%s pAgv or pRevMsg is null\n", __FILE__, __LINE__, + __func__); + return; + } + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + if (pReceiveMsg == NULL) + { + printf ("rmb_msg_malloc failed"); + return; + } + + StDemoArgv *p = (StDemoArgv *) pAgv; + + shift_buf_2_msg (pReceiveMsg, buf, len); + + //test for get dest + const char *pDest = NULL; + if ((pDest = rmb_msg_get_dest_ptr (pReceiveMsg)) != NULL) + { + printf ("get dest name is:%s\n", pDest); + } + + //test for get ConsumerSysId + const char *pConsumerSysId = NULL; + if ((pConsumerSysId = rmb_msg_get_consumerSysId_ptr (pReceiveMsg)) != NULL) + { + printf ("get consumer sys id is:%s\n", pConsumerSysId); + } + + //test for get cConsumerSvrId + const char *pConsumerSvrId = NULL; + if ((pConsumerSvrId = rmb_msg_get_consumerSvrId_ptr (pReceiveMsg)) != NULL) + { + printf ("get consumer svr id is:%s\n", pConsumerSvrId); + } + + printf ("get consumerSysVersion version:%s\n", + pReceiveMsg->sysHeader.cConsumerSysVersion); + + p->ulMsgTotal++; + const char *pContent = NULL; + unsigned int uiContentLen = 0; + if ((pContent = + rmb_msg_get_content_ptr (pReceiveMsg, &uiContentLen)) != NULL) + { + if (p->uiLog == 1) + { + printf ("***get message len=%d,%s\n", uiContentLen, pContent); + } + //if (p->uiLogServer == 1) { + // rmb_log_for_common(p->pRmbPub->pContext, LOG_MSG_LEVEL_INFO, "test", "%s", pReceiveMsg->sysHeader.cBizSeqNo, pReceiveMsg->sysHeader.cConsumerSeqNo, pReceiveMsg->sysHeader.cOrgSysId, pContent); + //} +// if (pReceiveMsg->iEventOrService == RMB_EVENT_CALL) { + if (strlen (pReceiveMsg->replyTo.cDestName) > 0) + { + char replyContent[MAX_MSG_LEN] = { 0 }; + unsigned int uiReplyLen = 0; + memcpy (replyContent, pContent, uiContentLen); + uiReplyLen += uiContentLen; + memcpy (&replyContent[uiReplyLen], "_reply", strlen ("_reply")); + uiReplyLen += strlen ("_reply"); + replyContent[uiReplyLen] = '\0'; + + rmb_msg_set_content (p->pReplyMsg, replyContent, uiReplyLen); + + char appHeader[10] = "{}"; + rmb_msg_set_app_header (p->pReplyMsg, appHeader, strlen (appHeader)); + //rmb_sub_reply_msg(p->pRmbSub, pReceiveMsg, p->pReplyMsg); + rmb_pub_reply_msg (p->pRmbPub, pReceiveMsg, p->pReplyMsg); + } + rmb_sub_ack_msg (p->pRmbSub, pReceiveMsg); + } + + rmb_msg_free (pReceiveMsg); + + return; +} + +/** + * broad cast sub callback + */ +void func_with_broadcast (const char *buf, const int len, void *pAgv) +//void func_with_broadcast(void *pRecvMsg, void* pAgv) +{ + if (pAgv == NULL) + { + printf ("%s:%d--%s pAgv is null\n", __FILE__, __LINE__, __func__); + return; + } + + StDemoArgv *p = (StDemoArgv *) pAgv; + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + if (pReceiveMsg == NULL) + { + printf ("rmb_msg_malloc failed\n"); + return; + } + + shift_buf_2_msg (pReceiveMsg, buf, len); + + p->ulMsgTotal++; + + const char *pContent = NULL; + unsigned int uiContentLen = 0; + if ((pContent = + rmb_msg_get_content_ptr (pReceiveMsg, &uiContentLen)) != NULL) + { + if (p->uiLog == 1) + { + LOG_PRINT (RMB_LOG_INFO, "receive broadcase content len=%u, %s", + uiContentLen, pContent); + } + } + + rmb_msg_free (pReceiveMsg); +} + +//RR异步时,pub回调函数 +void func_with_rr_rsp (const char *buf, const int len, void *pAgv) +{ + if (pAgv == NULL) + { + printf ("pAgv or pRevMsg is null"); + return; + } + + StDemoArgv *p = (StDemoArgv *) pAgv; + + shift_buf_2_msg (p->pReceiveMsg, buf, len); + + p->ulMsgTotal++; + + const char *pUniqueId = rmb_msg_get_uniqueId_ptr (p->pReceiveMsg); + if (pUniqueId == NULL) + { + printf ("%s:%d-%s ,get uniqueId error!\n", __FILE__, __LINE__, __func__); + } + printf ("receive Msg:uniqueId = %s\n", pUniqueId); + + const char *pContent = NULL; + unsigned int uiContentLen = 0; + + if ((pContent = + rmb_msg_get_content_ptr (p->pReceiveMsg, &uiContentLen)) != NULL) + { + + LOG_PRINT (RMB_LOG_INFO, "recevie reply msg:len=%d,%s\n", uiContentLen, + pContent); + } + + return; +} + +//key is topic, like: dcn-s-serviceid--scense_id AB0-s-11000000-26-0 +int get_dcn_service_scense (const char *key, char *dcn, char *event, + char *consumerSysId, char *service_id, + char *scense_id) +{ + if (key == NULL) + { + printf ("key is null"); + return -1; + } + + char *p = (char *) key; + char *p1 = NULL; + + //判断分隔符数量是否正确 + int i = 0; + + do + { + p1 = strchr (p, '-'); + if (p1 == NULL) + { + break; + } + i++; + p = p1 + 1; + } + while (p != NULL); + + if (i != 4) + { + LOG_PRINT (RMB_LOG_ERROR, "key:%s is error", key); + exit (1); + } + + char temp[100]; + memset (temp, 0x00, sizeof (temp)); + strncpy (temp, key, sizeof (temp) - 1); + + p = strrchr (temp, '-'); + *p = '\0'; + //copy scense id + p = strrchr (temp, '-'); + if (p == NULL || scense_id == NULL) + { + return -1; + } + strcpy (scense_id, p + 1); + *p = '\0'; + + //copy service id + p = strrchr (temp, '-'); + if (p == NULL || service_id == NULL) + { + return -1; + } + strcpy (service_id, p + 1); + *p = '\0'; + + //copy consumerSysId + /* + p = strrchr(temp, '/'); + if (p == NULL) { + return -1; + } + if (consumerSysId != NULL) { + strcpy(consumerSysId, p+1); + } + *p = '\0'; + */ + //copy event + p = strrchr (temp, '-'); + if (p == NULL) + { + return -1; + } + if (event != NULL) + { + strcpy (event, p + 1); + } + *p = '\0'; + + if (dcn == NULL) + { + return -1; + } + strcpy (dcn, temp); + + return 0; +} + +int pub_binary_message (StRmbPub * pRmbPub, const char *cDcn, + const char *cServiceId, const char *cSenaId) +{ + int iRet = 0; + StRmbMsg *pSendMsg = rmb_msg_malloc (); + rmb_msg_clear (pSendMsg); + rmb_msg_set_bizSeqNo (pSendMsg, "12345678901234567890123456789012"); + rmb_msg_set_consumerSeqNo (pSendMsg, "22222678901234567890123456799999"); + rmb_msg_set_orgSysId (pSendMsg, "9999"); + + int iEventOrService = *(cServiceId + 3) - '0'; + int flag = iEventOrService; + printf ("flag: %d\n", flag); + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, cDcn, iEventOrService, + cServiceId, cSenaId); + + char *p = "This is test binary message"; + char content[1024]; + unsigned int uiConLen = 0; + memset (content, 0x00, sizeof (content)); + content[0] = 0x02; + content[1] = 0; + memcpy (&content[2], p, strlen (p)); + uiConLen = 2 + strlen (p); + + rmb_msg_set_content (pSendMsg, content, uiConLen); + char appHeader[100] = "{}"; + rmb_msg_set_app_header (pSendMsg, appHeader, strlen (appHeader)); + + if (flag == 1) + { + iRet = rmb_pub_send_msg (pRmbPub, pSendMsg); + if (iRet == 0) + { + LOG_PRINT (RMB_LOG_INFO, "send msg=%s OK", pSendMsg->cContent); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_msg error!iRet = %d", iRet); + } + rmb_msg_free (pSendMsg); + return 0; + } + else + { + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + iRet = rmb_pub_send_and_receive (pRmbPub, pSendMsg, pReceiveMsg, 5000); + if (iRet == 0) + { + char receiveBuf[1024]; + unsigned int receiveLen = sizeof (receiveBuf); + rmb_msg_get_content (pReceiveMsg, receiveBuf, &receiveLen); + LOG_PRINT (RMB_LOG_INFO, "**********receive reply pkg len=%d", + receiveLen); + int i = 0; + for (i = 0; i < receiveLen; i++) + { + printf ("%c", receiveBuf[i]); + } + printf ("\n***********"); +// printf("%s:%d-%s ,receive reply pkg=%d%s\n", __FILE__, __LINE__, __func__, receiveBuf); + } + else + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_send_and_receive error!iRet = %d", + iRet); + } + rmb_msg_free (pSendMsg); + rmb_msg_free (pReceiveMsg); + return 0; + } + return 0; +} + +void destroy () +{ + if (pRmbSub != NULL) + { + rmb_sub_close_v2 (pRmbSub); + //exit(0); + } + if (pRmbPub != NULL) + { + rmb_pub_close_v2 (pRmbPub); + exit (0); + } +} + +void sigusr2_handle (int iSigVal) +{ + + LOG_PRINT (RMB_LOG_INFO, "sub accept signal USR2"); + //先stop_receive + if (rmb_sub_stop_receive (pRmbSub) != 0) + { + //没有成功停止接收,有异常 + destroy (); + } + else + { + while (rmb_sub_check_req_mq_is_null (pRmbSub) != 0) //本地的共享内存还有未处理完的消息 + { + rmb_sub_do_receive (pRmbSub, 1); + } + //处理完消息之后,退出 + destroy (); + } +} + +int main (int argc, char *argv[]) +{ + if (argc <= 1) + { + printfUsage (argv[0]); + } + + int ret = rmb_load_config ("./rmb.conf"); + if (ret != 0) + { + printf ("load rmb config file failed \n"); + return -1; + } + pRmbSub = (StRmbSub *) calloc (1, sizeof (StRmbSub)); + if (pRmbSub == NULL) + { + printf ("%s:%d -- calloc for pRmbSub failed:%s\n", __func__, __LINE__, + strerror (errno)); + return 0; + } + pRmbPub = (StRmbPub *) calloc (1, sizeof (StRmbPub)); + if (pRmbPub == NULL) + { + printf ("%s:%d -- calloc for pRmbPub failed:%s\n", __func__, __LINE__, + strerror (errno)); + return 0; + } + + char event[10]; + char dcn[10]; + char service_id[10]; + char scenario_id[10]; + + enum EVENT_OR_SERVICE_CALL event_or_serv = RMB_SERVICE_CALL; + + int iRet = 0; + + if (strcmp (argv[1], "sub") == 0) + { + //./process_name sub sleep_time log_control process_nums queue1 queue2 ... + // example: ./rmb_demo sub 1 1 1 FT0-s-98200001-01-1 + if (argc < 6) + printfUsage (argv[0]); + signal (SIGUSR2, sigusr2_handle); + unsigned int uiShmKeyForReq = pRmbStConfig->uiShmKeyForReq; + unsigned int uiShmSizeForReq = pRmbStConfig->uiShmSizeForReq; + char strFifoPathForReq[128]; + memset (strFifoPathForReq, 0x00, sizeof (strFifoPathForReq)); + strcpy (strFifoPathForReq, pRmbStConfig->strFifoPathForReq); + + LOG_PRINT (RMB_LOG_INFO, "sub pid:%d process nums:%d", getpid (), + atoi (argv[4])); + //多进程 + int i; + for (i = 1; i < atoi (argv[4]); i++) + { + if (fork () == 0) + { + uiShmKeyForReq += 4096 * i; + memset (strFifoPathForReq, 0x00, sizeof (strFifoPathForReq)); + snprintf (strFifoPathForReq, sizeof (strFifoPathForReq), + "./tmp_req_%d.fifo", getpid ()); + break; + } + } + + if ((iRet = rmb_sub_init (pRmbSub)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_sub_init error=%d", iRet); + return -1; + } + + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + StRmbMsg *pReplyMsg = rmb_msg_malloc (); + StDemoArgv *pTmp = (StDemoArgv *) calloc (1, sizeof (StDemoArgv)); + if (pReceiveMsg == NULL || pReplyMsg == NULL || pTmp == NULL) + { + LOG_PRINT (RMB_LOG_ERROR, + "pReceiveMsg is NULL or pReplyMsg is NULL or pTmp is NULL"); + return -1; + } + pTmp->pRmbPub = pRmbPub; + pTmp->pRmbSub = pRmbSub; + pTmp->pReplyMsg = pReplyMsg; + pTmp->uiLog = (unsigned int) atoi (argv[3]); + /////////// + pTmp->ulMsgTotal = 0; + pTmp->uiSleepTime = (unsigned int) atoi (argv[2]); + pTmp->uiFlag = 0; + + //注册回调 + if ((iRet = + rmb_sub_add_reveive_req_by_mq_v2 (pRmbSub, strFifoPathForReq, + uiShmKeyForReq, uiShmSizeForReq, + func_with_req, pTmp)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_sub_add_reveive_req_by_mq error=%d", + iRet); + return -1; + } + + st_rmb_queue_info *pQueueInfo; + pQueueInfo = + (st_rmb_queue_info *) malloc (sizeof (st_rmb_queue_info) * 100); + if (pQueueInfo == NULL) + { + printf ("malloc for pQueueInfo failed\n"); + return -1; + } + memset (pQueueInfo, 0x00, (sizeof (st_rmb_queue_info) * 100)); + st_rmb_queue_info *p = pQueueInfo; + unsigned int uiQueneNums = 0; + + for (i = 0; (i < argc - 5) && (i < 100); i++) + { + memset (event, 0x00, sizeof (event)); + memset (dcn, 0x00, sizeof (dcn)); + memset (service_id, 0x00, sizeof (service_id)); + memset (scenario_id, 0x00, sizeof (scenario_id)); + if ((iRet = + get_dcn_service_scense (argv[i + 5], dcn, event, NULL, service_id, + scenario_id)) < 0) + { + printf ("parse queue:%s failed,iRet=%d\n", argv[i + 5], iRet); + continue; + } + if (strcmp (event, "e") == 0) + { + event_or_serv = RMB_EVENT_CALL; + } + else + { + event_or_serv = RMB_SERVICE_CALL; + } + + LOG_PRINT (RMB_LOG_INFO, + "sub:dcn:%s event:%d service_id:%s scenario_id:%s", dcn, + (int) event_or_serv, service_id, scenario_id); + + strncpy (p->cDcn, dcn, strlen (dcn)); + strncpy (p->cServiceId, service_id, strlen (service_id)); + strncpy (p->cScenarioId, scenario_id, strlen (scenario_id)); + p += 1; + uiQueneNums += 1; + } + + if ((iRet = rmb_sub_add_listen (pRmbSub, pQueueInfo, uiQueneNums)) != 0) + { + printf ("rmb_sub_add_listen failed, iRet = %d\n", iRet); + return -2; + } + + unsigned long last_msg_total = 0; + unsigned long print_msg_ctrl = 0; + for (;;) + { + //to do recevive + rmb_sub_do_receive (pRmbSub, 1); + + print_msg_ctrl++; + + if (print_msg_ctrl > 5000) + { + if (last_msg_total != pTmp->ulMsgTotal) + { + printf ("%s:%d -- sub: pid:%d receive message total:%lu\n", + __FILE__, __LINE__, getpid (), pTmp->ulMsgTotal); + print_msg_ctrl = 0; + last_msg_total = pTmp->ulMsgTotal; + } + } + } + } + + else if (strcmp (argv[1], "sub_broadcast") == 0) + { + //./process_name sub_broadcast process_nums log_control topic(queue)1 topic(queue)2 ... + unsigned int uiShmKeyForBroadcastReq = pRmbStConfig->uiShmKeyForBroadcast; + unsigned int uiShmSizeRorBroadcastReq = + pRmbStConfig->uiShmSizeForBroadcast; + char strFifoPathForBroadcastReq[128]; + + snprintf (strFifoPathForBroadcastReq, sizeof (strFifoPathForBroadcastReq), + "%s", pRmbStConfig->strFifoPathForReq); + + printf ("sub_broadcast process nums:%d", atoi (argv[2])); + //mutil-process + int i; + for (i = 1; i < atoi (argv[2]); i++) + { + if (fork () == 0) + { + uiShmKeyForBroadcastReq += 4096 * i; + memset (uiShmSizeRorBroadcastReq, 0x00, + sizeof (uiShmSizeRorBroadcastReq)); + snprintf (strFifoPathForBroadcastReq, + sizeof (strFifoPathForBroadcastReq), "./tmp_req_%d.fifo", + getpid ()); + break; + } + } + + if ((iRet = rmb_sub_init (pRmbSub)) != 0) + { + printf ("rmb_sub_init failed\n"); + return -1; + } + + //StRmbMsg *pReceiveMsg = rmb_msg_malloc(); + StDemoArgv *pTmp = (StDemoArgv *) calloc (1, sizeof (StDemoArgv)); + pTmp->pRmbPub = pRmbPub; + pTmp->pRmbSub = pRmbSub; + pTmp->pReplyMsg = NULL; + pTmp->ulMsgTotal = 0; + pTmp->uiLog = (unsigned int) atoi (argv[3]); + + //rmb_callback_func func, void *func_msg, void* func_argv + if ((iRet = + rmb_sub_add_reveive_broadcast_by_mq_v2 (pRmbSub, + strFifoPathForBroadcastReq, + uiShmKeyForBroadcastReq, + uiShmSizeRorBroadcastReq, + func_with_broadcast, + pTmp)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, + "rmb_sub_add_reveive_broadcast_by_mq_v2 failed!iRet=%d", + iRet); + return -1; + } + + st_rmb_queue_info *pQueueInfo; + pQueueInfo = + (st_rmb_queue_info *) malloc (sizeof (st_rmb_queue_info) * 100); + if (pQueueInfo == NULL) + { + printf ("malloc for pQueueInfo failed\n"); + return -1; + } + memset (pQueueInfo, 0x00, (sizeof (st_rmb_queue_info) * 100)); + st_rmb_queue_info *p = pQueueInfo; + unsigned int uiQueneNums = 0; + + for (i = 0; (i < argc - 4) && (i < 100); i++) + { + memset (dcn, 0x00, sizeof (dcn)); + memset (service_id, 0x00, sizeof (service_id)); + memset (scenario_id, 0x00, sizeof (scenario_id)); + + if (get_dcn_service_scense + (argv[i + 4], dcn, NULL, NULL, service_id, scenario_id) < 0) + { + printf ("parse:%s failed\n", argv[i + 4]); + continue; + } + LOG_PRINT (RMB_LOG_INFO, "board_sub: dcn:%s service_id:%s scense_id:%s", + dcn, service_id, scenario_id); + + event_or_serv = RMB_EVENT_CALL; + + strncpy (p->cDcn, dcn, strlen (dcn)); + strncpy (p->cServiceId, service_id, strlen (service_id)); + strncpy (p->cScenarioId, scenario_id, strlen (scenario_id)); + p += 1; + uiQueneNums += 1; + } + + if ((iRet = rmb_sub_add_listen (pRmbSub, pQueueInfo, uiQueneNums)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_sub_add_listen failed, iRet = %d", iRet); + return -2; + } + + unsigned long print_msg_ctrl = 0; + for (;;) + { + rmb_sub_do_receive (pRmbSub, 1); + print_msg_ctrl++; + + if (print_msg_ctrl > 3000) + { + LOG_PRINT (RMB_LOG_INFO, "sub: pid:%d receive message total:%lu", + getpid (), pTmp->ulMsgTotal); + print_msg_ctrl = 0; + } + } + + } + else if (strcmp (argv[1], "pub") == 0) + { + //./process_name pub pthread_nums log_control msg_nums msg_len ttl_time sleep_time queue1 queue2 ... + /* + * pub:指"rr_sync_pub" or "unicast_pub" + * pthread_nums: 发送消息的线程数量 + * log_control: 是否打印收发消息的长度,这个是针对包大小测试加的 + * msg_nums: 每个线程发送消息的数量或单线程往每个queue上发送的消息数量 + * msg_len: 发送的消息体的总的长度,这个主要是针对测试包大小而加入的 + * queue1、queue2...: 发送消息使用的queue + * + * example: ./rmb_demo pub 1 1 1 10 3000 1 FT0-s-98200001-01-1 + */ + if (argc < 9) + printfUsage (argv[0]); + + if ((iRet = rmb_pub_init (pRmbPub)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_init error=%d", iRet); + return -1; + } + + int sleep_time = 0; + if (atoi (argv[7]) > 0) + sleep_time = atoi (argv[7]); + char *msg = (char *) calloc (sizeof (char), atoi (argv[5]) + 1); + int msg_len = strlen (send_msg); + int copy_nums = atoi (argv[5]) / msg_len; + + char *p = msg; + int i; + for (i = 0; i < copy_nums; i++) + { + memcpy (p, send_msg, msg_len); + p += msg_len; + } + + if (atoi (argv[5]) % msg_len != 0) + { + memcpy (p, send_msg, atoi (argv[5]) % msg_len); + } + + if (strcmp (argv[3], "1") == 0) + { + LOG_PRINT (RMB_LOG_INFO, "pub send msg len:%d, content len:%lu", + atoi (argv[5]), strlen (msg)); + } + + tMessage msg_info; + msg_info.type = 0; + msg_info.pid = getpid (); + msg_info.process_num = 1; + msg_info.send_msg_num = 0; + msg_info.recv_msg_num = 0; + enum EVENT_OR_SERVICE_CALL event_or_serv = RMB_SERVICE_CALL; + //queue numbers + int iQueueNumbers = argc - 8; + if (atoi (argv[2]) == 1) + { //single thread + for (i = 0; i < iQueueNumbers; i++) + { + char event[100]; + char dcn[100]; + char service_id[100]; + char scenario_id[100]; + + memset (event, 0x00, sizeof (event)); + memset (dcn, 0x00, sizeof (dcn)); + memset (service_id, 0x00, sizeof (service_id)); + memset (scenario_id, 0x00, sizeof (scenario_id)); + + if (get_dcn_service_scense + (argv[i + 8], dcn, event, NULL, service_id, scenario_id) < 0) + { + continue; + } + + if (strcmp (event, "e") == 0) + { + event_or_serv = RMB_EVENT_CALL; + } + + LOG_PRINT (RMB_LOG_INFO, + "dcn:%s event:%d service_id:%s scenario_id:%s", dcn, + (int) event_or_serv, service_id, scenario_id); + + unsigned long pub_send_msg = 0; + int l; + for (l = 0; l < atoi (argv[4]); l++) + { + iRet = + pubOwnMessage (pRmbPub, event_or_serv, atol (argv[6]), dcn, + service_id, scenario_id, + (unsigned int) atoi (argv[3]), msg); + if (iRet == 0) + { + pub_send_msg++; + } + if (sleep_time > 0) + sleep (sleep_time); + } + + msg_info.send_msg_num += (unsigned int) atoi (argv[4]); + msg_info.recv_msg_num += pub_send_msg; + + if (event_or_serv == RMB_EVENT_CALL) + { + LOG_PRINT (RMB_LOG_INFO, + "pid:%ld queue:%s pub send:%d and success:%lu\n", + (long) getpid (), argv[i + 8], atoi (argv[4]), + pub_send_msg); + } + else + { + LOG_PRINT (RMB_LOG_INFO, + "pid:%ld queue:%s pub send:%d and recv:%lu\n", + (long) getpid (), argv[i + 8], atoi (argv[4]), + pub_send_msg); + } + } + rmb_pub_close (pRmbPub); + } + else if (atoi (argv[2]) > 1) + { //mutil thread + //./process_name pub pthread_nums log_control msg_nums msg_len msg ttl_time queue1 queue2 ... + pthread_t thVec[200]; + tThreadArgs tArgs[200]; + unsigned int thread_nums = + (atoi (argv[2]) < 200 ? atoi (argv[2]) : 200); + for (i = 0; i < iQueueNumbers && i < 200; ++i) + { + tArgs[i].pRmbPub = pRmbPub; + tArgs[i].times = atoi (argv[4]); + tArgs[i].iContent = i; + tArgs[i].ulMsgSucc = 0; + tArgs[i].ttl = atol (argv[6]); + tArgs[i].pMsg = msg; + + char event[100]; + + memset (event, 0x00, sizeof (event)); + memset (tArgs[i].cDcn, 0x00, sizeof (tArgs[i].cDcn)); + memset (tArgs[i].cServiceId, 0x00, sizeof (tArgs[i].cServiceId)); + memset (tArgs[i].cSenaId, 0x00, sizeof (tArgs[i].cSenaId)); + + get_dcn_service_scense (argv[i + 8], tArgs[i].cDcn, event, NULL, + tArgs[i].cServiceId, tArgs[i].cSenaId); + + if (strcmp (event, "e") == 0) + { + event_or_serv = RMB_EVENT_CALL; + } + tArgs[i].event_or_service = event_or_serv; + } + if (thread_nums > iQueueNumbers) + { + for (i = iQueueNumbers; i < thread_nums; i++) + { + tArgs[i].pRmbPub = pRmbPub; + tArgs[i].times = atoi (argv[4]); + tArgs[i].event_or_service = + tArgs[i % iQueueNumbers].event_or_service; + tArgs[i].iContent = i; + tArgs[i].pMsg = msg; + + memset (tArgs[i].cDcn, 0x00, sizeof (tArgs[i].cDcn)); + strcpy (tArgs[i].cDcn, tArgs[i % iQueueNumbers].cDcn); + + memset (tArgs[i].cServiceId, 0x00, sizeof (tArgs[i].cServiceId)); + strcpy (tArgs[i].cServiceId, tArgs[i % iQueueNumbers].cServiceId); + + memset (tArgs[i].cSenaId, 0x00, sizeof (tArgs[i].cSenaId)); + strcpy (tArgs[i].cSenaId, tArgs[i % iQueueNumbers].cSenaId); + } + } + for (i = 0; i < thread_nums; ++i) + { + if ((iRet = + pthread_create (&thVec[i], NULL, (void *) &mutil_thread_for_pub, + (void *) &tArgs[i])) != 0) + { + printf ("%d thread error!iRet=%d\n", i, iRet); + } + } + + unsigned long total_msg = 0; + for (i = 0; i < thread_nums; ++i) + { + if ((iRet = pthread_join (thVec[i], NULL)) != 0) + { + printf ("%d thread error!iRet=%d\n", i, iRet); + } + else + { + total_msg += tArgs[i].ulMsgSucc; + } + } + if (event_or_serv == RMB_SERVICE_CALL) + { + LOG_PRINT (RMB_LOG_INFO, "*****pub send msg:%d recv:%lu", + thread_nums * atoi (argv[4]), total_msg); + } + else + { + LOG_PRINT (RMB_LOG_INFO, "*****pub send msg:%d success:%lu", + thread_nums * atoi (argv[4]), total_msg); + } + + msg_info.send_msg_num = thread_nums * atoi (argv[4]); + msg_info.recv_msg_num = total_msg; + } + + free (msg); + } + else if (strcmp (argv[1], "rr_async_pub") == 0) + { + //./test_rmb_capi rr_async_pub process_nums log_control msg_nums msg_len sleep_time timeout queue + if (argc < 9) + printfUsage (argv[0]); + + unsigned int uiShmKeyForRsq = pRmbStConfig->uiShmKeyForRRrsp; + unsigned int uiShmSizeForRsq = pRmbStConfig->uiShmSizeForRRrsp; + char strFifoPathForRsq[128]; + memset (strFifoPathForRsq, 0x00, sizeof (strFifoPathForRsq)); + strcpy (strFifoPathForRsq, pRmbStConfig->strFifoPathForRRrsp); + + LOG_PRINT (RMB_LOG_INFO, + "***RR async, process total:%d, per process send message numbers:%d", + atoi (argv[2]), atoi (argv[4])); + + int sleep_time = 0; + if (atoi (argv[6]) > 0) + sleep_time = atoi (argv[6]); + int i; + for (i = 1; i < atoi (argv[2]); i++) + { + if (fork () == 0) + { + uiShmKeyForRsq += 4096 * i; + memset (strFifoPathForRsq, 0x00, sizeof (strFifoPathForRsq)); + snprintf (strFifoPathForRsq, sizeof (strFifoPathForRsq), + "./tmp_rsq_%d.fifo", getpid ()); + break; + } + } + + if ((iRet = rmb_pub_init (pRmbPub)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_init error=%d", iRet); + return -1; + } + + if ((iRet = rmb_sub_init (pRmbSub)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_sub_init error=%d", iRet); + return -1; + } + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + StRmbMsg *pReplyMsg = rmb_msg_malloc (); + StDemoArgv *pTmp = (StDemoArgv *) calloc (1, sizeof (StDemoArgv)); + pTmp->pRmbPub = pRmbPub; + pTmp->pRmbSub = pRmbSub; + pTmp->pReceiveMsg = pReceiveMsg; + pTmp->pReplyMsg = pReplyMsg; + pTmp->uiLog = (unsigned int) atoi (argv[3]); + pTmp->ulMsgTotal = 0; + + if ((iRet = + rmb_sub_add_reveive_rsp_by_mq_v2 (pRmbSub, strFifoPathForRsq, + uiShmKeyForRsq, uiShmSizeForRsq, + func_with_rr_rsp, pTmp)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_sub_add_reveive_req_by_mq error=%d", + iRet); + return -1; + } + + //./test_rmb_capi rr_async_pub process_nums log_control msg_nums msg_len msg queue + char *msg = (char *) calloc (sizeof (char), atoi (argv[5]) + 1); + int msg_len = strlen (send_msg); + int copy_nums = atoi (argv[5]) / msg_len; + + char *p = msg; + for (i = 0; i < copy_nums; i++) + { + memcpy (p, send_msg, msg_len); + p += msg_len; + } + + if (atoi (argv[5]) % msg_len != 0) + { + memcpy (p, send_msg, atoi (argv[5]) % msg_len); + } + + LOG_PRINT (RMB_LOG_INFO, "rr async pub send msg len:%d, content len:%lu", + atoi (argv[5]), strlen (msg)); + + StRmbMsg *pSendMsg = rmb_msg_malloc (); + + static unsigned int uiSeq = 1; + struct timeval tv; + gettimeofday (&tv, NULL); + unsigned long ulNowTime = tv.tv_sec * 1000 + tv.tv_usec / 1000; + char cSeqNo[33]; + snprintf (cSeqNo, sizeof (cSeqNo), "%013lu%019u", ulNowTime, uiSeq++); + rmb_msg_set_bizSeqNo (pSendMsg, cSeqNo); + rmb_msg_set_consumerSeqNo (pSendMsg, cSeqNo); + rmb_msg_set_orgSysId (pSendMsg, "9999"); + rmb_msg_set_content (pSendMsg, msg, strlen (msg)); + char appHeader[100] = "{}"; + rmb_msg_set_app_header (pSendMsg, appHeader, strlen (appHeader)); + + //增加多个队列支持 + unsigned int send_msg = 0; + for (i = 0; i < argc - 7; i++) + { + char dcn[100]; + char service_id[100]; + char scense_id[100]; + memset (dcn, 0x00, sizeof (dcn)); + memset (service_id, 0x00, sizeof (service_id)); + memset (scense_id, 0x00, sizeof (scense_id)); + if (get_dcn_service_scense + (argv[i + 8], dcn, NULL, NULL, service_id, scense_id) < 0) + { + printf ("RR async pub queue error:%s\n", argv[i + 6]); + continue; + } + printf ("dcn:%s service_id:%s scense_id:%s\n", dcn, service_id, + scense_id); + + rmb_msg_set_dest (pSendMsg, RMB_DEST_TOPIC, dcn, RMB_SERVICE_CALL, + service_id, scense_id); + int j; + for (j = 0; j < atoi (argv[4]); j++) + { + iRet = rmb_pub_send_rr_msg_async (pRmbPub, pSendMsg, atoi (argv[7])); + if (iRet != 0) + { + printf ("%s:%d-%s ,rmb_pub_send_and_receive error!iRet = %d\n", + __FILE__, __LINE__, __func__, iRet); + } + else + { + send_msg++; + if (sleep_time > 0) + sleep (sleep_time); + } + } + } + + LOG_PRINT (RMB_LOG_INFO, "pid:%d rmb_pub_async_message success total: %u", + (int) getpid (), send_msg); + + tMessage msg_info; + msg_info.type = 0; + msg_info.pid = getpid (); + msg_info.process_num = atoi (argv[4]); + msg_info.send_msg_num = atoi (argv[4]) * (argc - 7); + msg_info.recv_msg_num = 0; + + unsigned long last_msg_total = 0; + unsigned long print_msg_ctrl = 0; + for (;;) + { + //to do recevive + rmb_sub_do_receive (pRmbSub, 1); + print_msg_ctrl++; + + if (print_msg_ctrl > 10000) + { + print_msg_ctrl = 0; + if (pTmp->ulMsgTotal != last_msg_total) + { + LOG_PRINT (RMB_LOG_INFO, "pid:%d get_reply_msg_total:%lu", + (int) getpid (), pTmp->ulMsgTotal); + last_msg_total = pTmp->ulMsgTotal; + } + } + } + } + else if (strcmp (argv[1], "pub_board") == 0) + { + //./process_name pub_board message_nums message orgId queue + //send board message + if ((iRet = rmb_pub_init (pRmbPub)) != 0) + { + LOG_PRINT (RMB_LOG_ERROR, "rmb_pub_init error=%d", iRet); + return -1; + } + + enum EVENT_OR_SERVICE_CALL event_or_serv = RMB_SERVICE_CALL; + + char event[100]; + char dcn[100]; + char service_id[100]; + char scenario_id[100]; + + memset (event, 0x00, sizeof (event)); + memset (dcn, 0x00, sizeof (dcn)); + memset (service_id, 0x00, sizeof (service_id)); + memset (scenario_id, 0x00, sizeof (scenario_id)); + + iRet = + get_dcn_service_scense (argv[5], dcn, event, NULL, service_id, + scenario_id); + + if (iRet < 0) + { + printf ("get_dcn_service_scense return:%d\n", iRet); + return iRet; + } + + if (strcmp (event, "e") == 0) + { + event_or_serv = RMB_EVENT_CALL; + } + LOG_PRINT (RMB_LOG_INFO, "dcn:%s event:%d service_id:%s scenario_id:%s", + dcn, (int) event_or_serv, service_id, scenario_id); + unsigned long pub_send_msg = 0; + int i; + for (i = 0; i < atoi (argv[2]); i++) + { + iRet = + pub_board_message (pRmbPub, event_or_serv, 0, dcn, service_id, + scenario_id, argv[4], 1, argv[3]); + if (iRet == 0) + { + pub_send_msg++; + } + } + } + + else + { + printf ("unknown argv[1]:%s\n", argv[1]); + printfUsage (argv[0]); + } + + return 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/message_log_api.h b/eventmesh-sdks/eventmesh-sdk-c/include/message_log_api.h new file mode 100644 index 0000000000..8c2eb9516d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/message_log_api.h @@ -0,0 +1,55 @@ +// 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. + +#ifndef __MESSAGE_LOG_API_H_ +#define __MESSAGE_LOG_API_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "rmb_define.h" +#include "rmb_pub.h" + +#define LOG_MSG_COM_CONSUMERID "consumerId" +#define LOG_MSG_COM_LOGNAME "logName" +#define LOG_MSG_COM_TIMESTAMP "logTimestamp" +#define LOG_MSG_COM_CONTENT "content" +#define LOG_MSG_COM_LOGTYPE "logType" +#define LOG_MSG_COM_LANG "lang" +#define LOG_MSG_COM_ID "id" +#define LOG_MSG_COM_PROCESSID "processId" +#define LOG_MSG_COM_THREADID "threadId" +#define LOG_MSG_COM_CONSUMERSVRID "consumerSvrId" +#define LOG_MSG_COM_LEVEL "level" +#define LOG_MSG_COM_EXTFIELDS "extFields" + +#define LOG_INFO_LEVEL "info" +#define LOG_DEBUG_LEVEL "debug" +#define LOG_WARN_LEVEL "warn" +#define LOG_ERROR_LEVEL "error" +#define LOG_FATAL_LEVEL "fatal" + +//应用可以调用此接口上传log日志 + int rmb_log_for_common (StContext * pStContext, const char *iLogLevel, + const char *cLogName, const char *content, + const char *extFields); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_access_config.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_access_config.h new file mode 100644 index 0000000000..3df3ded354 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_access_config.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef RMB_ACCESS_CONFIG_H_ +#define RMB_ACCESS_CONFIG_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + int rmb_get_wemq_proxy_list_num (); + + int rmb_get_wemq_proxy_list_used (); + +//int wemq_proxy_load_servers(char* url, long timeout, const char* path); + int wemq_proxy_load_servers (const char *url, long timeout); + + int wemq_proxy_get_server (char *host, size_t size, unsigned int *port); + + void wemq_proxy_goodbye (const char *host, unsigned int port); + + void wemq_proxy_to_black_list (const char *host, unsigned int port); + + int wemq_proxy_ip_is_connected (); + + void split_str (char *ips, char ipArray[][50], int *len); + +#ifdef __cplusplus +} +#endif + +#endif /* RMB_ACCESS_CONFIG_H_ */ diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_cfg.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_cfg.h new file mode 100644 index 0000000000..3ce38bd837 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_cfg.h @@ -0,0 +1,60 @@ +// 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. + +#ifndef RMB_CFG_H_ +#define RMB_CFG_H_ + +#include "rmb_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define CFG_STRING (int)1 +#define CFG_INT (int)2 +#define CFG_LONG (int)3 +#define CFG_DOUBLE (int)4 +#define CFG_LINE (int)5 +#define CFG_SHORT (int)6 + +#define US 0x1f + +#define MAX_CONFIG_LINE_LEN 1023 + + void RMB_TLib_Cfg_GetConfig (char *sConfigFilePath, ...); + +#define Rmb_TLib_Cfg_GetConfig(sConfigFilePath,fmt,args...) RMB_TLib_Cfg_GetConfig(sConfigFilePath,fmt,## args) + +/** + * Function: rmb_load_config + * Description: rmb load configure + * Return: + * 0: success + * -1: failed + */ + int rmb_load_config (const char *configPath); + + const char *rmb_get_host_ip (); + + void rmb_get_config_python (RmbPythonConfig * config); + + const char *getRmbLastError (); + +#ifdef __cplusplus +} +#endif + +#endif /* RMB_CFG_H_ */ diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_common.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_common.h new file mode 100644 index 0000000000..8bdf7745ba --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_common.h @@ -0,0 +1,269 @@ +// 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. + +#ifndef _RMB_COMMON_H_ +#define _RMB_COMMON_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include +#include + + extern unsigned int g_uiSendMsgSeq; + extern unsigned int g_uiRecvMsgSeq; +//extern unsigned int g_iSendReq = 0; +#define MAX_SEND_MSG_SEQ 65535 + extern unsigned int DEFAULT_WINDOW_SIZE; +#define CURRENT_WINDOW_SIZE (((g_uiRecvMsgSeq) <= (g_uiSendMsgSeq)) ? ((g_uiSendMsgSeq) - (g_uiRecvMsgSeq)) : (MAX_SEND_MSG_SEQ - (g_uiRecvMsgSeq) + (g_uiSendMsgSeq))) + + static int cmpQueueStr (const void *a, const void *b) + { + return strcmp (((StQueueName *) a)->cQueueName, + ((StQueueName *) b)->cQueueName); + } + + static int cmpQueueNodeStr (const void *a, const void *b) + { + return strcmp (((StQueueNode *) a)->cQueueName, + ((StQueueNode *) b)->cQueueName); + } + + static int cmpServiceStatusStr (const void *a, const void *b) + { +// if (((StServiceStatus*)a)->ulGetTimes == 0) +// { +// return 1; +// } +// if (((StServiceStatus*)b)->ulGetTimes == 0) +// { +// return -1; +// } +// if (((StServiceStatus*)a)->ulGetTimes < ((StServiceStatus*)b)->ulGetTimes) +// { +// return 1; +// } + int iRet = + strcmp (((StServiceStatus *) a)->strServiceId, + ((StServiceStatus *) b)->strServiceId); + if (iRet != 0) + { + return iRet; + } + iRet = + strcmp (((StServiceStatus *) a)->strScenarioId, + ((StServiceStatus *) b)->strScenarioId); + if (iRet != 0) + { + return iRet; + } + iRet = + strcmp (((StServiceStatus *) a)->strTargetOrgId, + ((StServiceStatus *) b)->strTargetOrgId); + if (iRet != 0) + { + return iRet; + } + if (((StServiceStatus *) a)->cFlagForOrgId < + ((StServiceStatus *) a)->cFlagForOrgId) + { + return -1; + } + else if (((StServiceStatus *) a)->cFlagForOrgId > + ((StServiceStatus *) a)->cFlagForOrgId) + { + return 1; + } + return 0; + } + + static int cmpBroadNodeStr (const void *a, const void *b) + { + int iRet = + strcmp (((StBroadcastNode *) a)->strServiceId, + ((StBroadcastNode *) b)->strServiceId); + if (iRet != 0) + return iRet; + + iRet = + strcmp (((StBroadcastNode *) a)->strScenarioId, + ((StBroadcastNode *) b)->strScenarioId); + if (iRet != 0) + return iRet; + +// iRet = strcmp(((StBroadcastNode*)a)->cConsumerSysId, ((StBroadcastNode*)b)->cConsumerSysId); +// if (iRet != 0) +// return iRet; + + return 0; + } + +/* +typedef struct StQueueTree +{ + char queueName[30]; + struct StQueueTree *pLeft; + struct StQueueTree *pRight; +}StQueueTree; + +static StQueueTree* InsertQueue(StQueueTree* pRoot, const char *cQueuName) +{ + StQueueTree* pCurNode = pRoot; + StQueueTree* pTmp; + StQueueTree* pNewNode = (StQueueTree*)malloc(sizeof(StQueueTree)); + strncpy(pNewNode->queueName, cQueuName, sizeof(pNewNode->queueName)); + pNewNode->pLeft = NULL; + pNewNode->pRight = NULL; + + if(pCurNode == NULL) + { + return pNewNode; + } + else + { + while(pCurNode != NULL) + { + pTmp = pCurNode; + if( strcmp(cQueuName, pTmp->queueName) > 0) + { + pCurNode = pCurNode->pRight; + } + else + { + pCurNode = pCurNode->pLeft; + } + } + + if(strcmp(cQueuName, pTmp->queueName) > 0) + { + pTmp->pRight = pNewNode; + } + else + { + pTmp->pLeft = pNewNode; + } + } + return pRoot; +} + +static StQueueTree* FindQueue(StQueueTree* pRoot, const char *cQueuName) +{ + int iRet = 1; + StQueueTree *pCurNode = pRoot; + while (iRet != 0) + { + if (pCurNode == NULL) + { + return NULL; + } + iRet = strcmp(cQueuName, pCurNode->queueName); + if( iRet > 0) + { + pCurNode = pCurNode->pRight; + } + else if( iRet < 0) + { + pCurNode = pCurNode->pLeft; + } + else + { + return pCurNode; + } + } + return NULL; +} + +typedef struct StQueueName StQueueName; + +static int rmb_partition(StQueueName* pQueueList,int low,int high) +{ + StQueueName tmpQueueName; + strcpy(tmpQueueName.cQueueName, (pQueueList + low)->cQueueName); + while(low < high) + { + if(lowcQueueName, tmpQueueName.cQueueName) >= 0) + { + --high; + } + strcpy((pQueueList+low)->cQueueName, (pQueueList+high)->cQueueName); + + if(lowcQueueName, tmpQueueName.cQueueName) <= 0) + { + ++low; + } + strcpy((pQueueList+high)->cQueueName, (pQueueList+low)->cQueueName); + } + strcpy((pQueueList + low)->cQueueName, tmpQueueName.cQueueName); + return low; +} + +static void rmb_quick_sort(StQueueName* pQueueList,int low,int high) +{ + if(lowcQueueName, cQueueName); + if ( iRet == 0) + { + return (pQueueList + m); + } + else if (iRet < 0) + { + if (i == m) + { + return NULL; + } + i = m; + } + else if (iRet > 0) + { + if (j == m) + { + return NULL; + } + j = m; + } + } + return NULL; +} +*/ +#ifdef __cplusplus +} +#endif + +#endif /* _RMB_COMMON_H_ */ diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_context.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_context.h new file mode 100644 index 0000000000..e4677db3fd --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_context.h @@ -0,0 +1,66 @@ +// 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. + +#ifndef RMB_CONTEXT_H_ +#define RMB_CONTEXT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "rmb_define.h" + + int rmb_context_init (StContext * pStContext); + + int rmb_context_add_rsp_socket (StContext * pStContext, + const char *cLocalIp, + unsigned short usReplyPort); + + int rmb_context_add_req_socket (StContext * pStContext, + const char *cLocalIp, + unsigned short usReqPort); + + int rmb_context_add_broadcast_socket (StContext * pStContext, + const char *cLocalIp, + unsigned short usBroadcastPort); + + int rmb_context_add_req_mq_fifo (StContext * pStContext, + const char *strFiFoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, void *func_argv); + int rmb_context_add_rr_rsp_mq_fifo (StContext * pStContext, + const char *strFiFoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + int rmb_context_add_broadcast_mq_fifo (StContext * pStContext, + const char *strFiFoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + + int rmb_context_enqueue (StContext * pStContext, + const enum RmbMqIndex uiMsgType, const char *data, + unsigned int uiDataLen); + +#ifdef __cplusplus +} +#endif + +#endif /* RMB_CONTEXT_H_ */ diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_define.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_define.h new file mode 100644 index 0000000000..20f8ea6f13 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_define.h @@ -0,0 +1,1264 @@ +// 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. + +#ifndef RMB_DEFINE_H_ +#define RMB_DEFINE_H_ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* +rmb_define.h +RMB基本定义 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "rmb_mq.h" +#include "rmb_log.h" +#include "rmb_errno.h" +#include "wemq_fifo.h" + +#include "wemq_topic_list.h" +#include "wemq_proto.h" + +#include +#include +#include +#include +#include + +#define RMBVERSION "2.2.0" +#define RMBVERSIONFORBIZ "00002200" + static const char rmbVersion[20] = "2.2.0"; + +#define DEFAULT_MSG_MAX_LIVE_TIME 14400000 +#define RR_ASYNC_MSG_MAX_LIVE_TIME 60000 +#define DEFAULT_DCN_LENGTH 3 +#define DEFAULT_SERVICE_ID_LENGTH 8 +#define DEFAULT_SCENE_ID_LENGTH 2 + +#define MAX_FLOWS_IN_A_SESSION 200 //the max flow numbers in one session +#define MAX_QUEUE_SESSIONS_IN_A_CONTEXT 1 //the max session numbers in one context +//#define MAX_LENTH_IN_A_MSG 2150000 //packages buf for send and receive +#define MAX_LENTH_IN_A_MSG 2625825 //packages buf for send and receive +#define MAX_PROPERTY_NUMS 50 //the max numbers for property +#define MAX_PROPERTY_LENTH 255 //the max length for one property +#define MAX_RMB_CONTEXT 2 //the max numbers of context -- solace threads + +#define MAX_SYSHEADER_LENGTH 20 +//流控比中每个topic最大的计数 +#define MAX_TOPIC_COUNT 1000000 +//#define MAX_APPHEADER_LENGTH 50000 +//0.9.12 保持和java一致 +//0.9.16,由于c会加\0,所以字节数需要加1 +//#define MAX_APPHEADER_LENGTH 525000 +//#define MAX_APPHEADER_LENGTH 525001 +#define MAX_APPHEADER_LENGTH (1 << 19) +#define MAX_PROPERTY_SIZE 50 +#define MAX_RET_MSG_SIZE 512 +//0.9.16,由于c会加\0,所以字节数需要加1 +//#define MAX_MSG_CONTENT_SIZE 2100000 +//#define MAX_MSG_CONTENT_SIZE 2100001 +#define MAX_MSG_CONTENT_SIZE (1 << 21) +#define MAX_MSG_ATTACHMENT_SIZE 2048 + +#define MAX_COMMON_SIZE 20 + +#define MAX_LOG_BUF_SIZE 20000 + +#define MAX_SERVICE_STATUS_CACHE_NUMS 1000 +#define MAX_GSL_REQ_BUF_SIZE 100 +#define MAX_GSL_RSP_BUF_SIZE 100 + +#define MAX_GSL_RSP_TOPIC_GROUP_SIZE 256 + +#define GSL_DEFAULT_DCN "GSL" +#define GSL_DEFAULT_SERVICE_ID "12300009" +#define GSL_DEFAULT_SCENE_ID "01" +#define GSL_DEFAULT_COMMON_ORGID "10006" + +#define MAX_RMB_WORKER_NUMS 400 +#define MAX_RMB_PROXY_NUMS 10 + +//for config center +#define WEMQ_ACCESS_SERVER "dynamicKey/v1/wemqAccessServer.json" +#define DYNAMIC_KEY_NAME "dynamicKey/v1" + +#define RMB_REQ_SINGLE "querySingle" +#define RMB_WHITE_LIST_RCV "whitelist-rcv" +#define RMB_WHITE_LIST_SND "whitelist-snd" +#define WEMQ_PROXY_SERVERS "wemq.proxy.servers" + +//#define RMB_WHITE_LIST_RCV_MAX 200 +//#define RMB_WHITE_LIST_SND_MAX 200 +#define RMB_TOPIC_PER_SYS_MAX 10000 +#define MAX_LISTEN_TOPIC_NUM 1000 + +#define RMB_MAX_NORMAL_SESSIONS_IN_A_CONTEXT_FOR_WEMQ 100 //the max normal session in context only for wemq proxy mode + +#define TCP_BUF_SIZE (3<<20) + + enum RmbGslSubcmd + { + GSL_SUBCMD_QUERY_SERVICE = 0x1, + GSL_SUBCMD_NEW_QUERY_SERVICE = 0x11, + GSL_SUBCMD_QUERY_TOPICGROUP = 0x02, + }; + + enum RmbMsgSource + { + RMB_MSG_FROM_SOLACE = 1, + RMB_MSG_FROM_WEMQ = 2, + }; + + enum RmbTargetOrgIdCommitType + { + RMB_COMMIT_BY_OWN = 0, + RMB_COMMIT_BY_API = 1, + }; + + enum RmbFlagForMsgInit + { + RMBMSG_DEST_HAS_SET = 0, + + }; + + enum EVENT_OR_SERVICE_CALL + { + RMB_EVENT_CALL = 0, + RMB_SERVICE_CALL = 1, + }; + + enum RMB_SVR_MODE + { + RMB_OLD_MODE = 0, + RMB_PROXY_WORKER = 1, + }; + + enum RMB_PROXY_MQ_TYPE + { + RMB_PROXY_MQ_RECEIVE = 1, + RMB_PROXY_MQ_SEND = 2, + RMB_PROXY_MQ_RR = 3, + }; + + enum RMB_LOG_POINT + { + RMB_LOG_START_CALL = 0, + RMB_LOG_ENTRY = 1, + RMB_LOG_EXIT = 2, + RMB_LOG_END_CALL = 3, + RMB_LOG_ON_ERROR = 4, + RMB_LOG_OTHER = 5, + }; + + //proxy-worker模式下使用 + typedef struct StMqFifoArg + { + char *_fiFoPath; + unsigned int _shmKey; + unsigned int _shmSize; + } StMqFifoArg; + + enum RMB_MSG_MODE + { + RMB_MSG_SOLACE = 0, + RMB_MSG_WEMQ = 1, + }; + + enum RMB_RSP_CODE + { + RMB_CODE_TIME_OUT = -1, + RMB_CODE_SUSS, + RMB_CODE_OTHER_FAIL, + RMB_CODE_AUT_FAIL, + RMB_CODE_DYED_MSG, + }; + +//**************************for wemq define******************************** +#define MAX_WEMQ_KFIFO_LENGTH (1UL << 16) +#define GETMSGID(buf,msgId) ({\ + char *p = (buf);\ + p += 2 * sizeof(int);\ + p += 3 * sizeof(char);\ + p += sizeof(StSystemHeader);\ + p += 2 * sizeof(StDestination);\ + (msgId) = *((unsigned long*)(p));\ +}) + +#define IS_DYED_MSG "IS_DYED_MSG" +#define MSG_HEAD_COMMAND_STR "command" +#define MSG_HEAD_SEQ_INT "seq" +#define MSG_HEAD_CODE_INT "code" +#define MSG_HEAD_MSG_STR "msg" + +#define MSG_HEAD_TYPE_INT "type" +#define MSG_HEAD_STATUS_INT "status" +#define MSG_HEAD_MSG_STR "msg" +#define MSG_HEAD_TIME_LINT "time" +#define MSG_HEAD_TIMESTAMP_LINT "timestamp" +#define MSG_HEAD_DEST_JSON "dest" +#define MSG_HEAD_DEST_SCENARIO_STR "scenario" +#define MSG_HEAD_DEST_SERVICE_STR "service" +#define MSG_HEAD_DEST_DCN_STR "dcn" +#define MSG_HEAD_DEST_ORGANIZATION_STR "organization" +#define MSG_HEAD_REDIRECT_OBJ "redirect" + +#define MSG_HEAD_SUB_BYPASS_TOPIC "topic" + +#define MSG_HEAD_IDC "idc" +#define MSG_HEAD_IP "ip" + +#define MSG_BODY_TOPIC_LIST_JSON "topicList" +#define MSG_BODY_TOPIC_STR "topic" +#define MSG_BODY_PROPERTY_JSON "properties" +#define MSG_BODY_PROPERTY_MSG_TYPE_STR "msgType" +#define MSG_BODY_PROPERTY_TTL_INT "TTL" +#define MSG_BODY_PROPERTY_SEQ_STR "SEQ" +#define MSG_BODY_PROPERTY_RR_REQUEST_UNIQ_ID_STR "RR_REQUEST_UNIQ_ID" +#define MSG_BODY_PROPERTY_KEYS_STR "keys" +#define MSG_BODY_PROPERTY_REPLYTO_STR "REPLY_TO" +#define MSG_BODY_PROPERTY_BORN_TIME_STR "BORN_TIME" +#define MSG_BODY_PROPERTY_STORE_TIME_STR "STORE_TIME" +#define MSG_BODY_PROPERTY_LEAVE_TIME_STR "LEAVE_TIME" +#define MSG_BODY_PROPERTY_ARRIVE_TIME_STR "ARRIVE_TIME" + +#define MSG_BODY_BYTE_BODY_JSON "body" +#define MSG_BODY_BYTE_BODY_APPHEADER_CONTENT_JSON "appHeaderContent" +#define MSG_BODY_BYTE_BODY_APPHEADER_NAME_STR "appHeaderName" +#define MSG_BODY_BYTE_BODY_CONTENT_STR "body" +#define MSG_BODY_BYTE_BODY_CREATETIME_LINT "createTime" +#define MSG_BODY_BYTE_BODY_SYSTEM_HEADER_CONTENT_JSON "sysHeaderContent" + +#define MSG_BODY_RMB_TRACE_LOG_JSON "rmbTraceLog" +#define MSG_BODY_RMB_TRACE_LOG_LOG_POINT_STR "logPoint" +#define MSG_BODY_RMB_TRACE_LOG_ERR_CODE_STR "errCode" +#define MSG_BODY_RMB_TRACE_LOG_ERR_MSG_STR "errMsg" +#define MSG_BODY_RMB_TRACE_LOG_MESSAGE_STR "message" +#define MSG_BODY_RMB_TRACE_LOG_EXTFIELDS_STR "extFields" + +#define MSG_BODY_SYSTEM_JSON "sysHeader" +#define MSG_BODY_SYSTEM_BIZ_STR "bizSeqNo" +#define MSG_BODY_SYSTEM_SEQNO_STR "consumerSeqNo" +#define MSG_BODY_SYSTEM_SVRID_STR "consumerSvrId" +#define MSG_BODY_SYSTEM_ORGSYS_STR "orgSysId" +#define MSG_BODY_SYSTEM_CSMID_STR "consumerId" +#define MSG_BODY_SYSTEM_TIME_LINT "tranTimestamp" +#define MSG_BODY_SYSTEM_CSMDCN_STR "consumerDCN" +#define MSG_BODY_SYSTEM_ORGSVR_STR "orgSvrId" +#define MSG_BODY_SYSTEM_ORGID_STR "organizationId" +#define MSG_BODY_SYSTEM_VER_STR "version" +#define MSG_BODY_SYSTEM_UNIID_STR "uniqueId" +#define MSG_BODY_SYSTEM_CONLEN_INT "contentLength" +#define MSG_BODY_SYSTEM_MSGTYPE_INT "messageType" +#define MSG_BODY_SYSTEM_RRTYPE_INT "rrType" +#define MSG_BODY_SYSTEM_ACK_SEQ "ack_seq" +#define MSG_BODY_SYSTEM_RECVTYPE_INT "receiveMode" +#define MSG_BODY_SYSTEM_SENDTIME_LINT "sendTimestamp" +#define MSG_BODY_SYSTEM_RECVTIME_LINT "receiveTimestamp" +#define MSG_BODY_SYSTEM_REPLYTIME_LINT "replyTimestamp" +#define MSG_BODY_SYSTEM_REPLYRECEIVETIME_LINT "replyReceiveTimestamp" +#define MSG_BODY_SYSTEM_APITYPE_INT "apiType" +#define MSG_BODY_SYSTEM_LOGICTYPE_INT "logicType" +#define MSG_BODY_SYSTEM_SOCOID_STR "solCorrelationId" +#define MSG_BODY_SYSTEM_EXTFIELDS_STR "extFields" +#define MSG_BODY_SYSTEM_API_VERSION "rmbVersion" +#define MSG_BODY_SYSTEM_REQ_IP "req_ip" +#define MSG_BODY_SYSTEM_REQ_SYS "req_sys" +#define MSG_BODY_SYSTEM_REQ_DCN "req_dcn" +#define MSG_BODY_SYSTEM_REQ_IDC "req_idc" +#define MSG_BODY_SYSTEM_RSP_IP "rsp_ip" +#define MSG_BODY_SYSTEM_RSP_SYS "rsp_sys" +#define MSG_BODY_SYSTEM_RSP_DCN "rsp_dcn" +#define MSG_BODY_SYSTEM_RSP_IDC "rsp_idc" + +#define MSG_BODY_APP_JSON "appHeader" + +#define MSG_BODY_DEST_JSON "destinationContent" +#define MSG_BODY_DEST_NAME_STR "name" +#define MSG_BODY_DEST_TYPE_STR "type" +#define MSG_BODY_DEST_SORE_STR "serviceOrEventId" +#define MSG_BODY_DEST_SCENARIO_STR "scenario" +#define MSG_BODY_DEST_ANY_DCN_STR "anyDCN" +#define MSG_BODY_DEST_DCN_STR "dcnNo" +#define MSG_BODY_DEST_ORGID_STR "organizationId" +#define MSG_BODY_DEST_ORGFLAG_INT "organizationIdInputFlag" + +#define MSG_BODY_TTL_LINT "timeToLive" +#define MSG_BODY_CONTENT_STR "content" +#define MSG_BODY_REPLYTO_STR "replyTo" +#define MSG_BODY_CREATETIME_LINT "createTime" +#define MSG_BODY_DELIVERYTIME_INT "deliveryTimes" +#define MSG_BODY_RESENT_BOOL "resent" +#define MSG_BODY_COID_STR "correlationId" +#define MSG_BODY_DUP_BOOL "duplicated" +#define MSG_BODY_SYN_BOOL "syn" +#define LOG_ERROR_POINT "ON_ERROR" + + typedef struct StRmbMsg StRmbMsg; + + typedef struct StWemqThreadMsg + { + unsigned int m_iCmd; + + unsigned int m_iHeaderLen; + unsigned int m_iBodyLen; + char *m_pHeader; + char *m_pBody; + } StWemqThreadMsg; + +#define RMB_MAX_UNIQUE_NUMS 2048 + + typedef struct StUniqueIdList + { + char unique_id[50]; + char biz_seq[50]; + unsigned int timeout; + unsigned int flag; + unsigned long timeStamp; + } StUniqueIdList; + + typedef struct StUniqueIdList DataType; + + typedef struct array + { + DataType *Data; + int size, max_size; + void (*Constructor) (struct array *); //构造函数 + void (*Input) (DataType, struct array *); //输入数据 + int (*get_array_size) (struct array *); //获取arr的大小 + int (*return_index_value) (struct array *, int); + void (*Destructor) (struct array *); //析构函数 + } Array; + +#define RMB_MAX_ERR_MSG_FROM_ACCESS 1024 + +//wemq msg 最多4m +#define WEMQ_MSG_MSX_LENGTH (1 << 22) + + typedef struct stContextProxy + { + pthread_t mainThreadId; + pthread_t coThreadId; + + char *mPubRRBuf; + + //for rr + pthread_mutex_t rrMutex; + pthread_cond_t rrCond; + int iFlagForRR; + + //for event msg, wait for ack + pthread_mutex_t eventMutex; + pthread_cond_t eventCond; + int iFlagForEvent; + long iSeqForEvent; + + //for add listen + pthread_mutex_t regMutex; + pthread_cond_t regCond; + int iFlagForReg; + //for add listen result check + int iResultForReg; + + //for pub session connect + pthread_mutex_t pubMutex; + pthread_cond_t pubCond; + int iFlagForPub; + int iFlagForPublish; + + //for sub session connect + pthread_mutex_t subMutex; + pthread_cond_t subCond; + int iFlagForSub; + +// myhash_t* rrHashTable; + void *pubContext; + void *subContext; + + StRmbMsg *pReplyMsg; + + //StUniqueIdList *pUniqueListForRRAsyncNew; + //StUniqueIdList *pUniqueListForRRAsyncOld; + + Array pUniqueListForRRAsyncNew; + Array pUniqueListForRRAsyncOld; + + StUniqueIdList stUnique; + + //StUniqueIdList stUniqueListForRRAsync[RMB_MAX_UNIQUE_NUMS]; + //StUniqueIdList stUniqueListForRRAsyncOld[RMB_MAX_UNIQUE_NUMS]; + + //Array stUniqueListForRRAsync; + //Array stUniqueListForRRAsyncOld; + + int iFlagForRun; + unsigned long ulGoodByeTime; + unsigned long ulLastClearRRAysncMsgTime; + unsigned long ulLastPrintOldListIsEmpty; + int iFlagForRRAsync; + + //for goodbye + pthread_mutex_t goodByeMutex; + pthread_cond_t goodByeCond; + int iFlagForGoodBye; + + StWemqTopicList stTopicList; + STRUCT_WEMQ_KFIFO (StWemqThreadMsg, MAX_WEMQ_KFIFO_LENGTH) pubFifo; + STRUCT_WEMQ_KFIFO (StWemqThreadMsg, MAX_WEMQ_KFIFO_LENGTH) subFifo; + } stContextProxy; + + typedef struct StThreadArgs + { + stContextProxy *pStContextProxy; + int contextType; + } StThreadArgs; + +#define WEMQ_FIFO_SIZE (2 << 20) + + typedef struct WemqThreadCtx + { + STRUCT_WEMQ_KFIFO (StWemqThreadMsg, WEMQ_FIFO_SIZE) * m_ptFifo; + stContextProxy *m_ptProxyContext; + + //int m_iThreadId; + char *m_pRecvBuff; + char *m_pSendBuff; + + //cache msg which from user thread; + StWemqThreadMsg m_stWemqThreadMsg; + StWemqThreadMsg m_stHeartBeat; + StWemqThreadMsg m_stHelloWord; + StWemqThreadMsg m_stListen; + + int m_iWemqThreadMsgHandled; + +// StWemqHeader m_stWemqHeader; + StWeMQMSG m_stWeMQMSG; + StWemqTopicList *m_ptTopicList; + + //for epoll + int m_iEpollFd; + struct epoll_event m_stEv; + struct epoll_event *m_ptEvents; + + int m_iFlagForSeverBreak; + + SSL_CTX *sslCtx; + + int m_iSockFd; + SSL *ssl; + + int m_iSockFdNew; + SSL *sslNew; + + int m_iSockFdOld; + SSL *sslOld; + + int m_iLastState; + int m_iState; + int m_contextType; + + int m_iHeartBeatCount; + unsigned int m_uiHeartBeatCurrent; + struct timeval stTimeNow; + struct timeval stTimeLast; + struct timeval stTimeLastRecv; + + // proxy server 地址 + char m_cProxyIP[100]; + char m_cProxyIPOld[100]; + unsigned int m_uiProxyPort; + unsigned int m_uiProxyPortOld; + int m_iLocalPort; // socket local port + + pthread_t m_threadID; // current thread's ID + +// bool m_lRedirect; + int m_lRedirect; + char m_cRedirectIP[100]; + int m_iRedirectPort; + + } WemqThreadCtx; +//************************************************************************* + +//**************************rmb msg define********************************* + + enum RmbDestinationType + { + RMB_DEST_TOPIC = 0, + RMB_DEST_QUEUE, + }; + +#define RMB_SYSTEMHEADER_EXTFIELDS_MAX_LEN 1024 * 2 // 2K +#define RMB_SYSTEMHEADER_PROPERTY_MAX_LEN 1024 * 2 // 2K + + typedef struct StSystemHeader + { + char cBizSeqNo[50]; //全局唯一业务流水号 + char cConsumerSeqNo[50]; //服务消费者系统调用流水号 + char cOrgSysId[10]; //交易原始发起方系统编号 + char cConsumerSysId[10]; //服务消费者系统编号 + char cConsumerSysVersion[10]; //服务消费者的系统版本号 + char cConsumerSvrId[50]; //服务消费者服务器标示(服务器名或IP地址) + char cRmbVersion[10]; //rmb版本号 + + char cOrgSvrId[50]; + char cUniqueId[50]; //unique id + char cConsumerDcn[10]; //服务消费者所在DCN + unsigned long ulTranTimeStamp; //交易发起时间戳 + char cAppHeaderClass[50]; //类名 + char cOrgId[10]; //法人号 + int flag; + + unsigned long ulSendTime; //发送时间 + unsigned long ulReceiveTime; //接收时间 + unsigned long ulReplyTime; //回包时间 + unsigned long ulReplyReceiveTime; //回包接收时间 + + unsigned long ulMessageDate; + + int iReceiveMode; + + int iContentLength; + char cExtFields[RMB_SYSTEMHEADER_EXTFIELDS_MAX_LEN]; + char cProperty[RMB_SYSTEMHEADER_PROPERTY_MAX_LEN]; + int iSetSysVersionFlag; + } StSystemHeader; + +#define REQ_BORN_TIMESTAMP "req_born_timestamp" +#define REQ_STORE_TIMESTAMP "req_store_timestamp" +#define REQ_LEAVE_TIMESTAMP "req_leave_timestamp" +#define REQ_ARRIVE_TIMESTAMP "req_arrive_timestamp" + +#define RSP_BORN_TIMESTAMP "rsp_born_timestamp" +#define RSP_STORE_TIMESTAMP "rsp_store_timestamp" +#define RSP_LEAVE_TIMESTAMP "rsp_leave_timestamp" +#define RSP_ARRIVE_TIMESTAMP "rsp_arrive_timestamp" + + typedef struct StAppHeader + { + char cTransCode[8]; // + char cSourceChannelType[32]; // + char cWordStationId[4]; // + } StAppHeader; + + typedef struct StDestination + { + int iDestType; //target type: 0: topic 1: queue + char cDestName[200]; + } StDestination; + + typedef struct StFlow StFlow; + +//包类型分类 + enum C_RMB_PKG_TYPE + { + ALL_TYPE_RMB = 0, //所有类型 + QUEUE_PKG = 1, //queue上的消息,一般为请求 + RR_TOPIC_PKG = 2, //RR的回包 + BROADCAST_TOPIC_PKG = 3, //广播包 + MANAGE_TOPIC_PKG = 4, //RMB内部管理topic包 + NEW_LOGIC_RECEIVE = 5, + NEW_LOGIC_SEND = 6, + }; + +//包来源分类 + enum C_RMB_LOGIC_TYPE + { + REQ_PKG_IN = 1, + RSP_PKG_IN = 2, + EVENT_PKG_IN = 3, + REQ_PKG_OUT = 4, + RSP_PKG_OUT = 5, + EVENT_PKG_OUT = 6, + + REQ_PKG_IN_WEMQ = 7, + RSP_PKG_IN_WEMQ = 8, + EVENT_PKG_IN_WEMQ = 9, + REQ_PKG_OUT_WEMQ = 10, + RSP_PKG_OUT_WEMQ = 11, + EVENT_PKG_OUT_WEMQ = 12, + MANAGE_PKG_IN_WEMQ = 13, + }; + + enum C_RMB_MESSAGE_TYPE + { + RMB_REQ_MSG = 1, + RMB_RSP_MSG = 2, + RMB_EVENT_MSG = 3, + }; + +//rmb转发包的方式 + enum UDP_OR_MQ + { + MSG_IPC_UDP = 0, + MSG_IPC_MQ = 1, + }; + + enum RMB_API_YPE + { + JAVA_TYPE = 1, + C_TYPE = 2, + JAVA_TYPE_WEMQ = 3, + C_TYPE_WEMQ = 4, + }; + + enum RMB_CONTEXT_TYPE + { + RMB_CONTEXT_TYPE_SUB = 0, + RMB_CONTEXT_TYPE_PUB = 1 + }; + +//typedef struct StRmbMsg + struct StRmbMsg + { + //sessionIndex for wemq + unsigned int uiSessIndex; + unsigned int uiFlowIndex; + + //pkg type + char cPkgType; //收到包的类型 + char cLogicType; //消息来源 + char cApiType; //apiType, enum RMB_API_YPE + StSystemHeader sysHeader; + StDestination dest; + StDestination replyTo; + unsigned long ulMsgId; + unsigned long ulMsgLiveTime; + char isDyedMsg[10]; + + //for receive msg + //char cServiceId[8]; + //char cScenario[2]; + + //char cAppHeader[MAX_APPHEADER_LENGTH]; + char *cAppHeader; + int iMallocAppHeaderLength; + int iAppHeaderLen; + + //char cContent[MAX_MSG_CONTENT_SIZE]; + char *cContent; + int iMallocContentLength; + int iContentLen; + + char cCorrId[MAX_COMMON_SIZE]; + int iCorrLen; + + //msg src + int iEventOrService; //0 event;1 service + char strTargetDcn[10]; + char strServiceId[10]; + char strScenarioId[5]; + + //for gsl + char strTargetOrgId[10]; + int iFLagForOrgId; + + //for flag check + int flag; + + int iMsgMode; //pub:send msg to wemq or solace sub:recv msg from wemq or solace + + char strLogBuf[1024]; +//}StRmbMsg; + }; + +//************for mq + typedef void (*rmb_callback_func) (const char *, const int, void *); + typedef int (*rmb_callback_func_v2) (const char *, const int, void *); +#define MAX_MQ_NUMS 10 +#define MAX_FIFO_PATH_NAME_LEN 200 +#define MAX_MQ_PKG_SIZE 10000000 +//static const unsigned int C_RMB_MQ_HEAD_SIZE = 2 * sizeof(unsigned int); +#define C_RMB_MQ_HEAD_SIZE 2 * sizeof(unsigned int) +#define C_RMB_MQ_PKG_HEAD_SIZE 2 * sizeof(unsigned int) +//static const unsigned int C_RMB_MQ_PKG_HEAD_SIZE = 2 * sizeof(unsigned int); + + typedef struct StRmbMq + { + unsigned int uiShmkey; + unsigned long ulShmId; + unsigned int uiShmSize; + + //head + tail + real data + char *pMqData; + unsigned int *pHead; + unsigned int *pTail; + + //real data + char *pBlock; + unsigned int uiBlockSize; + + } StRmbMq; + + typedef struct StRmbFifo + { + int iFd; + char strPath[MAX_FIFO_PATH_NAME_LEN]; + } StRmbFifo; + + typedef struct StRmbQueue + { + unsigned int uiSize; + + //head + tail + real data + char *pData; + unsigned int *pHead; + unsigned int *pTail; + + //real data + char *pBlock; + unsigned int uiBlockSize; + } StRmbQueue; + + typedef struct StRmbPipe + { + int fd[2]; + int r_fd; + int w_fd; + } StRmbPipe; + + typedef struct StMqInfo + { + StRmbMq *mq; + StRmbFifo *fifo; + + //for wemq + StRmbQueue *que; + StRmbPipe *pipe; + + int iIndex; //offset in vector + int iMsgType; //iPkgType,1 queue msg;2 rr topic msg;3 broadcast msg;4 manage msg + + rmb_callback_func func; + rmb_callback_func_v2 funcForNew; + void *args; + + //for epoll + int active; + + //for notify num + int iCount; + unsigned int uiLastCheckTime; + + int iMergeNotifyFLag; //0:not marge 1:marge + int iNotifyFactor; //the factor of notify + + pthread_mutex_t queMutex; + } StMqInfo; + + enum RmbMqIndex + { + req_mq_index = 1, + rr_rsp_mq_index = 2, + broadcast_mq_index = 3, + manage_mq_index = 4, + +// wemq_req_mq_index = 5, +// wemq_rr_rsp_mq_index = 6, +// wemq_broadcast_mq_index = 7, +// wemq_manage_mq_index = 8, + }; + +//for mq notify + typedef struct StRmbMqFifoNotify + { + StMqInfo vecMqInfo[MAX_MQ_NUMS]; + int iMqNum; + + StMqInfo *mqIndex[MAX_MQ_NUMS]; //see define of RmbMqIndex + //for select + fd_set readFd; + fd_set tmpReadFd; + struct timeval tv; + int iMaxFd; + + //for epoll + int iEpollFd; + + char *pBuf; + unsigned int uiBufLen; + + } StRmbMqFifoNotify; + +/////////////////////////////// + + typedef struct StContext StContext; + +//*************************context************************ + +//context的基本定义 + struct StContext + { + // for solace + unsigned int uiInitFlag; + + //for receive msgs + StRmbMsg *pReceiveMsg; + StRmbMsg *pReceiveMsgForRR; + StRmbMsg *pReceiveMsgForBroadCast; + + StRmbMsg *pReceiveWemqMsg; + StRmbMsg *pReceiveWemqMsgForRR; + StRmbMsg *pReceiveWemqMsgForBroadCast; + + //for receive msgs + char *pPkg; + unsigned int uiPkgLen; + + //for wemq + char *pWemqPkg; + unsigned int uiWemqPkgLen; + + char *pWemqPkgForRRAsync; + unsigned int uiWemqPkgForRRAsyncLen; + + //********UDP************* + //for rev req or broadcast + int iSocketForReq; + struct sockaddr_in tmpReqAddr; + + //for rev reply + int iSocketForRsp; + struct sockaddr_in tmpReplyAddr; + + //for rev broadcast + int iSocketForBroadcast; + struct sockaddr_in tmpBroadcastAddr; + + //*******MQ*************** + StRmbMqFifoNotify fifoMq; + + unsigned int uiNowTime; + + //sub or pub + void *pFather; + + //****for wemq + unsigned int uiInitWemqFlag; + + //for wemq proxy + stContextProxy *pContextProxy; + //sub or pub; + int contextType; + }; + +//********broadcast********* + typedef struct StBroadcastNode + { + char strServiceId[10]; + char strScenarioId[5]; + char cConsumerSysId[10]; + char cReserve[2]; + } StBroadcastNode; + +//********queue节点*********** + typedef struct StQueueNode + { + char cQueueName[30]; + int iQueueSize; + int iQueueUnackSize; + + } StQueueNode; + + typedef struct StQueueName + { + char cQueueName[30]; + } StQueueName; + + typedef struct StServiceStatus + { + char strTargetOrgId[10]; + char strServiceId[10]; + char strScenarioId[5]; + char cFlagForOrgId; + + char cResult; + char cRouteFlag; + char strTargetDcn[10]; + unsigned long ulGetTimes; + unsigned long ulInvalidTime; + } StServiceStatus; + + typedef struct StRmbConfig + { + char strConfigFile[500]; + + char cConsumerSysId[10]; + char cConsumerSysVersion[10]; + char cConsumerSvrId[100]; + char cOrgSvrId[50]; + //char cUniqueId[100]; + char cConsumerDcn[10]; + + //主机名 + char cHostName[100]; + char cHostIp[50]; + unsigned int uiPid; + + //log + int iLogLevel; + //RmbLogFile stLog; + char logFileName[200]; + int iLogFileNums; + int iLogFileSize; + int iLogShiftType; + + StRmbLog gRmbLog; + + //for solace api init + unsigned int uiIsInitSolaceApi; + //solace + int iSwitchForSolaceLog; + char strSolaceLog[100]; + int iSolaceLogLevel; + + //for connect success timeout + int createConnectionTimeOut; + + //debug switch + int iDebugSwitch; + + //queue config + StQueueNode queueNodeList[5000]; + int iQueueListSize; + + StBroadcastNode broadNodeList[5000]; + int iBroadListSize; + + //for browser + pthread_mutex_t configMutex; + pthread_cond_t configCond; + int iFlag; + + //for mergeq for gsl + pthread_mutex_t mergeqForGslMutex; + pthread_cond_t mergeqForGslCond; + int iFlagForMerge; + int iMergeQueue; + //for merge queue + pthread_mutex_t mergeQueueMutex; + + //for log + pthread_mutex_t configLog; + + //for send white list +// pthread_mutex_t sendWhiteListMutex; + + //for debug print + char *pLogBuf; + + //for manage session + int iManageFlag; //0 表示还没有, 1表示有 + + StQueueName fullQueueList[3000]; //queue + int iFullNums; + + //for flag + int iFlagForReq; //0:UDP,1:MQ + int iFlagForRRrsp; //0:UDP,1:MQ + int iFlagForBroadCast; //0:UDP,1:MQ + int iFlagForManage; //0:UDP,1:MQ + + //每次处理的个数 + int iEveryTimeProcessNum; + + //提醒的try间隔 + int iNotifyCheckSpan; + + //for req mq + char strFifoPathForReq[128]; + unsigned int uiShmKeyForReq; + unsigned int uiShmSizeForReq; + + //for rsp + char strFifoPathForRRrsp[128]; + unsigned int uiShmKeyForRRrsp; + unsigned int uiShmSizeForRRrsp; + + //for broadcast + char strFifoPathForBroadcast[128]; + unsigned int uiShmKeyForBroadcast; + unsigned int uiShmSizeForBroadcast; + + //flag + //是否合并通知的开关 + int iFLagForMergeNotify; + + //orgId + char strOrgId[10]; + + //last error + char _lastError[300]; + + //是否允许发送的开关 + int iFlagForPublish; + unsigned long ulLastStopTime; + unsigned long ulLastAllowTime; + char cLastMsg[50]; + + //rmb的启动时间 + unsigned long ulStartTime; //rmb init time + + //RR info + unsigned int uiSendRRMsgNums; + unsigned int uiSendRRMsgError; + + //Event info + unsigned int uiSendEventMsg; + unsigned int uiSendEventMsgError; + + //AyncRR + unsigned int uiSendAyncRRMsg; + unsigned int uiSendAyncRRMsgError; + + //receiveMsg + unsigned int uiReceiveServiceReqMsg; + unsigned int uiReceiveAyncRRReply; + unsigned int uiReceiveEventMsg; + + StServiceStatus serviceStatusList[MAX_SERVICE_STATUS_CACHE_NUMS]; + int iCacheServiceNums; + + int iCacheTimeoutTime; + int iCacheSuccTimeoutTime; //gsl query success, timeout default is 600s + int iCacheFailedTimeoutTime; //gsl query failed, timeout default is 30s + + //timtout + unsigned long ulNowTtime; + + //exit timtout + unsigned long ulExitTimeOut; + + //for rmb proxy worker + int iRmbMode; + + int iWorkerSendBufSize; + + //for reload cfg + //signal1 + int iSwitchForSignal1; + //signal2 + int iSwitchForSignal2; + + //for ack + int ackTimers; + int ackThresHold; + + //for query timeout + int iQueryTimeout; + + //for sub broadcast LVQ + unsigned int uiIsBroadcastLVQ; + + //for msg trans by solace timeout :daxin + int iCommonTimeOut; + //for rmb period stat log + int iStatPeriod; + //get group topic status time + int iGetGroupTopicTime; + //get send white list time + int iGetSendWhiteListTime; + + //for clean merge q thread + pthread_t pid_merge; + int flag_merge; + + // logServer log switch for user + int iLogserverSwitch; + //logServer log switch for api + int iApiLogserverSwitch; + //rmb mode: wemq + char cRmbMode[10]; + int iConnWemq; + + //gsl control + int iReqGsl; + + //for config center + char cConfigIp[256]; + int iConfigPort; + int iConfigTimeout; + int configIpPosInArr; + char ConfigAddr[512]; +// char cWemqSavePath[1024]; + + int tlsOnoff; + + //local IDC config + char cRegion[10]; + + int iFlagForLoop; + + //for proxyContext + int iProxyContextNums; + void *pProxyContext; + + //for mode worker heart beat; + int heartBeatPeriod; + int heartBeatTimeout; + + //for get access ip + int getAccessIpPeriod; + + //for access ack + int accessAckTimeOut; + + //for rr async + int rrAsyncTimeOut; + + //for access goodbye + int goodByeTimeOut; + + // wemq-access 配置中心服务器 + int iWemqUseHttpCfg; // 是否启用Http配置中心 + //for default tcp + char cWemqProxyIp[100]; + unsigned int cWemqProxyPort; + int iWemqTcpConnectRetryNum; // 连接wemq-access重试次数 + int iWemqTcpConnectDelayTime; // 每次重连间隔时间(ms) + + int iWemqTcpConnectTimeout; // 每次TCP连接超时时间 + int iWemqTcpSocketTimeout; // TCP socket 超时时间 + + //for topic + int iNormalTimeout; // 监听topic超时时间(ms), default is:120000 + + //for wemq user/passwd + char cWemqUser[100]; + char cWemqPasswd[100]; + + int mqIsEmpty; + + char strDepartMent[20]; + } StRmbConfig; + + typedef struct RmbPythonConfig + { + //for req mq + char strFifoPathForReq[128]; + unsigned int uiShmKeyForReq; + unsigned int uiShmSizeForReq; + + //for rsp + char strFifoPathForRRrsp[128]; + unsigned int uiShmKeyForRRrsp; + unsigned int uiShmSizeForRRrsp; + + //for broadcast + char strFifoPathForBroadcast[128]; + unsigned int uiShmKeyForBroadcast; + unsigned int uiShmSizeForBroadcast; + } RmbPythonConfig; + + enum MQ_STATUS + { + MQ_INIT = 0, + MQ_IS_NOT_EMPTY, + MQ_IS_EMPTY + }; + +//灰度完成queue的场景ID +#define GRAY_COMPLETE_SCENE "FR" + + enum TOPIC_STATUS + { + QUEUE_NOT_GRAY = 0, + QUEUE_GRAY_INIT, + QUEUE_GRAY_NOT_COMPLETE, + QUEUE_GRAY_COMPLETE + }; + + typedef struct StRmbListenQueueInfo + { + char cDcn[5]; + char cServiceId[10]; + char cScenarioId[5]; + } st_rmb_queue_info; + +//rmb topic info + typedef struct StRmbTopicInfo + { + char cServiceId[10]; + char cScenarioId[5]; + char cTopicGroup[32]; + char cTopicStatus[3]; + int flag; + } StRmbTopicInfo; + + extern StRmbConfig *pRmbStConfig; + extern char cManageTopic[30]; + extern char cQueueFullTopic[30]; + extern char cLogLevelTopic[30]; +///////////////add by wan + extern char cPublishCheck[30]; +///////////////////////////// + extern StContext *g_pStContextArry[MAX_RMB_CONTEXT]; +#define LOGRMB(loglevel,fmt, args...) {LogRmb(loglevel, "[%s:%d(%s)]["fmt"]", __FILE__, __LINE__, __FUNCTION__, ## args);\ + if(loglevel==RMB_LOG_ERROR) snprintf(pRmbStConfig->_lastError, sizeof(pRmbStConfig->_lastError)-1, fmt, ## args);} + +//****common tool******* +#define RMB_MGS_PRINT_P(p) p->cConsumerSysId,p->cConsumerSysId,p->cConsumerSysId, +#define RMB_MAX(a,b) (a>b)?a:b +#define RMB_MIN(a,b) (a len){return -1;} +#define RMB_LEN_CHECK(a,len); if(strlen(a) != len){rmb_errno=RMB_ERROR_ARGV_LEN_ERROR;return rmb_errno;} + +//#define RMB_CHECK_POINT_NULL(a,b); if((void*)a == NULL) {LOGRMB(RMB_LOG_ERROR,"%s is NULL!", b);return -1;} +#define RMB_CHECK_POINT_NULL(a,b); if((void*)a == NULL) {LOGRMB(RMB_LOG_ERROR,"%s is NULL!", b);rmb_errno=RMB_ERROR_ARGV_NULL;return RMB_ERROR_ARGV_NULL;} +//end +#define RMB_MEMSET(a); memset(&a, 0, sizeof(a)); + +#define RMB_ADD_SESSION_PROPERTY(a,b,c); sprintf(a->cSessionProps[a->uiPropIndex], "%s", b);\ + a->vecPSessProps[a->uiPropIndex] = a->cSessionProps[a->uiPropIndex];\ + a->uiPropIndex++;\ + sprintf(a->cSessionProps[a->uiPropIndex], "%s", c);\ + a->vecPSessProps[a->uiPropIndex] = a->cSessionProps[a->uiPropIndex];\ + a->uiPropIndex++; + +#define RMB_ADD_FLOW_PROPERTY(a,b,c); sprintf(a->cFlowProps[a->uiPropIndex], "%s", b);\ + a->vecPFlowProps[a->uiPropIndex] = a->cFlowProps[a->uiPropIndex];\ + a->uiPropIndex++;\ + sprintf(a->cFlowProps[a->uiPropIndex], "%s", c);\ + a->vecPFlowProps[a->uiPropIndex] = a->cFlowProps[a->uiPropIndex];\ + a->uiPropIndex++; + +#define RMB_ADD_FLOW_PROPERTY_INT(a,b,c); sprintf(a->cFlowProps[a->uiPropIndex], "%s", b);\ + a->vecPFlowProps[a->uiPropIndex] = a->cFlowProps[a->uiPropIndex]; \ + a->uiPropIndex++; \ + sprintf(a->cFlowProps[a->uiPropIndex], "%d", c);\ + a->vecPFlowProps[a->uiPropIndex] = a->cFlowProps[a->uiPropIndex];\ + a->uiPropIndex++; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_errno.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_errno.h new file mode 100644 index 0000000000..6f7d7aa9fe --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_errno.h @@ -0,0 +1,137 @@ +// 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. + +#ifndef __RMB_ERRNO_H__ +#define __RMB_ERRNO_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + extern int *rmb_error (void) __attribute__ ((__const__)); + +#define rmb_errno (*rmb_error()) + + struct rmb_err_msg + { + int err_no; + const char *err_msg; + }; + +#define RMB_MAX_ERR_NUMS 500 +#define RMB_ERROR_BASE_BEGIN 10000 + +//错误码列表 +#define RMB_ERROR_ARGV_NULL 10001 //参数为空 +#define RMB_ERROR_ARGV_LEN_ERROR 10002 //参数长度错误 +#define RMB_ERROR_MALLOC_FAIL 10003 //申请内存失败 +#define RMB_ERROR_INIT_CONTEXT_FAIL 10004 //初始化context失败 +#define RMB_ERROR_MSG_MISSING_PART 10005 //发送RMB消息必要字段缺少 +#define RMB_ERROR_RR_INTERFACE_CAN_NOT_SEND_EVENT_MSG 10006 //RMB同步接口不允许发送异步消息 +#define RMB_ERROR_EVENT_INTERFACE_CAN_NOT_SEND_RR_MSG 10007 //RMB异步接口不允许发送同步消息 +#define RMB_ERROR_NOW_CAN_NOT_SEND_MSG 10008 //现在禁止发送消息 +#define RMB_ERROR_QUEUE_FULL 10009 //该topic已queue满,不允许发送 +#define RMB_ERROR_GSL_SERVICE_ID_NULL 10010 //GSL服务id为空 +#define RMB_ERROR_GSL_SERVICE_ID_ERROR 10011 //GSL服务id路由失败 +#define RMB_ERROR_GSL_SVR_ERROR 10012 //GSL服务器返回失败 +#define RMB_ERROR_REQ_GSL_ERROR 10013 //请求GSL服务失败 +#define RMB_ERROR_MSG_UUID_FAIL 10014 //RMB消息生成UUID失败 +#define RMB_ERROR_MSG_SET_SYSTEMHEADER_FAIL 10015 //RMB消息初始化为SOLACE消息时设置systemHeader失败 +#define RMB_ERROR_SEND_GET_SESSION_FAIL 10016 //发送消息时,获取可用session失败 +#define RMB_ERROR_SEND_EVENT_MSG_FAIL 10017 //发送异步消息失败 +#define RMB_ERROR_SEND_RR_MSG_FAIL 10018 //发送同步消息失败 +#define RMB_ERROR_SEND_RR_MSG_TIMEOUT 10019 //发送同步消息超时 +#define RMB_ERROR_REPLY_TO_NULL 10020 //RR请求消息缺少replyTo,不允许reply +#define RMB_ERROR_REPLY_FAIL 10021 //回复消息失败 +#define RMB_ERROR_SESSION_CONNECT_FAIL 10022 //session连接失败--->连接session失败,请检查rmb配置文件是否正确 +#define RMB_ERROR_SESSION_RECONNECT_FAIL 10023 //session重连失败 +#define RMB_ERROR_SESSION_DESTORY_FAIL 10024 //session销毁失败 +#define RMB_ERROR_SESSION_NUMS_LIMIT 10025 //该类型session连接数已达上限 +#define RMB_ERROR_LISTEN_QUEUE_NOT_EXIST 10026 //监听queue失败,不存在该queue +#define RMB_ERROR_LISTEN_QUEUE_FAIL 10027 //监听queue失败 +#define RMB_ERROR_FLOW_DESTORY_FAIL 10028 //flow销毁失败 +#define RMB_ERROR_LISTEN_TOPIC_FAIL 10029 //监听topic失败 +#define RMB_ERROR_INIT_MQ_FAIL 10030 //初始化消息通信MQ失败 +#define RMB_ERROR_INIT_FIFO_FAIL 10031 //初始化通知FIFO失败 +#define RMB_ERROR_INIT_UDP_FAIL 10032 //初始化UDP失败 +#define RMB_ERROR_INIT_EPOLL_FAIL 10033 //初始化Epoll失败 +#define RMB_ERROR_MQ_NUMS_LIMIT 10034 //添加MQ数量超过上限 +#define RMB_ERROR_ENQUEUE_MQ_FAIL 10035 //消息入队MQ失败 +#define RMB_ERROR_DEQUEUE_MQ_FAIL 10036 //消息出队MQ失败 +#define RMB_ERROR_MSG_2_BUF_FAIL 10037 //RMB消息转为Buf失败 +#define RMB_ERROR_BUF_2_MSG_FAIL 10038 //Buf转RMB消息失败 +#define RMB_ERROR_MSG_SET_CONTENT_TOO_LARGE 10039 //RMB消息设置Content过大 +#define RMB_ERROR_MSG_SET_APPHEADER_TOO_LARGE 10040 //RMB消息设置AppHeader过大 +#define RMB_ERROR_MSG_TTL_0 10041 //RMB消息设置存活时间必须大于0 +#define RMB_ERROR_RCV_MSG_GET_CONTENT_FAIL 10042 //RMB接收消息获取Content失败 +#define RMB_ERROR_RCV_MSG_GET_BINARY_FAIL 10043 //RMB接收消息获取BinaryAttachment失败 +#define RMB_ERROR_RCV_MSG_CONTENT_TOO_LARGE 10044 //RMB接收消息Content过大 +#define RMB_ERROR_RCV_MSG_APPHEADER_TOO_LARGE 10045 //RMB接收消息AppHeader过大 +#define RMB_ERROR_MANAGE_MSG_PKG_ERROR 10046 //RMB管理消息包格式错误 +#define RMB_ERROR_MANAGE_MSG_PKG_CHECK_FAIL 10047 //RMB管理消息鉴权失败 +#define RMB_ERROR_CONTEXT_CREATE_FAIL 10048 //CONTEXT创建失败 +#define RMB_ERROR_FIFO_PARA_ERROR 10049 //FIFO参数错误 +#define RMB_ERROR_SHM_PARA_ERROR 10050 //SHM参数错误 +#define RMB_ERROR_SEND_FIFO_NOTIFY_ERROR 10051 //fifo发送通知失败 +#define RMB_ERROR_FLOW_NUMS_LIMIT 10052 //flow数目限制 +#define RMB_ERROR_MSG_GET_SYSTEMHEADER_ERROR 10053 //消息systemHeader错误 +#define RMB_ERROR_RMB_MSG_2_SOLACE_MSG_ERROR 10054 //copy rmb msg 2 solace msg error +#define RMB_ERROR_SOLACE_MSG_2_RMB_MSG_ERROR 10055 //copy solace msg 2 rmb msg error +#define RMB_ERROR_NO_AVAILABLE_SESSION 10056 //没有可用的session +#define RMB_ERROR_NO_BROADCAST_SESSION 10057 //没有可用的添加广播的session +#define RMB_ERROR_NO_AVAILABLE_CONTEXT 10058 //没有可用的context +#define RMB_ERROR_SET_FLOW_PROPETY 10059 //设置flow属性错误 +#define RMB_ERROR_ACK_MSG_FAIL 10060 //ack消息失败 +#define RMB_ERROR_LOGIC_NOTIFY_INIT 10061 //logic进程notify初始化失败 +#define RMB_ERROR_SESSION_ADD_FAIL 10062 //增加session失败 +#define RMB_ERROR_WORKER_NUMS_LIMIT 10063 //worker数量限制 +#define RMB_ERROR_BUF_NOT_ENOUGH 10064 //buf不够存储 +#define RMB_ERROR_STOP_FLOW_ERROR 10065 //停止flow收消息失败 +#define RMB_ERROR_DEQUEUE_MQ_EMPTY 10066 //消息队列出队为空 +#define RMB_ERROR_REMOVE_TOPIC_FAIL 10067 //删除监听topic失败 + +//proxy add +#define RMB_NOT_REGISTER_WORKER 10068 //worker还未注册 +#define RMB_SEND_MSG_ERROR_TYPE 10069 //发送消息错误的类型 +#define RMB_MSG_DECODE_ERROR 10070 //worker到proxy消息decode错误 +#define RMB_WORKER_BUF_FULL 10071 //worker满了 + +#define RMB_ERROR_CREATE_THREAD_FAIL 10072 //创建线程失败 +#define RMB_ERROR_ENCODE_FAIL 10073 //Encode失败 +#define RMB_ERROR_DECODE_FAIL 10074 //Decode失败 +#define RMB_ERROR_RR_RSP_NOTIFY_ERROR 10075 //RR回包唤醒错误 +#define RMB_ERROR_WORKER_REGISTER_ERROR 10076 //注册worker失败 +#define RMB_ERROR_WORKER_WINDOW_FULL 10077 //worker发送队列已满; +#define RMB_ERROR_WORKER_PUT_FIFO_ERROR 10078 //put msg into fifo error + +#define RMB_ERROR_START_CALL_FAIL 10079 +#define RMB_ERROR_END_CALL_FAIL 10080 +#define RMB_ERROR_ENTRY_FAIL 10081 +#define RMB_ERROR_EXIT_FAIL 10082 +#define RMB_ERROR_TOPIC_COUNT_TOO_LARGE 10083 //流控比时,topic个数超过最大个数 +#define RMB_ERROR_CLIENT_GOODBYE_TIMEOUT 10084 //客户端退出超时 + + void init_error (); + + const char *get_rmb_last_error (); + + void rmb_reset_error (); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_http_client.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_http_client.h new file mode 100644 index 0000000000..c916285e1c --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_http_client.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef __RMB_HTTP_CLIENT_H +#define __RMB_HTTP_CLIENT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + struct rmb_http_buffer + { + size_t len; + char *data; + }; + +// timeout: ms + int rmb_http_easy_get (const char *url, void *buffer, long timeout); +//int rmb_http_easy_post(char* url, char* post_data, size_t len, void* buffer, size_t size, size_t* used, long timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_list.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_list.h new file mode 100644 index 0000000000..0dd1c016d9 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_list.h @@ -0,0 +1,564 @@ +// 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. + +/** + * copy from linux_list.h + */ + +#ifndef RMB_LIST_H_ +#define RMB_LIST_H_ + +#include + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +typedef struct rmb_st_list +{ + struct st_list *prev, *next; + void *data; +} RMB_LIST; + +struct rmb_list_head +{ + struct rmb_list_head *next, *prev; +}; + +#define RMB_LIST_HEAD_INIT(name) { &(name), &(name) } + +#define RMB_LIST_HEAD(name) \ + struct rmb_list_head name = RMB_LIST_HEAD_INIT(name) + +static inline void RMB_INIT_LIST_HEAD (struct rmb_list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __rmb_list_add (struct rmb_list_head *newNode, + struct rmb_list_head *prev, + struct rmb_list_head *next) +{ + next->prev = newNode; + newNode->next = next; + newNode->prev = prev; + prev->next = newNode; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void rmb_list_add (struct rmb_list_head *newNode, + struct rmb_list_head *head) +{ + __rmb_list_add (newNode, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void rmb_list_add_tail (struct rmb_list_head *newNode, + struct rmb_list_head *head) +{ + __rmb_list_add (newNode, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __rmb_list_del (struct rmb_list_head *prev, + struct rmb_list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void rmb_list_del (struct rmb_list_head *entry) +{ + __rmb_list_del (entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void rmb_list_replace (struct rmb_list_head *old, + struct rmb_list_head *newNode) +{ + newNode->next = old->next; + newNode->next->prev = newNode; + newNode->prev = old->prev; + newNode->prev->next = newNode; +} + +static inline void rmb_list_replace_init (struct rmb_list_head *old, + struct rmb_list_head *newNode) +{ + rmb_list_replace (old, newNode); + RMB_INIT_LIST_HEAD (old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void rmb_list_del_init (struct rmb_list_head *entry) +{ + __rmb_list_del (entry->prev, entry->next); + RMB_INIT_LIST_HEAD (entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void rmb_list_move (struct rmb_list_head *list, + struct rmb_list_head *head) +{ + __rmb_list_del (list->prev, list->next); + rmb_list_add (list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void rmb_list_move_tail (struct rmb_list_head *list, + struct rmb_list_head *head) +{ + __rmb_list_del (list->prev, list->next); + rmb_list_add_tail (list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int rmb_list_is_last (const struct rmb_list_head *list, + const struct rmb_list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int rmb_list_empty (const struct rmb_list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int rmb_list_empty_careful (const struct rmb_list_head *head) +{ + struct rmb_list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int rmb_list_is_singular (const struct rmb_list_head *head) +{ + return !rmb_list_empty (head) && (head->next == head->prev); +} + +static inline void __rmb_list_cut_position (struct rmb_list_head *list, + struct rmb_list_head *head, + struct rmb_list_head *entry) +{ + struct rmb_list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void rmb_list_cut_position (struct rmb_list_head *list, + struct rmb_list_head *head, + struct rmb_list_head *entry) +{ + if (rmb_list_empty (head)) + return; + if (rmb_list_is_singular (head) && (head->next != entry && head != entry)) + return; + if (entry == head) + RMB_INIT_LIST_HEAD (list); + else + __rmb_list_cut_position (list, head, entry); +} + +static inline void __rmb_list_splice (const struct rmb_list_head *list, + struct rmb_list_head *prev, + struct rmb_list_head *next) +{ + struct rmb_list_head *first = list->next; + struct rmb_list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void rmb_list_splice (const struct rmb_list_head *list, + struct rmb_list_head *head) +{ + if (!rmb_list_empty (list)) + __rmb_list_splice (list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void rmb_list_splice_tail (struct rmb_list_head *list, + struct rmb_list_head *head) +{ + if (!rmb_list_empty (list)) + __rmb_list_splice (list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void rmb_list_splice_init (struct rmb_list_head *list, + struct rmb_list_head *head) +{ + if (!rmb_list_empty (list)) + { + __rmb_list_splice (list, head, head->next); + RMB_INIT_LIST_HEAD (list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void rmb_list_splice_tail_init (struct rmb_list_head *list, + struct rmb_list_head *head) +{ + if (!rmb_list_empty (list)) + { + __rmb_list_splice (list, head->prev, head); + RMB_INIT_LIST_HEAD (list); + } +} + +/** +* container_of - cast a member of a structure out to the containing structure +* @ptr: the pointer to the member. +* @type: the type of the container struct this is embedded in. +* @member: the name of the member within the struct. +* +*/ + +#define rmb_container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define rmb_list_entry(ptr, type, member) \ + rmb_container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define rmb_list_first_entry(ptr, type, member) \ + rmb_list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define rmb_list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __rmb_list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define rmb_list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define rmb_list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define rmb_list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define rmb_list_for_each_entry(pos, head, member) \ + for (pos = rmb_list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = rmb_list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define rmb_list_for_each_entry_reverse(pos, head, member) \ + for (pos = rmb_list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = rmb_list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define rmb_list_prepare_entry(pos, head, member) \ + ((pos) ? : rmb_list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define rmb_list_for_each_entry_continue(pos, head, member) \ + for (pos = rmb_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = rmb_list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define rmb_list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = rmb_list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = rmb_list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define rmb_list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = rmb_list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define rmb_list_for_each_entry_safe(pos, n, head, member) \ + for (pos = rmb_list_entry((head)->next, typeof(*pos), member), \ + n = rmb_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = rmb_list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define rmb_list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = rmb_list_entry(pos->member.next, typeof(*pos), member), \ + n = rmb_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = rmb_list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define rmb_list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = rmb_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = rmb_list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define rmb_list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = rmb_list_entry((head)->prev, typeof(*pos), member), \ + n = rmb_list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = rmb_list_entry(n->member.prev, typeof(*n), member)) + +#endif /* RMB_LIST_H_ */ diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_log.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_log.h new file mode 100644 index 0000000000..5ebae8fcf8 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_log.h @@ -0,0 +1,121 @@ +// 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. + +#ifndef _RMB_LOG_H_ +#define _RMB_LOG_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum RMB_LOG_TYPE +{ + RMB_LOG_TYPE_NORMAL = 0, //不需要滚动 + RMB_LOG_TYPE_CYCLE, //按大小滚动 + RMB_LOG_TYPE_DAILY, //按日期滚动 + RMB_LOG_TYPE_DAILY_AND_CYCLE, //按日期和大小一起滚动 + RMB_LOG_TYPE_CYCLE_BY = 6, //按大小滚动 +}; + +enum RMB_LOG_LEVEL +{ + RMB_LOG_FATAL = 0, + RMB_LOG_ERROR, + RMB_LOG_WARN, + RMB_LOG_INFO, + RMB_LOG_DEBUG, + RMB_LOG_ALL +}; + +typedef struct StRmbLogPara +{ + int _logLevel; + int _shiftType; + char _path[256]; + int _maxFileSize; + int _maxFileNum; +} StRmbLogPara; + +typedef struct StRmbLog +{ + FILE *_pStatFile; + FILE *_pLogFile; + char _logStatFileName[300]; + int _fd; + //int _fileOpen; //表示文件是否打开 + char _logFileName[300]; //next shift, 当前日志文件需要rename的名字 + char _logBaseFileName[280]; //当前写的日志名字 + time_t _lastShiftTime; + int _curFileNums; //当前日志数 + int _curFileNo; //当前第几个日志或者当天第几个日志,circle删除看这个 + + int _curFileSize; //当前日志大小 + + int _toDeleteFileNo; //for circle + char _toDeleteFileName[300]; //for daily + time_t _toDeleteTime; //删除哪天的日志 + StRmbLogPara _para; + + //pthread_spinlock_t logSpinLock = SPIN_LOCK_UNLOCKED; //自旋锁 + pthread_mutex_t rmbLogMutex; //临界区 + struct timeval stLogTv; + struct stat gRmbSb; + + //for file lock + struct flock logFileLock; + struct flock logStateLock; +} StRmbLog; + +typedef struct StDayInfo +{ + unsigned int _curFileNo; //当前天,下一个rename的名字 + unsigned int _deleteFileNo; //当前天,马上要被delete的序号 + time_t _dayTime; //代表当前天的时间 + unsigned int _curFileNum; //当前天的日志个数 + + char _baseFileName[280]; + char _logFileName[300]; +} StDayInfo; + +int ReloadCfg (int logLevel, int shiftType, const char *path, int maxFileSize, + int maxFileNum); +int GetCurFileNumFromStatFile (); +int SetCurFileNumToStatFile (); +int InitRmbLogFile (int logLevel, int shiftType, const char *path, + int maxFileSize, int maxFileNum); +int OpenRmbLog (); +int FindNextDeleteLog (); +int LogRmb (int logLevel, const char *format, ...); +int ShiftRmbLog (FILE * file); +int GetCurStateFromRmbLogByCirCle (); +int GetCurStateFromRmbLogByDaily (); +int GetCurStateFromRmbLogByDaily_V2 (); +int GetCurStateFromRmbLogByDaily_V3 (); +int GetCurStateFromRmbLogByDaily_V4 (); +int GetDayInfo (StDayInfo * dayInfo, time_t * curTime); +int GetDayInfoWithBreak (StDayInfo * dayInfo, time_t * curTime); +int GetRmbNowLongTime (); + +void _Log_Thread_func (void *args); +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_mq.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_mq.h new file mode 100644 index 0000000000..0aebc9532d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_mq.h @@ -0,0 +1,282 @@ +// 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. + +#ifndef RMB_MQ_H_ +#define RMB_MQ_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rmb_define.h" +#include "rmb_msg.h" +#include "rmb_sub.h" + +//typedef void (*rmb_callback_func)(const char*, const int, const int type, void*); +//typedef int(*rmb_callback_func_v2)(const char*, const int, void*); +//#define MAX_MQ_NUMS 10 +//#define MAX_FIFO_PATH_NAME_LEN 200 +//#define MAX_MQ_PKG_SIZE 10000000 +////static const unsigned int C_RMB_MQ_HEAD_SIZE = 2 * sizeof(unsigned int); +//#define C_RMB_MQ_HEAD_SIZE 2 * sizeof(unsigned int) +//#define C_RMB_MQ_PKG_HEAD_SIZE 2 * sizeof(unsigned int) +////static const unsigned int C_RMB_MQ_PKG_HEAD_SIZE = 2 * sizeof(unsigned int); + +//*************************for mq***************************** +//typedef struct StRmbMq +//{ +// unsigned int uiShmkey; +// unsigned long ulShmId; +// unsigned int uiShmSize; +// +// //head + tail + real data +// char* pMqData; +// unsigned int *pHead; +// unsigned int *pTail; +// +// //real data +// char *pBlock; +// unsigned int uiBlockSize; +// +//}StRmbMq; + +//mq init + int rmb_mq_init (StRmbMq * pMq, const unsigned int shmKey, + const unsigned int shmSize, const int bCreate, + const int bReadOnly); + +//mq_enqueue + int rmb_mq_enqueue (StRmbMq * pMq, const char *data, unsigned int uiDataLen, + unsigned int uiFLow); + +//mq_dequeue + int rmb_mq_dequeue (StRmbMq * pMq, char *buf, unsigned int uiBufSize, + unsigned int *pDataLen, unsigned int *pFlowId); + +//mq_try_deuque + int rmb_mq_try_dequeue (StRmbMq * pMq, char *buf, unsigned int uiBufSize, + unsigned int *pDataLen, unsigned int *pFlowId); + +//mq_get_stat + int rmb_mq_get_stat (StRmbMq * pMq); + +//*************************for fifo***************************** +//typedef struct StRmbFifo +//{ +// int iFd; +// char strPath[MAX_FIFO_PATH_NAME_LEN]; +//}StRmbFifo; + +//fifo init +//return -1 exist error + int rmb_fifo_init (StRmbFifo * pFifo, const char *pPath); + +//fifo + int rmb_fifo_send (StRmbFifo * pFifo); + +//clear notify + int rmb_fifo_clear_flag (StRmbFifo * pFifo); + +//*************************for queue****************************** +//typedef struct StRmbQueue +//{ +// unsigned int uiSize; +// +// //head + tail + real data +// char* pData; +// unsigned int *pHead; +// unsigned int *pTail; +// +// //real data +// char *pBlock; +// unsigned int uiBlockSize; +//}StRmbQueue; + +//queue init + int rmb_queue_init (StRmbQueue * pQue, const unsigned int size); + +//enqueue + int rmb_queue_enqueue (StRmbQueue * pQue, const char *data, + unsigned int uiDataLen, unsigned int uiFLow); + +//dequeue + int rmb_queue_dequeue (StRmbQueue * pQue, char *buf, unsigned int uiBufSize, + unsigned int *pDataLen, unsigned int *pFlowId); + +//try deuque + int rmb_queue_try_dequeue (StRmbQueue * pQue, char *buf, + unsigned int uiBufSize, unsigned int *pDataLen, + unsigned int *pFlowId); + +//get stat + int rmb_queue_get_stat (StRmbQueue * pQue); + +//*************************for pipe***************************** +//typedef struct StRmbPipe +//{ +// int fd[2]; +// int r_fd; +// int w_fd; +//}StRmbPipe; + +//pipe init +//return -1 exist error + int rmb_pipe_init (StRmbPipe * pPipe); + +//pipe + int rmb_pipe_send (StRmbPipe * pPipe); + +//clear notify + int rmb_pipe_clear_flag (StRmbPipe * pPipe); + +//*************************for mq & notify*********************** +//typedef struct StMqInfo +//{ +// StRmbMq* mq; +// StRmbFifo* fifo; +// +// //for wemq +// StRmbQueue *que; +// StRmbPipe *pipe; +// +// int iIndex; //offset in vector +// int iMsgType; //iPkgType,1 queue msg;2 rr topic msg;3 broadcast msg;4 manage msg +// +// rmb_callback_func func; +// rmb_callback_func_v2 funcForNew; +// void* args; +// +// //for epoll +// int active; +// +// //for notify num +// int iCount; +// unsigned int uiLastCheckTime; +// +// int iMergeNotifyFLag; //0:not marge 1:marge +// int iNotifyFactor; //the factor of notify +//}StMqInfo; + +//enum RmbMqIndex +//{ +// req_mq_index = 1, +// rr_rsp_mq_index = 2, +// broadcast_mq_index = 3, +// manage_mq_index = 4, +// +// wemq_req_mq_index = 5, +// wemq_rr_rsp_mq_index = 6, +// wemq_broadcast_mq_index = 7, +// wemq_manage_mq_index = 8, +//}; +// +////for mq notify +//typedef struct StRmbMqFifoNotify +//{ +// StMqInfo vecMqInfo[MAX_MQ_NUMS]; +// int iMqNum; +// +// StMqInfo* mqIndex[MAX_MQ_NUMS]; //see define of RmbMqIndex +// //for select +// fd_set readFd; +// fd_set tmpReadFd; +// struct timeval tv; +// int iMaxFd; +// +// //for epoll +// int iEpollFd; +// +// char* pBuf; +// unsigned int uiBufLen; +// int type; +// +//}StRmbMqFifoNotify; + +//******************************************************function******************************s + + int rmb_notify_init (StRmbMqFifoNotify * pMqNotify); + +//notify add + int rmb_notify_add (StRmbMqFifoNotify * pMqNotify, StRmbMq * mq, + StRmbFifo * fifo, const enum RmbMqIndex iMsgType, + rmb_callback_func func, void *func_argv); + +//enqueue +//-1:error argv +//-2:not enough space +//-3:enquque error +//-4:notify send failed + int rmb_notify_enqueue_by_type (StRmbMqFifoNotify * pMqNotify, + const enum RmbMqIndex uiMsgType, + const unsigned int uiCurTime, + const char *data, unsigned int uiDataLen); + +//enqueue +//-1:error argv +//-2:not enough space +//-3:enquque error +//-4:notify send failed + int rmb_notify_enqueue (const unsigned int uiCurTime, StMqInfo * pMqInfo, + const char *data, unsigned int uiDataLen); + +//dequeue + int rmb_notify_dequeue (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen); + +//try dequeue + int rmb_notify_try_dequeue (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen); + +//**************select or epoll************************* +//select fifo fd +//return >0 the mq index which has msg +// =0 all mq has no msg +// <0 all mq has no msg +//int rmb_notify_select(StRmbMqFifoNotify* pMqNotify, unsigned int uiSec, unsigned int uiUsec); + +//epoll mq + int rmb_notify_epoll (StRmbSub * pStRmbSub, int iTimeout); + +//filter rmb msg + int rmb_epoll_msg_filter (StRmbSub * pStRmbSub, StRmbMsg * pReceiveMsg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_msg.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_msg.h new file mode 100644 index 0000000000..e606ed9fb5 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_msg.h @@ -0,0 +1,163 @@ +// 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. + +#ifndef RMB_MSG_H_ +#define RMB_MSG_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "rmb_define.h" + + int rmb_msg_clear (StRmbMsg * pStMsg); + int rmb_msg_init (StRmbMsg * pRmbMsg, StRmbConfig * pConfig, + enum RMB_API_YPE type); + +//set fields +//you must fill in under fields + int rmb_msg_set_bizSeqNo (StRmbMsg * pRmbMsg, const char *cBizSeqNo); + + int rmb_msg_set_consumerSysVersion (StRmbMsg * pRmbMsg, + const char *cConsumerSysVersion); + + int rmb_msg_set_consumerSeqNo (StRmbMsg * pRmbMsg, + const char *cConsumerSeqNo); + + int rmb_msg_set_orgSysId (StRmbMsg * pRmbMsg, const char *cOrgSysId); + +//dyed msg,optional + int rmb_msg_set_dyedMsg (StRmbMsg * pRmbMsg, const char *sign); + +/* +Function: rmb_msg_set_dest +Description:设置发送目标 +Retrun:见rmb_error.h +*/ + + int rmb_msg_set_dest (StRmbMsg * pRmbMsg, int desType, + const char *cTargetDcn, int iServiceOrEven, + const char *cServiceId, const char *cScenario); + + int rmb_msg_set_dest_v2 (StRmbMsg * pRmbMsg, const char *cTargetDcn, + const char *cServiceId, const char *cScenario); + +//指定法人 + int rmb_msg_set_dest_v2_1 (StRmbMsg * pRmbMsg, const char *cTargetDcn, + const char *cServiceId, const char *cScenario, + const char *cTargetOrgId); + + int rmb_msg_set_live_time (StRmbMsg * pRmbMsg, unsigned long ulLiveTime); + + int rmb_msg_set_app_header (StRmbMsg * pRmbMsg, const char *appHeader, + unsigned int uiLen); + + int rmb_msg_set_content (StRmbMsg * pRmbMsg, const char *content, + unsigned int uiLen); + + const char *rmb_msg_print (StRmbMsg * pRmbMsg); + int rmb_msg_print_v (StRmbMsg * pRmbMsg); + +//获取msg的消息类型 +/** +* get msg type +* 0: undefined type +* 1: request in queue +* 2: reply package in RR +* 3: broadcast +* see: C_RMB_PKG_TYPE +*/ + int rmb_msg_get_msg_type (StRmbMsg * pRmbMsg); +//get cUniqueId + const char *rmb_msg_get_uniqueId_ptr (StRmbMsg * pRmbMsg); +//get cBizSeqNo + const char *rmb_msg_get_biz_seq_no_ptr (StRmbMsg * pRmbMsg); +//get cConsumerSeqNo + const char *rmb_msg_get_consumer_seq_no_ptr (StRmbMsg * pRmbMsg); +//get cConsumerDcn + const char *rmb_msg_get_consumer_dcn_ptr (StRmbMsg * pRmbMsg); +//get cOrgSysId + const char *rmb_msg_get_org_sys_id_ptr (StRmbMsg * pRmbMsg); +//get cOrgId + const char *rmb_msg_get_org_id_ptr (StRmbMsg * pRmbMsg); + +//get dest.cDestName + int rmb_msg_get_dest (StRmbMsg * pRmbMsg, char *dest, unsigned int *uiLen); + const char *rmb_msg_get_dest_ptr (StRmbMsg * pRmbMsg); + +//get cConsumerSysId + int rmb_msg_get_consumerSysId (StRmbMsg * pRmbMsg, char *cConsumerSysId, + unsigned int *uiLen); + const char *rmb_msg_get_consumerSysId_ptr (StRmbMsg * pRmbMsg); + +//cConsumerSvrId + int rmb_msg_get_consumerSvrId (StRmbMsg * pRmbMsg, char *cConsumerSvrId, + unsigned int *uiLen); + const char *rmb_msg_get_consumerSvrId_ptr (StRmbMsg * pRmbMsg); + +//获取appHeader + int rmb_msg_get_app_header (StRmbMsg * pRmbMsg, char *userHeader, + unsigned int *pLen); + +//获取appHeader指针 + const char *rmb_msg_get_app_header_ptr (StRmbMsg * pRmbMsg, + unsigned int *pLen); + +//获取消息内容 + int rmb_msg_get_content (StRmbMsg * pRmbMsg, char *content, + unsigned int *pLen); + +//获取消息内容指针 + const char *rmb_msg_get_content_ptr (StRmbMsg * pRmbMsg, + unsigned int *pLen); + +//将2进制buf反序列化为rmbMsg + int shift_buf_2_msg (StRmbMsg * pStMsg, const char *cBuf, + unsigned int uiLen); + +//将rmbMsg序列化成2进制buf + int shift_msg_2_buf (char *cBuf, unsigned int *pLen, + const StRmbMsg * pStMsg); + +//rmbMsg各必填字段校验 + int rmb_check_msg_valid (StRmbMsg * pStMsg); + +//获取下一个合适的连接 + int rmb_get_fit_size (const unsigned int uiLen, + const unsigned int uiMaxLen); + +//消息初始化 + StRmbMsg *rmb_msg_malloc (); + +//消息释放 + int rmb_msg_free (StRmbMsg * pRmbMsg); + +//wemq json message to rmb msg + int trans_json_2_rmb_msg (StRmbMsg * pStMsg, const char *bodyJson, + const char *command); + +//set extfields something to rmb msg + int set_extfields_2_rmb_msg (StRmbMsg * pStMsg, const char *command, + int iSeq); + +//生成uuid + int rmb_msg_random_uuid (char *puuid, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_pub.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_pub.h new file mode 100644 index 0000000000..7dcb435841 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_pub.h @@ -0,0 +1,157 @@ +// 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. + +/** + * rmb_pub.h + * ---rmb的发包管理,包括发送广播、RR模式等 + * + * History: + * 2014-11-06 RR模式、发topic包 + */ +#ifndef RMB_PUB_H_ +#define RMB_PUB_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "rmb_define.h" +#include "rmb_msg.h" +#include "message_log_api.h" + + typedef struct StRmbPub + { + StContext *pContext; + //StConfig config; + //for rr send msg + char cRrReplyTopic[200]; + int uiContextNum; //是否已经初始化 + + //for control send to wemq or solace + unsigned long ulLastTime; + unsigned int uiWeight; + + pthread_mutex_t pubMutex; //临界区 + StRmbMsg *pSendMsg; + StRmbMsg *pRcvMsg; + char pkgBuf[MAX_GSL_REQ_BUF_SIZE]; + char printGslBuf[1000]; + } StRmbPub; + +/** +Function: rmb_pub_init +Description:initialize +Retrun: + 0 --success + -1 --failed +*/ + int rmb_pub_init (StRmbPub * rmb_pub); + + int rmb_pub_init_python (); + +/** +Function: rmb_pub_send_and_receive +Description:send message and wait for report +Retrun: + 0 --success + -1 --timeout + -2 --error +*/ + int rmb_pub_send_and_receive (StRmbPub * rmb_pub, StRmbMsg * pSendMsg, + StRmbMsg * pRevMsg, unsigned int uiTimeOut); + int rmb_pub_send_and_receive_python (StRmbMsg * pSendMsg, + StRmbMsg * pRevMsg, + unsigned int uiTimeOut); + +/** +Function: rmb_pub_send_msg +Description:send message +Retrun: + 0 --success + -1 --failed + -2 --queue full +*/ + int rmb_pub_send_msg (StRmbPub * rmb_pub, StRmbMsg * pStMsg); + + int rmb_pub_send_msg_python (StRmbMsg * pStMsg); + +/** +Function: rmb_pub_send_rr_msg +Description:send RR asynchronous message +Retrun: + 0 --success + -1 --failed + -2 --queue full +*/ + int rmb_pub_send_rr_msg_async (StRmbPub * rmb_pub, StRmbMsg * pStMsg, + unsigned int uiTimeOut); + int rmb_pub_send_rr_msg_async_python (StRmbMsg * pStMsg, + unsigned int uiTimeOut); + +/** +Function: rmb_pub_reply_msg +Description:send report packet +Retrun: + 0 --success + -1 --failed +*/ + int rmb_pub_reply_msg (StRmbPub * pRmbPub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg); + +/** +Function: rmb_pub_close +Description:close pub +Retrun: + 0 --success + -1 --failed +*/ + int rmb_pub_close (StRmbPub * pRmbPub); + int rmb_pub_close_python (); + +/** +Function: rmb_pub_close_v2 +Description:close pub对象,2.0.12后使用 +Retrun: + 0 --success + -1 --failed +*/ + int rmb_pub_close_v2 (StRmbPub * pRmbPub); + + int rmb_pub_encode_thread_msg (unsigned int uiCmd, + StWemqThreadMsg * ptThreadMsg, + StRmbMsg * ptSendMsg, + unsigned long ulTimeToAlive); + +/** + * 给GSL发送染色消息 + */ + int rmb_pub_send_dyed_msg_to_gsl (StRmbPub * pStPub); + +//extern StRmbPub *pRmbGlobalPub; + +/* + * send log to logserver by wemq + * when iLogPoint is RMB_LOG_ON_ERROR, need iErrCode, cErrMsg + * others, not need + */ +//int rmb_send_log_to_logserver(StRmbMsg *pStMsg, int iContextType, int iLogPoint, int iErrCode, char* cErrMsg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_sub.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_sub.h new file mode 100644 index 0000000000..8ab677e3d8 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_sub.h @@ -0,0 +1,335 @@ +// 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. + +#ifndef RMB_SUB_H_ +#define RMB_SUB_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include "rmb_msg.h" +#include "rmb_context.h" +#include "rmb_define.h" +#include "rmb_udp.h" + + typedef struct StRmbSub + { + StContext *pStContext; + unsigned int uiContextNum; + //for rr reply topic + char cRrReply[255]; + unsigned int uiInitFlag; + //for filter unlisten receive msg + //unsigned int uiFlagForFilter; //rr异步与sub做区分 + //unsigned int uiFlagForSubType; + st_rmb_queue_info *pQueueInfo; + int iQueueNum; + //char **cTopic; + //int iTopicNum; + /* + //for rev req + int iReqPort; + + //for rev reply + int iReplyPort; + + //for rev broadcast + int iBroadcastPort; + */ + } StRmbSub; + +/** + * Function: rmb_sub_init + * Description: rmb sub对象初始化 + * Return: + * 见rmb_errno.h文件 + */ + int rmb_sub_init (StRmbSub * stRmbSub); + + int rmb_sub_init_python (); + +/** + * Function: rmb_sub_add_reveive_req + * Description: init, sub add receive queue request packet + * Return: + * 见rmb_errno.h文件 + */ +#define rmb_sub_add_reveive_req_by_udp rmb_sub_add_reveive_req + int rmb_sub_add_reveive_req (StRmbSub * stRmbSub, + unsigned short usRevReqPort); + +/* +* Function: rmb_sub_add_reveive_req_by_mq +* Description:初始化接收请求的操作(使用mq接收) +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_req_by_mq (StRmbSub * stRmbSub, + rmb_callback_func func, void *func_argv); + +/* +* Function: rmb_sub_add_reveive_req_by_mq_v2 +* Description:初始化接收请求的操作(使用mq接收),自定义mq的key +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_req_by_mq_v2 (StRmbSub * stRmbSub, + const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + + int rmb_sub_add_reveive_req_by_mq_python (const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + +/* +Function: rmb_sub_get_receve_req_mq +Description:获取接收请求的mq对象 +* Return: +* 见rmb_errno.h文件 +*/ + StMqInfo *rmb_sub_get_receve_req_mq (StRmbSub * stRmbSub); + +/* +Function: rmb_sub_add_reveive_rsp +Description:初始化接收回包(使用UDP) +* Return: +* 见rmb_errno.h文件 +*/ +#define rmb_sub_add_reveive_rsp_by_udp rmb_sub_add_reveive_rsp + int rmb_sub_add_reveive_rsp (StRmbSub * stRmbSub, + unsigned short usRevRspPort); + +/* +Function: rmb_sub_add_reveive_rsp_by_mq +Description:初始化接收回包(使用mq) +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_rsp_by_mq (StRmbSub * stRmbSub, + rmb_callback_func func, void *func_argv); + +/* +Function: rmb_sub_add_reveive_rsp_by_mq_v2 +Description:初始化接收回包(使用UDP),自定义mq key +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_rsp_by_mq_v2 (StRmbSub * stRmbSub, + const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + + int rmb_sub_add_reveive_rsp_by_mq_python (const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + +/* +Function: rmb_sub_get_receve_rsp_mq +Description:获取接收回包的mq对象 +* Return: +* 见rmb_errno.h文件 +*/ + StMqInfo *rmb_sub_get_receve_rsp_mq (StRmbSub * stRmbSub); + +/* +Function: rmb_sub_add_reveive_broadcast +Description:初始化接收广播(使用UDP) +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_broadcast (StRmbSub * stRmbSub, + unsigned short usRevBroadcastPort); + +/* +Function: rmb_sub_add_reveive_broadcast_by_mq +Description:初始化接收广播(使用mq) +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_broadcast_by_mq (StRmbSub * stRmbSub, + rmb_callback_func func, + void *func_argv); + +/* +Function: rmb_sub_add_reveive_broadcast_by_mq_v2 +Description:初始化接收回包(使用mq),自定义mq key +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_add_reveive_broadcast_by_mq_v2 (StRmbSub * stRmbSub, + const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv); + int rmb_sub_add_reveive_broadcast_by_mq_python (const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int + uiShmSize, + rmb_callback_func func, + void *func_argv); + +/* +Function: rmb_sub_get_receve_broadcast_mq +Description:获取接收回包mq对象 +* Return: +* 见rmb_errno.h文件 +*/ + StMqInfo *rmb_sub_get_receve_broadcast_mq (StRmbSub * stRmbSub); + +/* +Function: rmb_sub_get_fd +Description:获取mq对象的fd +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_get_fd (StMqInfo * pMqInfo); + +/* +Function: rmb_sub_receive_from_mq +Description:从mq中获取消息 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_receive_from_mq (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen); + +/* +Function: rmb_sub_try_receive_from_mq +Description:尝试从mq中获取消息 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_try_receive_from_mq (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen); + +/* +Function: rmb_sub_add_listen +Description:听queue +* Return: +* 见rmb_errno.h文件 +*/ +//int rmb_sub_add_listen(StRmbSub *pStRmbSub, const char *cOwnDcn, int iServiceOrEven, const char *cServiceId, const char *cScenario); + int rmb_sub_add_listen (StRmbSub * pStRmbSub, + const st_rmb_queue_info * pQueueInfo, + unsigned int uiQueueSize); + + int rmb_sub_add_listen_python (const st_rmb_queue_info * pQueueInfo, + unsigned int uiQueueSize); + +/* +Function: rmb_sub_add_listen_broadcast +Description:听topic +* Return: +* 见rmb_errno.h文件 +*/ +//int rmb_sub_add_listen_broadcast(StRmbSub *pStRmbSub, const char *cOwnDcn, const char *cServiceId, const char *cScenario); + +/* +Function: rmb_sub_do_receive +Description:听queue +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_do_receive (StRmbSub * pStRmbSub, int iTimeout); + + int rmb_sub_do_receive_python (); + +/* +Function: rmb_sub_reply_msg +Description:回复消息 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_reply_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg); + + int rmb_sub_reply_msg_python (StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg); + +/* +Function: rmb_sub_ack_msg +Description:ack消息 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_ack_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg); + +/* +Function: rmb_sub_close +Description:关闭rmb_sub对象 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_close (StRmbSub * pStRmbSub); + int rmb_sub_close_python (); + +/* +Function: rmb_sub_close_v2 +Description:关闭rmb_sub对象,2.0.12后使用 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_close_v2 (StRmbSub * pStRmbSub); + +/* +Function: rmb_sub_stop_receive +Description:rmb_sub停止接受queue消息 +* Return: +* 见rmb_errno.h文件 +*/ + int rmb_sub_stop_receive (StRmbSub * pStRmbSub); + int rmb_sub_stop_receive_python (); + +/* +Function: rmb_sub_check_req_mq_is_null +Description:校验是否请求队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ + int rmb_sub_check_req_mq_is_null (StRmbSub * pStRmbSub); + + unsigned long rmb_get_topic_thread_id (); + +/** + * 专用于监听wemq的旁路topic + */ +//int rmb_sub_add_listen_topic_bypass(StRmbSub *pStRmbSub, const char *cTopic); + int rmb_sub_add_listen_topic_bypass (StRmbSub * pStRmbSub, + const char **cTopic, + unsigned int uiTopicSize); + + unsigned long rmb_get_topic_thread_id (); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_udp.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_udp.h new file mode 100644 index 0000000000..7dc9e7180c --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_udp.h @@ -0,0 +1,78 @@ +// 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. + +#ifndef _UDP_SOCKET_FOR_RMB_H_ +#define _UDP_SOCKET_FOR_RMB_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include /* required for ip.h */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////// +#include "rmb_define.h" +//////////////////////// + + typedef struct sockaddr_in StSockAddr; + + int udp_get_socket (const char *host, const char *serv, + socklen_t * addrlenp); + + int udp_server (const char *pszHost, unsigned short usPort); + + int check_socket (int iSocket, fd_set * stReadFds, int iNFd); + + int check_socket_with_timeout (int iSocket, fd_set * pStReadFds, int iNfd, + int sec, int usec); + + int check_and_process_socket (int iSocket, fd_set * stReadFds, + char *cPkgBuf, const unsigned int uiMaxLen, + unsigned int *pPkgLen); + + int tcp_nodelay (int iSockfd); + + int get_host_name (char *hostName, unsigned int uiHostNameLen); + + int get_local_ip (char *addr, unsigned int uiAddrLen); + + int get_local_ip_v2 (char *addr, unsigned int uiAddrLen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/rmb_vector.h b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_vector.h new file mode 100644 index 0000000000..31055477ae --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/rmb_vector.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef __RMB_VECTOR_H_ +#define __RMB_VECTOR_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include +#include "rmb_define.h" + +#define MAX_SIZE_PER_TIME 1024 + + void Init (Array * this); + void _constructor (Array * this); + void _destructor (Array * this); + void _input (DataType data, Array * this); + int _get_size (Array * this); + DataType _return_index_value (Array * this, int index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/wemq_fifo.h b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_fifo.h new file mode 100644 index 0000000000..eed6129af9 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_fifo.h @@ -0,0 +1,639 @@ +// 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. + +/* + * API : + * DEFINE_WEMQ_KFIFO : statically allocated FIFO object + * DECLARE_WEMQ_KFIFO : declare a FIFO object + * DECLARE_WEMQ_KFIFO_PTR: declare a pointer whitch point to a FIFO object + * INIT_WEMQFIFO : init a FIFO object + * + * wemq_kfifo_len : return the num of element that in the fifo + * wemq_kfifo_peek_len: return the num of bytes that in use + * + * wemq_kfifo_is_empty: retruns true if the fifo is empty + * wemq_kfifo_is_full : returns true if the fifo is full + * wemq_kfifo_is_avail: returns the numer of unused elements in the fifo + * wemq_kfifo_skip : skip a element in fifo + * + * wemq_kfifo_alloc : dynamically allocates a new fifo buffer + * wemq_kfifo_free : frees the fifo + * + * wemq_kfifo_put : copies the given value into the fifo (by element) + * wemq_kfifo_get : reads a element from the fifo + * wemq_kfifo_peek : reads a element from the fifo without removing it form the fifo + * + * wemq_kfifo_in : copies the given buffer into the fifo and returnns the number of copied elements + * wemq_kfifo_out : get some elements form the fifo and return the numbers of elements + * wemq_kfifo_out_peek: get the data from the fifo and return the numbers of elements copied. These elements is not removed from the fifo + * + */ + +#ifndef _WEMQ_WEMQ_KFIFO_H +#define _WEMQ_WEMQ_KFIFO_H +#ifdef __cplusplus +extern "C" +{ +#endif +//#include +//#include +//#include + +#define __u32 uint32_t +#define __u64 uint64_t +#define __must_check __attribute__((warn_unused_result)) + +#define __must_be_array(arr) 0 +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) + + enum + { + KFIFO_EINVAL = -1, + KFIFO_ENOMEM = -2 + }; + + static inline int fls (int x) + { + int r; + + __asm__ ("bsrl %1,%0\n\t" + "jnz 1f\n\t" "movl $-1,%0\n" "1:":"=r" (r):"rm" (x)); + return r + 1; + } + + static inline int fls64 (__u64 x) + { + __u32 h = x >> 32; + if (h) + return fls (h) + 32; + return fls (x); + } + + static inline unsigned fls_long (unsigned long l) + { + if (sizeof (l) == 4) + return fls (l); + return fls64 (l); + } + + static inline unsigned long roundup_pow_of_two (unsigned long x) + { + return 1UL << fls_long (x - 1); + } + + struct __wemq_kfifo + { + unsigned int in; + unsigned int out; + unsigned int mask; + unsigned int esize; + void *data; + }; + +#define __STRUCT_WEMQ_KFIFO_COMMON(datatype, recsize, ptrtype) \ + union { \ + struct __wemq_kfifo wemq_kfifo; \ + datatype *type; \ + const datatype *const_type; \ + char (*rectype)[recsize]; \ + ptrtype *ptr; \ + ptrtype const *ptr_const; \ + } + +#define __STRUCT_WEMQ_KFIFO(type, size, recsize, ptrtype) \ +{ \ + __STRUCT_WEMQ_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ +} + +#define STRUCT_WEMQ_KFIFO(type, size) \ + struct __STRUCT_WEMQ_KFIFO(type, size, 0, type) + +#define __STRUCT_WEMQ_KFIFO_PTR(type, recsize, ptrtype) \ +{ \ + __STRUCT_WEMQ_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[0]; \ +} + +#define STRUCT_WEMQ_KFIFO_PTR(type) \ + struct __STRUCT_WEMQ_KFIFO_PTR(type, 0, type) + +/* + * define compatibility "struct wemq_kfifo" for dynamic allocated fifos + */ + struct st_wemq_kfifo __STRUCT_WEMQ_KFIFO_PTR (unsigned char, 0, void); + +#define STRUCT_WEMQ_KFIFO_REC_1(size) \ + struct __STRUCT_WEMQ_KFIFO(unsigned char, size, 1, void) + +#define STRUCT_WEMQ_KFIFO_REC_2(size) \ + struct __STRUCT_WEMQ_KFIFO(unsigned char, size, 2, void) + +/* + * define wemq_kfifo_rec types + */ + struct wemq_kfifo_rec_ptr_1 __STRUCT_WEMQ_KFIFO_PTR (unsigned char, 1, + void); + struct wemq_kfifo_rec_ptr_2 __STRUCT_WEMQ_KFIFO_PTR (unsigned char, 2, + void); + +/* + * helper macro to distinguish between real in place fifo where the fifo + * array is a part of the structure and the fifo type where the array is + * outside of the fifo structure. + */ +#define __is_wemq_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __wemq_kfifo)) + +/** + * DECLARE_WEMQ_KFIFO_PTR - macro to declare a fifo pointer object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + */ +#define DECLARE_WEMQ_KFIFO_PTR(fifo, type) STRUCT_WEMQ_KFIFO_PTR(type) fifo + +/** + * DECLARE_WEMQ_KFIFO - macro to declare a fifo object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + */ +#define DECLARE_WEMQ_KFIFO(fifo, type, size) STRUCT_WEMQ_KFIFO(type, size) fifo + +/** + * INIT_WEMQ_KFIFO - Initialize a fifo declared by DECLARE_WEMQ_KFIFO + * @fifo: name of the declared fifo datatype + */ +#define INIT_WEMQ_KFIFO(fifo) \ +(void)({ \ + typeof(&(fifo)) __tmp = &(fifo); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + __wemq_kfifo->in = 0; \ + __wemq_kfifo->out = 0; \ + __wemq_kfifo->mask = __is_wemq_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\ + __wemq_kfifo->esize = sizeof(*__tmp->buf); \ + __wemq_kfifo->data = __is_wemq_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \ +}) + +/** + * DEFINE_WEMQ_KFIFO - macro to define and initialize a fifo + * @fifo: name of the declared fifo datatype + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + * + * Note: the macro can be used for global and local fifo data type variables. + */ +#define DEFINE_WEMQ_KFIFO(fifo, type, size) \ + DECLARE_WEMQ_KFIFO(fifo, type, size) = \ + (typeof(fifo)) { \ + { \ + { \ + .in = 0, \ + .out = 0, \ + .mask = __is_wemq_kfifo_ptr(&(fifo)) ? \ + 0 : \ + ARRAY_SIZE((fifo).buf) - 1, \ + .esize = sizeof(*(fifo).buf), \ + .data = __is_wemq_kfifo_ptr(&(fifo)) ? \ + NULL : \ + (fifo).buf, \ + } \ + } \ + } + + static inline unsigned int __must_check + __wemq_kfifo_uint_must_check_helper (unsigned int val) + { + return val; + } + + static inline int __must_check __wemq_kfifo_int_must_check_helper (int val) + { + return val; + } + +/** + * wemq_kfifo_initialized - Check if the fifo is initialized + * @fifo: address of the fifo to check + * + * Return %true if fifo is initialized, otherwise %false. + * Assumes the fifo was 0 before. + */ +#define wemq_kfifo_initialized(fifo) ((fifo)->wemq_kfifo.mask) + +/** + * wemq_kfifo_esize - returns the size of the element managed by the fifo + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_esize(fifo) ((fifo)->wemq_kfifo.esize) + +/** + * wemq_kfifo_recsize - returns the size of the record length field + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_recsize(fifo) (sizeof(*(fifo)->rectype)) + +/** + * wemq_kfifo_size - returns the size of the fifo in elements + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_size(fifo) ((fifo)->wemq_kfifo.mask + 1) + +/** + * wemq_kfifo_reset - removes the entire fifo content + * @fifo: address of the fifo to be used + * + * Note: usage of wemq_kfifo_reset() is dangerous. It should be only called when the + * fifo is exclusived locked or when it is secured that no other thread is + * accessing the fifo. + */ +#define wemq_kfifo_reset(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->wemq_kfifo.in = __tmp->wemq_kfifo.out = 0; \ +}) + +/** + * wemq_kfifo_reset_out - skip fifo content + * @fifo: address of the fifo to be used + * + * Note: The usage of wemq_kfifo_reset_out() is safe until it will be only called + * from the reader thread and there is only one concurrent reader. Otherwise + * it is dangerous and must be handled in the same way as wemq_kfifo_reset(). + */ +#define wemq_kfifo_reset_out(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->wemq_kfifo.out = __tmp->wemq_kfifo.in; \ +}) + +/** + * wemq_kfifo_len - returns the number of used elements in the fifo + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_len(fifo) \ +({ \ + typeof((fifo) + 1) __tmpl = (fifo); \ + __tmpl->wemq_kfifo.in - __tmpl->wemq_kfifo.out; \ +}) + +/** + * wemq_kfifo_is_empty - returns true if the fifo is empty + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_is_empty(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + __tmpq->wemq_kfifo.in == __tmpq->wemq_kfifo.out; \ +}) + +/** + * wemq_kfifo_is_full - returns true if the fifo is full + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_is_full(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + wemq_kfifo_len(__tmpq) > __tmpq->wemq_kfifo.mask; \ +}) + +/** + * wemq_kfifo_avail - returns the number of unused elements in the fifo + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_avail(fifo) \ +__wemq_kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + const size_t __recsize = sizeof(*__tmpq->rectype); \ + unsigned int __avail = wemq_kfifo_size(__tmpq) - wemq_kfifo_len(__tmpq); \ + (__recsize) ? ((__avail <= __recsize) ? 0 : \ + __wemq_kfifo_max_r(__avail - __recsize, __recsize)) : \ + __avail; \ +}) \ +) + +/** + * wemq_kfifo_skip - skip output data + * @fifo: address of the fifo to be used + */ +#define wemq_kfifo_skip(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + if (__recsize) \ + __wemq_kfifo_skip_r(__wemq_kfifo, __recsize); \ + else \ + __wemq_kfifo->out++; \ +}) + +/** + * wemq_kfifo_peek_len - gets the size of the next fifo record + * @fifo: address of the fifo to be used + * + * This function returns the size of the next fifo record in number of bytes. + */ +#define wemq_kfifo_peek_len(fifo) \ +__wemq_kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + (!__recsize) ? wemq_kfifo_len(__tmp) * sizeof(*__tmp->type) : \ + __wemq_kfifo_len_r(__wemq_kfifo, __recsize); \ +}) \ +) + +/** + * wemq_kfifo_alloc - dynamically allocates a new fifo buffer + * @fifo: pointer to the fifo + * @size: the number of elements in the fifo, this must be a power of 2 + * @gfp_mask: get_free_pages mask, passed to kmalloc() + * + * This macro dynamically allocates a new fifo buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * The fifo will be release with wemq_kfifo_free(). + * Return 0 if no error, otherwise an error code. + */ +#define wemq_kfifo_alloc(fifo, size) \ +__wemq_kfifo_int_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + __is_wemq_kfifo_ptr(__tmp) ? \ + __wemq_kfifo_alloc(__wemq_kfifo, size, sizeof(*__tmp->type)) : \ + -KFIFO_EINVAL; \ +}) \ +) + +/** + * wemq_kfifo_free - frees the fifo + * @fifo: the fifo to be freed + */ +#define wemq_kfifo_free(fifo) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + if (__is_wemq_kfifo_ptr(__tmp)) \ + __wemq_kfifo_free(__wemq_kfifo); \ +}) + +/** + * wemq_kfifo_init - initialize a fifo using a preallocated buffer + * @fifo: the fifo to assign the buffer + * @buffer: the preallocated buffer to be used + * @size: the size of the internal buffer, this have to be a power of 2 + * + * This macro initialize a fifo using a preallocated buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * Return 0 if no error, otherwise an error code. + */ +#define wemq_kfifo_init(fifo, buffer, size) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + __is_wemq_kfifo_ptr(__tmp) ? \ + __wemq_kfifo_init(__wemq_kfifo, buffer, size, sizeof(*__tmp->type)) : \ + -KFIFO_EINVAL; \ +}) + +/** + * wemq_kfifo_put - put data into the fifo + * @fifo: address of the fifo to be used + * @val: the data to be added + * + * This macro copies the given value into the fifo. + * It returns 0 if the fifo was full. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define wemq_kfifo_put(fifo, val) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof(*__tmp->const_type) __val = (val); \ + unsigned int __ret; \ + size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + if (__recsize) \ + __ret = __wemq_kfifo_in_r(__wemq_kfifo, &__val, sizeof(__val), \ + __recsize); \ + else { \ + __ret = !wemq_kfifo_is_full(__tmp); \ + if (__ret) { \ + (__is_wemq_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__wemq_kfifo->data) : \ + (__tmp->buf) \ + )[__wemq_kfifo->in & __tmp->wemq_kfifo.mask] = \ + *(typeof(__tmp->type))&__val; \ + __wemq_kfifo->in++; \ + } \ + } \ + __ret; \ +}) + +/** + * wemq_kfifo_get - get data from the fifo + * @fifo: address of the fifo to be used + * @val: address where to store the data + * + * This macro reads the data from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define wemq_kfifo_get(fifo, val) \ +__wemq_kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof(__tmp->ptr) __val = (val); \ + unsigned int __ret; \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + if (__recsize) \ + __ret = __wemq_kfifo_out_r(__wemq_kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !wemq_kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_wemq_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__wemq_kfifo->data) : \ + (__tmp->buf) \ + )[__wemq_kfifo->out & __tmp->wemq_kfifo.mask]; \ + __wemq_kfifo->out++; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * wemq_kfifo_peek - get data from the fifo without removing + * @fifo: address of the fifo to be used + * @val: address where to store the data + * + * This reads the data from the fifo without removing it from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define wemq_kfifo_peek(fifo, val) \ +__wemq_kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof(__tmp->ptr) __val = (val); \ + unsigned int __ret; \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + if (__recsize) \ + __ret = __wemq_kfifo_out_peek_r(__wemq_kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !wemq_kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_wemq_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__wemq_kfifo->data) : \ + (__tmp->buf) \ + )[__wemq_kfifo->out & __tmp->wemq_kfifo.mask]; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * wemq_kfifo_in - put data into the fifo + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * + * This macro copies the given buffer into the fifo and returns the + * number of copied elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define wemq_kfifo_in(fifo, buf, n) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof(__tmp->ptr_const) __buf = (buf); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + (__recsize) ?\ + __wemq_kfifo_in_r(__wemq_kfifo, __buf, __n, __recsize) : \ + __wemq_kfifo_in(__wemq_kfifo, __buf, __n); \ +}) + +/** + * wemq_kfifo_out - get data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get some data from the fifo and return the numbers of elements + * copied. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define wemq_kfifo_out(fifo, buf, n) \ +__wemq_kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof(__tmp->ptr) __buf = (buf); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + (__recsize) ?\ + __wemq_kfifo_out_r(__wemq_kfifo, __buf, __n, __recsize) : \ + __wemq_kfifo_out(__wemq_kfifo, __buf, __n); \ +}) \ +) + +/** + * wemq_kfifo_out_peek - gets some data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get the data from the fifo and return the numbers of elements + * copied. The data is not removed from the fifo. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define wemq_kfifo_out_peek(fifo, buf, n) \ +__wemq_kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof(__tmp->ptr) __buf = (buf); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __wemq_kfifo *__wemq_kfifo = &__tmp->wemq_kfifo; \ + (__recsize) ? \ + __wemq_kfifo_out_peek_r(__wemq_kfifo, __buf, __n, __recsize) : \ + __wemq_kfifo_out_peek(__wemq_kfifo, __buf, __n); \ +}) \ +) + + extern int __wemq_kfifo_alloc (struct __wemq_kfifo *fifo, unsigned int size, + size_t esize); + + extern void __wemq_kfifo_free (struct __wemq_kfifo *fifo); + + extern int __wemq_kfifo_init (struct __wemq_kfifo *fifo, void *buffer, + unsigned int size, size_t esize); + + extern unsigned int __wemq_kfifo_in (struct __wemq_kfifo *fifo, + const void *buf, unsigned int len); + + extern unsigned int __wemq_kfifo_out (struct __wemq_kfifo *fifo, + void *buf, unsigned int len); + + extern unsigned int __wemq_kfifo_out_peek (struct __wemq_kfifo *fifo, + void *buf, unsigned int len); + + extern unsigned int __wemq_kfifo_in_r (struct __wemq_kfifo *fifo, + const void *buf, unsigned int len, + size_t recsize); + + extern unsigned int __wemq_kfifo_out_r (struct __wemq_kfifo *fifo, + void *buf, unsigned int len, + size_t recsize); + + extern unsigned int __wemq_kfifo_len_r (struct __wemq_kfifo *fifo, + size_t recsize); + + extern void __wemq_kfifo_skip_r (struct __wemq_kfifo *fifo, size_t recsize); + + extern unsigned int __wemq_kfifo_out_peek_r (struct __wemq_kfifo *fifo, + void *buf, unsigned int len, + size_t recsize); + + extern unsigned int __wemq_kfifo_max_r (unsigned int len, size_t recsize); +#ifdef __cplusplus +} +#endif +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/wemq_proto.h b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_proto.h new file mode 100644 index 0000000000..1091be72a0 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_proto.h @@ -0,0 +1,562 @@ +// 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. + +//wemq-c-api与access协议 +#ifndef _WEMQ_PROXY_WORKER_PROTO_H_ +#define _WEMQ_PROXY_WORKER_PROTO_H_ + +#include +#include +#include +#include + +//#pragma pack(1) +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SERVICE_ID_LENGTH 9 +#define SCENE_ID_LENGTH 3 +#define MAX_LISTEN_SIZE 100 + +#define BYTES_LENGTH ((2<<8)-1) +#define WORD_LENGTH ((2<<16)-1) +#define DWORD_LENGTH ((2<<32)-1) + +#define MAX_MSG_WEMQ_MSG_SIZE 2200000 + +/** + * wemq建立监听topic时,在2.0.8版本之前的流程为: + * 第一阶段 发送hello world, access会建立CLIENT Hello session, new出producer和consumer,耗时大约4s + * 第二阶段发送订阅命令,access的subscribe会同时start和consumer,后续的第二次subscribe会有大量的topic not exist,命令如下: + * --- subscribe(51, "订阅(不区分同步/异步) topic") --- + * --- unsubscribe(50, "取消注册服务 --- topic") --- + * --- subscribeTopic(53, "订阅服务(不区分同步/异步) -- 针对非类似生产的topic,例如ft-bq-bypass") --- + * --- unsubscribeTopic(52, "取消注册服务 -- 针对非类似生产的topic, 例如ft-bq-bypass") --- + * + * 在2.0.8版本为了解决access使用wemq的sub和start时序问题,修改为如下: + * 第一阶段 发送hello world, access会建立CLIENT Hello session, new出producer和consumer,耗时大约1s + * 第二阶段只subscribe, 如果客户端有多个topic,则循环发出sub命令, access收到,会sub在第一阶段建立的consumer上,耗时大约30ms + * 第三阶段api发送start命令给access, access会Listen,将ready好的带上了subscribe信息的consumer启动起来,正式开始收发消息, 耗时大约是3s + * 命令字如下: + * --- subscribe(61, "订阅(不区分同步/异步) topic") --- + * --- unsubscribe(60, "取消注册服务 --- topic") --- + * --- subscribeTopic(63, "订阅服务(不区分同步/异步) -- 针对非类似生产的topic,例如ft-bq-bypass") --- + * --- unsubscribeTopic(62, "取消注册服务 -- 针对非类似生产的topic, 例如ft-bq-bypass") --- + * start命令字: + * listen request: + * decode|length=295|headerLength=291|bodyLength=0|header={"type":123,"time":1497331206231,"seq":8995349179,"status":0,"idc":"ft","ip":"10.39.84.50"}|body=null. + * listen response: + * encode|length=299|headerLength=291|bodyLength=0|header={"type":123,"time":1497331206231,"seq":8995349179,,"status":0,"idc":"ft","ip":"10.39.84.50"}|body=null. + * + * 在2.0.12版本,采用新的wemq-access协议 http://rpddoc.weoa.com/index.php?s=/389&page_id=3967 + +enum CMD_FOR_WEMQ_PROXY_WORKER +{ + //proxy offer + //client(worker)-->server(proxy) + WEMQ_CMD_HELLO = 0, //客户端上线通知 + WEMQ_CMD_GOODBYE = 88, //客户端离线通知 + WEMQ_CMD_CLIENTGOODBYE = 881, //客户端主动离线通知 + WEMQ_CMD_SERVERGOODBYE = 882, //access端主动离线通知 + WEMQ_CMD_HEARTBEAT = 66, //ECHO心跳包 + WEMQ_CMD_SYNCREQ = 10, //同步请求消息 + WEMQ_CMD_SYNCRSP = 11, //同步响应消息 + WEMQ_CMD_ASYNCRSP = 21, //RR异步响应消息 + WEMQ_CMD_ASYNCREQ = 20, //RR异步请求消息 + WEMQ_CMD_ASYNCEVENT_PUB = 30, //发送事件消息(发送端) + WEMQ_CMD_ASYNCEVENT_SUB = 31, //接收事件(订阅端) + WEMQ_CMD_ASYNCEVENT_LOG_PUB = 34, //发送事件(发送logserver的命令字) + WEMQ_CMD_BROADCAST_PUB = 40, //广播消息发送(发送端) + WEMQ_CMD_BROADCAST_SUB = 41, //广播消息接收(订阅端) + WEMQ_CMD_REDIRECT = 32, //重定向C客户端到新的ACCESS服务器 + WEMQ_CMD_SUB = 51, //订阅服务(不区分同步/异步) + WEMQ_UNSUBSCRIBE = 50, //取消注册服务 + WEMQ_ACKNOWLEDGED = 100, //ack消息 + WEMQ_UNACKNOWLEDGED = 59, //unack消息 + //由于wemq针对旁边的topic是没有dcn、服务ID等的概念,故增加如下SUB指令 + WEMQ_CMD_SUB_TOPIC = 53, //订阅topic + WEMQ_CMD_UNSUB_TOPIC = 52, //取消topic订阅 + //version 2.0.8 add, for access + WEMQ_CMD_SUB_LISTEN = 61, //订阅服务(不区分同步/异步) + WEMQ_UNSUBSCRIBE_LISTEN = 60, //取消注册服务 + //由于wemq针对旁边的topic是没有dcn、服务ID等的概念,故增加如下SUB指令 + WEMQ_CMD_SUB_TOPIC_LISTEN = 63, //订阅topic + WEMQ_CMD_UNSUB_TOPIC_LISTEN = 62, //取消topic订阅 + WEMQ_CMD_SUB_START = 123, //sub add listen之后,发送start命令 +}; +*/ + + //心跳 +#define HEARTBEAT_REQUEST "HEARTBEAT_REQUEST" //client发给server的心跳包 +#define HEARTBEAT_RESPONSE "HEARTBEAT_RESPONSE" //server回复client的心跳包 + //握手 +#define HELLO_REQUEST "HELLO_REQUEST" //client发给server的握手请求 +#define HELLO_RESPONSE "HELLO_RESPONSE" //server回复client的握手请求 + //断连 +#define CLIENT_GOODBYE_REQUEST "CLIENT_GOODBYE_REQUEST" //client主动断连时通知server +#define CLIENT_GOODBYE_RESPONSE "CLIENT_GOODBYE_RESPONSE" //server回复client的主动断连通知 +#define SERVER_GOODBYE_REQUEST "SERVER_GOODBYE_REQUEST" //server主动断连时通知client +#define SERVER_GOODBYE_RESPONSE "SERVER_GOODBYE_RESPONSE" //client回复server的主动断连通知(client不会回复,准备好之后直接断连) + //订阅管理 +#define SUBSCRIBE_REQUEST "SUBSCRIBE_REQUEST" //client发给server的订阅请求 +#define SUBSCRIBE_RESPONSE "SUBSCRIBE_RESPONSE" //server回复client的订阅请求 +#define UNSUBSCRIBE_REQUEST "UNSUBSCRIBE_REQUEST" //client发给server的取消订阅请求 +#define UNSUBSCRIBE_RESPONSE "UNSUBSCRIBE_RESPONSE" //server回复client的取消订阅请求 + //监听 +#define LISTEN_REQUEST "LISTEN_REQUEST" //client发给server的启动topic监听的请求 +#define LISTEN_RESPONSE "LISTEN_RESPONSE" //server回复client的监听请求 + +#define REQUEST_TO_SERVER "REQUEST_TO_SERVER" //client将RR请求发送给server +#define REQUEST_TO_CLIENT "REQUEST_TO_CLIENT" //server将RR请求推送给client +#define REQUEST_TO_CLIENT_ACK "REQUEST_TO_CLIENT_ACK" //client收到RR请求后回ack给server +#define RESPONSE_TO_SERVER "RESPONSE_TO_SERVER" //client将RR回包发送给server +#define RESPONSE_TO_CLIENT "RESPONSE_TO_CLIENT" //server将RR回包推送给client +#define RESPONSE_TO_CLIENT_ACK "RESPONSE_TO_CLIENT_ACK" //client收到RR回包后回ack给server + + //异步事件 +#define ASYNC_MESSAGE_TO_SERVER "ASYNC_MESSAGE_TO_SERVER" //client将异步事件发送给server +#define ASYNC_MESSAGE_TO_SERVER_ACK "ASYNC_MESSAGE_TO_SERVER_ACK" //server收到异步事件后ACK给client +#define ASYNC_MESSAGE_TO_CLIENT "ASYNC_MESSAGE_TO_CLIENT" //server将异步事件推送给client +#define ASYNC_MESSAGE_TO_CLIENT_ACK "ASYNC_MESSAGE_TO_CLIENT_ACK" // client收到异步事件后回ack给server + + //广播 +#define BROADCAST_MESSAGE_TO_SERVER "BROADCAST_MESSAGE_TO_SERVER" //client将广播消息发送给server +#define BROADCAST_MESSAGE_TO_SERVER_ACK "BROADCAST_MESSAGE_TO_SERVER_ACK" //server收到广播消息后ACK给client +#define BROADCAST_MESSAGE_TO_CLIENT "BROADCAST_MESSAGE_TO_CLIENT" //server将广播消息推送给client +#define BROADCAST_MESSAGE_TO_CLIENT_ACK "BROADCAST_MESSAGE_TO_CLIENT_ACK" //client收到异步事件后回ack给server + //日志上报 +#define TRACE_LOG_TO_LOGSERVER "TRACE_LOG_TO_LOGSERVER" //RMB跟踪日志上报,异常场景也要上报 +#define SYS_LOG_TO_LOGSERVER "SYS_LOG_TO_LOGSERVER" //业务日志上报 + //重定向指令 +#define REDIRECT_TO_CLIENT "REDIRECT_TO_CLIENT" //server将重定向指令推动给client + +#define MSG_ACK "MSG_ACK" //api 内部构造ack包命令字 + +//协议严格按照顺序,不要随便改变结构体的次序 +//严格按照encode和decode函数进行序列化和反序列化 + +//for uint64 + typedef union union64HN + { + unsigned int src[2]; + unsigned long long dest; + } union64HN; + +#define WEMQ_PROXY_MEMCPY(buf,bufLen,p,pLen) \ +if (bufLen > pLen) \ +{ \ + memcpy(buf, p, pLen); \ + return 0; \ +}\ +else \ + return -1; + +#define ENCODE_CHAR(buf,tmp)\ + *buf = tmp; \ + buf += sizeof(char); + +#define ENCODE_SHORT(buf,tmp)\ + *((short*)buf) = htons(tmp); \ + buf += sizeof(short); + +#define ENCODE_INT(buf,tmp)\ + *((int*)buf) = htonl(tmp); \ + buf += sizeof(int); + +#define ENCODE_LONG(buf,tmp)\ + *((long*)buf) = htonll_z(tmp); \ + buf += sizeof(long); + +#define DECODE_CHAR(tmp,buf,pBufLen) \ +if (*pBufLen < sizeof(char)) \ + return -2; \ + tmp = *((char*)(buf)); \ + buf += sizeof(char); \ + *pBufLen -= sizeof(char); + +#define DECODE_SHORT(tmp,buf,pBufLen)\ +if (*pBufLen < sizeof(short))\ + return -2; \ + tmp = ntohs(*((short*)buf)); \ + buf += sizeof(short); \ + *pBufLen -= sizeof(short); + +#define DECODE_INT(tmp,buf,pBufLen)\ +if (*pBufLen < sizeof(int))\ + return -2; \ + tmp = ntohl(*((int*)buf)); \ + buf += sizeof(int); \ + *pBufLen -= sizeof(int); + +#define DECODE_LONG(tmp,buf,pBufLen)\ +if (*pBufLen < sizeof(long))\ + return -2; \ + tmp = ntohll_z(*((long*)buf)); \ + buf += sizeof(long); \ + *pBufLen -= sizeof(long); + +#define ENCODE_CSTR_MEMCPY(buf, str, strLen) \ + ENCODE_CHAR(buf, strLen); \ + memcpy(buf, str, strLen); \ + buf += strLen; + +#define ENCODE_WSTR_MEMCPY(buf, str, strLen) \ + ENCODE_SHORT(buf, strLen); \ + memcpy(buf, str, strLen); \ + buf += strLen; + +/* +#define ENCODE_DWSTR_MEMCPY(buf, str, strLen) \ + ENCODE_INT(buf, strLen); \ + memcpy(buf, str, strLen); \ + buf += strLen; +*/ + +#define ENCODE_DWSTR_MEMCPY(buf, str, strLen) \ + memcpy(buf, str, strLen); \ + buf += strLen; + +#define DECODE_CSTR_MEMCPY(str, strLen, buf, pBufLen) \ + DECODE_CHAR(strLen, buf, pBufLen); \ + if (*pBufLen < strLen) return -2; \ + memcpy(str, buf, strLen); \ + buf += strLen; \ + *pBufLen -= strLen; + +#define DECODE_WSTR_MEMCPY(str, strLen, buf, pBufLen) \ + DECODE_SHORT(strLen, buf, pBufLen); \ + if (*pBufLen < strLen) return -2; \ + memcpy(str, buf, strLen);\ + buf += strLen; \ + *pBufLen -= strLen; +/* +#define DECODE_DWSTR_MEMCPY(str, strLen, buf, pBufLen) \ + DECODE_INT(strLen, buf, pBufLen); \ + if (*pBufLen < strLen) return -2; \ + memcpy(str, buf, strLen);\ + buf += strLen; \ + *pBufLen -= strLen; +*/ + +#define DECODE_DWSTR_MEMCPY(str, strLen, buf, pBufLen) \ + if (*pBufLen < strLen) return -2; \ + memcpy(str, buf, strLen);\ + buf += strLen; \ + *pBufLen -= strLen; + +//***************************0x01 心跳************************** +//请求 + typedef struct StHeartBeatReq + { + int pid; //进程号 + unsigned int uiCount; //心跳次数 + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StHeartBeatReq; + + int EncodeStHeartBeatReq (char *buf, int *pBufLen, + const StHeartBeatReq * pReq); + int DecodeHeartBeatReq (StHeartBeatReq * pReq, const char *buf, + const int bufLen); + +//回复 + typedef struct StHeartBeatRsp + { + unsigned int uiResult; //回复状态,0为ok,非0为不ok + int pid; //进程号 + unsigned int uiCount; //心跳次数 + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StHeartBeatRsp; + + int EncodeStHeartBeatRsp (char *buf, int *pBufLen, + const StHeartBeatRsp * pRsp); + int DecodeHeartBeatRsp (StHeartBeatRsp * pRsp, const char *buf, + const int bufLen); + +//***************************0x02 注册,建立连接************************** +//请求 + typedef struct StRegisterReq + { + int iPid; + char cSolaceHostLen; + char strSolaceHost[BYTES_LENGTH]; + char cSolaceVpnLen; + char strSolaceVpn[BYTES_LENGTH]; + char cSolaceUserLen; + char strSolaceUser[BYTES_LENGTH]; + char cSolacePwdLen; + char strSolacePwd[BYTES_LENGTH]; + char cConsumerIpLen; + char strConsumerIp[BYTES_LENGTH]; + char cConsumerSysIdLen; + char strConsumerSysId[BYTES_LENGTH]; + char cConsumerDcnLen; + char strConsumerDcn[BYTES_LENGTH]; + char cConsumerOrgIdLen; + char strConsumerOrgId[BYTES_LENGTH]; + char cConsumerVersionLen; + char strConsumerVersion[BYTES_LENGTH]; + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StRegisterReq; + + int EncodeStRegisterReq (char *buf, int *pBufLen, + const StRegisterReq * pReq); + int DecodeStRegisterReq (StRegisterReq * pReq, const char *buf, + const int bufLen); + + typedef struct StRegisterRsp + { + unsigned int uiResult; + unsigned int uiCcdIndex; + unsigned int uiCcdFlow; + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StRegisterRsp; + + int EncodeStRegisterRsp (char *buf, int *pBufLen, + const StRegisterRsp * pRsp); + int DecodeStRegisterRsp (StRegisterRsp * pRsp, const char *buf, + const int bufLen); + +//***********************************0x06 注册接收连接*********************************** + typedef struct StRegisterReceiveReq + { + unsigned int uiCcdIndex; + unsigned int uiCcdFlow; + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StRegisterReceiveReq; + + int EncodeStRegisterReceiveReq (char *buf, int *pBufLen, + const StRegisterReceiveReq * pReq); + int DecodeStRegisterReceiveReq (StRegisterReceiveReq * pReq, + const char *buf, const int bufLen); + + typedef struct StRegisterReceiveRsp + { + unsigned int uiResult; + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StRegisterReceiveRsp; + + int EncodeStRegisterReceiveRsp (char *buf, int *pBufLen, + const StRegisterReceiveRsp * pRsp); + int DecodeStRegisterReceiveRsp (StRegisterRsp * pRsp, const char *buf, + const int bufLen); + +//请求 + typedef struct StAddListenReq + { + char strServiceId[SERVICE_ID_LENGTH]; + char strSceneId[SCENE_ID_LENGTH]; + } StAddListenReq; + + int EncodeAddListenReq (char *buf, int *pBufLen, + const StAddListenReq * pReq); + int DecodeAddListenReq (StAddListenReq * pReq, const char *buf, + const int bufLen); + + typedef struct StAddListenRsp + { + unsigned int uiResult; //见last_error + char strServiceId[SERVICE_ID_LENGTH]; + char strSceneId[SCENE_ID_LENGTH]; + } StAddListenRsp; + + int EncodeAddListenRsp (char *buf, int *pBufLen, + const StAddListenRsp * pRsp); + int DecodeAddListenRsp (StAddListenRsp * pRsp, const char *buf, + const int bufLen); + +//***************************0x03 增加监听************************** + +//请求 + typedef struct StAddManageReq + { + char cManageTopicLength; + char strManageTopic[BYTES_LENGTH]; + } StAddManageReq; + + int EncodeAddManageReq (char *buf, int *pBufLen, + const StAddManageReq * pReq); + int DecodeAddManageReq (StAddManageReq * pReq, const char *buf, + const int bufLen); + + typedef struct StAddManageRsp + { + unsigned int uiResult; //见last_error + char cManageTopicLength; + char strManageTopic[BYTES_LENGTH]; + } StAddManageRsp; + + int EncodeAddManageRsp (char *buf, int *pBufLen, + const StAddManageRsp * pRsp); + int DecodeAddManageRsp (StAddManageRsp * pRsp, const char *buf, + const int bufLen); + +//***************************0x04 worker发包************************** +//请求 + enum WORKER_SEND_MSG_TYPE + { + SEND_EVENT_MSG_TYPE = 1, + SEND_RR_MSG_TYPE = 2, + SEND_ASYNC_RR_MSG_TYPE = 3, + SEND_REPLY_MSG_TYPE = 4, + }; + + typedef struct StSendMsgReq + { + unsigned int uiMsgType; //见WORKER_SEND_MSG_TYPE定义 + unsigned int uiWemqMsgLen; + unsigned int uiSendMsgSeq; + char strWemqMsg[MAX_MSG_WEMQ_MSG_SIZE]; + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StSendMsgReq; + + int EncodeSendMsgReq (char *buf, int *pBufLen, const StSendMsgReq * pReq); + int DecodeSendMsgReq (StSendMsgReq * pReq, const char *buf, + const int bufLen); + +//回包 + typedef struct StSendMsgRsp + { + unsigned int uiResult; + unsigned int uiMsgType; //见WORKER_SEND_MSG_TYPE定义 + unsigned int uiRecvMsgSeq; //Worker send window size; + char cUuidLen; //消息uuid长度 + char strUuid[BYTES_LENGTH]; //消息uuid + } StSendMsgRsp; + +//return -1.空间不足 + int EncodeSendMsgRsp (char *buf, int *pBufLen, const StSendMsgRsp * pRsp); + int DecodeSendMsgRsp (StSendMsgRsp * pRsp, const char *buf, + const int bufLen); + +//***************************0x05 worker发送消息ack************************** +//请求,为避免其他业务代码错误导致把其他人的msg ack掉。因此这里将sessionId和sessionIndex、flowIndex做核对。 + typedef struct StAckMsgReq + { + unsigned int uiSessionIndex; + unsigned int uiFlowIndex; + unsigned long ulMsgId; + char cUuidLen; //消息uuid长度 + char strUuid[BYTES_LENGTH]; //消息uuid + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StAckMsgReq; + + int EncodeAckMsgReq (char *buf, int *pBufLen, const StAckMsgReq * pReq); + int DecodeAckMsgReq (StAckMsgReq * pReq, const char *buf, const int bufLen); + +//回包 + typedef struct StAckMsgRsp + { + unsigned int uiResult; + unsigned int uiSessionIndex; + unsigned int uiFlowIndex; + unsigned long ulMsgId; + char cUuidLen; //消息uuid长度 + char strUuid[BYTES_LENGTH]; //消息uuid + } StAckMsgRsp; + + int EncodeAckMsgRsp (char *buf, int *pBufLen, const StAckMsgRsp * pRsp); + int DecodeAckMsgRsp (StAckMsgRsp * pRsp, const char *buf, const int bufLen); + +//以下为proxy推送消息 +//***************************0x50 proxy下发消息************************** +//请求 + enum PUSH_MSG_TYPE + { + PUSH_QUEUE_MSG = 1, + PUSH_BROADCAST_MSG = 2, + PUSH_MANAGE_MSG = 3, + PUSH_RR_REPLY_MSG = 4, + }; + + typedef struct StPushMsgReq + { + char cWemqMsgType; + unsigned int uiSeq; + unsigned int uiWemqMsgLen; + char strWemqMsg[MAX_MSG_WEMQ_MSG_SIZE]; + char cReseveLength; //一字节长度 + char strReserve[BYTES_LENGTH]; //保留字段 + } StPushMsgReq; + + int EncodePushMsgReq (char *buf, int *pBufLen, const StPushMsgReq * pReq); + int DecodePushMsgReq (StPushMsgReq * pReq, const char *buf, + const int bufLen); + +//回包 + typedef struct StPushMsgRsp + { + unsigned int uiResult; + char cUuidLen; //消息uuid长度 + char strUuid[BYTES_LENGTH]; //消息uuid + } StPushMsgRsp; + + int EncodePushMsgRsp (char *buf, int *pBufLen, const StPushMsgRsp * pRsp); + int DecodePushMsgRsp (StPushMsgRsp * pRsp, const char *buf, + const int bufLen); + +//*************************************************wemq worker-proxy包格式***************************** +//msg的组成都是header + msgBuf,其中header的头4个字节为长度, + typedef struct StWemqHeader + { + unsigned int uiPkgLen; + unsigned int uiColorFlag; + unsigned short usCmd; + unsigned int uiSessionId; + unsigned int uiSeq; + unsigned int uiReserved; + } StWemqHeader; + +#define MAX_WEMQ_HEADER_LEN (4096) +#define MAX_WEMQ_BODY_LEN (3 * 1024 * 1024) + typedef struct StWeMQMSG + { + unsigned int uiTotalLen; + unsigned int uiHeaderLen; + char cStrJsonHeader[MAX_WEMQ_HEADER_LEN]; + char cStrJsonBody[MAX_WEMQ_BODY_LEN]; + } StWeMQMSG; + + int GetWemqHeaderLen (); + int EncodeWemqHeader (char *buf, int *pBufLen, + const StWemqHeader * pHeader); + int DecodeWemqHeader (StWemqHeader * pHeader, const char *buf, + const int bufLen); + int DecodeWeMQMsg (StWeMQMSG * pMsg, const char *buf, const int bufLen); + +//��ʽ������������ + int GetAckMsgReqLength (const StAckMsgReq * pReq); + int GetAddListenReqLegth (const StAddListenReq * pReq); + int GetAddManageReqLegth (const StAddManageReq * pReq); + int GetPushMsgReqLegth (const StPushMsgReq * pReq); + int GetRegisterReceiveReqLegth (const StRegisterReceiveReq * pReq); + int GetRegisterReqLegth (const StRegisterReq * pReq); + int GetSendMsgReqLength (const StSendMsgReq * pReq); + int GetStHeartBeatReqLegth (const StHeartBeatReq * pReq); + +#ifdef __cplusplus +} +#endif +//#pragma pack() +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/wemq_tcp.h b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_tcp.h new file mode 100644 index 0000000000..4bf9c5e412 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_tcp.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef _TCP_SOCKET_FOR_WEMQ_H_ +#define _TCP_SOCKET_FOR_WEMQ_H_ +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + int wemq_tcp_connect (const char *ip, uint16_t port, int timeout); + int wemq_tcp_send (int fd, void *msg, uint32_t totalLen, uint32_t headerLen, + int iTimeOut, SSL * ssl); + int wemq_tcp_recv (int fd, void *msg, uint32_t * len, int iTimeout, + SSL * ssl); + + void wemq_getsockename (int fd, char *ip, uint32_t len, int *port); + void wemq_getpeername (int fd, char *ip, uint32_t len, int *port); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/wemq_thread.h b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_thread.h new file mode 100644 index 0000000000..670c070fd3 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_thread.h @@ -0,0 +1,113 @@ +// 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. + +#ifndef _WEMQ_THREAD_ +#define _WEMQ_THREAD_ + +#include +#include "rmb_define.h" +#define MAX_EVENT 10 +#define TCP_PKG_LEN_BTYES 4 + +#ifdef _WEMQ_THREAD_DEBUG_ +#define ASSERT(A) assert((A)) +#else +#define ASSERT(A) ((void)(0)) +#endif +enum +{ + THREAD_STATE_INIT = 0, + THREAD_STATE_CONNECT, + THREAD_STATE_REGI, + THREAD_STATE_OK, + THREAD_STATE_CLOSE, //准备关闭状态 + THREAD_STATE_SERVER_BREAK, //服务端退出状态 + THREAD_STATE_BREAK, + THREAD_STATE_RECONNECT, + THREAD_STATE_DESTROY, + THREAD_STATE_EXIT +}; + +enum +{ + THREAD_MSG_CMD_BEAT = 0x01, + THREAD_MSG_CMD_REGI = 0x02, + THREAD_MSG_CMD_ADD_LISTEN = 0x03, + THREAD_MSG_CMD_SEND_MSG = 0x04, + THREAD_MSG_CMD_SEND_MSG_ACK = 0x05, + THREAD_MSG_CMD_ADD_MANAGE = 0x06, + THREAD_MSG_CMD_SEND_REQUEST = 0x07, + THREAD_MSG_CMD_SEND_REQUEST_ASYNC = 0x08, + THREAD_MSG_CMD_SEND_REPLY = 0x09, + THREAD_MSG_CMD_START = 0x0a, + THREAD_MSG_CMD_SEND_PUSH = 0x50, + THREAD_MSG_CMD_SEND_CLIENT_GOODBYE = 0x0b, + THREAD_MSG_CMD_SEND_LOG = 0x10, + THREAD_MSG_CMD_RECV_MSG_ACK = 0x11 +}; +/* +typedef struct StWemqThreadMsg +{ + unsigned int m_iCmd; + StWemqHeader m_stWemqHeader; + void* m_stReq; +}StWemqThreadMsg; +*/ +/* +typedef struct WemqThreadCtx +{ +// STRUCT_WEMQ_KFIFO(StWemqThreadMsg, 1024)* m_ptFifo; + stContextProxy* m_ptProxyContext; + + int m_iThreadId; + char* m_pRecvBuff; + char* m_pSendBuff; + + //cache msg which from user thread; + StWemqThreadMsg m_stWemqThreadMsg; + int m_iWemqThreadMsgHandled; + + StRegisterReq m_stReqForRegister; + StAddManageReq m_stReqForAddManage; + StAddListenReq m_stReqForAddListen; + + StWemqHeader m_stWemqHeader; + + StTopicList* m_ptTopicList; + + //for epoll + int m_iEpollFd; + struct epoll_event m_stEv; + struct epoll_event* m_ptEvents; + + int m_iSockFd; + int m_iLastState; + int m_iState; + int m_contextType; + +}WemqThreadCtx; +*/ +#define GetWemqThreadMsgLen() (sizeof(StWemqThreadMsg)) + +int32_t wemq_thread_state_init (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_state_connect (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_state_regi (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_state_ok (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_state_break (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_state_reconnect (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_state_destory (WemqThreadCtx * pThreadCtx); +int32_t wemq_thread_run (WemqThreadCtx * pThreadCtx); +int32_t check_dyed_msg (StRmbMsg * rmbMsg); +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/include/wemq_topic_list.h b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_topic_list.h new file mode 100644 index 0000000000..2d0971e1ad --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/include/wemq_topic_list.h @@ -0,0 +1,53 @@ +// 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. + +#ifndef _WEMQ_TOPIC_LIST_H_ +#define _WEMQ_TOPIC_LIST_H_ +#include +#include +#include +#include + +#define WEMQ_TOPIC_MAX_LEN 100 + +typedef struct StWemqTopicProp +{ + char cServiceId[32]; + char cScenario[32]; + char cTopic[WEMQ_TOPIC_MAX_LEN]; + int flag; //flag=0, serviceid flag=1, topic + struct StWemqTopicProp *next; +} StWemqTopicProp; + +typedef struct StWemqTopicList +{ + StWemqTopicProp *next; + StWemqTopicProp *tail; +} StWemqTopicList; + +typedef int (*WEMQ_DEC_FUNC) (StWemqTopicProp * pArg); + +void wemq_topic_list_init (StWemqTopicList * ptTopicList); +int32_t wemq_topic_list_delete (StWemqTopicList * pt); +int32_t wemq_topic_list_add_node (StWemqTopicList * pt, + StWemqTopicProp * ptpp); +int32_t wemq_topic_list_find_node (StWemqTopicList * pt, + StWemqTopicProp * ptpp, + StWemqTopicProp ** pos); +int32_t wemq_topic_list_del_node (StWemqTopicList * pt, + StWemqTopicProp * ptpp); +int32_t wemq_topic_list_is_empty (StWemqTopicList * pt); +int32_t wemq_topic_list_clear (StWemqTopicList * ptTopicList); +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/makefile b/eventmesh-sdks/eventmesh-sdk-c/makefile new file mode 100644 index 0000000000..116182478f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/makefile @@ -0,0 +1,99 @@ +# 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. + +CC=gcc +RANLIB = ranlib + +RMB_VERSION=$(shell grep "RMBVERSION" include/rmb_define.h|grep -v "RMBVERSIONFORBIZ"|awk -F " |\"" '{print $$4}') + +INC = -I./include -I./src + +DIR_THIRD_PARTY = ./third_party + +DIR_CURL = $(DIR_THIRD_PARTY)/curl +INC_CURL = -I$(DIR_CURL)/include +LIB_A_CURL = $(DIR_THIRD_PARTY)/libcurl.a +LIB_CURL = -L$(DIR_THIRD_PARTY) -lcurl + +DIR_JSONC = $(DIR_THIRD_PARTY)/json-c +DIR_BUILD_JSONC = $(DIR_JSONC)/cmake/build +INC_JSONC = -I$(DIR_JSONC) -I$(DIR_BUILD_JSONC) +LIB_A_JSONC = $(DIR_THIRD_PARTY)/libjson-c.a +LIB_JSONC = -L$(DIR_THIRD_PARTY) -ljson-c + +LIB_UUID = -luuid + +LIB_OPENSSL = -lssl -lcrypto + +INC += $(INC_CURL) $(INC_JSONC) +LIB = $(LIB_CURL) $(LIB_JSONC) $(LIB_UUID) $(LIB_OPENSSL) + +CFLAGS=-Wall -g -gstabs+ -ggdb -fPIC -Wunused-function + +TARGET_STATIC = librmb.a +TARGET_DYNAMIC = librmb.so +TARGET = $(TARGET_STATIC) $(TARGET_DYNAMIC) + +OBJ = $(patsubst %.c,%.o,$(wildcard ./src/*.c)) + +all:$(TARGET) + +$(LIB_A_CURL): + @echo + @echo "Building $^ ==> $@..." + @cd $(DIR_CURL) && autoreconf -fi && ./configure --without-ssl + @cd $(DIR_CURL) && make + @cp -f $(DIR_CURL)/./lib/.libs/libcurl.a $@ + +$(LIB_A_JSONC): + @echo + @echo "Building $^ ==> $@..." + @mkdir -p $(DIR_BUILD_JSONC) + @cd $(DIR_BUILD_JSONC) && cmake ../.. + @cd $(DIR_JSONC)/cmake/build && make + @cp $(DIR_JSONC)/cmake/build/libjson-c.a $@ + +./tmp/libm.a: $(OBJ) + @echo + @echo "Building $^ ==> $@..." + @-mkdir -p ./tmp + $(AR) cq $@ $^ + $(RANLIB) $@ + +$(TARGET_STATIC): $(LIB_A_CURL) $(LIB_A_JSONC) ./tmp/libm.a + @echo + @echo "Building $^ ==> $@..." + @cp -f $(LIB_A_CURL) ./tmp + @cp -f $(LIB_A_JSONC) ./tmp + @rm -f $@ + $(AR) cqT $@ ./tmp/*.a && echo -e 'create $@\naddlib $@\nsave\nend' | $(AR) -M + +$(TARGET_DYNAMIC): $(LIB_A_CURL) $(LIB_A_JSONC) $(OBJ) + @echo + @echo "Building $^ ==> $@..." + @rm -f $@ + $(CC) -shared -fPIC $(CFLAGS) -o $@ $(OBJ) $(LIB) + +%.o: %.c + $(CC) $(CFLAGS) $(INC) -c $^ -o $@ + +.PHONY: clean +clean: + rm -rf $(TARGET) $(OBJ) ./tmp + +demo: $(TARGET_STATIC) + @echo + @echo "Building $^ ==> $@..." + $(CC) -o $@ examples/demo.c $(CCFLAGS) -I./include -L./ -l:librmb.a -luuid $(LIB_OPENSSL) -lz -pthread -lrt -dl -static-libgcc diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/common.h b/eventmesh-sdks/eventmesh-sdk-c/src/common.h new file mode 100644 index 0000000000..1c2db39639 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/common.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef COMMON_H_ +#define COMMON_H_ +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "json.h" +#include "rmb_define.h" + +// context proxy新增结构 + typedef struct json_object WEMQJSON; + typedef struct json_object PROPERTY; + + WEMQJSON *rmb_pub_encode_byte_body_for_wemq (unsigned int uiCmd, + StRmbMsg * ptSendMsg); + WEMQJSON *rmb_pub_encode_property_for_wemq (unsigned int uiCmd, + StRmbMsg * ptSendMsg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/message_log_api.c b/eventmesh-sdks/eventmesh-sdk-c/src/message_log_api.c new file mode 100644 index 0000000000..ee58205a7d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/message_log_api.c @@ -0,0 +1,397 @@ +// 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. + +#include +#include +#include +#include +#include "common.h" +#include "message_log_api.h" +#include "wemq_thread.h" + +#define gettidv1() syscall(__NR_gettid) +#define gettidv2() syscall(SYS_gettid) + +static int get_log_id (char *clogId, int size) +{ + if (0 != rmb_msg_random_uuid (clogId, size)) + { + return -1; + } + + int i = 0; + for (i = 0; i < size; i++) + { + if (*(clogId + i) == '-') + { + *(clogId + i) = '0'; + } + } + + return 0; +} + +/*headerJson={“code”:0,”command”:”SYS_LOG_TO_LOGSERVER”} + bodyJson={“id”:”839232”,”consumerId”:”5982”,”logName”:”test”,”logTimestamp”:0, + ”content”:”test”,”logType”:”sys”,”lang”:”c”,”level”:”debug”,”processId”:5176,”threadId”:0,”consumerSvrId”:”dsi”,”extFields”:{}} +*/ + +int rmb_send_sys_log_for_api (stContextProxy * pContextProxy, + const char *iLogLevel, const char *cConsumerId, + const char *cLogName, const char *cContent, + const char *extFields) +{ + + if (pContextProxy == NULL || NULL == extFields) + { + LOGRMB (RMB_LOG_ERROR, "pContextProxy or extFields is null"); + return -1; + } + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_LOG; + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object for jsonHeader failed"); + return -1; + } + + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (SYS_LOG_TO_LOGSERVER)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object for jsonBody failed"); + json_object_put (jsonHeader); + return -1; + } + char cLogId[33] = { 0 }; + + if (0 != get_log_id (cLogId, sizeof (cLogId))) + { + LOGRMB (RMB_LOG_ERROR, "get_log_id failed"); + return -1; + } + + GetRmbNowLongTime (); + json_object_object_add (jsonBody, LOG_MSG_COM_ID, + json_object_new_string (cLogId)); + json_object_object_add (jsonBody, LOG_MSG_COM_CONSUMERID, + json_object_new_string (cConsumerId)); + json_object_object_add (jsonBody, LOG_MSG_COM_LOGNAME, + json_object_new_string (cLogName)); + json_object_object_add (jsonBody, LOG_MSG_COM_TIMESTAMP, + json_object_new_int64 (pRmbStConfig->ulNowTtime)); + json_object_object_add (jsonBody, LOG_MSG_COM_CONTENT, + json_object_new_string (cContent)); + json_object_object_add (jsonBody, LOG_MSG_COM_LOGTYPE, + json_object_new_string ("sys")); + json_object_object_add (jsonBody, LOG_MSG_COM_LANG, + json_object_new_string ("c")); + json_object_object_add (jsonBody, LOG_MSG_COM_PROCESSID, + json_object_new_int ((int) getpid ())); + json_object_object_add (jsonBody, LOG_MSG_COM_THREADID, + json_object_new_int64 ((long int) gettidv1 ())); + json_object_object_add (jsonBody, LOG_MSG_COM_CONSUMERSVRID, + json_object_new_string (pRmbStConfig->cHostIp)); + json_object_object_add (jsonBody, LOG_MSG_COM_LEVEL, + json_object_new_string (iLogLevel)); + + WEMQJSON *jsonExtFields = json_tokener_parse (extFields); + WEMQJSON *tmp = NULL; + if (jsonExtFields == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_tokener_parse extFields failed"); + tmp = json_tokener_parse ("{}"); + json_object_object_add (jsonBody, LOG_MSG_COM_EXTFIELDS, tmp); + } + else + { + json_object_object_add (jsonBody, LOG_MSG_COM_EXTFIELDS, jsonExtFields); + } + const char *header_str = json_object_get_string (jsonHeader); + + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_get_string for header is null"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -2; + } + stThreadMsg.m_iHeaderLen = strlen (header_str); + + LOGRMB (RMB_LOG_INFO, "Gen thread msg header succ, len=%d, %s", + stThreadMsg.m_iHeaderLen, header_str); + stThreadMsg.m_pHeader = + (char *) malloc (stThreadMsg.m_iHeaderLen * sizeof (char) + 1); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for m_pHeader failed, errno=%d", errno); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + strncpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + + stThreadMsg.m_iBodyLen = strlen (body_str); + stThreadMsg.m_pBody = + (char *) malloc (stThreadMsg.m_iBodyLen * sizeof (char) + 1); + if (stThreadMsg.m_pBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for hello body failed"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + memcpy (stThreadMsg.m_pBody, body_str, stThreadMsg.m_iBodyLen); + stThreadMsg.m_pBody[stThreadMsg.m_iBodyLen] = '\0'; + + json_object_put (jsonBody); + json_object_put (jsonHeader); + + int iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!,iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + return -5; + } + else + { + LOGRMB (RMB_LOG_DEBUG, "put sys log msg to fifo"); + return 0; + } +} + +/* +header=Header{cmd=TRACE_LOG_TO_LOGSERVER, code=0, msg='null', seq='null'}, body=RmbTraceLog{level=debug, logTimestamp=1525674893639, +logPoint=LOG_ERROR_POINT, message='null', model='model', retCode='retCode', retMsg='retMsg', lang='c', extFields={key=value}}} +*/ + +int rmb_send_log_for_error (stContextProxy * pContextProxy, int errCode, + char *errMsg, StRmbMsg * ptSendMsg) +{ + if (pRmbStConfig->iApiLogserverSwitch == 0) + { + return 0; + } + + if (pContextProxy == NULL || NULL == ptSendMsg) + { + LOGRMB (RMB_LOG_ERROR, "pContextProxy or ptSendMsg is null"); + return -1; + } + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_LOG; + + int iRet = -1; + WEMQJSON *jsonHeader = json_object_new_object (); + + // 组装消息 + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (TRACE_LOG_TO_LOGSERVER)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + json_object_put (jsonHeader); + return -1; + } + WEMQJSON *jsonMessage = json_object_new_object (); + if (jsonMessage == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + return -1; + } + char cTopic[128]; + char serviceOrEvent = (*(ptSendMsg->strServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + ptSendMsg->strTargetDcn, serviceOrEvent, ptSendMsg->strServiceId, + ptSendMsg->strScenarioId, *(ptSendMsg->strServiceId + 3)); + json_object_object_add (jsonMessage, MSG_BODY_TOPIC_STR, + json_object_new_string (cTopic)); + + WEMQJSON *jsonBodyProperty = + rmb_pub_encode_property_for_wemq (THREAD_MSG_CMD_SEND_LOG, ptSendMsg); + if (jsonBodyProperty == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_property_for_wemq return null"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonBody); + return -1; + } + + json_object_object_add (jsonMessage, MSG_BODY_PROPERTY_JSON, + jsonBodyProperty); + + WEMQJSON *jsonByteBody = + rmb_pub_encode_byte_body_for_wemq (THREAD_MSG_CMD_SEND_LOG, ptSendMsg); + if (jsonByteBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_byte_body_for_wemq return null"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonBody); + return -1; + } + const char *byteBodyStr = json_object_get_string (jsonByteBody); + + json_object_object_add (jsonMessage, MSG_BODY_BYTE_BODY_JSON, + json_object_new_string (byteBodyStr)); + + const char *message_str = json_object_get_string (jsonMessage); + if (message_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + + return -1; + } + + json_object_object_add (jsonBody, "retCode", json_object_new_int (errCode)); + json_object_object_add (jsonBody, "retMsg", + json_object_new_string (errMsg)); + json_object_object_add (jsonBody, "level", + json_object_new_string ("error")); + json_object_object_add (jsonBody, "logPoint", + json_object_new_string (LOG_ERROR_POINT)); + json_object_object_add (jsonBody, "model", + json_object_new_string ("model")); + json_object_object_add (jsonBody, "lang", json_object_new_string ("c")); + json_object_object_add (jsonBody, "message", + json_object_new_string (message_str)); + + const char *header_str = json_object_get_string (jsonHeader); + + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_get_string for header is null"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + return -2; + } + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + return -1; + } + + stThreadMsg.m_iHeaderLen = strlen (header_str); + + stThreadMsg.m_pHeader = + (char *) malloc (stThreadMsg.m_iHeaderLen * sizeof (char) + 1); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for m_pHeader failed, errno=%d", errno); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + return -1; + } + strncpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + stThreadMsg.m_iBodyLen = strlen (body_str); + stThreadMsg.m_pBody = + (char *) malloc (stThreadMsg.m_iBodyLen * sizeof (char) + 1); + if (stThreadMsg.m_pBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for hello body failed"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + return -1; + } + memcpy (stThreadMsg.m_pBody, body_str, stThreadMsg.m_iBodyLen); + stThreadMsg.m_pBody[stThreadMsg.m_iBodyLen] = '\0'; + LOGRMB (RMB_LOG_INFO, "Gen error log succ, header :%s, body:%s", header_str, + body_str); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + + iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!,iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + return -5; + } + else + { + LOGRMB (RMB_LOG_DEBUG, "error log msg put into fofo"); + return 0; + } +} + +/** + * 提供给业务调用,用于业务主动上报logserver + */ +int rmb_log_for_common (StContext * pStContext, const char *iLogLevel, + const char *cLogName, const char *content, + const char *extFields) +{ + if (pRmbStConfig->iApiLogserverSwitch == 0) + { + return 0; + } + stContextProxy *pContextProxy = pStContext->pContextProxy; + int iRet = + rmb_send_sys_log_for_api (pContextProxy, iLogLevel, + pRmbStConfig->cConsumerSysId, cLogName, content, + extFields); + return iRet; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_access_config.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_access_config.c new file mode 100644 index 0000000000..8d39edc1a3 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_access_config.c @@ -0,0 +1,827 @@ +// 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. + +#include +#include +#include "curl/curl.h" +#include "common.h" +#include "rmb_define.h" +#include "rmb_http_client.h" + +#define WEMQ_PROXY_MAX_SIZE (512) +#define WEMQ_PROXY_BUFFER_SIZE (262144) // 256K +//#define WEMQ_PROXY_SERVER_MAX_TIME (3600) // 1H +#define WEMQ_PROXY_SERVER_MAX_TIME (1 * 60 * 1000000) // 1m + +#define atomic_set(x, y) __sync_lock_test_and_set((x), (y)) + +typedef struct StWemqProxy +{ + char host[100]; + char idc[30]; + unsigned int port; + unsigned int weight; + unsigned int index; + + long failed_time; // 0: 没有失败; >0: 失败时间戳 + int flag; //用于初始连接时,该host是否已连接过 +} StWemqProxy; + +static struct StWemqProxy _wemq_proxy_list[WEMQ_PROXY_MAX_SIZE]; +static int _wemq_proxy_list_num = 0; // proxy个数 +static int _wemq_proxy_list_used = -1; // 当前使用proxy +static int _wemq_proxy_weight_tol = 0; // 权重总和 + +static int _wemq_proxy_inited = 0; + +static pthread_mutex_t __wemq_proxy_rmutex; + +int rmb_get_wemq_proxy_list_num () +{ + return _wemq_proxy_list_num; +} + +int rmb_get_wemq_proxy_list_used () +{ + return _wemq_proxy_list_used; +} + +static void ltrim (char *s) +{ + char *p = s; + int len = 0; + + if (s == NULL || *s == '\0') + { + return; + } + while (*p != '\0' && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) + { + p++; + len++; + } + memmove (s, p, strlen (s) - len + 1); +} + +static void rtrim (char *s) +{ + int i; + + if (s == NULL || *s == '\0') + { + return; + } + i = strlen (s) - 1; + while ((s[i] == ' ' || + s[i] == '\t' || s[i] == '\n' || s[i] == '\r') && i >= 0) + { + s[i] = '\0'; + i--; + } +} + +static void trim (char *s) +{ + ltrim (s); + rtrim (s); +} + +static int _wemq_proxy_cmp (const void *val1, const void *val2) +{ + const StWemqProxy *proxy1 = (const StWemqProxy *) val1; + const StWemqProxy *proxy2 = (const StWemqProxy *) val2; + + if (proxy1->weight > proxy2->weight) + return 1; + if (proxy1->weight < proxy2->weight) + return -1; + return 0; +} + +/* +返回示例 +{ +"wemq-proxy-servers" : "10.255.1.144:10000#3;;127.0.0.1:36000#1;" +} +服务器列表格式 +host:port#weight; +host:port#weight;host:port#weight; +*/ +static int _wemq_proxy_load_item (StWemqProxy * pproxy, const char *pstr, + size_t len) +{ + char weight[64] = ""; + char idc[32] = ""; + char port[64] = ""; + int index1 = -1; // ':'位置 + int index2 = -1; // '#'位置 + int index3 = -1; // '|' 位置 + int begin = 0; + int size = 0; + int i = 0; + + if (pstr == NULL || pproxy == NULL || len == 0) + { + return -1; + } + + for (i = 0; i < (int) len; i++) + { + if (pstr[i] == ':') + { + if (index1 != -1) + { + return -2; + } + index1 = i; + } + else if (pstr[i] == '#') + { + if (index2 != -1) + { + return -2; + } + index2 = i; + } + else if (pstr[i] == '|') + { + if (index3 != -1) + { + return -2; + } + index3 = i; + } + } + + // 确认格式是否正确 + if (index1 == -1 || index2 == -1 || index1 >= index2 || index2 >= index3) + { + return -2; + } + + // IP + if (index1 > 100 || index1 == 0) + { + return -3; + } + memcpy (pproxy->host, pstr, index1); + pproxy->host[index1] = '\0'; + + // port + begin = index1 + 1; + size = index2 - begin; + if (size > 64 || size == 0) + { + return -3; + } + memcpy (port, &pstr[begin], size); + port[size] = '\0'; + + // weight + begin = index2 + 1; + size = index3 - begin; + if (size > 64 || size == 0) + { + return -3; + } + memcpy (weight, &pstr[begin], size); + weight[size] = '\0'; + + // idc + begin = index3 + 1; + size = len - begin; + if (size > 64 || size == 0) + { + return -3; + } + memcpy (pproxy->idc, &pstr[begin], size); + pproxy->idc[size] = '\0'; + + pproxy->port = atoi (port); + pproxy->weight = atoi (weight); + + if (pproxy->port == 0 || pproxy->weight == 0) + { + return -4; + } + + pproxy->flag = 0; + return 0; +} + +static int _wemq_proxy_load_by_http (StWemqProxy * pproxy, size_t size, + const char *url, long timeout) +{ + + int ret = 0; + if (pproxy == NULL || url == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pproxy or url is null"); + return -1; + } + + char *servers = NULL; + struct rmb_http_buffer req; + req.len = 0; + req.data = (char *) malloc (sizeof (char)); + if (req.data == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for req.data failed"); + return -1; + } + + if ((ret = rmb_http_easy_get (url, (void *) &req, timeout)) != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_http_easy_get error,iRet=%d", ret); + ret = -2; + goto _LOAD_ITEM_END; + } + + servers = (char *) malloc (sizeof (char) * (req.len + 1)); + if (servers == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for servers failed"); + free (req.data); + req.data = NULL; + return -1; + } + + LOGRMB (RMB_LOG_INFO, "_wemq_proxy_load_by_http:[resp:len=%u,%s]!", + (unsigned int) req.len, req.data); + if (req.len <= 2) + return -1; + // 解析json字符串 + + WEMQJSON *json = json_tokener_parse (req.data); + WEMQJSON *wemq_proxy_servers = NULL; + if (json == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "_wemq_proxy_load_by_http: json_tokener_parse error!"); + ret = -3; + goto _LOAD_ITEM_END; + } + + char *config_param = "wemqAccessServer"; + if (strstr (url, "wemqAccessServer") == NULL) + config_param = pRmbStConfig->strDepartMent; + if (!json_object_object_get_ex (json, config_param, &wemq_proxy_servers)) + { + LOGRMB (RMB_LOG_ERROR, + "_wemq_proxy_load_by_http: json_object_object_get_ex error!"); + ret = -3; + json_object_put (json); + goto _LOAD_ITEM_END; + } + + const char *pservers = json_object_get_string (wemq_proxy_servers); + if (pservers != NULL) + { + snprintf (servers, WEMQ_PROXY_BUFFER_SIZE, "%s", pservers); + } + else + { + LOGRMB (RMB_LOG_ERROR, + "_wemq_proxy_load_by_http: wemqAccessServer is null"); + } + json_object_put (json); + + LOGRMB (RMB_LOG_INFO, "_wemq_proxy_load_by_http: [servers:%s]!", servers); + + json = json_tokener_parse (servers); + wemq_proxy_servers = NULL; + if (json == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "_wemq_proxy_load_by_http: json_tokener_parse error!"); + ret = -3; + goto _LOAD_ITEM_END; + } + + //如果当前子系统有特定的access,没有就默认 + if (!json_object_object_get_ex + (json, pRmbStConfig->cConsumerSysId, &wemq_proxy_servers)) + { + LOGRMB (RMB_LOG_INFO, + "current subsystem does not have special access list"); + if (!json_object_object_get_ex + (json, "wemqAccessServer", &wemq_proxy_servers)) + { + LOGRMB (RMB_LOG_ERROR, + "_wemq_proxy_load_by_http: json_object_object_get_ex error!"); + ret = -3; + json_object_put (json); + goto _LOAD_ITEM_END; + } + + } + + pservers = json_object_get_string (wemq_proxy_servers); + if (pservers != NULL) + { + snprintf (servers, WEMQ_PROXY_BUFFER_SIZE, "%s", pservers); + } + else + { + LOGRMB (RMB_LOG_ERROR, + "_wemq_proxy_load_by_http: wemqAccessServer is null"); + } + json_object_put (json); + + // 解析每个字段 + trim (servers); + { + char *item = NULL; + char *saveptr = NULL; + char *ptr = servers; + int i = 0; + + while ((item = strtok_r (ptr, ";", &saveptr)) != NULL) + { + if (i >= (int) size) + { + LOGRMB (RMB_LOG_WARN, + " [index: %d] [size: %zu] _wemq_proxy_load_by_http: servers too more!\n", + i, size); + break; + } + if (_wemq_proxy_load_item (&pproxy[i], item, strlen (item)) == 0) + { + i++; + } + else + { + LOGRMB (RMB_LOG_WARN, + "[item: %s] _wemq_proxy_load_by_http: _wemq_proxy_load_item error!\n", + item); + } + ptr = NULL; + } + if (i == 0) + { + LOGRMB (RMB_LOG_ERROR, "_wemq_proxy_load_by_http: servers is 0!\n"); + } + + ret = i; + } + +_LOAD_ITEM_END: + if (req.data != NULL) + { + free (req.data); + req.data = NULL; + } + if (servers != NULL) + { + free (servers); + servers = NULL; + } + return ret; +} + +static int _wemq_proxy_save (StWemqProxy * pproxy, size_t size, + const char *path) +{ + FILE *fp = NULL; + int i = 0; + + if ((fp = fopen (path, "w")) == NULL) + { + LOGRMB (RMB_LOG_ERROR, "[path: %s] _wemq_proxy_save: fopen error!\n", + path); + return -1; + } + for (i = 0; i < (int) size; i++) + { + fprintf (fp, "%s:%u#%u\n", pproxy[i].host, pproxy[i].port, + pproxy[i].weight); + } + fclose (fp); + return 0; +} + +//int wemq_proxy_load_servers(char* url, long timeout, const char* path) +int wemq_proxy_load_servers (const char *url, long timeout) +{ + int ret = 0; + int tol = 0; + int i = 0; + int j = 0; + if (pRmbStConfig->iWemqUseHttpCfg != 1) + { + return 0; + } + + if (_wemq_proxy_inited == 0) + { + _wemq_proxy_inited = 1; + pthread_mutex_init (&__wemq_proxy_rmutex, NULL); + } + + int tmp_wemq_proxy_list_num = 0; + struct StWemqProxy tmp_wemq_proxy_list[WEMQ_PROXY_MAX_SIZE]; + + memset (tmp_wemq_proxy_list, 0, sizeof (StWemqProxy) * WEMQ_PROXY_MAX_SIZE); + + //1. 通过HTTP请求配置中心 + ret = + _wemq_proxy_load_by_http (tmp_wemq_proxy_list, WEMQ_PROXY_MAX_SIZE, url, + timeout); + if (ret <= 0 && (strstr (url, "wemqAccessServer") == NULL)) + { + LOGRMB (RMB_LOG_WARN, "get wemq proxy departMent ip list failed,url=%s", + url); + return -1; + } + if (ret <= 0) + { + LOGRMB (RMB_LOG_ERROR, "get wemq proxy ip list failed,url=%s", url); + return -1; + } + tmp_wemq_proxy_list_num = ret; + + //2. 排序 + qsort (tmp_wemq_proxy_list, tmp_wemq_proxy_list_num, sizeof (StWemqProxy), + _wemq_proxy_cmp); + + //3. 权重相加 + for (i = 0; i < tmp_wemq_proxy_list_num; i++) + { + tol += tmp_wemq_proxy_list[i].weight; + } + _wemq_proxy_weight_tol = tol; + int equal_flag = 0; + + if (tmp_wemq_proxy_list_num == _wemq_proxy_list_num) + { + for (i = 0; i < _wemq_proxy_list_num; i++) + { + if (strcmp (_wemq_proxy_list[i].host, tmp_wemq_proxy_list[i].host) != 0 + || _wemq_proxy_list[i].port != tmp_wemq_proxy_list[i].port + || _wemq_proxy_list[i].weight != tmp_wemq_proxy_list[i].weight) + { + equal_flag = 1; + break; + } + } + //配置中心和本地的配置相同 + if (equal_flag == 0) + return 0; + } + //打印配置中心和本地的配置 + for (i = 0; i < _wemq_proxy_list_num; i++) + { + LOGRMB (RMB_LOG_DEBUG, + "[local address %d: host,%s|port,%u|idc:%s|weight,%u|index,%u|failed_time,%ld|flag,%d", + i, _wemq_proxy_list[i].host, _wemq_proxy_list[i].port, + _wemq_proxy_list[i].idc, _wemq_proxy_list[i].weight, + _wemq_proxy_list[i].index, _wemq_proxy_list[i].failed_time, + _wemq_proxy_list[i].flag); + } + for (j = 0; j < tmp_wemq_proxy_list_num; j++) + { + LOGRMB (RMB_LOG_DEBUG, + "[configcenter address %d: host,%s|port,%u|idc:%s|weight,%u|index,%u|failed_time,%ld|flag,%d", + j, tmp_wemq_proxy_list[j].host, tmp_wemq_proxy_list[j].port, + tmp_wemq_proxy_list[j].idc, tmp_wemq_proxy_list[j].weight, + tmp_wemq_proxy_list[j].index, tmp_wemq_proxy_list[j].failed_time, + tmp_wemq_proxy_list[j].flag); + } + + pthread_mutex_lock (&__wemq_proxy_rmutex); + //比较缓存数据和配置中心获取的数据,保留缓存数据中的flag和failedtime + for (i = 0; i < _wemq_proxy_list_num; i++) + { + if (_wemq_proxy_list[i].failed_time == 0 && _wemq_proxy_list[i].flag == 0) + continue; + for (j = 0; j < tmp_wemq_proxy_list_num; j++) + { + if (strcmp (_wemq_proxy_list[i].host, tmp_wemq_proxy_list[j].host) == 0 + && _wemq_proxy_list[i].port == tmp_wemq_proxy_list[j].port) + { + tmp_wemq_proxy_list[j].failed_time = _wemq_proxy_list[i].failed_time; + tmp_wemq_proxy_list[j].flag = _wemq_proxy_list[i].flag; + } + } + } + //更新缓存数据 + memset (_wemq_proxy_list, 0, sizeof (StWemqProxy) * WEMQ_PROXY_MAX_SIZE); + memcpy (_wemq_proxy_list, tmp_wemq_proxy_list, + sizeof (StWemqProxy) * tmp_wemq_proxy_list_num); + _wemq_proxy_list_num = tmp_wemq_proxy_list_num; + _wemq_proxy_list_used = -1; + pthread_mutex_unlock (&__wemq_proxy_rmutex); + + return 0; +} + +int wemq_proxy_get_server (char *host, size_t size, unsigned int *port) +{ + int now_index = -1; + int tmp = -1; + int wemq_proxy_usable_server_list[_wemq_proxy_list_num]; + long now_time = 0; + struct timeval tv; + + if (pRmbStConfig->iWemqUseHttpCfg != 1) + { + *port = pRmbStConfig->cWemqProxyPort; + snprintf (host, size, "%s", pRmbStConfig->cWemqProxyIp); + return 1; + } + + pthread_mutex_lock (&__wemq_proxy_rmutex); + if (_wemq_proxy_list_num <= 0) + { + pthread_mutex_unlock (&__wemq_proxy_rmutex); + LOGRMB (RMB_LOG_ERROR, "get proxy list number is:%d", + _wemq_proxy_list_num); + *port = 0; + memset (host, 0x00, sizeof (char) * size); + return 2; + } + + //从可以连接的ip中选取 + int wemq_proxy_usable_sever_weight = 0; + int wemq_proxy_usable_count = 0; + wemq_proxy_get_usable_server_list (wemq_proxy_usable_server_list, + &wemq_proxy_usable_sever_weight, + &wemq_proxy_usable_count); + //LOGRMB(RMB_LOG_DEBUG, "final count: %d | final weight: %d", wemq_proxy_usable_count, wemq_proxy_usable_sever_weight); + if (wemq_proxy_usable_count == 0) + { + pthread_mutex_unlock (&__wemq_proxy_rmutex); + LOGRMB (RMB_LOG_ERROR, "local proxy list all in black list"); + *port = 0; + memset (host, 0x00, sizeof (char) * size); + return 2; + } + else if (wemq_proxy_usable_count == 1) + { + now_index = wemq_proxy_usable_server_list[0]; + } + else + { + + //use weight + gettimeofday (&tv, NULL); + now_time = tv.tv_sec * 1000000 + tv.tv_usec; + srand ((unsigned int) now_time); + int random_index = rand () % wemq_proxy_usable_sever_weight; + int i = 0; + int tmp_weight = 0; + int tmp_index = 0; + for (; i < wemq_proxy_usable_count; i++) + { + tmp_index = wemq_proxy_usable_server_list[i]; + tmp_weight += _wemq_proxy_list[tmp_index].weight; + if (random_index < tmp_weight) + { + //LOGRMB(RMB_LOG_DEBUG, "choose host: %s | failed_time:%ld", _wemq_proxy_list[tmp_index].host, _wemq_proxy_list[tmp_index].failed_time); + now_index = tmp_index; + break; + } + } + } + gettimeofday (&tv, NULL); + now_time = tv.tv_sec * 1000000 + tv.tv_usec; + if ((_wemq_proxy_list[now_index].failed_time + + WEMQ_PROXY_SERVER_MAX_TIME) <= now_time) + { + atomic_set (&_wemq_proxy_list[now_index].failed_time, 0); + } + + // } while (tmp != now_index); + + _wemq_proxy_list_used = now_index; + if (_wemq_proxy_list[now_index].flag == 0) + { + _wemq_proxy_list[now_index].flag = 1; + } + + // 如果没有找到,由之前的使用默认IP调整为打印error日志,并等待黑名单解禁 + if (_wemq_proxy_list[now_index].failed_time != 0 && + (_wemq_proxy_list[now_index].failed_time + WEMQ_PROXY_SERVER_MAX_TIME) > + now_time) + { + pthread_mutex_unlock (&__wemq_proxy_rmutex); + LOGRMB (RMB_LOG_ERROR, "local proxy list all in black list"); + //*port = pRmbStConfig->cWemqProxyPort; + //snprintf(host, size, "%s", pRmbStConfig->cWemqProxyIp); + *port = 0; + memset (host, 0x00, sizeof (char) * size); + return 2; + } + + *port = (int) _wemq_proxy_list[now_index].port; + snprintf (host, size, "%s", _wemq_proxy_list[now_index].host); + pthread_mutex_unlock (&__wemq_proxy_rmutex); + + return 0; +} + +void wemq_proxy_goodbye (const char *host, unsigned int port) +{ + if (pRmbStConfig->iWemqUseHttpCfg != 1) + { + return; + } + + struct timeval tv; + gettimeofday (&tv, NULL); +// long now_time = time(NULL); + long now_time = tv.tv_sec * 1000000 + tv.tv_usec; + + LOGRMB (RMB_LOG_INFO, + "[used: host,%s|port,%u] [wemq_proxy_list_used:%d] wemq_proxy_goodbye!\n", + host, port, _wemq_proxy_list_used); + pthread_mutex_lock (&__wemq_proxy_rmutex); + + int i = 0; + for (i = 0; i < _wemq_proxy_list_num; i++) + { + if ((strcmp (host, _wemq_proxy_list[i].host) == 0) + && (port == _wemq_proxy_list[i].port)) + { +// LOGRMB(RMB_LOG_WARN, "[used: host:%s|port:%d] wemq_proxy_goodbye inconformity!", host, port); + atomic_set (&_wemq_proxy_list[i].failed_time, now_time); + } + } + pthread_mutex_unlock (&__wemq_proxy_rmutex); +} + +void wemq_proxy_to_black_list (const char *host, unsigned int port) +{ + if (pRmbStConfig->iWemqUseHttpCfg != 1) + { + return; + } + + struct timeval tv; + gettimeofday (&tv, NULL); + long now_time = tv.tv_sec * 1000000 + tv.tv_usec; + + LOGRMB (RMB_LOG_INFO, "[host:%s|port:%u] add to black list!\n", host, port); + pthread_mutex_lock (&__wemq_proxy_rmutex); + int i = 0; + for (i = 0; i < _wemq_proxy_list_num; i++) + { + if ((strcmp (host, _wemq_proxy_list[i].host) == 0) + && (port == _wemq_proxy_list[i].port)) + { + atomic_set (&_wemq_proxy_list[i].failed_time, now_time); + } + } + pthread_mutex_unlock (&__wemq_proxy_rmutex); +} + +void wemq_proxy_get_usable_server_list (int *wemq_proxy_usable_server_list, + int *wemq_proxy_usable_sever_weight, + int *wemq_proxy_usable_count) +{ + if (pRmbStConfig->iWemqUseHttpCfg != 1) + { + return; + } + int i = 0; + int j = 0; + int loop = 0; + int local_idc_usable_flag = 0; + int wemq_proxy_usable_server_list_backup[_wemq_proxy_list_num]; + memset (wemq_proxy_usable_server_list_backup, 0x00, + sizeof (int) * _wemq_proxy_list_num); + int wemq_proxy_usable_count_backup = 0; + int wemq_proxy_usable_sever_weight_backup = 0; + bool usableLocalIdc = false; + + struct timeval tv; + gettimeofday (&tv, NULL); + long now_time = tv.tv_sec * 1000000 + tv.tv_usec; + + for (; i < _wemq_proxy_list_num; i++) + { + char isBlack = + ((_wemq_proxy_list[i].failed_time + WEMQ_PROXY_SERVER_MAX_TIME) <= + now_time) ? 'n' : 'y'; + //LOGRMB(RMB_LOG_DEBUG, "[host:%s, port:%d, black:%c]", _wemq_proxy_list[i].host, _wemq_proxy_list[i].port, isBlack); + if (strcmp (_wemq_proxy_list[i].idc, pRmbStConfig->cRegion) == 0) + { + + if (_wemq_proxy_list[i].failed_time == 0 + || (_wemq_proxy_list[i].failed_time + WEMQ_PROXY_SERVER_MAX_TIME) <= + now_time) + { + wemq_proxy_usable_server_list[j] = i; + j++; + *wemq_proxy_usable_count += 1; + *wemq_proxy_usable_sever_weight += (int) _wemq_proxy_list[i].weight; + usableLocalIdc = true; + //LOGRMB(RMB_LOG_DEBUG, "[host:%s | port:%u | weight:%d | index: %d] is usable!\n", _wemq_proxy_list[i].host, _wemq_proxy_list[i].port, _wemq_proxy_list[i].weight, i); + //LOGRMB(RMB_LOG_DEBUG, "j: %d | count: %d | weight: %d", j, *wemq_proxy_usable_count, *wemq_proxy_usable_sever_weight); + } + } + else + { + if (_wemq_proxy_list[i].failed_time == 0 + || (_wemq_proxy_list[i].failed_time + WEMQ_PROXY_SERVER_MAX_TIME) <= + now_time) + { + wemq_proxy_usable_server_list_backup[loop] = i; + loop++; + wemq_proxy_usable_count_backup += 1; + wemq_proxy_usable_sever_weight_backup += + (int) _wemq_proxy_list[i].weight; + //LOGRMB(RMB_LOG_DEBUG, "[host:%s | port:%u | weight:%d | index: %d] is usable!\n", _wemq_proxy_list[i].host, _wemq_proxy_list[i].port, _wemq_proxy_list[i].weight, i); + //LOGRMB(RMB_LOG_DEBUG, "j: %d | count: %d | weight: %d", j, *wemq_proxy_usable_count, *wemq_proxy_usable_sever_weight); + } + } + } + /* + for(i = 0; i < *wemq_proxy_usable_count; i++){ + LOGRMB(RMB_LOG_DEBUG, "[local usable index: %d]\n", wemq_proxy_usable_server_list[i]); + } + for(i = 0; i < wemq_proxy_usable_count_backup; i++){ + LOGRMB(RMB_LOG_DEBUG, "[backup usable index: %d]\n", wemq_proxy_usable_server_list_backup[i]); + } */ + + if (!usableLocalIdc) + { + memset (wemq_proxy_usable_server_list, 0, + sizeof (int) * _wemq_proxy_list_num); + memcpy (wemq_proxy_usable_server_list, + wemq_proxy_usable_server_list_backup, + sizeof (int) * wemq_proxy_usable_count_backup); + *wemq_proxy_usable_count = wemq_proxy_usable_count_backup; + *wemq_proxy_usable_sever_weight = wemq_proxy_usable_sever_weight_backup; + } + /* + for(i = 0; i < *wemq_proxy_usable_count; i++){ + LOGRMB(RMB_LOG_DEBUG, "[final usable index: %d]\n", wemq_proxy_usable_server_list[i]); + } + */ +} + +/** + * 判断所有的ip是否均连接过 + */ +int wemq_proxy_ip_is_connected () +{ + if (pRmbStConfig->iWemqUseHttpCfg != 1) + { + return 1; + } + + int iRet = 0; + int i = 0; + pthread_mutex_lock (&__wemq_proxy_rmutex); + for (i = 0; i < _wemq_proxy_list_num; i++) + { + if (_wemq_proxy_list[i].flag == 0) + break; + } + pthread_mutex_unlock (&__wemq_proxy_rmutex); + + if (i >= _wemq_proxy_list_num) + { + iRet = 1; + } + + return iRet; +} + +/** + * 分隔IP列表 + */ +void split_str (char *ips, char ipArray[][50], int *len) +{ + // printf("%s\n", ips); + //char (*ipArray)[50] = (char(*)[50])malloc(sizeof(char) * 15 * 50); + int count = 0; + char *ip = NULL; + ip = strtok (ips, ";"); + if (ip == NULL) + { + *len = 0; + return; + } + strcpy (ipArray[count], ip); + count++; + while (ip = strtok (NULL, ";")) + { + strcpy (ipArray[count], ip); + count++; + } + *len = count; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_cfg.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_cfg.c new file mode 100644 index 0000000000..15b9fdc0ed --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_cfg.c @@ -0,0 +1,594 @@ +// 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. + +#include +#include +#include +#include +#include "rmb_log.h" +#include "rmb_udp.h" +#include "rmb_cfg.h" +#include +#include +#include +#include + +#include "rmb_access_config.h" + +StRmbConfig *pRmbStConfig; + +int rmb_reload_config (); + +static char *rmb_get_val (char *desc, char *src) +{ + char *descp = desc, *srcp = src; + int mtime = 0, space = 0; + + while (mtime != 2 && *srcp != '\0') + { + switch (*srcp) + { + case ' ': + case '\t': + case '\0': + case '\n': + case US: + space = 1; + srcp++; + break; + default: + if (space || srcp == src) + mtime++; + space = 0; + if (mtime == 2) + break; + *descp = *srcp; + descp++; + srcp++; + } + } + *descp = '\0'; + strcpy (src, srcp); + return desc; +} + +static void rmb_InitDefault (va_list ap) +{ + char *sParam, *sVal, *sDefault; + double *pdVal, dDefault; + long *plVal, lDefault; + int iType, *piVal, iDefault; + long lSize; + short *pwVal = NULL; + short wDefault; + + sParam = va_arg (ap, char *); + + while (sParam != NULL) + { + iType = va_arg (ap, int); + + switch (iType) + { + case CFG_LINE: + sVal = va_arg (ap, char *); + sDefault = va_arg (ap, char *); + lSize = va_arg (ap, long); + + strncpy (sVal, sDefault, (int) lSize - 1); + sVal[lSize - 1] = 0; + //snprintf(sVal,lSize,"%s",sDefault); + break; + case CFG_STRING: + sVal = va_arg (ap, char *); + sDefault = va_arg (ap, char *); + lSize = va_arg (ap, long); + + strncpy (sVal, sDefault, (int) lSize - 1); + sVal[lSize - 1] = 0; + //snprintf(sVal,lSize,"%s",sDefault); + break; + case CFG_LONG: + plVal = va_arg (ap, long *); + lDefault = va_arg (ap, long); + + *plVal = lDefault; + break; + case CFG_INT: + piVal = va_arg (ap, int *); + iDefault = va_arg (ap, int); + + *piVal = iDefault; + break; + case CFG_SHORT: + pwVal = va_arg (ap, short *); + wDefault = va_arg (ap, int); + *pwVal = wDefault; + break; + case CFG_DOUBLE: + pdVal = va_arg (ap, double *); + dDefault = va_arg (ap, double); + + *pdVal = dDefault; + break; + } + sParam = va_arg (ap, char *); + } +} + +static void rmb_SetVal (va_list ap, const char *sP, char *sV) +{ + char *sParam = NULL, *sVal = NULL, *sDefault = NULL; + double *pdVal = NULL, dDefault; + long *plVal = NULL, lDefault; + int iType, *piVal = NULL, iDefault; + long lSize = 0; + char sLine[MAX_CONFIG_LINE_LEN + 1], sLine1[MAX_CONFIG_LINE_LEN + 1]; + short *pwVal = NULL; + short wDefault; + + strcpy (sLine, sV); + strcpy (sLine1, sV); + rmb_get_val (sV, sLine1); + sParam = va_arg (ap, char *); + + while (sParam != NULL) + { + iType = va_arg (ap, int); + + switch (iType) + { + case CFG_LINE: + sVal = va_arg (ap, char *); + sDefault = va_arg (ap, char *); + lSize = va_arg (ap, long); + + if (strcmp (sP, sParam) == 0) + { + strncpy (sVal, sLine, (int) lSize - 1); + sVal[lSize - 1] = 0; + //snprintf(sVal,lSize,"%s",sLine); + } + break; + case CFG_STRING: + sVal = va_arg (ap, char *); + sDefault = va_arg (ap, char *); + lSize = va_arg (ap, long); + + break; + case CFG_LONG: + plVal = va_arg (ap, long *); + lDefault = va_arg (ap, long); + + /* + if (strcmp(sP, sParam) == 0) + { + *plVal = atol(sV); + } + */ + break; + case CFG_INT: + piVal = va_arg (ap, int *); + iDefault = va_arg (ap, int); + + /* + if (strcmp(sP, sParam) == 0) + { + *piVal = iDefault; + } + */ + break; + case CFG_SHORT: + pwVal = va_arg (ap, short *); + wDefault = va_arg (ap, int); + break; + case CFG_DOUBLE: + pdVal = va_arg (ap, double *); + dDefault = va_arg (ap, double); + + *pdVal = dDefault; + break; + } + + if (strcmp (sP, sParam) == 0) + { + switch (iType) + { + case CFG_STRING: + strncpy (sVal, sV, (int) lSize - 1); + sVal[lSize - 1] = 0; + break; + case CFG_LONG: + //*plVal = atol(sV); + *plVal = strtoul (sV, NULL, 0); + break; + case CFG_INT: + //*piVal = atoi(sV); + *piVal = strtoul (sV, NULL, 0); + break; + case CFG_SHORT: + *pwVal = strtoul (sV, NULL, 0); + break; + case CFG_DOUBLE: + *pdVal = atof (sV); + break; + } + + return; + } + + sParam = va_arg (ap, char *); + } +} + +static int rmb_GetParamVal (char *sLine, char *sParam, char *sVal) +{ + + rmb_get_val (sParam, sLine); + strcpy (sVal, sLine); + + if (sParam[0] == '#') + return 1; + + return 0; +} + +void RMB_TLib_Cfg_GetConfig (char *sConfigFilePath, ...) +{ + FILE *pstFile; + char sLine[MAX_CONFIG_LINE_LEN + 1], sParam[MAX_CONFIG_LINE_LEN + 1], + sVal[MAX_CONFIG_LINE_LEN + 1]; + va_list ap; + char *pCur = NULL; + + va_start (ap, sConfigFilePath); + rmb_InitDefault (ap); + va_end (ap); + + if ((pstFile = fopen (sConfigFilePath, "r")) == NULL) + { + // printf("Can't open Config file '%s', ignore.", sConfigFilePath); + return; + } + + while (1) + { + pCur = fgets (sLine, sizeof (sLine), pstFile); + if (pCur == NULL) + break; + + if (feof (pstFile)) + { + break; + } + + if (rmb_GetParamVal (sLine, sParam, sVal) == 0) + { + va_start (ap, sConfigFilePath); + rmb_SetVal (ap, sParam, sVal); + va_end (ap); + } + } + + fclose (pstFile); +} + +void rmb_cfg_process_signal (int sigalNo) +{ + switch (sigalNo) + { + case SIGUSR1: + { + LOGRMB (RMB_LOG_INFO, "pid=%u receive user signal 1,reload cfg!", + pRmbStConfig->uiPid); + rmb_reload_config (); + LOGRMB (RMB_LOG_INFO, "pid=%u reload cfg succ!", pRmbStConfig->uiPid); + break; + } + case SIGUSR2: + { + LOGRMB (RMB_LOG_INFO, "pid=%u receive user signal 2,reload cfg!", + pRmbStConfig->uiPid); + rmb_reload_config (); + LOGRMB (RMB_LOG_INFO, "pid=%u reload cfg succ!", pRmbStConfig->uiPid); + break; + } + default: + { + printf ("receive signal=%u", sigalNo); + } + } + return; +} + +int rmb_reload_config () +{ + Rmb_TLib_Cfg_GetConfig (pRmbStConfig->strConfigFile, + "consumerSysId", CFG_STRING, + pRmbStConfig->cConsumerSysId, "", + sizeof (pRmbStConfig->cConsumerSysId), + "consumerSysVersion", CFG_STRING, + pRmbStConfig->cConsumerSysVersion, "", + sizeof (pRmbStConfig->cConsumerSysVersion), + "consumerDcn", CFG_STRING, + pRmbStConfig->cConsumerDcn, "", + sizeof (pRmbStConfig->cConsumerDcn), "logFile", + CFG_STRING, pRmbStConfig->logFileName, "../rmb/log", + sizeof (pRmbStConfig->logFileName), "logLevel", + CFG_INT, &(pRmbStConfig->iLogLevel), 5, + "logFileNums", CFG_INT, + &(pRmbStConfig->iLogFileNums), 100, "logFileSize", + CFG_INT, &(pRmbStConfig->iLogFileSize), 500000000, + "logSwiftType", CFG_INT, + &(pRmbStConfig->iLogShiftType), 1, "debugSwitch", + CFG_INT, &(pRmbStConfig->iDebugSwitch), 0, + "everyProcessNumFromMq", CFG_INT, + &(pRmbStConfig->iEveryTimeProcessNum), 10, + "notifyCheckSpan", CFG_INT, + &(pRmbStConfig->iNotifyCheckSpan), 1, + "notifyMergeSwitch", CFG_INT, + &(pRmbStConfig->iFLagForMergeNotify), 1, "orgId", + CFG_STRING, pRmbStConfig->strOrgId, "99996", + sizeof (pRmbStConfig->strOrgId), "cacheTimeout", + CFG_INT, &(pRmbStConfig->iCacheTimeoutTime), 10, + "cacheSuccTimeout", CFG_INT, + &(pRmbStConfig->iCacheSuccTimeoutTime), 600, + "cacheFailedTimeout", CFG_INT, + &(pRmbStConfig->iCacheFailedTimeoutTime), 30, + "switchForReloadSignal1", CFG_INT, + &(pRmbStConfig->iSwitchForSignal1), 1, + "switchForReloadSignal2", CFG_INT, + &(pRmbStConfig->iSwitchForSignal2), 0, "ackTimer", + CFG_INT, &(pRmbStConfig->ackTimers), 100, + "ackThreshold", CFG_INT, + &(pRmbStConfig->ackThresHold), 30, "queryTimeout", + CFG_INT, &(pRmbStConfig->iQueryTimeout), 1000, + "CommonTimeOut", CFG_INT, + &(pRmbStConfig->iCommonTimeOut), 500, "StatPeriod", + CFG_INT, &(pRmbStConfig->iStatPeriod), 300, + "GetGroupTopicTime", CFG_INT, + &(pRmbStConfig->iGetGroupTopicTime), 5, + "GetSendWhiteListTime", CFG_INT, + &(pRmbStConfig->iGetSendWhiteListTime), 30, NULL); + + //ackTimer的范围为20到1500 + if (pRmbStConfig->ackTimers > 1500) + pRmbStConfig->ackTimers = 1500; + if (pRmbStConfig->ackTimers < 20) + pRmbStConfig->ackTimers = 20; + + //ackThreshold的范围为1 到75 + if (pRmbStConfig->ackThresHold > 75) + pRmbStConfig->ackThresHold = 75; + if (pRmbStConfig->ackThresHold < 1) + pRmbStConfig->ackThresHold = 1; + + if (pRmbStConfig->iQueryTimeout > 5000) + pRmbStConfig->iQueryTimeout = 5000; + if (pRmbStConfig->iQueryTimeout < 500) + pRmbStConfig->iQueryTimeout = 500; + + if (pRmbStConfig->iSwitchForSignal1) + { + signal (SIGUSR1, rmb_cfg_process_signal); + } + + if (pRmbStConfig->iSwitchForSignal2) + { + signal (SIGUSR2, rmb_cfg_process_signal); + } + + return 0; +} + +int rmb_load_config (const char *configPath) +{ + pRmbStConfig = (StRmbConfig *) calloc (1, sizeof (StRmbConfig)); + if (pRmbStConfig == NULL) + { + printf ("rmb_load_config pRmbStConfig calloc error!"); + return -1; + } + + init_error (); + snprintf (pRmbStConfig->strConfigFile, + sizeof (pRmbStConfig->strConfigFile) - 1, "%s", configPath); + Rmb_TLib_Cfg_GetConfig (pRmbStConfig->strConfigFile, "consumerSysId", CFG_STRING, pRmbStConfig->cConsumerSysId, "", sizeof (pRmbStConfig->cConsumerSysId), "consumerSysVersion", CFG_STRING, pRmbStConfig->cConsumerSysVersion, "1.0.0", sizeof (pRmbStConfig->cConsumerSysVersion), "consumerDcn", CFG_STRING, pRmbStConfig->cConsumerDcn, "", sizeof (pRmbStConfig->cConsumerDcn), "logFile", CFG_STRING, pRmbStConfig->logFileName, "../log/rmb.log", sizeof (pRmbStConfig->logFileName), "logLevel", CFG_INT, &(pRmbStConfig->iLogLevel), 5, "logFileNums", CFG_INT, &(pRmbStConfig->iLogFileNums), 100, "logFileSize", CFG_INT, &(pRmbStConfig->iLogFileSize), 500000000, "logSwiftType", CFG_INT, &(pRmbStConfig->iLogShiftType), 1, "debugSwitch", CFG_INT, &(pRmbStConfig->iDebugSwitch), 0, "everyProcessNumFromMq", CFG_INT, &(pRmbStConfig->iEveryTimeProcessNum), 10, "notifyCheckSpan", CFG_INT, &(pRmbStConfig->iNotifyCheckSpan), 1, "notifyMergeSwitch", CFG_INT, &(pRmbStConfig->iFLagForMergeNotify), 1, "reqFifoPath", CFG_STRING, pRmbStConfig->strFifoPathForReq, "./tmp_req.fifo", sizeof (pRmbStConfig->strFifoPathForReq), "reqShmKey", CFG_INT, &(pRmbStConfig->uiShmKeyForReq), 0x20150203, "reqShmSize", CFG_INT, &(pRmbStConfig->uiShmSizeForReq), 200000000, "ayncRspFifoPath", CFG_STRING, pRmbStConfig->strFifoPathForRRrsp, "./tmp_aync_rsp.fifo", sizeof (pRmbStConfig->strFifoPathForReq), "ayncRspShmKey", CFG_INT, &(pRmbStConfig->uiShmKeyForRRrsp), 0x20150204, "ayncRspShmSize", CFG_INT, &(pRmbStConfig->uiShmSizeForRRrsp), 200000000, "broadcastFifoPath", CFG_STRING, pRmbStConfig->strFifoPathForBroadcast, "./tmp_broadcast.fifo", sizeof (pRmbStConfig->strFifoPathForReq), "broadcastShmKey", CFG_INT, &(pRmbStConfig->uiShmKeyForBroadcast), 0x20150205, "broadcastShmSize", CFG_INT, &(pRmbStConfig->uiShmSizeForBroadcast), 200000000, "orgId", CFG_STRING, pRmbStConfig->strOrgId, "99996", sizeof (pRmbStConfig->strOrgId), "cacheTimeout", CFG_INT, &(pRmbStConfig->iCacheTimeoutTime), 10, "cacheSuccTimeout", CFG_INT, &(pRmbStConfig->iCacheSuccTimeoutTime), 600, "cacheFailedTimeout", CFG_INT, &(pRmbStConfig->iCacheFailedTimeoutTime), 30, "createConnectionTimeOut", CFG_INT, &(pRmbStConfig->createConnectionTimeOut), 120, "switchForReloadSignal1", CFG_INT, &(pRmbStConfig->iSwitchForSignal1), 1, "switchForReloadSignal2", CFG_INT, &(pRmbStConfig->iSwitchForSignal2), 0, "ackTimer", CFG_INT, &(pRmbStConfig->ackTimers), 100, "ackThreshold", CFG_INT, &(pRmbStConfig->ackThresHold), 30, "queryTimeout", CFG_INT, &(pRmbStConfig->iQueryTimeout), 1000, "CommonTimeOut", CFG_INT, &(pRmbStConfig->iCommonTimeOut), 500, "StatPeriod", CFG_INT, &(pRmbStConfig->iStatPeriod), 300, "GetGroupTopicTime", CFG_INT, &(pRmbStConfig->iGetGroupTopicTime), 5, "logserverSwitch", CFG_INT, &(pRmbStConfig->iLogserverSwitch), 1, "logserverForApiSwitch", CFG_INT, &(pRmbStConfig->iApiLogserverSwitch), 1, "ReqGslSwitch", CFG_INT, &(pRmbStConfig->iReqGsl), 1, "wemqUseHttpCfg", CFG_INT, &(pRmbStConfig->iWemqUseHttpCfg), 1, "configCenterIp", CFG_STRING, pRmbStConfig->cConfigIp, "", sizeof (pRmbStConfig->cConfigIp), "configCenterPort", CFG_INT, &(pRmbStConfig->iConfigPort), 8091, "configCenterAddrMulti", CFG_STRING, pRmbStConfig->ConfigAddr, "", sizeof (pRmbStConfig->ConfigAddr), "configCenterTimeout", CFG_INT, &(pRmbStConfig->iConfigTimeout), 10000, "mergeQueueSwitch", CFG_INT, &(pRmbStConfig->iMergeQueue), 0, "tlsOnoff", CFG_INT, &(pRmbStConfig->tlsOnoff), 0, "wemq_user", CFG_STRING, pRmbStConfig->cWemqUser, "", sizeof (pRmbStConfig->cWemqUser), "wemq_passwd", CFG_STRING, pRmbStConfig->cWemqPasswd, "", sizeof (pRmbStConfig->cWemqPasswd), "localIdc", CFG_STRING, pRmbStConfig->cRegion, "", sizeof (pRmbStConfig->cRegion), "heartBeatPeriod", CFG_INT, &(pRmbStConfig->heartBeatPeriod), 30, "heartBeatTimeout", CFG_INT, &(pRmbStConfig->heartBeatTimeout), 45, "getAccessIpPeriod", CFG_INT, &(pRmbStConfig->getAccessIpPeriod), 30, "wemqTcpConnectRetryNum", CFG_INT, &(pRmbStConfig->iWemqTcpConnectRetryNum), 1, "wemqTcpConnectDelayTime", CFG_INT, &(pRmbStConfig->iWemqTcpConnectDelayTime), 5, "wemqTcpConnectTimeout", CFG_INT, &(pRmbStConfig->iWemqTcpConnectTimeout), 3000, "wemqTcpSocketTimeout", CFG_INT, &(pRmbStConfig->iWemqTcpSocketTimeout), 5000, "wemqProxyIp", CFG_STRING, pRmbStConfig->cWemqProxyIp, "", sizeof (pRmbStConfig->cWemqProxyIp), "wemqProxyPort", CFG_INT, &(pRmbStConfig->cWemqProxyPort), 50001, "normalTimeout", CFG_INT, &(pRmbStConfig->iNormalTimeout), 120000, "exitTimeOut", CFG_INT, &(pRmbStConfig->ulExitTimeOut), 30000, "getSendWhiteListTime", CFG_INT, &(pRmbStConfig->iGetSendWhiteListTime), 300, "accessAckTimeOut", CFG_INT, &(pRmbStConfig->accessAckTimeOut), 2000, "rrAsyncTimeOut", CFG_INT, &(pRmbStConfig->rrAsyncTimeOut), 3, //默认rr异步3秒超时 + "goodByeTimeOut", CFG_INT, &(pRmbStConfig->goodByeTimeOut), 2000, //goodbye time 2s + //"rrAsyncListNum", CFG_INT, &(pRmbStConfig->accessAckTimeOut),10240, + "mqIsEmpty", CFG_INT, &(pRmbStConfig->mqIsEmpty), + MQ_INIT, "departMent", CFG_STRING, + pRmbStConfig->strDepartMent, "wemqAccessServer", + sizeof (pRmbStConfig->strDepartMent), NULL); + + pRmbStConfig->uiPid = getpid (); + snprintf (pRmbStConfig->cRmbMode, sizeof (pRmbStConfig->cRmbMode), "wemq"); + //initialize for log + InitRmbLogFile (pRmbStConfig->iLogLevel, pRmbStConfig->iLogShiftType, + pRmbStConfig->logFileName, pRmbStConfig->iLogFileSize, + pRmbStConfig->iLogFileNums); + //API CONNECT MODE + //connect to wemq + pRmbStConfig->iConnWemq = 1; + + //solace api 初始化,用于生成uuid + pRmbStConfig->uiIsInitSolaceApi = 0; + + int iRet = 0; + //从配置中心拉取access的ip list,如果配置为指定access的ip,则无须从配置中心拉取 + if ((pRmbStConfig->iWemqUseHttpCfg == 1) + && (pRmbStConfig->iConnWemq == 1 + || pRmbStConfig->iApiLogserverSwitch == 1)) + { + char url[512]; + char addrArr[15][50] = { 0 }; + int lenAddrs = 0; + pRmbStConfig->configIpPosInArr = 0; + char tmpIps[512] = { 0 }; + strcpy (tmpIps, pRmbStConfig->ConfigAddr); + LOGRMB (RMB_LOG_DEBUG, "config center addr str is:%s", tmpIps); + split_str (tmpIps, addrArr, &lenAddrs); + LOGRMB (RMB_LOG_DEBUG, "config center addr list len is %d,lists:", + lenAddrs); + int j = 0; + for (j = 0; j < lenAddrs; ++j) + { + LOGRMB (RMB_LOG_DEBUG, "%s", addrArr[j]); + } + + if (lenAddrs == 0) + { + LOGRMB (RMB_LOG_ERROR, + "config center addr list len is 0,please check if configCenterAddrMulti is empty in conf file"); + return -1; + } + int i = 0; + for (i = 0; i < lenAddrs; ++i) + { + memset (&url, 0x00, sizeof (url)); + snprintf (url, sizeof (url), "%s/%s", + addrArr[(i + pRmbStConfig->configIpPosInArr) % lenAddrs], + WEMQ_ACCESS_SERVER); + LOGRMB (RMB_LOG_DEBUG, "try to get access addr from %s", url); + iRet = wemq_proxy_load_servers (url, pRmbStConfig->iConfigTimeout); + if (iRet != 0) + { + LOGRMB (RMB_LOG_WARN, + "get access ip from %s failed,try next config center ip", + url); + continue; + } + else + { + LOGRMB (RMB_LOG_INFO, "get all access ip list result=%d from url:%s", + iRet, url); + pRmbStConfig->configIpPosInArr = pRmbStConfig->configIpPosInArr + i; + break; + } + } + if (i == lenAddrs) + { + LOGRMB (RMB_LOG_ERROR, " no available cc"); + return -1; + } + } + pRmbStConfig->iFlagForLoop = 0; + + //ackTimer的范围为20到1500 + if (pRmbStConfig->ackTimers > 1500) + pRmbStConfig->ackTimers = 1500; + if (pRmbStConfig->ackTimers < 20) + pRmbStConfig->ackTimers = 20; + + //ackThreshold的范围为1 到75 + if (pRmbStConfig->ackThresHold > 75) + pRmbStConfig->ackThresHold = 75; + if (pRmbStConfig->ackThresHold < 1) + pRmbStConfig->ackThresHold = 1; + + if (pRmbStConfig->iQueryTimeout > 5000) + pRmbStConfig->iQueryTimeout = 5000; + if (pRmbStConfig->iQueryTimeout < 500) + pRmbStConfig->iQueryTimeout = 500; + + pRmbStConfig->pLogBuf = NULL; + pRmbStConfig->pLogBuf = (char *) malloc ((size_t) MAX_LOG_BUF_SIZE); + if (pRmbStConfig->pLogBuf == NULL) + { + printf ("malloc for pRmbStConfig->pLogBuf error!"); + return -1; + } + + iRet = + get_host_name (pRmbStConfig->cHostName, sizeof (pRmbStConfig->cHostName)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, " get_host_name failed!"); + //exit(1); + } + +// iRet = get_local_ip(pRmbStConfig->cHostIp, sizeof(pRmbStConfig->cHostIp)); + iRet = + get_local_ip_v2 (pRmbStConfig->cHostIp, sizeof (pRmbStConfig->cHostIp)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "get_local_ip failed!"); + //exit(1); + } + + LOGRMB (RMB_LOG_INFO, "get_host_name hostname=%s,ip=%s", + pRmbStConfig->cHostName, pRmbStConfig->cHostIp); + + //init queue config + pthread_mutex_init (&pRmbStConfig->configMutex, NULL); + pthread_cond_init (&pRmbStConfig->configCond, NULL); + pRmbStConfig->iFlag = 0; + GetRmbNowLongTime (); + pRmbStConfig->ulStartTime = pRmbStConfig->ulNowTtime; + pRmbStConfig->iCacheServiceNums = 0; + + //init mergeq for gsl + pthread_mutex_init (&pRmbStConfig->mergeqForGslMutex, NULL); + pthread_cond_init (&pRmbStConfig->mergeqForGslCond, NULL); + pRmbStConfig->iFlagForMerge = 0; + + //init merge queue mutex + pthread_mutex_init (&pRmbStConfig->mergeQueueMutex, NULL); + + //init for log + pthread_mutex_init (&pRmbStConfig->configLog, NULL); + + //pthread_mutex_init(&pRmbStConfig->sendWhiteListMutex, NULL); + + if (pRmbStConfig->iSwitchForSignal1) + { + signal (SIGUSR1, rmb_cfg_process_signal); + } + + if (pRmbStConfig->iSwitchForSignal2) + { + signal (SIGUSR2, rmb_cfg_process_signal); + } + + pRmbStConfig->flag_merge = 0; + pRmbStConfig->pid_merge = 0; + + return 0; +} + +void rmb_get_config_python (RmbPythonConfig * config) +{ + //pythonConfig init + snprintf (config->strFifoPathForReq, sizeof (config->strFifoPathForReq), + pRmbStConfig->strFifoPathForReq); + config->uiShmKeyForReq = pRmbStConfig->uiShmKeyForReq; + config->uiShmSizeForReq = pRmbStConfig->uiShmSizeForReq; + snprintf (config->strFifoPathForRRrsp, sizeof (config->strFifoPathForRRrsp), + pRmbStConfig->strFifoPathForRRrsp); + config->uiShmKeyForRRrsp = pRmbStConfig->uiShmKeyForRRrsp; + config->uiShmSizeForRRrsp = pRmbStConfig->uiShmSizeForRRrsp; + + snprintf (config->strFifoPathForBroadcast, + sizeof (config->strFifoPathForBroadcast), + pRmbStConfig->strFifoPathForBroadcast); + config->uiShmKeyForBroadcast = pRmbStConfig->uiShmKeyForBroadcast; + config->uiShmSizeForBroadcast = pRmbStConfig->uiShmSizeForBroadcast; + return; +} + +const char *rmb_get_host_ip () +{ + return pRmbStConfig->cHostIp; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_context.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_context.c new file mode 100644 index 0000000000..b8ad1c9e1f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_context.c @@ -0,0 +1,907 @@ +// 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. + +#include "rmb_context.h" +#include "rmb_udp.h" +#include "rmb_log.h" +#include "rmb_common.h" +#include "rmb_msg.h" +#include "rmb_mq.h" +#include "rmb_errno.h" +#include +#include +#include "wemq_thread.h" + +//char cManageTopic[30] = "rmb_c/manage"; +char cManageTopic[30] = "rmb_c_api/manage"; +char cQueueFullTopic[30] = "VPN_AD_MSG_SPOOL_TOPIC"; +char cLogLevelTopic[30] = "OPEN_DEBUG_LOG_TOPIC"; +char cPublishCheck[30] = "ALLOW_PUBLISH_MESSAGE_TOPIC"; +#define TWO_STOP_TIME 300000 + +//add for period log thread +int g_iLogThreadInit = 0; +pthread_t g_stLogThreadId; + +//////////////for wemq +static void _wemq_worker_thread_func (void *arg) +{ + StThreadArgs *pArg = (StThreadArgs *) arg; + WemqThreadCtx stThreadCtx; + stThreadCtx.m_ptProxyContext = pArg->pStContextProxy; + stThreadCtx.m_contextType = pArg->contextType; + stThreadCtx.m_iState = THREAD_STATE_INIT; + + stThreadCtx.sslCtx = NULL; + stThreadCtx.m_iSockFd = -1; + stThreadCtx.ssl = NULL; + stThreadCtx.m_iSockFdNew = -1; + stThreadCtx.sslNew = NULL; + stThreadCtx.m_iSockFdOld = -1; + stThreadCtx.sslOld = NULL; + + if (pArg->contextType == RMB_CONTEXT_TYPE_PUB) + { + stThreadCtx.m_ptTopicList = NULL; + stThreadCtx.m_ptFifo = (void *) &(pArg->pStContextProxy->pubFifo); + } + else + { + stThreadCtx.m_ptTopicList = &(pArg->pStContextProxy->stTopicList); + stThreadCtx.m_ptFifo = (void *) &(pArg->pStContextProxy->subFifo); + } + + wemq_thread_run (&stThreadCtx); + free (pArg); +} + +static int _wemq_context_create_thread (int contextType, + stContextProxy * pContextProxy) +{ + int iRet = -1; + if (contextType == RMB_CONTEXT_TYPE_PUB) + { + //thread has been created + if (pContextProxy->mainThreadId != 0) + { + return 0; + } + + //create pub thread (main thread); + StThreadArgs *pMainArgs = (StThreadArgs *) malloc (sizeof (StThreadArgs)); + if (pMainArgs == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for pMainArgs failed!"); + return -1; + } + pMainArgs->pStContextProxy = pContextProxy; + pMainArgs->contextType = RMB_CONTEXT_TYPE_PUB; + + iRet = + pthread_create (&pContextProxy->mainThreadId, NULL, + (void *) &_wemq_worker_thread_func, pMainArgs); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "create main thread error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_CREATE_THREAD_FAIL; + return rmb_errno; + } + + struct timeval nowTimeVal; + gettimeofday (&nowTimeVal, NULL); + struct timespec timeout; + timeout.tv_sec = + nowTimeVal.tv_sec + pRmbStConfig->createConnectionTimeOut; + timeout.tv_nsec = nowTimeVal.tv_usec * 1000; + + pContextProxy->iFlagForPub = 0; + pthread_mutex_lock (&pContextProxy->pubMutex); + if (pContextProxy->iFlagForPub == 0) + { + pthread_cond_timedwait (&pContextProxy->pubCond, + &pContextProxy->pubMutex, &timeout); + } + pthread_mutex_unlock (&pContextProxy->pubMutex); + if (pContextProxy->iFlagForPub != 1) + { + return -1; + } + } + else if (contextType == RMB_CONTEXT_TYPE_SUB) + { + //thread has been created + if (pContextProxy->coThreadId != 0) + { + return 0; + } + + //create sub thread (co thread) + StThreadArgs *pCoArgs = (StThreadArgs *) malloc (sizeof (StThreadArgs)); + if (pCoArgs == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for pCoArgs failed!"); + return -2; + } + pCoArgs->pStContextProxy = pContextProxy; + pCoArgs->contextType = RMB_CONTEXT_TYPE_SUB; + iRet = + pthread_create (&pContextProxy->coThreadId, NULL, + (void *) &_wemq_worker_thread_func, pCoArgs); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "create co thread error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_CREATE_THREAD_FAIL; + return rmb_errno; + } + + struct timeval nowTimeVal; + gettimeofday (&nowTimeVal, NULL); + struct timespec timeout; + timeout.tv_sec = + nowTimeVal.tv_sec + pRmbStConfig->createConnectionTimeOut; + timeout.tv_nsec = nowTimeVal.tv_usec * 1000; + + pContextProxy->iFlagForSub = 0; + pthread_mutex_lock (&pContextProxy->subMutex); + if (pContextProxy->iFlagForSub == 0) + { + pthread_cond_timedwait (&pContextProxy->subCond, + &pContextProxy->subMutex, &timeout); + } + pthread_mutex_unlock (&pContextProxy->subMutex); + if (pContextProxy->iFlagForSub != 1) + { + return -1; + } + } + else + { + LOGRMB (RMB_LOG_ERROR, "contextType is illegal(%d)!", contextType); + rmb_errno = RMB_ERROR_CREATE_THREAD_FAIL; + return rmb_errno; + } +// sleep(1); //等待线程先执行 + return 0; +} + +static void wemq_context_init_thread_sync_obj (stContextProxy * pContextProxy) +{ + pthread_mutex_init (&pContextProxy->rrMutex, NULL); + pthread_cond_init (&pContextProxy->rrCond, NULL); + pContextProxy->iFlagForRR = 0; + + pthread_mutex_init (&pContextProxy->regMutex, NULL); + pthread_cond_init (&pContextProxy->regCond, NULL); + pContextProxy->iFlagForReg = 0; + + pthread_mutex_init (&pContextProxy->pubMutex, NULL); + pthread_cond_init (&pContextProxy->pubCond, NULL); + pContextProxy->iFlagForPub = 0; + + pthread_mutex_init (&pContextProxy->subMutex, NULL); + pthread_cond_init (&pContextProxy->subCond, NULL); + pContextProxy->iFlagForSub = 0; + + pthread_mutex_init (&pContextProxy->eventMutex, NULL); + pthread_cond_init (&pContextProxy->eventCond, NULL); + pContextProxy->iFlagForEvent = 0; //初始值设置为0,发送时设为-1,发送完ack再设为0。确保所有消息都回来的时候为0.相当于初始状态 + pContextProxy->iFlagForRRAsync = 0; + +} + +int wemq_context_init_add_manage_topic (stContextProxy * pContextProxy, + int type) +{ + int iRet = -1; + StWemqThreadMsg stThreadMsg; + stThreadMsg.m_iCmd = THREAD_MSG_CMD_ADD_MANAGE; + + if (type == 1) + { + iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "send msg to worker thread by kfifo error\n"); + } + } + else + { + iRet = wemq_kfifo_put (&pContextProxy->subFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "send msg to worker thread by kfifo error\n"); + } + } + + struct timeval nowTimeVal; + struct timespec timeout; + gettimeofday (&nowTimeVal, NULL); + timeout.tv_sec = + nowTimeVal.tv_sec + (nowTimeVal.tv_usec / 1000 + + pRmbStConfig->iNormalTimeout) / 1000; + timeout.tv_nsec = + ((nowTimeVal.tv_usec / 1000 + + pRmbStConfig->iNormalTimeout) % 1000) * 1000 * 1000; + + pContextProxy->iFlagForReg = 0; + pthread_mutex_lock (&pContextProxy->regMutex); + if (pContextProxy->iFlagForReg == 0) + { + pthread_cond_timedwait (&pContextProxy->regCond, &pContextProxy->regMutex, + &timeout); + } + pthread_mutex_unlock (&pContextProxy->regMutex); + + if (pContextProxy->iFlagForReg != 1) + { + LOGRMB (RMB_LOG_ERROR, "add manage topic timeout!\n"); + rmb_errno = RMB_ERROR_WORKER_REGISTER_ERROR; + return rmb_errno; + } + + /* + if (pContextProxy->rspForAddManage.uiResult != 0) + { + LOGWEMQ(WEMQ_LOG_ERROR, "Failed to add magnage!manageTopic=%s\n", pContextProxy->rspForAddManage.strManageTopic); + return -1; + } + */ + return 0; +} + +static int wemq_context_init_proxy_model (StContext * pStContext) +{ + stContextProxy *pContextProxy = NULL; + + //context proxy has been init; + //get only one contextproxy; + if (pRmbStConfig->iProxyContextNums == 1) + { + pStContext->pContextProxy = pRmbStConfig->pProxyContext; + pContextProxy = pRmbStConfig->pProxyContext; + if (pStContext->contextType == RMB_CONTEXT_TYPE_PUB) + { + pContextProxy->pubContext = (void *) pStContext; + } + else + { + pContextProxy->subContext = (void *) pStContext; + } + + return _wemq_context_create_thread (pStContext->contextType, + pContextProxy); + } + + //create proxy context + pContextProxy = (stContextProxy *) malloc (sizeof (stContextProxy)); + if (pContextProxy == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStContext->pContextProxy malloc error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + memset (pContextProxy, 0, sizeof (stContextProxy)); + pContextProxy->iFlagForRun = 1; + pContextProxy->ulGoodByeTime = 0; + pContextProxy->ulLastClearRRAysncMsgTime = 0; + + pStContext->pContextProxy = pContextProxy; + + if (pStContext->contextType == RMB_CONTEXT_TYPE_PUB) + { + pContextProxy->pubContext = (void *) pStContext; + } + else + { + pContextProxy->subContext = (void *) pStContext; + } + + INIT_WEMQ_KFIFO (pContextProxy->pubFifo); + INIT_WEMQ_KFIFO (pContextProxy->subFifo); + + wemq_topic_list_init (&pContextProxy->stTopicList); + + wemq_context_init_thread_sync_obj (pContextProxy); + +// pContextProxy->rrHashTable = (myhast_t *)malloc(sizeof(myhash_t)); +// if (pContextProxy->rrHashTable == NULL || +// myhash_init(pContextProxy->rrHashTable, 10000000)) +// { +// LOGRMB(RMB_LOG_ERROR, "pContextProxy->rrHashTable malloc or init error!\n"); +// rmb_errno = RMB_ERROR_MALLOC_FAIL; +// return rmb_errno; +// } + + pContextProxy->pReplyMsg = rmb_msg_malloc (); + + //all buffer initialize + pContextProxy->mPubRRBuf = (char *) malloc (TCP_BUF_SIZE * sizeof (char)); + if (pContextProxy->mPubRRBuf == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pContextProxy->mPubRRBuf malloc error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + memset (pContextProxy->mPubRRBuf, 0x00, TCP_BUF_SIZE * sizeof (char)); + + Init (&pContextProxy->pUniqueListForRRAsyncNew); + Init (&pContextProxy->pUniqueListForRRAsyncOld); + + //pContextProxy->pUniqueListForRRAsyncNew = pContextProxy->stUniqueListForRRAsync; + //pContextProxy->pUniqueListForRRAsyncOld = pContextProxy->stUniqueListForRRAsyncOld; + //memset(pContextProxy->pUniqueListForRRAsyncNew,0x00,RMB_MAX_UNIQUE_NUMS * sizeof(StUniqueIdList)); + //memset(pContextProxy->pUniqueListForRRAsyncOld,0x00,RMB_MAX_UNIQUE_NUMS * sizeof(StUniqueIdList)); + + // context proxy init ok; + pRmbStConfig->pProxyContext = pContextProxy; + pRmbStConfig->iProxyContextNums = 1; + + return _wemq_context_create_thread (pStContext->contextType, pContextProxy); +} + +StContext *g_pStContextArry[MAX_RMB_CONTEXT] = { NULL }; + +int Log_Thread_Start (StContext * pStContext) +{ + LOGRMB (RMB_LOG_INFO, "call thread start StContext = 0x%p", pStContext); + + if (pStContext->contextType == RMB_CONTEXT_TYPE_PUB) + { + pRmbStConfig->iFlagForLoop = 1; + } + + pthread_mutex_lock (&pRmbStConfig->configLog); + if (g_iLogThreadInit == 1) + { + if (g_pStContextArry[1] == NULL) + g_pStContextArry[1] = pStContext; + pthread_mutex_unlock (&pRmbStConfig->configLog); + return 0; + } + + g_iLogThreadInit = 1; + pthread_mutex_unlock (&pRmbStConfig->configLog); + + g_pStContextArry[0] = pStContext; + g_pStContextArry[1] = NULL; + + int iRet = + pthread_create (&g_stLogThreadId, NULL, (void *) &_Log_Thread_func, NULL); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "create Log thread error!iRet=%d\n", iRet); + } + return iRet; +} + +int rmb_context_init (StContext * pStContext) +{ + if (pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStContext is null!"); + rmb_errno = RMB_ERROR_ARGV_NULL; + return -1; + } + if (pStContext->uiInitFlag == 1) + { + LOGRMB (RMB_LOG_ERROR, "pStContext has already init!"); + return 0; + } + + int iRet = 0; + + pStContext->pReceiveWemqMsg = NULL; + pStContext->pReceiveWemqMsg = rmb_msg_malloc (); + if (pStContext->pReceiveWemqMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for pStContext->pReceiveWemqMsg error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + + pStContext->pReceiveWemqMsgForRR = NULL; + pStContext->pReceiveWemqMsgForRR = rmb_msg_malloc (); + if (pStContext->pReceiveWemqMsgForRR == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "malloc for pStContext->pReceiveWemqMsgForRR error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + + pStContext->pReceiveWemqMsgForBroadCast = NULL; + pStContext->pReceiveWemqMsgForBroadCast = rmb_msg_malloc (); + if (pStContext->pReceiveWemqMsgForBroadCast == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "malloc for pStContext->pReceiveWemqMsgForBroadCast failed!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + + pStContext->pWemqPkg = NULL; + pStContext->pWemqPkg = (char *) malloc (MAX_LENTH_IN_A_MSG); + if (pStContext->pWemqPkg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for pStContext->pWemqPkg error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + memset (pStContext->pWemqPkg, 0x00, MAX_LENTH_IN_A_MSG); + + pStContext->pWemqPkgForRRAsync = NULL; + pStContext->pWemqPkgForRRAsync = (char *) malloc (MAX_LENTH_IN_A_MSG); + if (pStContext->pWemqPkgForRRAsync == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "malloc for pStContext->pWemqPkgForRRAsync error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + memset (pStContext->pWemqPkgForRRAsync, 0x00, MAX_LENTH_IN_A_MSG); + + pStContext->uiInitFlag = 1; +// int iRet = Log_Thread_Start(pStContext); + iRet = wemq_context_init_proxy_model (pStContext); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_context_init_proxy_model failed, iRet=%d", + iRet); + return iRet; + } + + iRet = Log_Thread_Start (pStContext); + + return 0; +} + +int rmb_context_add_rsp_socket (StContext * pStContext, const char *cLocalIp, + unsigned short usRspPort) +{ + if (usRspPort != 0) + { + //init udp + pStContext->iSocketForRsp = udp_get_socket ("0.0.0.0", "0", NULL); + if (pStContext->iSocketForRsp < 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of udp socket init failed!port=%u", + (unsigned int) usRspPort); + rmb_errno = RMB_ERROR_INIT_UDP_FAIL; + return -3; + } + tcp_nodelay (pStContext->iSocketForRsp); + bzero (&pStContext->tmpReplyAddr, sizeof (pStContext->tmpReplyAddr)); + pStContext->tmpReplyAddr.sin_addr.s_addr = inet_addr (cLocalIp); + pStContext->tmpReplyAddr.sin_port = htons (usRspPort); + pRmbStConfig->iFlagForRRrsp = (int) MSG_IPC_UDP; + } + else + { + pStContext->iSocketForRsp = 0; + } + return 0; +} + +int rmb_context_add_broadcast_socket (StContext * pStContext, + const char *cLocalIp, + unsigned short usBroadcastPort) +{ + if (usBroadcastPort != 0) + { + //init udp + pStContext->iSocketForBroadcast = udp_get_socket ("0.0.0.0", "0", NULL); + if (pStContext->iSocketForBroadcast < 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of udp socket init failed!port=%u", + (unsigned int) usBroadcastPort); + rmb_errno = RMB_ERROR_INIT_UDP_FAIL; + return -3; + } + tcp_nodelay (pStContext->iSocketForBroadcast); + bzero (&pStContext->tmpBroadcastAddr, + sizeof (pStContext->tmpBroadcastAddr)); + pStContext->tmpBroadcastAddr.sin_addr.s_addr = inet_addr (cLocalIp); + pStContext->tmpBroadcastAddr.sin_port = htons (usBroadcastPort); + pRmbStConfig->iFlagForBroadCast = (int) MSG_IPC_UDP; + } + else + { + pStContext->iSocketForBroadcast = 0; + } + return 0; +} + +int rmb_context_add_req_socket (StContext * pStContext, const char *cLocalIp, + unsigned short usReqPort) +{ + if (usReqPort != 0) + { + //init udp + pStContext->iSocketForReq = udp_get_socket ("0.0.0.0", "0", NULL); + if (pStContext->iSocketForReq < 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of udp socket init failed!port=%u", + (unsigned int) usReqPort); + rmb_errno = RMB_ERROR_INIT_UDP_FAIL; + return -3; + } + tcp_nodelay (pStContext->iSocketForReq); + bzero (&pStContext->tmpReqAddr, sizeof (pStContext->tmpReqAddr)); + //pStContext->tmpReqAddr.sin_family = AF_INET; + pStContext->tmpReqAddr.sin_addr.s_addr = inet_addr (cLocalIp); + pStContext->tmpReqAddr.sin_port = htons (usReqPort); + + if (pRmbStConfig->iDebugSwitch) + { + LOGRMB (RMB_LOG_DEBUG, "add_req,socket=%u,ip=%s,port=%u", + pStContext->iSocketForReq, cLocalIp, usReqPort); + } + pRmbStConfig->iFlagForReq = (int) MSG_IPC_UDP; + } + else + { + pStContext->iSocketForReq = 0; + } + return 0; +} + +int rmb_context_add_req_mq_fifo (StContext * pStContext, + const char *strFiFoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, void *func_argv) +{ + int iRet = 0; + if (strlen (strFiFoPath) == 0) + { + LOGRMB (RMB_LOG_ERROR, "context_add_req_mq error!strFiFoPath size=0!"); + rmb_errno = RMB_ERROR_FIFO_PARA_ERROR; + return -1; + } + if (uiShmKey == 0 || uiShmSize == 0) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_req_mq error!shmKey=%u,shmSize=%u,fifoPath=%s", + uiShmKey, uiShmSize, strFiFoPath); + rmb_errno = RMB_ERROR_SHM_PARA_ERROR; + return -1; + } + //init mq + StRmbMq *pMq = (StRmbMq *) calloc (1, sizeof (StRmbMq)); + if (pMq == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of calloc mq failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + iRet = rmb_mq_init (pMq, uiShmKey, uiShmSize, true, false); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of rmb_mq_init failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + rmb_errno = RMB_ERROR_INIT_MQ_FAIL; + return -3; + } + + //init fifo + StRmbFifo *pFifo = (StRmbFifo *) calloc (1, sizeof (StRmbFifo)); + if (pFifo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of calloc fifo failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -4; + } + iRet = rmb_fifo_init (pFifo, strFiFoPath); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of rmb_fifo_init failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pFifo); + free (pMq); + rmb_errno = RMB_ERROR_INIT_FIFO_FAIL; + return -5; + } + + iRet = + rmb_notify_add (&pStContext->fifoMq, pMq, pFifo, req_mq_index, func, + func_argv); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of rmb_notify_add failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + free (pFifo); + return -6; + } + LOGRMB (RMB_LOG_INFO, "context_add_req_mq succ!"); + pRmbStConfig->iFlagForReq = (int) MSG_IPC_MQ; + return 0; +} + +int rmb_context_add_rr_rsp_mq_fifo (StContext * pStContext, + const char *strFiFoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, void *func_argv) +{ + int iRet = 0; + if (strlen (strFiFoPath) == 0) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo error!strFiFoPath size=0!"); + rmb_errno = RMB_ERROR_FIFO_PARA_ERROR; + return -1; + } + if (uiShmKey == 0 || uiShmSize == 0) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo error!shmKey=%u,shmSize=%u,fifoPath=%s", + uiShmKey, uiShmSize, strFiFoPath); + rmb_errno = RMB_ERROR_SHM_PARA_ERROR; + return -1; + } + //init mq + StRmbMq *pMq = (StRmbMq *) calloc (1, sizeof (StRmbMq)); + if (pMq == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo error!because of calloc mq failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + iRet = rmb_mq_init (pMq, uiShmKey, uiShmSize, true, false); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo error!because of rmb_mq_init failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + rmb_errno = RMB_ERROR_INIT_MQ_FAIL; + return -3; + } + + //init fifo + StRmbFifo *pFifo = (StRmbFifo *) calloc (1, sizeof (StRmbFifo)); + if (pFifo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo error!because of calloc fifo failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -4; + } + iRet = rmb_fifo_init (pFifo, strFiFoPath); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo error!because of rmb_fifo_init failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pFifo); + free (pMq); + rmb_errno = RMB_ERROR_INIT_FIFO_FAIL; + return -5; + } + + iRet = + rmb_notify_add (&pStContext->fifoMq, pMq, pFifo, rr_rsp_mq_index, func, + func_argv); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context_add_rr_rsp_mq_fifo!because of rmb_notify_add failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + free (pFifo); + return -6; + } + pRmbStConfig->iFlagForRRrsp = (int) MSG_IPC_MQ; + return 0; +} + +int rmb_context_add_broadcast_mq_fifo (StContext * pStContext, + const char *strFiFoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv) +{ + int iRet = 0; + if (strlen (strFiFoPath) == 0) + { + LOGRMB (RMB_LOG_ERROR, "fifo error!strFiFoPath size=0!"); + rmb_errno = RMB_ERROR_FIFO_PARA_ERROR; + return -1; + } + if (uiShmKey == 0 || uiShmSize == 0) + { + LOGRMB (RMB_LOG_ERROR, "shm error!shmKey=%u,shmSize=%u,fifoPath=%s", + uiShmKey, uiShmSize, strFiFoPath); + rmb_errno = RMB_ERROR_SHM_PARA_ERROR; + return -1; + } + //init mq + StRmbMq *pMq = (StRmbMq *) calloc (1, sizeof (StRmbMq)); + if (pMq == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmbMq error!because of calloc mq failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + iRet = rmb_mq_init (pMq, uiShmKey, uiShmSize, true, false); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "mq_init error!because of rmb_mq_init failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + rmb_errno = RMB_ERROR_INIT_MQ_FAIL; + return -3; + } + + //init fifo + StRmbFifo *pFifo = (StRmbFifo *) calloc (1, sizeof (StRmbFifo)); + if (pFifo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "fifo null error!because of calloc fifo failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -4; + } + iRet = rmb_fifo_init (pFifo, strFiFoPath); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "fifo init error!because of rmb_fifo_init failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pFifo); + free (pMq); + rmb_errno = RMB_ERROR_INIT_FIFO_FAIL; + return -5; + } + + iRet = + rmb_notify_add (&pStContext->fifoMq, pMq, pFifo, broadcast_mq_index, func, + func_argv); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "notify add error!because of rmb_notify_add failed!iRet=%d,shmKey=%u,shmSize=%u,fifoPath=%s", + iRet, uiShmKey, uiShmSize, strFiFoPath); + free (pMq); + free (pFifo); + return -6; + } + LOGRMB (RMB_LOG_INFO, "context_add_broadcast_mq succ!"); + pRmbStConfig->iFlagForBroadCast = (int) MSG_IPC_MQ; + return 0; +} + +//////////////////////////////////////////////////////////////////////// +static int rmb_context_add_queue_pipe (StContext * pStContext, + const unsigned int uiSize, + const enum RmbMqIndex iMsgType, + rmb_callback_func func, + void *func_argv) +{ + RMB_CHECK_POINT_NULL (pStContext, "rmb_context_add_queue_pipe:pStContext"); + + int iRet = 0; + if (uiSize == 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_context_add_queue_pipe error!uiSize=%u", + uiSize); + rmb_errno = RMB_ERROR_SHM_PARA_ERROR; + return -1; + } + //init queue + StRmbQueue *pQue = (StRmbQueue *) calloc (1, sizeof (StRmbQueue)); + if (pQue == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_context_add_queue_pipe error!because calloc for queue failed!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + + iRet = rmb_queue_init (pQue, uiSize); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_context_add_queue_pipe error!because rmb_queue_init failed!"); + free (pQue); + rmb_errno = RMB_ERROR_INIT_MQ_FAIL; + return -3; + } + + StRmbPipe *pPipe = (StRmbPipe *) calloc (1, sizeof (StRmbPipe)); + if (pPipe == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_context_add_queue_pipe error!because calloc for pipe failed!"); + free (pQue); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -4; + } + + iRet = rmb_pipe_init (pPipe); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_context_add_queue_pipe error!becaulse rmb_pipe_init failed!"); + free (pPipe); + free (pQue); + rmb_errno = RMB_ERROR_INIT_FIFO_FAIL; + return -5; + } + + iRet = + rmb_wemq_notify_add (&pStContext->fifoMq, pQue, pPipe, iMsgType, func, + func_argv); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "context init error!because of rmb_notify_add failed!"); + free (pPipe); + free (pQue); + return -6; + } + + LOGRMB (RMB_LOG_INFO, "rmb_context_add_queue_pipe succ!"); + pRmbStConfig->iFlagForReq = (int) MSG_IPC_MQ; + return 0; +} + +//static int rmb_context_add_req_queue_pipe(StContext *pStContext, const unsigned int uiSize, rmb_callback_func func, void *func_msg, void* func_argv) +//{ +// return rmb_context_add_queue_pipe(pStContext, uiSize, wemq_req_mq_index, func, func_msg, func_argv); +//} +// +//static int rmb_context_add_rr_rsp_queue_pipe(StContext *pStContext, const unsigned int uiSize, rmb_callback_func func, void *func_msg, void* func_argv) +//{ +// return rmb_context_add_queue_pipe(pStContext, uiSize, wemq_rr_rsp_mq_index, func, func_msg, func_argv); +//} +// +//static int rmb_context_add_broadcast_queue_pipe(StContext *pStContext, const unsigned int uiSize, rmb_callback_func func, void *func_msg, void* func_argv) +//{ +// return rmb_context_add_queue_pipe(pStContext, uiSize, wemq_broadcast_mq_index, func, func_msg, func_argv); +//} +//////////////////////////////////////////////////////////////////////// + +int rmb_context_enqueue (StContext * pStContext, + const enum RmbMqIndex uiMsgType, const char *data, + unsigned int uiDataLen) +{ + pStContext->uiNowTime = time (NULL); + return rmb_notify_enqueue_by_type (&(pStContext->fifoMq), uiMsgType, + pStContext->uiNowTime, data, uiDataLen); +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_errno.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_errno.c new file mode 100644 index 0000000000..ffab955166 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_errno.c @@ -0,0 +1,155 @@ +// 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. + +#include +#include +#include +#include +#include "rmb_errno.h" + +char *p_err_msg[RMB_MAX_ERR_NUMS] = { 0 }; + +struct rmb_err_msg rmb_err_msg_array[] = { + {RMB_ERROR_ARGV_NULL, "argv is null"}, + {RMB_ERROR_ARGV_LEN_ERROR, "argv len error"}, + {RMB_ERROR_MALLOC_FAIL, "malloc fail"}, + {RMB_ERROR_INIT_CONTEXT_FAIL, "init context fail"}, + {RMB_ERROR_MSG_MISSING_PART, "msg missing necessary part"}, + {RMB_ERROR_RR_INTERFACE_CAN_NOT_SEND_EVENT_MSG, + "rr interface can't send event msg"}, + {RMB_ERROR_EVENT_INTERFACE_CAN_NOT_SEND_RR_MSG, + "event msg can't send rr msg"}, + {RMB_ERROR_NOW_CAN_NOT_SEND_MSG, "now can't send msg"}, + {RMB_ERROR_QUEUE_FULL, "queue is full"}, + {RMB_ERROR_GSL_SERVICE_ID_NULL, "gsl service id null"}, + {RMB_ERROR_GSL_SERVICE_ID_ERROR, "gsl service id error"}, + {RMB_ERROR_GSL_SVR_ERROR, "gsl svr return error"}, + {RMB_ERROR_REQ_GSL_ERROR, "req gsl error"}, + {RMB_ERROR_MSG_UUID_FAIL, "msg generate uuid fail"}, + {RMB_ERROR_MSG_SET_SYSTEMHEADER_FAIL, "msg set systemheadfer fail"}, + {RMB_ERROR_SEND_GET_SESSION_FAIL, "send get session fail"}, + {RMB_ERROR_SEND_EVENT_MSG_FAIL, "send event msg fail"}, + {RMB_ERROR_SEND_RR_MSG_FAIL, "send rr msg fail"}, + {RMB_ERROR_SEND_RR_MSG_TIMEOUT, "send rr msg timeout"}, + {RMB_ERROR_REPLY_TO_NULL, "reply to is null"}, + {RMB_ERROR_REPLY_FAIL, "reply msg fail"}, + {RMB_ERROR_SESSION_CONNECT_FAIL, "session connect fail"}, + {RMB_ERROR_SESSION_RECONNECT_FAIL, "session reconnect fail"}, + {RMB_ERROR_SESSION_DESTORY_FAIL, "session destory fail"}, + {RMB_ERROR_SESSION_NUMS_LIMIT, "session nums limit"}, + {RMB_ERROR_LISTEN_QUEUE_NOT_EXIST, "listen queue not exist"}, + {RMB_ERROR_LISTEN_QUEUE_FAIL, "listen queue fail"}, + {RMB_ERROR_FLOW_DESTORY_FAIL, "flow destory fail"}, + {RMB_ERROR_LISTEN_TOPIC_FAIL, "listen topic fail"}, + {RMB_ERROR_INIT_MQ_FAIL, "init mq fail"}, + {RMB_ERROR_INIT_FIFO_FAIL, "init fifo fail"}, + {RMB_ERROR_INIT_UDP_FAIL, "init udp fail"}, + {RMB_ERROR_INIT_EPOLL_FAIL, "init epoll fail"}, + {RMB_ERROR_MQ_NUMS_LIMIT, "mq nums limit"}, + {RMB_ERROR_ENQUEUE_MQ_FAIL, "enqueue mq fail"}, + {RMB_ERROR_DEQUEUE_MQ_FAIL, "dequeue mq fail"}, + {RMB_ERROR_MSG_2_BUF_FAIL, "shift msg to buf fail"}, + {RMB_ERROR_BUF_2_MSG_FAIL, "shift buf to msg fail"}, + {RMB_ERROR_MSG_SET_CONTENT_TOO_LARGE, "msg set content too large"}, + {RMB_ERROR_MSG_SET_APPHEADER_TOO_LARGE, "msg set appheader too large"}, + {RMB_ERROR_MSG_TTL_0, "message ttl can't be 0"}, + {RMB_ERROR_RCV_MSG_GET_CONTENT_FAIL, "receive msg has no content"}, + {RMB_ERROR_RCV_MSG_GET_BINARY_FAIL, "receive msg has no binary"}, + {RMB_ERROR_RCV_MSG_CONTENT_TOO_LARGE, "receive msg content too large"}, + {RMB_ERROR_RCV_MSG_APPHEADER_TOO_LARGE, + "receive message appheader too large"}, + {RMB_ERROR_MANAGE_MSG_PKG_ERROR, "manage msg format error"}, + {RMB_ERROR_MANAGE_MSG_PKG_CHECK_FAIL, "manage msg check fail"}, + {RMB_ERROR_CONTEXT_CREATE_FAIL, "context create fail"}, + {RMB_ERROR_FIFO_PARA_ERROR, "fifo para error"}, + {RMB_ERROR_SHM_PARA_ERROR, "shm para error"}, + {RMB_ERROR_SEND_FIFO_NOTIFY_ERROR, "send notify fail"}, + {RMB_ERROR_FLOW_NUMS_LIMIT, "flow nums limit"}, + {RMB_ERROR_MSG_GET_SYSTEMHEADER_ERROR, "get system header error"}, + {RMB_ERROR_RMB_MSG_2_SOLACE_MSG_ERROR, "copy rmb msg 2 solace msg error"}, + {RMB_ERROR_SOLACE_MSG_2_RMB_MSG_ERROR, "copy solace msg 2 rmb msg error"}, + {RMB_ERROR_NO_AVAILABLE_SESSION, "no available session"}, + {RMB_ERROR_NO_BROADCAST_SESSION, "no broadcast session"}, + {RMB_ERROR_NO_AVAILABLE_CONTEXT, "no available context"}, + {RMB_ERROR_SET_FLOW_PROPETY, "set flow property fail"}, + {RMB_ERROR_ACK_MSG_FAIL, "ack msg fail"}, + {RMB_ERROR_LOGIC_NOTIFY_INIT, "notify for logic init error"}, + {RMB_ERROR_SESSION_ADD_FAIL, "session add fail"}, + {RMB_ERROR_WORKER_NUMS_LIMIT, "worker nums limit"}, + {RMB_ERROR_BUF_NOT_ENOUGH, "buf not enough"}, + {RMB_ERROR_STOP_FLOW_ERROR, "stop flow receive error"}, + {RMB_ERROR_DEQUEUE_MQ_EMPTY, "dequeue empty"}, + {RMB_ERROR_WORKER_WINDOW_FULL, "worker send window full"}, + {RMB_ERROR_WORKER_PUT_FIFO_ERROR, "worker put msg into fifo error"}, + {RMB_ERROR_START_CALL_FAIL, "send log for start call error"}, + {RMB_ERROR_END_CALL_FAIL, "send log for end call error"}, + {RMB_ERROR_ENTRY_FAIL, "send log for entry error"}, + {RMB_ERROR_EXIT_FAIL, "send log for exit error"}, + {RMB_ERROR_BASE_BEGIN, NULL} +}; + +static pthread_key_t rmb_user_key; +static pthread_once_t rmb_user_key_once = PTHREAD_ONCE_INIT; + +static void rmb_make_key () +{ + (void) pthread_key_create (&rmb_user_key, NULL); +} + +int *rmb_error () +{ + int *ptr; + + (void) pthread_once (&rmb_user_key_once, rmb_make_key); + if ((ptr = pthread_getspecific (rmb_user_key)) == NULL) + { + ptr = malloc (sizeof (int)); + memset (ptr, 0, sizeof (int)); + (void) pthread_setspecific (rmb_user_key, ptr); + } + return ptr; +} + +void init_error () +{ + int i = 0; + for (; rmb_err_msg_array[i].err_msg != NULL && i < RMB_MAX_ERR_NUMS; i++) + { + p_err_msg[rmb_err_msg_array[i].err_no - RMB_ERROR_BASE_BEGIN] = + rmb_err_msg_array[i].err_msg; + } + rmb_errno = 0; +} + +const char *get_rmb_last_error () +{ + if (rmb_errno == 0) + { + return "ok"; + } + if (rmb_errno <= RMB_ERROR_BASE_BEGIN + && rmb_errno >= RMB_ERROR_BASE_BEGIN + RMB_MAX_ERR_NUMS) + { + return "unknown errorno"; + } + return ((p_err_msg[rmb_errno - RMB_ERROR_BASE_BEGIN] == + NULL) ? "unknown errorno" : p_err_msg[rmb_errno - + RMB_ERROR_BASE_BEGIN]); +} + +void rmb_reset_error () +{ + rmb_errno = 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_http_client.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_http_client.c new file mode 100644 index 0000000000..acab4b0b4d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_http_client.c @@ -0,0 +1,211 @@ +// 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. + +#include +#include +#include +#include +#include "curl/curl.h" +#include "rmb_http_client.h" +#include "rmb_define.h" + +static pthread_mutex_t LIBCURL_LOCK = PTHREAD_MUTEX_INITIALIZER; +static int LIBCURL_INIT_FLAG = 0; + +static void atexit_callback (void) +{ + if (0 != LIBCURL_INIT_FLAG) + { +#ifdef RMB_HTTP_DEBUG + printf ("[Exit]curl_global_cleanup\n"); +#endif + curl_global_cleanup (); + LIBCURL_INIT_FLAG = 0; + } +} + +static void libcurl_init (void) +{ + pthread_mutex_lock (&LIBCURL_LOCK); + if (0 == LIBCURL_INIT_FLAG) + { +#ifdef RMB_HTTP_DEBUG + printf ("[INIT]curl_global_init\n"); +#endif + curl_global_init (CURL_GLOBAL_ALL); + atexit (atexit_callback); + LIBCURL_INIT_FLAG = 1; + } + pthread_mutex_unlock (&LIBCURL_LOCK); +} + +static int on_http_debug (CURL * handle, curl_infotype type, char *data, + size_t size, void *userptr) +{ + if (type == CURLINFO_TEXT) + { + //printf("[TEXT]%s\n", data); + } + else if (type == CURLINFO_HEADER_IN) + { + printf ("[HEADER_IN]%s\n", data); + } + else if (type == CURLINFO_HEADER_OUT) + { + printf ("[HEADER_OUT]%s\n", data); + } + else if (type == CURLINFO_DATA_IN) + { + printf ("[DATA_IN]%s\n", data); + } + else if (type == CURLINFO_DATA_OUT) + { + printf ("[DATA_OUT]%s\n", data); + } + return 0; +} + +static size_t on_http_body (char *ptr, size_t size, size_t nmemb, + void *userdata) +{ + size_t len = size * nmemb; + + if (ptr == NULL || userdata == NULL) + { + printf ("%s ptr is null\n", __func__); + return -1; + } + + struct rmb_http_buffer *buf = (struct rmb_http_buffer *) userdata; + + buf->data = + (char *) realloc (buf->data, sizeof (char) * (buf->len + len + 1)); + if (buf->data == NULL) + { + /* out of memory */ + printf ("not enough memory for realloc(buf->data)"); + return 0; + } + + memcpy (&(buf->data[buf->len]), ptr, len); + buf->len += len; + buf->data[buf->len] = '\0'; + + return len; +} + +int rmb_http_easy_get (const char *url, void *buffer, long timeout) +{ + CURLcode res; + CURL *curl = NULL; + struct curl_slist *headers = NULL; + + libcurl_init (); + curl = curl_easy_init (); + if (NULL == curl) + { + LOGRMB (RMB_LOG_ERROR, "curl_easy_init failed"); + return -1; + } + + struct rmb_http_buffer *response = (struct rmb_http_buffer *) buffer; + + headers = curl_slist_append (headers, "Connection: Keep-Alive"); + +#ifdef RMB_HTTP_DEBUG + curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt (curl, CURLOPT_DEBUGFUNCTION, on_http_debug); +#endif + curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt (curl, CURLOPT_URL, url); + curl_easy_setopt (curl, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, on_http_body); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *) response); + curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT_MS, timeout); + curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, timeout); + res = curl_easy_perform (curl); + curl_easy_cleanup (curl); + curl_slist_free_all (headers); + + if (res == CURLE_COULDNT_CONNECT) + { + return 1; + } + + if (res != CURLE_OK) + { + LOGRMB (RMB_LOG_ERROR, "curl_easy_perform failed: %s\n", + curl_easy_strerror (res)); + return -2; + } + + return 0; +} + +/* +int rmb_http_easy_post(char* url, char* post_data, size_t len, void* buffer, size_t size, size_t* used, long timeout) +{ + CURLcode res; + CURL* curl = NULL; + struct curl_slist *headers = NULL; + struct http_buffer response; + + libcurl_init(); + curl = curl_easy_init(); + if (NULL == curl) + { + return -1; + } + + response.buf = (char*)buffer; + response.size = size; + response.len = 0; + headers = curl_slist_append(headers, "Connection: Keep-Alive"); + +#ifdef HTTP_DEBUG + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, on_http_debug); +#endif + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_URL, url); + + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)len); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, on_http_body); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout); + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + if (res == CURLE_COULDNT_CONNECT) { + return 1; + } + if (0 != res) { + return -1; + } + *used = response.len; + if (response.len >= response.size) { + return 2; + } + *(response.buf + response.len) = '\0'; + return 0; +} +*/ diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_log.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_log.c new file mode 100644 index 0000000000..2b04f39a32 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_log.c @@ -0,0 +1,1273 @@ +// 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. + +#include "rmb_log.h" +#include +#include "string.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmb_define.h" +#include "string.h" +#include "rmb_access_config.h" +#include + +StRmbLog *pStRmbLog = NULL; + +struct tm currRmb; +struct tm lastRmb; +static char StatLogLevel[6][10] = + { "FATAL", "ERROR", "WARN ", "INFO", "DEBUG", "ALL" }; + +int GetRmbNowLongTime () +{ + struct timeval nowRmbTimeVal; + gettimeofday (&nowRmbTimeVal, NULL); + pRmbStConfig->ulNowTtime = + (unsigned long) nowRmbTimeVal.tv_sec * (unsigned long) 1000UL + + (unsigned long) nowRmbTimeVal.tv_usec / 1000UL; + return 0; +} + +char *RmbGetDateTimeStr (const time_t * mytime) +{ + static char s[50]; + currRmb = *localtime (mytime); + if (currRmb.tm_year > 50) + snprintf (s, sizeof (s), "%04d-%02d-%02d %02d:%02d:%02d", + currRmb.tm_year + 1900, currRmb.tm_mon + 1, currRmb.tm_mday, + currRmb.tm_hour, currRmb.tm_min, currRmb.tm_sec); + else + snprintf (s, sizeof (s), "%04d-%02d-%02d %02d:%02d:%02d", + currRmb.tm_year + 2000, currRmb.tm_mon + 1, currRmb.tm_mday, + currRmb.tm_hour, currRmb.tm_min, currRmb.tm_sec); + return s; +} + +char *RmbGetCurDateTimeStr () +{ + time_t mytime = time (NULL); + return RmbGetDateTimeStr (&mytime); +} + +char *RmbGetShortDateStr (const time_t * mytime) +{ + static char s[50]; + currRmb = *localtime (mytime); + if (currRmb.tm_year > 50) + snprintf (s, sizeof (s), "%04d%02d%02d", currRmb.tm_year + 1900, + currRmb.tm_mon + 1, currRmb.tm_mday); + else + snprintf (s, sizeof (s), "%04d%02d%02d", currRmb.tm_year + 2000, + currRmb.tm_mon + 1, currRmb.tm_mday); + + return s; +} + +char *RmbGetCurShortDateStr () +{ + time_t mytime = time (NULL); + return RmbGetShortDateStr (&mytime); +} + +int RmbIsOtherDay (time_t * newTime, time_t * oldTime) +{ + lastRmb = *localtime (oldTime); + currRmb = *localtime (newTime); + if (currRmb.tm_mday != lastRmb.tm_mday) + { + return 1; + } + return 0; +} + +int GetCurFileNum (FILE * fl) +{ + if (fl != NULL) + { + fscanf (fl, "%d %d %lu", &pStRmbLog->_curFileNo, &pStRmbLog->_curFileNums, + &pStRmbLog->_lastShiftTime); + } + return 0; +} + +int SetCurFileNum (FILE * fl) +{ + if (fl != NULL) + { + ftruncate (fileno (fl), 0); + rewind (fl); + fprintf (fl, "%d %d %lu", pStRmbLog->_curFileNo, pStRmbLog->_curFileNums, + pStRmbLog->_lastShiftTime); + } + return 0; +} + +int GetCurFileNumFromStatFile () +{ + FILE *fp = fopen (pStRmbLog->_logStatFileName, "r"); + if (fp == NULL) + { + return 0; + } + fscanf (fp, "%d %d %lu", &pStRmbLog->_curFileNo, &pStRmbLog->_curFileNums, + &pStRmbLog->_lastShiftTime); + fclose (fp); + return 0; +} + +int SetCurFileNumToStatFile () +{ + struct flock lock; + FILE *fp = fopen (pStRmbLog->_logStatFileName, "w"); + if (fp == NULL) + { + return 0; + } + int fd = fileno (fp); + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock.l_pid = getpid (); + if (-1 != fcntl (fd, F_SETLKW, &lock)) + { +// printf("pid=%d set FileNo=%d.Num=%d", getpid(), pStRmbLog->_curFileNo, pStRmbLog->_curFileNums); + fprintf (fp, "%d %d", pStRmbLog->_curFileNo, pStRmbLog->_curFileNums); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + fcntl (fd, F_SETLKW, &lock); + } + fclose (fp); + return 0; +} + +int ReloadCfg (int logLevel, int shiftType, const char *path, int maxFileSize, + int maxFileNum) +{ + int iRet = 0; + pStRmbLog->_para._logLevel = logLevel; + pStRmbLog->_para._shiftType = shiftType; + if (shiftType == 6) + { + pStRmbLog->_para._shiftType = (int) RMB_LOG_TYPE_CYCLE; + } + strncpy (pStRmbLog->_para._path, path, sizeof (pStRmbLog->_para._path) - 1); + snprintf (pStRmbLog->_logStatFileName, + sizeof (pStRmbLog->_logStatFileName) - 1, "%s.stat", path); + pStRmbLog->_para._maxFileSize = maxFileSize; + pStRmbLog->_para._maxFileNum = maxFileNum; + pStRmbLog->_lastShiftTime = time (NULL); + if (strlen (pStRmbLog->_para._path) == 0 + || pStRmbLog->_para._shiftType == RMB_LOG_TYPE_NORMAL) + { + pStRmbLog->_pLogFile = stdout; + pStRmbLog->_curFileNums = 1; + pStRmbLog->_para._shiftType = 0; + pStRmbLog->_lastShiftTime = 0; + return 0; + } + + if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_CYCLE) + { + iRet = GetCurStateFromRmbLogByCirCle (); + if (iRet != 0) + { + return -1; + } + } + else if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_DAILY + || pStRmbLog->_para._shiftType == RMB_LOG_TYPE_DAILY_AND_CYCLE) + { + pStRmbLog->_para._shiftType = RMB_LOG_TYPE_DAILY; + iRet = GetCurStateFromRmbLogByDaily_V4 (); + if (iRet != 0) + { + return -1; + } + } + else + { + pStRmbLog->_para._shiftType = RMB_LOG_TYPE_CYCLE; + iRet = GetCurStateFromRmbLogByCirCle (); + if (iRet != 0) + { + return -1; + } + } + return 0; +} + +int InitRmbLogFile (int logLevel, int shiftType, const char *path, + int maxFileSize, int maxFileNum) +{ + int iRet = 0; + memset (&pRmbStConfig->gRmbLog, 0, sizeof (StRmbLog)); + pStRmbLog = &pRmbStConfig->gRmbLog; + pStRmbLog->_para._logLevel = logLevel; + + pStRmbLog->_para._shiftType = shiftType; + if (shiftType == 6) + { + pStRmbLog->_para._shiftType = (int) RMB_LOG_TYPE_CYCLE; + } + strncpy (pStRmbLog->_para._path, path, sizeof (pStRmbLog->_para._path) - 1); + snprintf (pStRmbLog->_logStatFileName, + sizeof (pStRmbLog->_logStatFileName) - 1, "%s.stat", path); + pStRmbLog->_para._maxFileSize = maxFileSize; + pStRmbLog->_para._maxFileNum = maxFileNum; + pStRmbLog->_lastShiftTime = time (NULL); + + //spin_lock_init(&logSpinLock); + pthread_mutex_init (&pStRmbLog->rmbLogMutex, NULL); + //printf("log init!!"); + //if len(path) = 0, use stdout + + if (strlen (pStRmbLog->_para._path) == 0 + || pStRmbLog->_para._shiftType == RMB_LOG_TYPE_NORMAL) + { + pStRmbLog->_pLogFile = stdout; + pStRmbLog->_curFileNums = 1; + pStRmbLog->_para._shiftType = 0; + pStRmbLog->_lastShiftTime = 0; + return 0; + } + + if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_CYCLE) + { + iRet = GetCurStateFromRmbLogByCirCle (); + if (iRet != 0) + { + return -1; + } + } + else if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_DAILY + || pStRmbLog->_para._shiftType == RMB_LOG_TYPE_DAILY_AND_CYCLE) + { + pStRmbLog->_para._shiftType = RMB_LOG_TYPE_DAILY; + iRet = GetCurStateFromRmbLogByDaily_V4 (); + if (iRet != 0) + { + return -1; + } + } + else + { + pStRmbLog->_para._shiftType = RMB_LOG_TYPE_CYCLE; + iRet = GetCurStateFromRmbLogByCirCle (); + if (iRet != 0) + { + return -1; + } + } + return 0; +} + +int CloseRmbLog () +{ +// if(pStRmbLog->_pLogFile == NULL) +// { +// return 0; +// } +// fclose(pStRmbLog->_pLogFile); +// pStRmbLog->_pLogFile = NULL; +// return 0; + close (pStRmbLog->_fd); + pStRmbLog->_fd = -1; + return 0; +} + +int OpenRmbLog () +{ +// if (pStRmbLog->_pLogFile != NULL) +// { +// return 0; +// } +// printf("open file=%s", pStRmbLog->_logBaseFileName); +// if ((pStRmbLog->_pLogFile = fopen(pStRmbLog->_logBaseFileName, "a+")) == NULL) +// { +// pStRmbLog->_pLogFile = stdout; +// printf("openLog failed!fileName=%s, now select stdout!", pStRmbLog->_logBaseFileName); +// return -1; +// } +// printf("open file=%s succ", pStRmbLog->_logBaseFileName); + pStRmbLog->_fd = + open (pStRmbLog->_logBaseFileName, O_RDWR | O_CREAT | O_APPEND, 0666); + if (pStRmbLog->_fd == -1) + { + printf ("openLog failed!fileName=%s, now select stdout!", + pStRmbLog->_logBaseFileName); + pStRmbLog->_fd = 1; + return 0; + } + return 0; +} + +int OpenStateLog () +{ + pStRmbLog->_pStatFile = fopen (pStRmbLog->_logStatFileName, "a+"); + if (pStRmbLog->_pStatFile == NULL) + { + return 0; + } + return fileno (pStRmbLog->_pStatFile); +} + +int CloseStateLog () +{ + if (pStRmbLog->_pStatFile != NULL) + { + fclose (pStRmbLog->_pStatFile); + } + pStRmbLog->_pStatFile = NULL; + return 0; +} + +int FindNextDeleteLog (StDayInfo * dayInfo) +{ + //update next delete file name and time + int i = 0; + //找当天的 + for (i = 1; i < pStRmbLog->_para._maxFileNum; i++) + { + pStRmbLog->_toDeleteFileNo = + (pStRmbLog->_toDeleteFileNo + 1) % pStRmbLog->_para._maxFileNum; + if (pStRmbLog->_toDeleteFileNo == 0) + { + pStRmbLog->_toDeleteFileNo = 1; + } + + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s_%s.%d", + pStRmbLog->_para._path, + RmbGetShortDateStr ((time_t *) & pStRmbLog->_toDeleteTime), + pStRmbLog->_toDeleteFileNo); +// printf("check fileName=%s is exist or not!", pStRmbLog->_toDeleteFileName); + struct stat sb; + if (stat (pStRmbLog->_toDeleteFileName, &sb) != 0) + { +// printf("i=%u,logFile=%s not exist!", i, pStRmbLog->_toDeleteFileName); + break; + } +// printf("Next deleteNo=%u,deleteFileName=%s", pStRmbLog->_toDeleteFileNo, pStRmbLog->_toDeleteFileName); + return 0; + } + + int count = (time (NULL) - pStRmbLog->_toDeleteTime) / 60 * 60 * 24 + 1; + for (i = 1; i < count; i++) + { + pStRmbLog->_toDeleteTime = pStRmbLog->_toDeleteTime + 60 * 60 * 24; + GetDayInfo (dayInfo, &pStRmbLog->_toDeleteTime); + if (dayInfo->_curFileNum != 0) + { + pStRmbLog->_toDeleteFileNo = dayInfo->_deleteFileNo; + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s_%s.%d", + pStRmbLog->_para._path, + RmbGetShortDateStr ((time_t *) & pStRmbLog->_toDeleteTime), + pStRmbLog->_toDeleteFileNo); + break; + } + } + + return 0; +} + +int ShiftRmbLog (FILE * file) +{ + if (strlen (pStRmbLog->_para._path) == 0 + || pStRmbLog->_para._shiftType == RMB_LOG_TYPE_NORMAL) + { + return 0; + } + + if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_CYCLE) + { + + if (stat (pStRmbLog->_logBaseFileName, &pStRmbLog->gRmbSb) < 0) + { + pStRmbLog->_curFileSize = 0; + } + else + { + pStRmbLog->_curFileSize = (int) pStRmbLog->gRmbSb.st_size; + } + + if (pStRmbLog->_curFileSize < pStRmbLog->_para._maxFileSize) + { + return 0; + } + + OpenRmbLog (); + //file lock + pStRmbLog->logFileLock.l_type = F_WRLCK; + pStRmbLog->logFileLock.l_start = 0; + pStRmbLog->logFileLock.l_whence = SEEK_SET; + pStRmbLog->logFileLock.l_len = 0; + pStRmbLog->logFileLock.l_pid = getpid (); + if (-1 != fcntl (pStRmbLog->_fd, F_SETLKW, &pStRmbLog->logFileLock)) + { + int fd = OpenStateLog (); + pStRmbLog->logStateLock.l_type = F_WRLCK; + pStRmbLog->logStateLock.l_start = 0; + pStRmbLog->logStateLock.l_whence = SEEK_SET; + pStRmbLog->logStateLock.l_len = 0; + pStRmbLog->logStateLock.l_pid = getpid (); + if (-1 != fcntl (fd, F_SETLKW, &pStRmbLog->logStateLock)) + { + //GetCurFileNum(pStRmbLog->_pStatFile); + GetCurFileNum (pStRmbLog->_pStatFile); +// printf("pid=%d,getCurNo=%d,CurNums=%d", getpid(), pStRmbLog->_curFileNo, pStRmbLog->_curFileNums); + snprintf (pStRmbLog->_logFileName, + sizeof (pStRmbLog->_logFileName) - 1, "%s.%d", + pStRmbLog->_logBaseFileName, pStRmbLog->_curFileNo); + + if (stat (pStRmbLog->_logBaseFileName, &pStRmbLog->gRmbSb) != -1 + && (int) pStRmbLog->gRmbSb.st_size >= + pStRmbLog->_para._maxFileSize) + { + pStRmbLog->_curFileNums += 1; + if (pStRmbLog->_curFileNums > pStRmbLog->_para._maxFileNum) + { + if (access (pStRmbLog->_logFileName, F_OK) == 0) + { +// printf("pid=%d remove file=%s,curNo=%d, curNum=%d", getpid(), pStRmbLog->_logFileName, pStRmbLog->_curFileNo, pStRmbLog->_curFileNums); + remove (pStRmbLog->_logFileName); + } + pStRmbLog->_curFileNums -= 1; + } + + if (access (pStRmbLog->_logBaseFileName, F_OK) == 0) + { +// printf("pid=%d rename %s-->%s, curNo=%d,curNum=%d", getpid(), pStRmbLog->_logBaseFileName, pStRmbLog->_logFileName, pStRmbLog->_curFileNo, pStRmbLog->_curFileNums); + rename (pStRmbLog->_logBaseFileName, pStRmbLog->_logFileName); + } + else + { +// printf("pid=%d baseFileName=%s not exist", getpid(), pStRmbLog->_logBaseFileName); + } + pStRmbLog->_curFileNo = + (pStRmbLog->_curFileNo + 1) % pStRmbLog->_para._maxFileNum; +// if (pStRmbLog->_curFileNo == 0) +// { +// pStRmbLog->_curFileNo = 1; +// } + SetCurFileNum (pStRmbLog->_pStatFile); + //snprintf(pStRmbLog->_logFileName, sizeof(pStRmbLog->_logFileName) - 1, "%s.%d", pStRmbLog->_logBaseFileName, pStRmbLog->_curFileNo); + } + +// printf("pid=%d setFileNum.curNo=%d curNum=%d", getpid(), pStRmbLog->_curFileNo, pStRmbLog->_curFileNums); + pStRmbLog->logStateLock.l_type = F_UNLCK; + pStRmbLog->logStateLock.l_whence = SEEK_SET; + pStRmbLog->logStateLock.l_start = 0; + pStRmbLog->logStateLock.l_len = 0; + fcntl (fd, F_SETLKW, &pStRmbLog->logStateLock); + } + CloseStateLog (); + +// printf("shift over!pid=%d, curNo=%d,curNum=%d, logFileName=%s", getpid(), pStRmbLog->_curFileNo, pStRmbLog->_curFileNums, pStRmbLog->_logFileName); + //strncpy(pStRmbLog->_toDeleteFileName, pStRmbLog->_logFileName, sizeof(pStRmbLog->_toDeleteFileName) - 1); + + pStRmbLog->logFileLock.l_type = F_UNLCK; + pStRmbLog->logFileLock.l_whence = SEEK_SET; + pStRmbLog->logFileLock.l_start = 0; + pStRmbLog->logFileLock.l_len = 0; + fcntl (pStRmbLog->_fd, F_SETLKW, &pStRmbLog->logFileLock); + } + CloseRmbLog (); + return 0; + } + else if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_DAILY) + { + time_t curTime = time (NULL); + //日期变更发送滚动 + if (RmbIsOtherDay (&curTime, &pStRmbLog->_lastShiftTime)) + { + OpenRmbLog (); + //file lock + pStRmbLog->logFileLock.l_type = F_WRLCK; + pStRmbLog->logFileLock.l_start = 0; + pStRmbLog->logFileLock.l_whence = SEEK_SET; + pStRmbLog->logFileLock.l_len = 0; + pStRmbLog->logFileLock.l_pid = getpid (); + if (-1 != fcntl (pStRmbLog->_fd, F_SETLKW, &pStRmbLog->logFileLock)) + { + int fd = OpenStateLog (); + pStRmbLog->logStateLock.l_type = F_WRLCK; + pStRmbLog->logStateLock.l_start = 0; + pStRmbLog->logStateLock.l_whence = SEEK_SET; + pStRmbLog->logStateLock.l_len = 0; + pStRmbLog->logStateLock.l_pid = getpid (); + if (-1 != fcntl (fd, F_SETLKW, &pStRmbLog->logStateLock)) + { + GetCurFileNum (pStRmbLog->_pStatFile); + snprintf (pStRmbLog->_logFileName, + sizeof (pStRmbLog->_logFileName) - 1, "%s.%d", + pStRmbLog->_logBaseFileName, pStRmbLog->_curFileNo); + + if (RmbIsOtherDay (&curTime, &pStRmbLog->_lastShiftTime)) + { + pStRmbLog->_curFileNums += 1; + if (pStRmbLog->_curFileNums > pStRmbLog->_para._maxFileNum) + { + if (access (pStRmbLog->_logFileName, F_OK) == 0) + { + remove (pStRmbLog->_logFileName); + } + pStRmbLog->_curFileNums -= 1; + } + if (access (pStRmbLog->_logBaseFileName, F_OK) == 0) + { + rename (pStRmbLog->_logBaseFileName, pStRmbLog->_logFileName); + } + + snprintf (pStRmbLog->_logBaseFileName, + sizeof (pStRmbLog->_logBaseFileName), "%s_%s.log", + pStRmbLog->_para._path, RmbGetShortDateStr (&curTime)); + snprintf (pStRmbLog->_logFileName, + sizeof (pStRmbLog->_logFileName), "%s.0", + pStRmbLog->_logBaseFileName); + pStRmbLog->_curFileNo = 0; + pStRmbLog->_curFileNums = 0; + pStRmbLog->_lastShiftTime = curTime; + SetCurFileNum (pStRmbLog->_pStatFile); + } + else + { + snprintf (pStRmbLog->_logBaseFileName, + sizeof (pStRmbLog->_logBaseFileName), "%s_%s.log", + pStRmbLog->_para._path, RmbGetShortDateStr (&curTime)); + } + pStRmbLog->logStateLock.l_type = F_UNLCK; + pStRmbLog->logStateLock.l_whence = SEEK_SET; + pStRmbLog->logStateLock.l_start = 0; + pStRmbLog->logStateLock.l_len = 0; + fcntl (fd, F_SETLKW, &pStRmbLog->logStateLock); + } + CloseStateLog (); + + pStRmbLog->logFileLock.l_type = F_UNLCK; + pStRmbLog->logFileLock.l_whence = SEEK_SET; + pStRmbLog->logFileLock.l_start = 0; + pStRmbLog->logFileLock.l_len = 0; + fcntl (pStRmbLog->_fd, F_SETLKW, &pStRmbLog->logFileLock); + } + CloseRmbLog (); + return 0; + } + + if (stat (pStRmbLog->_logBaseFileName, &pStRmbLog->gRmbSb) < 0) + { + pStRmbLog->_curFileSize = 0; + } + else + { + pStRmbLog->_curFileSize = (int) pStRmbLog->gRmbSb.st_size; + } + + if (pStRmbLog->_curFileSize < pStRmbLog->_para._maxFileSize) + { + return 0; + } + + OpenRmbLog (); + //file lock + pStRmbLog->logFileLock.l_type = F_WRLCK; + pStRmbLog->logFileLock.l_start = 0; + pStRmbLog->logFileLock.l_whence = SEEK_SET; + pStRmbLog->logFileLock.l_len = 0; + pStRmbLog->logFileLock.l_pid = getpid (); + if (-1 != fcntl (pStRmbLog->_fd, F_SETLKW, &pStRmbLog->logFileLock)) + { + int fd = OpenStateLog (); + pStRmbLog->logStateLock.l_type = F_WRLCK; + pStRmbLog->logStateLock.l_start = 0; + pStRmbLog->logStateLock.l_whence = SEEK_SET; + pStRmbLog->logStateLock.l_len = 0; + pStRmbLog->logStateLock.l_pid = getpid (); + if (-1 != fcntl (fd, F_SETLKW, &pStRmbLog->logStateLock)) + { + GetCurFileNum (pStRmbLog->_pStatFile); + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName), + "%s.%d", pStRmbLog->_logBaseFileName, + pStRmbLog->_curFileNo); + + if (stat (pStRmbLog->_logBaseFileName, &pStRmbLog->gRmbSb) != -1 + && (int) pStRmbLog->gRmbSb.st_size >= + pStRmbLog->_para._maxFileSize) + { + pStRmbLog->_curFileNums += 1; + if (pStRmbLog->_curFileNums > pStRmbLog->_para._maxFileNum) + { + if (access (pStRmbLog->_logFileName, F_OK) == 0) + { + remove (pStRmbLog->_logFileName); + } + pStRmbLog->_curFileNums -= 1; + } + //CloseZrdLog(); + if (access (pStRmbLog->_logBaseFileName, F_OK) == 0) + { + rename (pStRmbLog->_logBaseFileName, pStRmbLog->_logFileName); + } + + pStRmbLog->_curFileNo = + (pStRmbLog->_curFileNo + 1) % pStRmbLog->_para._maxFileNum; +// if (pStRmbLog->_curFileNo == 0) +// { +// pStRmbLog->_curFileNo = 1; +// } + SetCurFileNum (pStRmbLog->_pStatFile); + + } + + pStRmbLog->logStateLock.l_type = F_UNLCK; + pStRmbLog->logStateLock.l_whence = SEEK_SET; + pStRmbLog->logStateLock.l_start = 0; + pStRmbLog->logStateLock.l_len = 0; + fcntl (fd, F_SETLKW, &pStRmbLog->logStateLock); + } + CloseStateLog (); + + pStRmbLog->logFileLock.l_type = F_UNLCK; + pStRmbLog->logFileLock.l_whence = SEEK_SET; + pStRmbLog->logFileLock.l_start = 0; + pStRmbLog->logFileLock.l_len = 0; + fcntl (pStRmbLog->_fd, F_SETLKW, &pStRmbLog->logFileLock); + } + CloseRmbLog (); + return 0; + } + else if (pStRmbLog->_para._shiftType == RMB_LOG_TYPE_DAILY_AND_CYCLE) + { + time_t curTime = time (NULL); + //日期变更发送滚动 + if (RmbIsOtherDay (&curTime, &pStRmbLog->_lastShiftTime)) + { + pStRmbLog->_curFileNums += 1; + //假如个数限制,则删除老的 + if (pStRmbLog->_curFileNums > pStRmbLog->_para._maxFileNum) + { + remove (pStRmbLog->_toDeleteFileName); + pStRmbLog->_curFileNums -= 1; + StDayInfo dayInfo; + FindNextDeleteLog (&dayInfo); + } + //GetCurStateFromRmbLogByDaily_V3(); //保证没有出错 + //rename + //CloseRmbLog(); + rename (pStRmbLog->_logBaseFileName, pStRmbLog->_logFileName); + snprintf (pStRmbLog->_logBaseFileName, + sizeof (pStRmbLog->_logBaseFileName), "%s_%s.log", + pStRmbLog->_para._path, RmbGetShortDateStr (&curTime)); + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName), + "%s_1.log", pStRmbLog->_logBaseFileName); + pStRmbLog->_curFileNo = 1; + //OpenRmbLog(); + return 0; + } + + if (stat (pStRmbLog->_logBaseFileName, &pStRmbLog->gRmbSb) < 0) + { + pStRmbLog->_curFileSize = 0; + } + else + { + pStRmbLog->_curFileSize = (int) pStRmbLog->gRmbSb.st_size; + } + + if (pStRmbLog->_curFileSize < pStRmbLog->_para._maxFileSize) + { + return 0; + } + //文件大小促发滚动 + pStRmbLog->_curFileNums += 1; + if (pStRmbLog->_curFileNums > pStRmbLog->_para._maxFileNum) + { + remove (pStRmbLog->_toDeleteFileName); + pStRmbLog->_curFileNums -= 1; + StDayInfo dayInfo; + FindNextDeleteLog (&dayInfo); + } + //rename + //CloseRmbLog(); + rename (pStRmbLog->_logBaseFileName, pStRmbLog->_logFileName); + pStRmbLog->_curFileNo += 1; + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName), + "%s_%d.log", pStRmbLog->_logBaseFileName, + pStRmbLog->_curFileNo); + //OpenRmbLog(); + return 0; + } + return 0; +} + +int LogRmb (int logLevel, const char *format, ...) +{ +// printf("logLevel=%u,sysLevel=%u,file=%p,baseFile=%s", +// logLevel, pStRmbLog->_para._logLevel, pStRmbLog->_pLogFile, pStRmbLog->_logBaseFileName); +// va_list ap1; +// va_start(ap1, format); +// printf(format, ap1); +// va_end(ap1); +// return 0; +// return ShiftRmbLog(pStRmbLog->_pLogFile); + + if (logLevel > pStRmbLog->_para._logLevel) + { + return 0; + } + + //pthread_spin_lock(&logSpinLock); + pthread_mutex_lock (&pStRmbLog->rmbLogMutex); + ShiftRmbLog (pStRmbLog->_pLogFile); + va_list ap; + if ((pStRmbLog->_pLogFile = + fopen (pStRmbLog->_logBaseFileName, "a+")) == NULL) + { + pStRmbLog->_pLogFile = stdout; + //printf("openLog failed!fileName=%s, now select stdout!", pStRmbLog->_logBaseFileName); + } + va_start (ap, format); + gettimeofday (&pStRmbLog->stLogTv, NULL); + fprintf (pStRmbLog->_pLogFile, "[%s][%s %03d][%d][%lu]", + StatLogLevel[logLevel], + RmbGetDateTimeStr ((const time_t *) &(pStRmbLog->stLogTv.tv_sec)), + (int) ((pStRmbLog->stLogTv.tv_usec) / 1000), pRmbStConfig->uiPid, + pthread_self ()); + vfprintf (pStRmbLog->_pLogFile, format, ap); + va_end (ap); + fprintf (pStRmbLog->_pLogFile, "\n"); + if (pStRmbLog->_pLogFile != stdout) + { + fclose (pStRmbLog->_pLogFile); + } + + //pthread_spin_unlock(&logSpinLock); + pthread_mutex_unlock (&pStRmbLog->rmbLogMutex); + return 0; +} + +//统计现在有几个日志,当前日志马上要被rename成什么,是不是需要促发删除 +int GetCurStateFromRmbLogByCirCle () +{ + pStRmbLog->_curFileNums = 1; + //unsigned int minModifyTime = 0; + //int i = 0; + snprintf (pStRmbLog->_logBaseFileName, sizeof (pStRmbLog->_logBaseFileName), + "%s.log", pStRmbLog->_para._path); + //strncpy(pStRmbLog->_logFileName, pStRmbLog->_logBaseFileName, sizeof(pStRmbLog->_logFileName) - 1); + pStRmbLog->_curFileNo = 0; + /* + for (i = 1; i < pStRmbLog->_para._maxFileNum ; i++) + { + snprintf(pStRmbLog->_logFileName, sizeof(pStRmbLog->_logFileName) - 1, "%s.%d", pStRmbLog->_logBaseFileName, i); + printf("log file:%s", pStRmbLog->_logFileName); + + struct stat sb; + if (stat (pStRmbLog->_logFileName, &sb) != 0) + { + //�ļ�������, ʹ�øñ�� + pStRmbLog->_curFileNo = i; + printf("logFile=%s not exist!", pStRmbLog->_logFileName); + break; + } + pStRmbLog->_curFileNums++; + + printf("fileName=%s,modifyTime=%lu", pStRmbLog->_logFileName, sb.st_mtime); + //ѭ����־, ��Ҫ������޸�ʱ��������� + if (minModifyTime == 0 || sb.st_mtime < minModifyTime) + { + pStRmbLog->_toDeleteFileNo = i; + minModifyTime = sb.st_mtime; + } + // if (sb.st_mtime > maxModifyTime) + // { + // pStRmbLog->_curFileNo = i; + // maxModifyTime = sb.st_mtime; + // } + } + */ + pStRmbLog->_curFileNums = 0; + GetCurFileNumFromStatFile (); +// if (pStRmbLog->_curFileNo == 0) +// { +// pStRmbLog->_curFileNo = pStRmbLog->_toDeleteFileNo; +// } + //SetCurFileNumToStatFile(); + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName) - 1, + "%s.%d", pStRmbLog->_logBaseFileName, pStRmbLog->_curFileNo); + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s.%d", + pStRmbLog->_logBaseFileName, pStRmbLog->_toDeleteFileNo); + //printf("Circle Log: curFileNo=%u", pStRmbLog->_curFileNo); + return 0; +} + +//统计现在有几个日志,当前日志马上要被rename成什么,是不是需要促发删除(按编号大小) +int GetCurStateFromRmbLogByDaily () +{ + pStRmbLog->_curFileNums = 1; + int i = 0; + snprintf (pStRmbLog->_logBaseFileName, sizeof (pStRmbLog->_logBaseFileName), + "%s_%s.log", pStRmbLog->_para._path, RmbGetCurShortDateStr ()); + //strncpy(pStRmbLog->_logFileName, pStRmbLog->_logBaseFileName, sizeof(pStRmbLog->_logFileName) - 1); + //int todayFileNo = 0; + unsigned int curTime = time (NULL); + //当天 + for (i = 1; i < pStRmbLog->_para._maxFileNum - 1; i++) + { + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName) - 1, + "%s.%d", pStRmbLog->_logBaseFileName, i); +// printf("GetCurStateFromRmbLogByDaily log file:%s", pStRmbLog->_logFileName); + + struct stat sb; + if (stat (pStRmbLog->_logFileName, &sb) != 0) + { + //file not exist, use it + pStRmbLog->_curFileNo = i; + //pStRmbLog->_curFileNums = i; +// printf("GetCurStateFromRmbLogByDaily logFile=%s not exist!", pStRmbLog->_logFileName); + break; + } + pStRmbLog->_toDeleteTime = curTime; + pStRmbLog->_curFileNums++; + } + + //unsigned int minModifyTime = 0; + char baseFileName[300] = { 0 }; + int j = 0; + int finishFlag = 0; + int deleteNo = 0; + //往前找 + for (i = 1; !finishFlag && i < pStRmbLog->_para._maxFileNum; i++) + { + pStRmbLog->_toDeleteFileNo = deleteNo; + pStRmbLog->_toDeleteTime = curTime - 60 * 60 * 24 * i; + snprintf (baseFileName, sizeof (baseFileName), "%s_%s.log", + pStRmbLog->_para._path, + RmbGetShortDateStr ((time_t *) & pStRmbLog->_toDeleteTime)); +// printf("%d_baseName=%s", i , baseFileName); + int iNotNullFlag = 0; + for (j = 1; j < pStRmbLog->_para._maxFileNum; j++) + { + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s.%d", + baseFileName, i); +// printf("check fileName=%s is exist or not!", pStRmbLog->_toDeleteFileName); + struct stat sb; + if (stat (pStRmbLog->_toDeleteFileName, &sb) != 0) + { + if (iNotNullFlag == 1) + { +// printf("GetCurStateFromRmbLogByDaily logFile=%s not exist!", pStRmbLog->_toDeleteFileName); + break; + } + if (j == pStRmbLog->_para._maxFileNum - 1) + { + if (iNotNullFlag == 0) + { + finishFlag = 1; +// printf("GetCurStateFromRmbLogByDaily logFile=%s has't exist", pStRmbLog->_toDeleteFileName); + break; + } + } + + continue; + } + if (deleteNo == 0) + { + deleteNo = j; + } + iNotNullFlag = 1; + pStRmbLog->_curFileNums++; + } + } + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s.1", baseFileName); +// printf("Status:curFileNums=%u,mayBeDeleteFileName=%s", pStRmbLog->_curFileNums, pStRmbLog->_toDeleteFileName); + return 0; +} + +int GetDayInfo (StDayInfo * dayInfo, time_t * curTime) +{ + int i = 0; + time_t minModifyTime = 0; + dayInfo->_deleteFileNo = 1; + dayInfo->_curFileNo = 0; + dayInfo->_curFileNum = 0; + + snprintf (dayInfo->_baseFileName, sizeof (dayInfo->_baseFileName), + "%s_%s.log", pStRmbLog->_para._path, + RmbGetShortDateStr (curTime)); + + //当天 + for (i = 1; i < pStRmbLog->_para._maxFileNum; i++) + { + snprintf (dayInfo->_logFileName, sizeof (dayInfo->_logFileName) - 1, + "%s.%d", dayInfo->_baseFileName, i); +// printf("GetDayInfo log file:%s", dayInfo->_logFileName); + + struct stat sb; + if (stat (dayInfo->_logFileName, &sb) != 0) + { + //file not exist, use it + if (dayInfo->_curFileNo == 0) + { + dayInfo->_curFileNo = i; + } +// printf("GetDayInfo logFile=%s not exist!", dayInfo->_logFileName); + continue; + //break; //之所以不用break, 因为存在消除该日期下其他日志的可能 + } + dayInfo->_curFileNum++; + //循环日志,需要按最后修改时间排序 + if (minModifyTime == 0 || sb.st_mtime < minModifyTime) + { + dayInfo->_deleteFileNo = i; + minModifyTime = sb.st_mtime; + } + } + return 0; +} + +int GetDayInfoWithBreak (StDayInfo * dayInfo, time_t * curTime) +{ + int i = 0; + time_t minModifyTime = 0; + dayInfo->_deleteFileNo = 1; + dayInfo->_curFileNo = 0; + dayInfo->_curFileNum = 0; + snprintf (dayInfo->_baseFileName, sizeof (dayInfo->_baseFileName), + "%s_%s.log", pStRmbLog->_para._path, + RmbGetShortDateStr (curTime)); + + //当天 + for (i = 1; i < pStRmbLog->_para._maxFileNum; i++) + { + snprintf (dayInfo->_logFileName, sizeof (dayInfo->_logFileName) - 1, + "%s.%d", dayInfo->_baseFileName, i); +// printf("GetDayInfoWithBreak log file:%s", dayInfo->_logFileName); + + struct stat sb; + if (stat (dayInfo->_logFileName, &sb) != 0) + { + //file not exist, use it + if (dayInfo->_curFileNo == 0) + { + dayInfo->_curFileNo = i; + } +// printf("GetDayInfoWithBreak logFile=%s not exist!", dayInfo->_logFileName); + break; + } + dayInfo->_curFileNum++; + //循环日志,需要按最后修改时间排序 + if (minModifyTime == 0 || sb.st_mtime < minModifyTime) + { + dayInfo->_deleteFileNo = i; + minModifyTime = sb.st_mtime; + } + } + return 0; +} + +//统计现在有几个日志,当前日志马上要被rename成什么,是不是需要促发删除(同一个日期,按修改日期滚动) +int GetCurStateFromRmbLogByDaily_V3 () +{ + pStRmbLog->_curFileNums = 1; + int i = 0; + //当前天 + time_t curTime = time (NULL); + StDayInfo dayInfo; + GetDayInfo (&dayInfo, &curTime); + if (dayInfo._curFileNo == 0) + { + pStRmbLog->_curFileNo = dayInfo._deleteFileNo; + } + else + { + pStRmbLog->_curFileNo = dayInfo._curFileNo; + } + pStRmbLog->_curFileNums += dayInfo._curFileNum; + pStRmbLog->_toDeleteFileNo = dayInfo._deleteFileNo; + pStRmbLog->_toDeleteTime = curTime; + snprintf (pStRmbLog->_logBaseFileName, sizeof (pStRmbLog->_logBaseFileName), + "%s_%s.log", pStRmbLog->_para._path, + RmbGetShortDateStr (&curTime)); + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName) - 1, + "%s.%d", pStRmbLog->_logBaseFileName, pStRmbLog->_curFileNo); + + //往前数 + for (i = 1; i < pStRmbLog->_para._maxFileNum; i++) + { + curTime = curTime - 60 * 60 * 24; + GetDayInfo (&dayInfo, &curTime); + if (dayInfo._curFileNum != 0) + { + pStRmbLog->_curFileNums += dayInfo._curFileNum; + pStRmbLog->_toDeleteFileNo = dayInfo._deleteFileNo; + pStRmbLog->_toDeleteTime = curTime; + } + else + { + break; + } + + } + + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s_%s.%d", + pStRmbLog->_para._path, + RmbGetShortDateStr (&pStRmbLog->_toDeleteTime), + pStRmbLog->_toDeleteFileNo); +// printf("GetCurStateFromRmbLogByDaily_V3 Status:curFileNums=%u,mayBeDeleteFileName=%s", pStRmbLog->_curFileNums, pStRmbLog->_toDeleteFileName); + return 0; +} + +//统计现在有几个日志,当前日志马上要被rename成什么,是不是需要促发删除(同一个日期,按修改日期滚动) +int GetCurStateFromRmbLogByDaily_V2 () +{ + pStRmbLog->_curFileNums = 1; + int i = 0; + snprintf (pStRmbLog->_logBaseFileName, sizeof (pStRmbLog->_logBaseFileName), + "%s_%s.log", pStRmbLog->_para._path, RmbGetCurShortDateStr ()); + //strncpy(pStRmbLog->_logFileName, pStRmbLog->_logBaseFileName, sizeof(pStRmbLog->_logFileName) - 1); + //int todayFileNo = 0; + unsigned int curTime = time (NULL); + //unsigned int maxModifyTime = 0; + unsigned int minModifyTime = 0; + + pStRmbLog->_toDeleteFileNo = 1; + //当天 + for (i = 1; i < pStRmbLog->_para._maxFileNum; i++) + { + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName) - 1, + "%s.%d", pStRmbLog->_logBaseFileName, i); +// printf("GetCurStateFromRmbLogByDaily log file:%s", pStRmbLog->_logFileName); + + struct stat sb; + if (stat (pStRmbLog->_logFileName, &sb) != 0) + { + //file not exist, use it + pStRmbLog->_curFileNo = i; + +// printf("GetCurStateFromRmbLogByDaily logFile=%s not exist!", pStRmbLog->_logFileName); + break; + } + pStRmbLog->_toDeleteTime = curTime; + pStRmbLog->_curFileNums++; + + //循环日志,需要按最后修改时间排序 + if (minModifyTime == 0 || sb.st_mtime < minModifyTime) + { + pStRmbLog->_toDeleteFileNo = i; + minModifyTime = sb.st_mtime; + } + } + + char baseFileName[300] = { 0 }; + int j = 0; + int finishFlag = 0; + int deleteNo = 0; + //往前 + for (i = 1; !finishFlag && i < pStRmbLog->_para._maxFileNum; i++) + { + pStRmbLog->_toDeleteTime = curTime - 60 * 60 * 24 * i; + time_t uiDeleteTime = pStRmbLog->_toDeleteTime; + snprintf (baseFileName, sizeof (baseFileName), "%s_%s.log", + pStRmbLog->_para._path, RmbGetShortDateStr (&uiDeleteTime)); +// printf("%d_baseName=%s", i , baseFileName); + int iNotNullFlag = 0; + deleteNo = 0; + //针对每一天查找 + for (j = 1; j < pStRmbLog->_para._maxFileNum; j++) + { + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s.%d", + baseFileName, j); +// printf("check fileName=%s is exist or not!", pStRmbLog->_toDeleteFileName); + struct stat sb; + if (stat (pStRmbLog->_toDeleteFileName, &sb) != 0) + { + if (iNotNullFlag == 1) + { +// printf("GetCurStateFromRmbLogByDaily logFile=%s not exist!", pStRmbLog->_toDeleteFileName); + break; + } + if (j == pStRmbLog->_para._maxFileNum - 1) + { + if (iNotNullFlag == 0) + { + finishFlag = 1; + pStRmbLog->_toDeleteTime = + pStRmbLog->_toDeleteTime + 60 * 60 * 24; +// printf("GetCurStateFromRmbLogByDaily logFile=%s has't exist", pStRmbLog->_toDeleteFileName); + break; + } + } + + continue; + } + if (deleteNo == 0) + { + deleteNo = j; + pStRmbLog->_toDeleteFileNo = deleteNo; //记录当前最应该删除的 + } + iNotNullFlag = 1; //表示前面不是空的,没有类似000111的情况 + pStRmbLog->_curFileNums++; + } + + } + time_t uiDeleteTime = pStRmbLog->_toDeleteTime; + snprintf (baseFileName, sizeof (baseFileName), "%s_%s.log", + pStRmbLog->_para._path, RmbGetShortDateStr (&uiDeleteTime)); + snprintf (pStRmbLog->_toDeleteFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1, "%s.%d", baseFileName, + pStRmbLog->_toDeleteFileNo); +// printf("Status:curFileNums=%u,mayBeDeleteFileName=%s", pStRmbLog->_curFileNums, pStRmbLog->_toDeleteFileName); + return 0; +} + +//只在当天滚 +int GetCurStateFromRmbLogByDaily_V4 () +{ + pStRmbLog->_curFileNums = 0; + //当前天 + /* + time_t curTime = time(NULL); + StDayInfo dayInfo; + GetDayInfoWithBreak(&dayInfo, &curTime); + if (dayInfo._curFileNo == 0) + { + pStRmbLog->_curFileNo = dayInfo._deleteFileNo; + } + else + { + pStRmbLog->_curFileNo = dayInfo._curFileNo; + } + pStRmbLog->_curFileNums = dayInfo._curFileNum; + pStRmbLog->_toDeleteFileNo = dayInfo._curFileNo; + pStRmbLog->_toDeleteTime = curTime; + */ + pStRmbLog->_curFileNo = 0; + time_t curTime = time (NULL); + pStRmbLog->_lastShiftTime = curTime; + GetCurFileNumFromStatFile (); + pStRmbLog->_toDeleteFileNo = pStRmbLog->_curFileNo; + + snprintf (pStRmbLog->_logBaseFileName, sizeof (pStRmbLog->_logBaseFileName), + "%s_%s.log", pStRmbLog->_para._path, + RmbGetShortDateStr (&curTime)); + snprintf (pStRmbLog->_logFileName, sizeof (pStRmbLog->_logFileName) - 1, + "%s.%d", pStRmbLog->_logBaseFileName, pStRmbLog->_curFileNo); + strncpy (pStRmbLog->_toDeleteFileName, pStRmbLog->_logFileName, + sizeof (pStRmbLog->_toDeleteFileName) - 1); + return 0; +} + +void _Log_Thread_func (void *args) +{ + struct timeval nowTimeVal; + gettimeofday (&nowTimeVal, NULL); + unsigned long ulNowTime = + (unsigned long) nowTimeVal.tv_sec * (unsigned long) 1000UL + + (unsigned long) nowTimeVal.tv_usec / 1000UL; + unsigned long lastPrintTime = 0; + + struct timeval tv_now; + unsigned long ulLastGetConfigTime = 0; + unsigned long ulLastGetAccessTime = 0; + + // char url[512]; + // snprintf(url, sizeof(url), "http://%s:%d/%s/%s/%s/%s", pRmbStConfig->cConfigIp, pRmbStConfig->iConfigPort, RMB_REQ_SINGLE, RMB_WHITE_LIST_SND, pRmbStConfig->cConsumerSysId, pRmbStConfig->cRegion); + + while (1) + { + int i = 0; + if ((pRmbStConfig->iWemqUseHttpCfg == 1)) + { + gettimeofday (&tv_now, NULL); + if (tv_now.tv_sec > + (ulLastGetAccessTime + pRmbStConfig->getAccessIpPeriod)) + { + ulLastGetAccessTime = tv_now.tv_sec; + //int iRet = wemq_proxy_load_servers(cAccessIpUrl, pRmbStConfig->iConfigTimeout, pRmbStConfig->cWemqSavePath); + char cAccessIpUrl[512]; + char addrArr[15][50] = { 0 }; + int lenAddrs = 0; + char tmpAddrs[512] = { 0 }; + strcpy (tmpAddrs, pRmbStConfig->ConfigAddr); + LOGRMB (RMB_LOG_DEBUG, + "config center ip str is:%s,try get access ip from the %d config center in list,lists:", + tmpAddrs, pRmbStConfig->configIpPosInArr + 1); + split_str (tmpAddrs, addrArr, &lenAddrs); + int j = 0; + for (j = 0; j < lenAddrs; ++j) + { + LOGRMB (RMB_LOG_DEBUG, "%s", addrArr[j]); + } + if (lenAddrs == 0) + { + LOGRMB (RMB_LOG_ERROR, + "config center addr list len is 0,please check if configCenterAddrMulti is empty in conf file"); + return -1; + } + + int iRet = 0; + int i = 0; + for (i = 0; i < lenAddrs; ++i) + { + memset (&cAccessIpUrl, 0x00, sizeof (cAccessIpUrl)); + snprintf (cAccessIpUrl, sizeof (cAccessIpUrl), "%s/%s", + addrArr[(i + pRmbStConfig->configIpPosInArr) % lenAddrs], + WEMQ_ACCESS_SERVER); + LOGRMB (RMB_LOG_DEBUG, "try to get access addr from %s", + cAccessIpUrl); + iRet = + wemq_proxy_load_servers (cAccessIpUrl, + pRmbStConfig->iConfigTimeout); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_WARN, + "get access ip from %s failed,try next config center ip", + cAccessIpUrl); + continue; + } + else + { + LOGRMB (RMB_LOG_INFO, + "get all access ip list result=%d from url:%s", iRet, + cAccessIpUrl); + pRmbStConfig->configIpPosInArr = + pRmbStConfig->configIpPosInArr + i; + break; + } + } + + // free addrArr + } + } + + sleep (1); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_mq.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_mq.c new file mode 100644 index 0000000000..c6e6dfd302 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_mq.c @@ -0,0 +1,1357 @@ +// 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. + +#include "rmb_mq.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmb_cfg.h" +#include "rmb_log.h" +#include "rmb_define.h" +#include +#include "rmb_pub.h" + +#define NO_CLEAR_FLAG 0 +#define CLEAR_FLAG 1 + +int rmb_notify_get_fator (const int iCount) +{ + if (iCount < 5000) + { + return iCount / 1000 + 1; + } + else if (iCount < 10000) + { + return 5; + } + else if (iCount < 20000) + { + return 8; + } + else if (iCount < 30000) + { + return 12; + } + else if (iCount < 50000) + { + return 20; + } + else if (iCount < 100000) + { + return 30; + } + return 40; +} + +//get shared mem +int rmb_mq_get_shm (StRmbMq * pMq, const unsigned int shmKey, + const unsigned int shmSize, const int flags, + const int bReadOnly) +{ + long lRet; + if ((pMq->ulShmId = shmget (shmKey, shmSize, flags)) == -1) + { + return -1; + } + if (1 == bReadOnly) + { + if ((lRet = (long) shmat (pMq->ulShmId, NULL, SHM_RDONLY)) == -1) + { + return -2; + } + } + else + { + if ((lRet = (long) shmat (pMq->ulShmId, NULL, 0)) == -1) + { + return -3; + } + } + pMq->pMqData = (char *) lRet; + return 0; +} + +//mq init +int rmb_mq_init (StRmbMq * pMq, const unsigned int shmKey, + const unsigned int shmSize, const int bCreate, + const int bReadOnly) +{ + if (shmSize <= C_RMB_MQ_HEAD_SIZE) + { + LOGRMB (RMB_LOG_ERROR, "rmb_mq_init shmSize if too small=%d", + (int) shmSize); + return -1; + } + pMq->uiShmkey = shmKey; + pMq->uiShmSize = shmSize; + + int nFlag = 0666; + //pMq->mqStat.ulShmId = + int iRet = rmb_mq_get_shm (pMq, shmKey, shmSize, nFlag, bReadOnly); + if (iRet != 0) + { + if (bCreate) + { + nFlag = nFlag | IPC_CREAT; + iRet = rmb_mq_get_shm (pMq, shmKey, shmSize, nFlag, bReadOnly); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_mq_init get shm failed! has create,iRet=%d", iRet); + return -2; + } + if (!bReadOnly) + { + //memset(pMq->pMqData, 0, pMq->uiShmSize); + memset (pMq->pMqData, 0, C_RMB_MQ_HEAD_SIZE); // set head and tail + } + } + else + { + LOGRMB (RMB_LOG_ERROR, "rmb_mq_init get shm failed! no create,iRet=%d", + iRet); + return -3; + } + } + + //init shm + pMq->pHead = (unsigned int *) pMq->pMqData; + pMq->pTail = (unsigned int *) (pMq->pMqData + sizeof (unsigned int)); + *(pMq->pHead) = 0; + *(pMq->pTail) = 0; + pMq->pBlock = (char *) (pMq->pTail + 1); + pMq->uiBlockSize = pMq->uiShmSize - C_RMB_MQ_HEAD_SIZE; + return 0; +} + +//mq_enqueue +//return -2: not enough space +int rmb_mq_enqueue (StRmbMq * pMq, const char *data, unsigned int uiDataLen, + unsigned int uiFLow) +{ + if (pMq == NULL || data == NULL) + { + LOGRMB (RMB_LOG_ERROR, "enqueue failed!pMq==NULL or data==NULL"); + rmb_errno = RMB_ERROR_ARGV_NULL; + return -1; + } + + unsigned int uiHead = *pMq->pHead; + unsigned int uiTail = *pMq->pTail; + unsigned int uiFreeLen = + uiHead > uiTail ? uiHead - uiTail : uiHead + pMq->uiBlockSize - uiTail; + unsigned int uiTailLen = pMq->uiBlockSize - uiTail; + char *pBlock = pMq->pBlock; + + char sHead[C_RMB_MQ_PKG_HEAD_SIZE] = { 0 }; + unsigned int uiTotalLen = uiDataLen + C_RMB_MQ_PKG_HEAD_SIZE; + + //1.if no enough space + if (uiFreeLen <= uiTotalLen) + { + return -2; + } + + memcpy (sHead, &uiTotalLen, sizeof (unsigned int)); + memcpy (sHead + sizeof (unsigned int), &uiFLow, sizeof (unsigned int)); + + //2.if tail space > 8+len + //copy 8 byte, copy data + if (uiTailLen >= uiTotalLen) + { + memcpy (pBlock + uiTail, sHead, C_RMB_MQ_PKG_HEAD_SIZE); + memcpy (pBlock + uiTail + C_RMB_MQ_PKG_HEAD_SIZE, data, uiDataLen); + //update tail + *pMq->pTail += (uiDataLen + C_RMB_MQ_PKG_HEAD_SIZE); + + } + //3.if tail space > 8 && < 8+len + else if (uiTailLen >= C_RMB_MQ_PKG_HEAD_SIZE + && uiTailLen < C_RMB_MQ_PKG_HEAD_SIZE + uiDataLen) + { + // copy 8 byte + memcpy (pBlock + uiTail, sHead, C_RMB_MQ_PKG_HEAD_SIZE); + + // copy firstlen + unsigned int uiFirstLen = uiTailLen - C_RMB_MQ_PKG_HEAD_SIZE; + memcpy (pBlock + uiTail + C_RMB_MQ_PKG_HEAD_SIZE, data, uiFirstLen); + + // copy secondlen + unsigned int uiSecondLen = uiDataLen - uiFirstLen; + memcpy (pBlock, data + uiFirstLen, uiSecondLen); + + //update tail + unsigned int tail = + *pMq->pTail + uiDataLen + C_RMB_MQ_PKG_HEAD_SIZE - pMq->uiBlockSize; + *pMq->pTail = tail; + } + //4.if tail space < 8 + else + { + //copy tail byte + memcpy (pBlock + uiTail, sHead, uiTailLen); + + //copy 8-tail byte + unsigned int uiSecondLen = C_RMB_MQ_PKG_HEAD_SIZE - uiTailLen; + memcpy (pBlock, sHead + uiTailLen, uiSecondLen); + + //copy data + memcpy (pBlock + uiSecondLen, data, uiDataLen); + + //update tail + *pMq->pTail = uiSecondLen + uiDataLen; + } + return 0; +} + +//mq_dequeue +int rmb_mq_dequeue (StRmbMq * pMq, char *buf, unsigned int uiBufSize, + unsigned int *pDataLen, unsigned int *pFlowId) +{ + RMB_CHECK_POINT_NULL (pMq, "pMq"); + RMB_CHECK_POINT_NULL (pMq, "buf"); + RMB_CHECK_POINT_NULL (pMq, "pDataLen"); + + unsigned int uiHead = *pMq->pHead; + unsigned int uiTail = *pMq->pTail; + const char *pBlock = pMq->pBlock; + + if (uiHead == uiTail) + { + *pDataLen = 0; + return 0; + } + unsigned int uiUsedLen = + uiTail > uiHead ? uiTail - uiHead : uiTail + pMq->uiBlockSize - uiHead; + char sHead[C_RMB_MQ_PKG_HEAD_SIZE]; + + //1.get head + if (uiHead + C_RMB_MQ_PKG_HEAD_SIZE > pMq->uiBlockSize) + { + unsigned int uiFirstSize = pMq->uiBlockSize - uiHead; + unsigned int uiSecondSize = C_RMB_MQ_PKG_HEAD_SIZE - uiFirstSize; + memcpy (sHead, pBlock + uiHead, uiFirstSize); + memcpy (sHead + uiFirstSize, pBlock, uiSecondSize); + uiHead = uiSecondSize; + } + else + { + memcpy (sHead, pBlock + uiHead, C_RMB_MQ_PKG_HEAD_SIZE); + uiHead += C_RMB_MQ_PKG_HEAD_SIZE; + } + + //2.get meta data len + unsigned int uiTotalLen = *((unsigned int *) sHead); + if (pFlowId) + { + *pFlowId = *((unsigned *) (sHead + sizeof (unsigned int))); + } + + if (uiTotalLen > uiUsedLen) + { + LOGRMB (RMB_LOG_ERROR, "dequeue error!uiTotallen=%u > usedLen=%u", + uiTotalLen, uiUsedLen); + return -1; + } + + *pDataLen = uiTotalLen - C_RMB_MQ_PKG_HEAD_SIZE; + if (*pDataLen > uiBufSize) + { + LOGRMB (RMB_LOG_ERROR, + "dequeue error!buffer size=%u is not enough,at least=%u!", + uiBufSize, *pDataLen); + return -1; + } + + //3.memcpy the meata data + if (uiHead + *pDataLen > pMq->uiBlockSize) + { + unsigned int uiFirstSize = pMq->uiBlockSize - uiHead; + unsigned int uiSecondSize = *pDataLen - uiFirstSize; + memcpy (buf, pBlock + uiHead, uiFirstSize); + memcpy (buf + uiFirstSize, pBlock, uiSecondSize); + //update the head + *pMq->pHead = uiSecondSize; + } + else + { + memcpy (buf, pBlock + uiHead, *pDataLen); + //update the head + *pMq->pHead = uiHead + *pDataLen; + } + + return 0; +} + +//mq_try_deuque +int rmb_mq_try_dequeue (StRmbMq * pMq, char *buf, unsigned int uiBufSize, + unsigned int *pDataLen, unsigned int *pFlowId) +{ + return rmb_mq_dequeue (pMq, buf, uiBufSize, pDataLen, pFlowId); +} + +//mq_get_stat +int rmb_mq_get_stat (StRmbMq * pMq) +{ + unsigned int uiHead = *pMq->pHead; + unsigned int uiTail = *pMq->pTail; + unsigned int uiFreeLen = + uiHead > uiTail ? uiHead - uiTail : uiHead + pMq->uiBlockSize - uiTail; + unsigned int uiUsedLen = + uiTail > uiHead ? uiTail - uiHead : uiTail + pMq->uiBlockSize - uiHead; + LOGRMB (RMB_LOG_ERROR, "Mq Stat:[head=%u,tail=%u,freeLen=%u,usedLen=%u]", + uiHead, uiTail, uiFreeLen, uiUsedLen); + return 0; +} + +//*****************************for rmb queue(private memory)************************************ +//queue init +int rmb_queue_init (StRmbQueue * pQue, const unsigned int size) +{ + if (size <= C_RMB_MQ_HEAD_SIZE) + { + LOGRMB (RMB_LOG_ERROR, "rmb_queue_init size is too small=%u", size); + return -1; + } + + pQue->pData = (char *) malloc (sizeof (char) * size); + if (pQue->pData == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_queue_init malloc for pQue->pData failed"); + return -2; + } + + pQue->uiSize = size; + + pQue->pHead = (unsigned int *) pQue->pData; + pQue->pTail = (unsigned int *) (pQue->pData + sizeof (unsigned int)); + *(pQue->pHead) = 0; + *(pQue->pTail) = 0; + pQue->pBlock = (char *) (pQue->pTail + 1); + pQue->uiBlockSize = pQue->uiSize - C_RMB_MQ_HEAD_SIZE; + + return 0; +} + +int rmb_queue_enqueue (StRmbQueue * pQue, const char *data, + unsigned int uiDataLen, unsigned int uiFLow) +{ + RMB_CHECK_POINT_NULL (pQue, "StRmbQueue:pQue"); + RMB_CHECK_POINT_NULL (data, "StRmbQueue:data"); + + unsigned int uiHead = *pQue->pHead; + unsigned int uiTail = *pQue->pTail; + unsigned int uiFreeLen = + (uiHead > + uiTail) ? (uiHead - uiTail) : (uiHead + pQue->uiBlockSize - uiTail); + unsigned int uiTailLen = pQue->uiBlockSize - uiTail; + char *pBlock = pQue->pBlock; + + char sHead[C_RMB_MQ_PKG_HEAD_SIZE] = { 0 }; + unsigned int uiTotalLen = uiDataLen + C_RMB_MQ_PKG_HEAD_SIZE; + + //1.if no enough space + if (uiFreeLen <= uiTotalLen) + { + return -2; + } + + memcpy (sHead, &uiTotalLen, sizeof (unsigned int)); + memcpy (sHead + sizeof (unsigned int), &uiFLow, sizeof (unsigned int)); + + //2.if tail space > 8+len + //copy 8 byte, copy data + if (uiTailLen >= uiTotalLen) + { + memcpy (pBlock + uiTail, sHead, C_RMB_MQ_PKG_HEAD_SIZE); + memcpy (pBlock + uiTail + C_RMB_MQ_PKG_HEAD_SIZE, data, uiDataLen); + //update tail + *pQue->pTail += (uiDataLen + C_RMB_MQ_PKG_HEAD_SIZE); + } + //3.if tail space > 8 && < 8+len + else if (uiTailLen >= C_RMB_MQ_PKG_HEAD_SIZE + && uiTailLen < C_RMB_MQ_PKG_HEAD_SIZE + uiDataLen) + { + // copy 8 byte + memcpy (pBlock + uiTail, sHead, C_RMB_MQ_PKG_HEAD_SIZE); + + // copy firstlen + unsigned int uiFirstLen = uiTailLen - C_RMB_MQ_PKG_HEAD_SIZE; + memcpy (pBlock + uiTail + C_RMB_MQ_PKG_HEAD_SIZE, data, uiFirstLen); + + // copy secondlen + unsigned int uiSecondLen = uiDataLen - uiFirstLen; + memcpy (pBlock, data + uiFirstLen, uiSecondLen); + + //update tail + unsigned int tail = + *pQue->pTail + uiDataLen + C_RMB_MQ_PKG_HEAD_SIZE - pQue->uiBlockSize; + *pQue->pTail = tail; + } + //4.if tail space < 8 + else + { + //copy tail byte + memcpy (pBlock + uiTail, sHead, uiTailLen); + + //copy 8-tail byte + unsigned int uiSecondLen = C_RMB_MQ_PKG_HEAD_SIZE - uiTailLen; + memcpy (pBlock, sHead + uiTailLen, uiSecondLen); + + //copy data + memcpy (pBlock + uiSecondLen, data, uiDataLen); + + //update tail + *pQue->pTail = uiSecondLen + uiDataLen; + } + + return 0; +} + +int rmb_queue_dequeue (StRmbQueue * pQue, char *buf, unsigned int uiBufSize, + unsigned int *pDataLen, unsigned int *pFlowId) +{ + RMB_CHECK_POINT_NULL (pQue, "rmb_queue_dequeue:pQue"); + RMB_CHECK_POINT_NULL (buf, "rmb_queue_dequeue:buf"); + RMB_CHECK_POINT_NULL (pDataLen, "rmb_queue_dequeue:pDataLen"); + + unsigned int uiHead = *pQue->pHead; + unsigned int uiTail = *pQue->pTail; + const char *pBlock = pQue->pBlock; + + if (uiHead == uiTail) + { + *pDataLen = 0; + return 0; + } + unsigned int uiUsedLen = + uiTail > uiHead ? uiTail - uiHead : uiTail + pQue->uiBlockSize - uiHead; + char sHead[C_RMB_MQ_PKG_HEAD_SIZE]; + + //1.get head + if (uiHead + C_RMB_MQ_PKG_HEAD_SIZE > pQue->uiBlockSize) + { + unsigned int uiFirstSize = pQue->uiBlockSize - uiHead; + unsigned int uiSecondSize = C_RMB_MQ_PKG_HEAD_SIZE - uiFirstSize; + memcpy (sHead, pBlock + uiHead, uiFirstSize); + memcpy (sHead + uiFirstSize, pBlock, uiSecondSize); + uiHead = uiSecondSize; + } + else + { + memcpy (sHead, pBlock + uiHead, C_RMB_MQ_PKG_HEAD_SIZE); + uiHead += C_RMB_MQ_PKG_HEAD_SIZE; + } + + //2.get meta data len + unsigned int uiTotalLen = *((unsigned int *) sHead); + if (pFlowId) + { + *pFlowId = *((unsigned *) (sHead + sizeof (unsigned int))); + } + + if (uiTotalLen > uiUsedLen) + { + LOGRMB (RMB_LOG_ERROR, "dequeue error!uiTotallen=%u > usedLen=%u", + uiTotalLen, uiUsedLen); + return -1; + } + + *pDataLen = uiTotalLen - C_RMB_MQ_PKG_HEAD_SIZE; + if (*pDataLen > uiBufSize) + { + LOGRMB (RMB_LOG_ERROR, + "dequeue error!buffer size=%u is not enough,at least=%u!", + uiBufSize, *pDataLen); + return -1; + } + + //3.memcpy the meata data + if (uiHead + *pDataLen > pQue->uiBlockSize) + { + unsigned int uiFirstSize = pQue->uiBlockSize - uiHead; + unsigned int uiSecondSize = *pDataLen - uiFirstSize; + memcpy (buf, pBlock + uiHead, uiFirstSize); + memcpy (buf + uiFirstSize, pBlock, uiSecondSize); + //update the head + *pQue->pHead = uiSecondSize; + } + else + { + memcpy (buf, pBlock + uiHead, *pDataLen); + //update the head + *pQue->pHead = uiHead + *pDataLen; + } + + return 0; +} + +int rmb_queue_try_dequeue (StRmbQueue * pQue, char *buf, + unsigned int uiBufSize, unsigned int *pDataLen, + unsigned int *pFlowId) +{ + return rmb_queue_dequeue (pQue, buf, uiBufSize, pDataLen, pFlowId); +} + +int rmb_queue_get_stat (StRmbQueue * pQue) +{ + unsigned int uiHead = *pQue->pHead; + unsigned int uiTail = *pQue->pTail; + unsigned int uiFreeLen = + uiHead > uiTail ? uiHead - uiTail : uiHead + pQue->uiBlockSize - uiTail; + unsigned int uiUsedLen = + uiTail > uiHead ? uiTail - uiHead : uiTail + pQue->uiBlockSize - uiHead; + LOGRMB (RMB_LOG_ERROR, "queue Stat:[head=%u,tail=%u,freeLen=%u,usedLen=%u]", + uiHead, uiTail, uiFreeLen, uiUsedLen); + return 0; +} + +//*****************************for fifo**************************************** +//fifo init +//return -1 exist error +int rmb_fifo_init (StRmbFifo * pFifo, const char *strPath) +{ + errno = 0; + int mode = 0666 | O_NONBLOCK | O_NDELAY; + if ((mkfifo (strPath, mode)) < 0) + { + if (errno != EEXIST) + { + LOGRMB (RMB_LOG_ERROR, "fifo strPath=%s has exist", strPath); + return -1; + } + } + + if (pFifo->iFd != -1 && pFifo->iFd != 0) + { + close (pFifo->iFd); + pFifo->iFd = -1; + } + + if ((pFifo->iFd = open (strPath, O_RDWR)) < 0) + { + return -2; + } + if (pFifo->iFd > 1024) + { + close (pFifo->iFd); + return -3; + } + + int val = fcntl (pFifo->iFd, F_GETFL, 0); + + if (val == -1) + { + return -4; + } + + if (val & O_NONBLOCK) + { + return 0; + } + + int iRet = fcntl (pFifo->iFd, F_SETFL, val | O_NONBLOCK | O_NDELAY); + if (iRet < 0) + { + return -5; + } + return 0; +} + +//notify +int rmb_fifo_send (StRmbFifo * pFifo) +{ + int iRet = write (pFifo->iFd, "\0", 1); + //LOGRMB(RMB_LOG_DEBUG, "rmb_fifo_send succ!iRet=%d, fd=%d", iRet, pFifo->iFd); + if (iRet != 0) + { + //return -1; + } + return 0; +} + +//clear notify +int rmb_fifo_clear_flag (StRmbFifo * pFifo) +{ + static char buffer[1]; + read (pFifo->iFd, buffer, 1); + //LOGRMB(RMB_LOG_DEBUG, "rmb_fifo_clear_flag succ!fd=%d", pFifo->iFd); + return 0; +} + +//*****************************for pipe**************************************** +//pipe init +//return -1 exist error +int rmb_pipe_init (StRmbPipe * pPipe) +{ + RMB_CHECK_POINT_NULL (pPipe, "rmb_pipe_init:pPipe"); + + if (pipe (pPipe->fd) < 0) + { + LOGRMB (RMB_LOG_ERROR, "pipe failed\n"); + return -1; + } + + int val = fcntl (pPipe->fd[0], F_GETFL, 0); + if (val == -1) + { + LOGRMB (RMB_LOG_ERROR, "fcntl get fd[0] failed\n"); + return -2; + } + + int iRet = fcntl (pPipe->fd[0], F_SETFL, val | O_NONBLOCK | O_NDELAY); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "fcntl set fd[0] failed\n"); + return -3; + } + + val = fcntl (pPipe->fd[1], F_GETFL, 0); + if (val == -1) + { + LOGRMB (RMB_LOG_ERROR, "fcntl get fd[1] failed\n"); + return -2; + } + + iRet = fcntl (pPipe->fd[1], F_SETFL, val | O_NONBLOCK | O_NDELAY); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "fcntl set fd[1] failed\n"); + return -3; + } + + pPipe->r_fd = pPipe->fd[0]; + pPipe->w_fd = pPipe->fd[1]; + + return 0; +} + +//notify +int rmb_pipe_send (StRmbPipe * pPipe) +{ + RMB_CHECK_POINT_NULL (pPipe, "rmb_pipe_send:pPipe"); + + write (pPipe->w_fd, "\0", 1); + + return 0; +} + +//clear notify +int rmb_pipe_clear_flag (StRmbPipe * pPipe) +{ + RMB_CHECK_POINT_NULL (pPipe, "rmb_pipe_send:pPipe"); + + static char buffer[1]; + read (pPipe->r_fd, buffer, 1); + + return 0; +} + +//******************************for rmb mq notify******************************* +int rmb_notify_init (StRmbMqFifoNotify * pMqNotify) +{ + memset ((char *) pMqNotify, 0, sizeof (StRmbMqFifoNotify)); + if (pMqNotify->pBuf == NULL) + { + pMqNotify->pBuf = (char *) calloc (MAX_MQ_PKG_SIZE, sizeof (char)); + if (pMqNotify->pBuf == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_init error!calloc buf failed!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return rmb_errno; + } + } + + //epoll init + pMqNotify->iEpollFd = epoll_create (MAX_MQ_NUMS); + if (pMqNotify->iEpollFd < 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_init error!epoll_create failed!"); + rmb_errno = RMB_ERROR_INIT_EPOLL_FAIL; + return rmb_errno; + } + return 0; +} + +//notify add +int rmb_notify_add (StRmbMqFifoNotify * pMqNotify, StRmbMq * mq, + StRmbFifo * fifo, const enum RmbMqIndex iMsgType, + rmb_callback_func func, void *func_argv) +{ + if (pMqNotify->iMqNum >= MAX_MQ_NUMS) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_add error!mqCurNum=%d,maxNum=%d", + pMqNotify->iMqNum, MAX_MQ_NUMS); + rmb_errno = RMB_ERROR_MQ_NUMS_LIMIT; + return -1; + } + + if (pMqNotify->mqIndex[(int) iMsgType] != NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_add error!type:%d has add!!!", + (int) iMsgType); + return -1; + } + + pMqNotify->vecMqInfo[pMqNotify->iMqNum].mq = mq; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].fifo = fifo; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].que = NULL; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].pipe = NULL; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].func = func; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].args = func_argv; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iMsgType = iMsgType; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iIndex = pMqNotify->iMqNum; + //add init mutex + pthread_mutex_init (&(pMqNotify->vecMqInfo[pMqNotify->iMqNum].queMutex), + NULL); + pMqNotify->mqIndex[(int) iMsgType] = + &(pMqNotify->vecMqInfo[pMqNotify->iMqNum]); + + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iMergeNotifyFLag = 1; + if (func == NULL) + { + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iMergeNotifyFLag = 0; + } + + //for select + FD_SET (fifo->iFd, &pMqNotify->readFd); + if (fifo->iFd >= pMqNotify->iMaxFd) + { + pMqNotify->iMaxFd = fifo->iFd + 1; + } + + //for epoll + struct epoll_event ev; + ev.events = EPOLLIN | EPOLLERR; + ev.data.fd = fifo->iFd; + ev.data.u32 = pMqNotify->iMqNum; + epoll_ctl (pMqNotify->iEpollFd, EPOLL_CTL_ADD, fifo->iFd, &ev); + pMqNotify->vecMqInfo[pMqNotify->iMqNum].active = 0; + + pMqNotify->iMqNum += 1; + return 0; +} + +int rmb_wemq_notify_add (StRmbMqFifoNotify * pMqNotify, StRmbQueue * que, + StRmbPipe * pipe, const enum RmbMqIndex iMsgType, + rmb_callback_func func, void *func_argv) +{ + if (pMqNotify->iMqNum >= MAX_MQ_NUMS) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_add error!mqCurNum=%d,maxNum=%d", + pMqNotify->iMqNum, MAX_MQ_NUMS); + rmb_errno = RMB_ERROR_MQ_NUMS_LIMIT; + return -1; + } + pMqNotify->vecMqInfo[pMqNotify->iMqNum].mq = NULL; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].fifo = NULL; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].que = que; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].pipe = pipe; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].func = func; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].args = func_argv; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iMsgType = iMsgType; + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iIndex = pMqNotify->iMqNum; + pMqNotify->mqIndex[(int) iMsgType] = + &(pMqNotify->vecMqInfo[pMqNotify->iMqNum]); + + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iMergeNotifyFLag = 1; + if (func == NULL) + { + pMqNotify->vecMqInfo[pMqNotify->iMqNum].iMergeNotifyFLag = 0; + } + + //for select + FD_SET (pipe->r_fd, &pMqNotify->readFd); + if (pipe->r_fd >= pMqNotify->iMaxFd) + { + pMqNotify->iMaxFd = pipe->r_fd + 1; + } + + //for epoll + struct epoll_event ev; + ev.events = EPOLLIN | EPOLLERR; + ev.data.fd = pipe->r_fd; + ev.data.u32 = pMqNotify->iMqNum; + epoll_ctl (pMqNotify->iEpollFd, EPOLL_CTL_ADD, pipe->r_fd, &ev); + pMqNotify->vecMqInfo[pMqNotify->iMqNum].active = 0; + + pMqNotify->iMqNum += 1; + return 0; +} + +int rmb_notify_enqueue_by_type_for_wemq (StRmbMqFifoNotify * pMqNotify, + const enum RmbMqIndex uiMsgType, + const unsigned int uiCurTime, + const char *data, + unsigned int uiDataLen) +{ + StMqInfo *pMqInfo = pMqNotify->mqIndex[(int) uiMsgType]; + if (pMqInfo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_enqueue_for_wemq error!pMqInfo is NULL"); + return -1; + } + + return rmb_notify_enqueue_for_wemq (uiCurTime, pMqInfo, data, uiDataLen); +} + +int rmb_notify_enqueue_for_wemq (const unsigned int uiCurTime, + StMqInfo * pMqInfo, const char *data, + unsigned int uiDataLen) +{ + if (pMqInfo == NULL || pMqInfo->que == NULL || pMqInfo->pipe == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_enqueue_for_wemq error!pMqInfo==NULL || pMqInfo->que==NULL || pMqInfo->pipe==NULL"); + return -1; + } + + int iRet = + rmb_queue_enqueue (pMqInfo->que, data, uiDataLen, pMqInfo->iMsgType); + if (iRet == -2) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_enqueue_for_wemq failed!queue full!"); + rmb_errno = RMB_ERROR_ENQUEUE_MQ_FAIL; + return -2; + } + else if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_enqueue_for_wemq failed!iRet=%d", + iRet); + return -3; + } + if (pMqInfo->iMergeNotifyFLag == 1) + { + if (uiCurTime >= + pMqInfo->uiLastCheckTime + pRmbStConfig->iNotifyCheckSpan) + { + pMqInfo->uiLastCheckTime = uiCurTime; + pMqInfo->iNotifyFactor = rmb_notify_get_fator (pMqInfo->iCount); + pMqInfo->iCount = 0; + } + else + { + pMqInfo->iCount++; + } + if (pMqInfo->iCount % pMqInfo->iNotifyFactor == 0) + { + iRet = rmb_pipe_send (pMqInfo->pipe); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_enqueue failed!rmb_pipe_send return iRet=%d", + iRet); + rmb_errno = RMB_ERROR_SEND_FIFO_NOTIFY_ERROR; + return -4; + } + } + } + else + { + iRet = rmb_pipe_send (pMqInfo->pipe); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_enqueue failed!rmb_pipe_send return iRet=%d", iRet); + rmb_errno = RMB_ERROR_SEND_FIFO_NOTIFY_ERROR; + return -5; + } + } + + return 0; +} + +//enqueue +int rmb_notify_enqueue_by_type (StRmbMqFifoNotify * pMqNotify, + const enum RmbMqIndex uiMsgType, + const unsigned int uiCurTime, + const char *data, unsigned int uiDataLen) +{ + StMqInfo *pMqInfo = pMqNotify->mqIndex[(int) uiMsgType]; + if (pMqInfo == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_enqueue error!pMqInfo == NULL"); + return -1; + } + return rmb_notify_enqueue (uiCurTime, pMqInfo, data, uiDataLen); +} + +//enqueue +//-1:error argv +//-2:not enough space +//-3:enquque error +//-4:notify send failed +int rmb_notify_enqueue (const unsigned int uiCurTime, StMqInfo * pMqInfo, + const char *data, unsigned int uiDataLen) +{ +// if (pMqInfo->iMsgType >= wemq_req_mq_index) { +// return rmb_notify_enqueue_for_wemq(uiCurTime, pMqInfo, data, uiDataLen); +// } + + pthread_mutex_lock (&pMqInfo->queMutex); + + //StMqInfo *pMqInfo = &(pMqNotify->vecMqInfo[(int)iOffset]); + if (pMqInfo->mq == NULL || pMqInfo->fifo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_enqueue error!pMqInfo->mq == NULL || pMqInfo->fifo == NULL"); + rmb_errno = RMB_ERROR_ARGV_NULL; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -1; + } + + int iRet = rmb_mq_enqueue (pMqInfo->mq, data, uiDataLen, pMqInfo->iMsgType); + if (iRet == -2) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_enqueue error!queue full!"); + rmb_errno = RMB_ERROR_ENQUEUE_MQ_FAIL; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -2; + } + else if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_enqueue error!rmb_mq_enqueue iRet=%d", + iRet); + rmb_errno = RMB_ERROR_ENQUEUE_MQ_FAIL; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -3; + } + if (pMqInfo->iMergeNotifyFLag == 1) + { + if (uiCurTime >= + pMqInfo->uiLastCheckTime + pRmbStConfig->iNotifyCheckSpan) + { + pMqInfo->uiLastCheckTime = uiCurTime; + pMqInfo->iNotifyFactor = rmb_notify_get_fator (pMqInfo->iCount); + pMqInfo->iCount = 0; + } + else + { + pMqInfo->iCount++; + } + if (pMqInfo->iCount % pMqInfo->iNotifyFactor == 0) + { + iRet = rmb_fifo_send (pMqInfo->fifo); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_enqueue error!rmb_fifo_send iRet=%d", iRet); + rmb_errno = RMB_ERROR_SEND_FIFO_NOTIFY_ERROR; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -4; + } + } + } + else + { + iRet = rmb_fifo_send (pMqInfo->fifo); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_enqueue error!rmb_fifo_send iRet=%d", + iRet); + rmb_errno = RMB_ERROR_SEND_FIFO_NOTIFY_ERROR; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -5; + } + } + pthread_mutex_unlock (&pMqInfo->queMutex); + return 0; +} + +int rmb_notify_dequeue_for_wemq (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen) +{ + if (pMqInfo->que == NULL || pMqInfo->pipe == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_dequeue_for_wemq error!pMqInfo->que == NULL || pMqInfo->pipe == NULL"); + return -1; + } + + int iRet = rmb_queue_dequeue (pMqInfo->que, buf, uiBufSize, pDataLen, NULL); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_queue_dequeue error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_DEQUEUE_MQ_FAIL; + return -2; + } + + if (pMqInfo->iMergeNotifyFLag == 0) + { + iRet = rmb_pipe_clear_flag (pMqInfo->pipe); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue_for_wemq error!iRet=%d", + iRet); + rmb_errno = RMB_ERROR_DEQUEUE_MQ_FAIL; + return -2; + } + } + + return 0; +} + +//dequeue +int rmb_notify_dequeue (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, unsigned int *pDataLen) +{ +// if (pMqInfo->iMsgType >= wemq_req_mq_index) { +// return rmb_notify_dequeue_for_wemq(pMqInfo, buf, uiBufSize, pDataLen); +// } + + pthread_mutex_lock (&pMqInfo->queMutex); + //StMqInfo *pMqInfo = &(pMqNotify->vecMqInfo[(int)iOffset]); + if (pMqInfo->mq == NULL || pMqInfo->fifo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_dequeue error!pMqInfo->mq == NULL || pMqInfo->fifo == NULL"); + rmb_errno = RMB_ERROR_ARGV_NULL; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -1; + } + + int iRet = rmb_mq_dequeue (pMqInfo->mq, buf, uiBufSize, pDataLen, NULL); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue error!rmb_mq_dequeue iRet=%d", + iRet); + rmb_errno = RMB_ERROR_DEQUEUE_MQ_FAIL; + pthread_mutex_unlock (&pMqInfo->queMutex); + return -2; + } + if (pMqInfo->iMergeNotifyFLag == 0) + { + iRet = rmb_fifo_clear_flag (pMqInfo->fifo); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_dequeue error!rmb_fifo_clear_flag iRet=%d", iRet); + //return -3; + //return 0; + } + } + pthread_mutex_unlock (&pMqInfo->queMutex); + return 0; +} + +int rmb_notify_try_dequeue_for_wemq (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen) +{ + if (pMqInfo == NULL || pMqInfo->que == NULL || pMqInfo->pipe == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_try_dequeue_for_wemq failed!pMqInfo==NULL or pMqInfo->que==NULL || pMqInfo->pipe==NULL"); + return -1; + } + + int iRet = + rmb_queue_try_dequeue (pMqInfo->que, buf, uiBufSize, pDataLen, NULL); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_queue_try_dequeue failed!iRet=%d", iRet); + rmb_errno = RMB_ERROR_DEQUEUE_MQ_FAIL; + return -2; + } + + if (*pDataLen == 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_try_dequeue_for_wemq failed!queue is empty"); + rmb_errno = RMB_ERROR_DEQUEUE_MQ_EMPTY; + return -3; + } + + return 0; +} + +//try dequeue +int rmb_notify_try_dequeue (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen) +{ +// if (pMqInfo->iMsgType >= wemq_req_mq_index) { +// return rmb_notify_try_dequeue_for_wemq(pMqInfo, buf, uiBufSize, pDataLen); +// } + //StMqInfo *pMqInfo = &(pMqNotify->vecMqInfo[(int)iOffset]); + if (pMqInfo->mq == NULL || pMqInfo->fifo == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb_notify_dequeue error!pMqInfo->mq == NULL || pMqInfo->fifo == NULL"); + rmb_errno = RMB_ERROR_ARGV_NULL; + return -1; + } + + pthread_mutex_lock (&pMqInfo->queMutex); + int iRet = rmb_mq_try_dequeue (pMqInfo->mq, buf, uiBufSize, pDataLen, NULL); + pthread_mutex_unlock (&pMqInfo->queMutex); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue error!rmb_mq_dequeue iRet=%d", + iRet); + rmb_errno = RMB_ERROR_DEQUEUE_MQ_FAIL; + return -2; + } + if (*pDataLen == 0) + { + rmb_errno = RMB_ERROR_DEQUEUE_MQ_EMPTY; + return -3; + } +// iRet = rmb_fifo_clear_flag(pMqInfo->fifo); +// if (iRet != 0) +// { +// printf("rmb_notify_dequeue error!rmb_fifo_clear_flag iRet=%d", iRet); +// return -3; +// } + return 0; +} + +//**************select or epoll************************* +//select fifo fd +//return >0 the mq index which has msg +// =0 all mq has no msg +// <0 all mq has no msg +static int rmb_notify_select (StRmbMqFifoNotify * pMqNotify, + unsigned int uiSec, unsigned int uiUsec) +{ + int i = 0; + int j = 0; + errno = 0; + StMqInfo *pMqInfo; + FD_ZERO (&(pMqNotify->tmpReadFd)); + pMqNotify->tmpReadFd = pMqNotify->readFd; + pMqNotify->tv.tv_sec = uiSec; + pMqNotify->tv.tv_usec = uiUsec; + int iRet = + select (pMqNotify->iMaxFd, &(pMqNotify->tmpReadFd), NULL, NULL, + &(pMqNotify->tv)); + if (iRet > 0) + { + for (i = 0; i < pMqNotify->iMqNum; i++) + { + if (FD_ISSET + (pMqNotify->vecMqInfo[i].fifo->iFd, &(pMqNotify->tmpReadFd))) + { + pMqInfo = &(pMqNotify->vecMqInfo[i]); + rmb_fifo_clear_flag (pMqInfo->fifo); + + for (j = 0; j < pRmbStConfig->iEveryTimeProcessNum; i++) + { + iRet = + rmb_notify_dequeue (&(pMqNotify->vecMqInfo[i]), pMqNotify->pBuf, + MAX_MQ_PKG_SIZE, &(pMqNotify->uiBufLen)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue error!iRet=%d", iRet); + break;; + } + if (pMqNotify->uiBufLen == 0) + { + break; + } + + pMqNotify->pBuf[pMqNotify->uiBufLen] = '\0'; + //shift_buf_2_msg((StRmbMsg *)pMqInfo->pReceiveMsg, pMqNotify->pBuf, pMqNotify->uiBufLen); + pMqInfo->func (pMqNotify->pBuf, pMqNotify->uiBufLen, pMqInfo->args); + } + } + } + } + else + { + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "select error!iRet=%d", iRet); + } + for (i = 0; i < pMqNotify->iMqNum; i++) + { + for (j = 0; j < pRmbStConfig->iEveryTimeProcessNum; i++) + { + iRet = + rmb_notify_dequeue (&(pMqNotify->vecMqInfo[i]), pMqNotify->pBuf, + MAX_MQ_PKG_SIZE, &(pMqNotify->uiBufLen)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue error!iRet=%d", iRet); + break;; + } + if (pMqNotify->uiBufLen == 0) + { + break; + } + + pMqNotify->pBuf[pMqNotify->uiBufLen] = '\0'; + //shift_buf_2_msg((StRmbMsg *)pMqInfo->pReceiveMsg, pMqNotify->pBuf, pMqNotify->uiBufLen); + pMqInfo = &pMqNotify->vecMqInfo[i]; + pMqInfo->func (pMqNotify->pBuf, pMqNotify->uiBufLen, pMqInfo->args); + + LOGRMB (RMB_LOG_ERROR, "try_dequee succ,j=%d!", j); + //rmb_mq_get_stat(pMqNotify->vecMqInfo[i].mq); + } + } + } + return 0; +} + +//***********************for epoll************************* +//epoll +int rmb_notify_epoll (StRmbSub * pStRmbSub, int iTimeout) +{ + StRmbMqFifoNotify *pMqNotify = &pStRmbSub->pStContext->fifoMq; + static struct epoll_event epv[MAX_MQ_NUMS]; + int iEventNum = + epoll_wait (pMqNotify->iEpollFd, epv, MAX_MQ_NUMS, iTimeout); + int iRet = 0; + StMqInfo *pMqInfo; + int i = 0; + int j = 0; + StRmbMsg *pReceiveMsg = rmb_msg_malloc (); + for (; i < iEventNum; ++i) + { + LOGRMB (RMB_LOG_DEBUG, "rmb_notify_epoll succ!num=%d,i=%d,eventNum=%d", + epv[i].data.u32, i, iEventNum); + pMqInfo = &(pMqNotify->vecMqInfo[epv[i].data.u32]); + + rmb_fifo_clear_flag (pMqInfo->fifo); + + for (j = 0; j < pRmbStConfig->iEveryTimeProcessNum; j++) + { + iRet = + rmb_notify_dequeue (pMqInfo, pMqNotify->pBuf, MAX_MQ_PKG_SIZE, + &(pMqNotify->uiBufLen)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue error!iRet=%d", iRet); + break; + } + if (pMqNotify->uiBufLen == 0) + { + break; + } + + pMqNotify->pBuf[pMqNotify->uiBufLen] = '\0'; + //rmb_send_log_for_func(pMqNotify->pBuf, pMqNotify->uiBufLen, RMB_CONTEXT_TYPE_SUB, pMqInfo->iMsgType); + shift_buf_2_msg (pReceiveMsg, pMqNotify->pBuf, pMqNotify->uiBufLen); + //do not filter + if (rmb_epoll_msg_filter (pStRmbSub, pReceiveMsg) == 0) + { + pRmbStConfig->mqIsEmpty = MQ_IS_NOT_EMPTY; + pMqInfo->func (pMqNotify->pBuf, pMqNotify->uiBufLen, pMqInfo->args); + wemq_sub_ack_msg (pStRmbSub, pReceiveMsg); + if (rmb_sub_check_mq_is_null (pStRmbSub) == 0) + { + pRmbStConfig->mqIsEmpty = MQ_IS_EMPTY; + } + pMqInfo->active = 1; + } + + } + } + + //for sure write fd is ok! + for (i = 0; i < pMqNotify->iMqNum; ++i) + { + pMqInfo = &pMqNotify->vecMqInfo[i]; + if (pMqInfo->active == 0) + { + for (j = 0; j < pRmbStConfig->iEveryTimeProcessNum; j++) + { + iRet = + rmb_notify_dequeue (pMqInfo, pMqNotify->pBuf, MAX_MQ_PKG_SIZE, + &(pMqNotify->uiBufLen)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_dequeue error!iRet=%d", iRet); + break; + } + if (pMqNotify->uiBufLen == 0) + { + break; + } + + pMqNotify->pBuf[pMqNotify->uiBufLen] = '\0'; + //rmb_send_log_for_func(pMqNotify->pBuf, pMqNotify->uiBufLen, RMB_CONTEXT_TYPE_SUB, pMqInfo->iMsgType); + shift_buf_2_msg (pReceiveMsg, pMqNotify->pBuf, pMqNotify->uiBufLen); + if (rmb_epoll_msg_filter (pStRmbSub, pReceiveMsg) == 0) + { + pRmbStConfig->mqIsEmpty = MQ_IS_NOT_EMPTY; + pMqInfo->func (pMqNotify->pBuf, pMqNotify->uiBufLen, pMqInfo->args); + wemq_sub_ack_msg (pStRmbSub, pReceiveMsg); + if (rmb_sub_check_mq_is_null (pStRmbSub) == 0) + { + pRmbStConfig->mqIsEmpty = MQ_IS_EMPTY; + } + } + } + } + else + { + pMqInfo->active = 0; + } + } + rmb_msg_free (pReceiveMsg); + + return 0; +} + +int rmb_epoll_msg_filter (StRmbSub * pStRmbSub, StRmbMsg * pReceiveMsg) +{ + RMB_CHECK_POINT_NULL (pStRmbSub, "pStRmbSub"); + RMB_CHECK_POINT_NULL (pReceiveMsg, "pReceiveMsg"); + //rr异步的包,直接返回 + if (pReceiveMsg->cPkgType == RR_TOPIC_PKG) + { + return 0; + } + + //监听模式下调用do_receive,过滤 + int iFlag = 1; + int i; + st_rmb_queue_info *p = pStRmbSub->pQueueInfo; + for (i = 0; i < pStRmbSub->iQueueNum; i++) + { + if (strcmp (pReceiveMsg->strServiceId, p->cServiceId) == 0) + { + iFlag = 0; + break; + } + p += 1; + } + + if (iFlag != 0) + { + LOGRMB (RMB_LOG_WARN, "pReceiveMsg bizseqno=%s not at listen topic!", + pReceiveMsg->sysHeader.cBizSeqNo); + return -2; + } + return 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_msg.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_msg.c new file mode 100644 index 0000000000..47c0c61c6f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_msg.c @@ -0,0 +1,1686 @@ +// 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. + +#include "uuid/uuid.h" +#include "common.h" +#include "rmb_msg.h" +#include "string.h" +#include "time.h" +#include "rmb_errno.h" + +static const int i1KB = 1 << 10; +static const int i2KB = 1 << 11; +static const int i4KB = 1 << 12; +static const int i8KB = 1 << 13; +static const int i16KB = 1 << 14; +static const int i32KB = 1 << 15; +static const int i64KB = 1 << 16; +static const int i128KB = 1 << 17; +static const int i256KB = 1 << 18; +static const int i512KB = 1 << 19; +static const int i1024KB = 1 << 20; +static const int i2048KB = 1 << 21; + +//private func +const static char *strLogicType[] = + { "null", "req_in", "rsp_in", "event_in", "req_out", "rsp_out", "event_out", +"null" }; + +int rmb_msg_clear (StRmbMsg * pStMsg) +{ + RMB_CHECK_POINT_NULL (pStMsg, "pStMsg"); + + //pStMsg->cPkgType = 0; + //pStMsg->cLogicType = 0; + memset (&(pStMsg->sysHeader), 0, sizeof (StSystemHeader)); + pStMsg->replyTo.cDestName[0] = '\0'; + pStMsg->dest.cDestName[0] = '\0'; + pStMsg->iCorrLen = 0; + pStMsg->iContentLen = 0; + pStMsg->iAppHeaderLen = 0; + pStMsg->ulMsgId = 0; + pStMsg->ulMsgLiveTime = 0; + //add in 2016-09-26 + pStMsg->flag = 0; + pStMsg->isDyedMsg[0] = "\0"; + return 0; +} + +int rmb_msg_init (StRmbMsg * pRmbMsg, StRmbConfig * pConfig, + enum RMB_API_YPE type) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + + pRmbMsg->replyTo.cDestName[0] = '\0'; + char cUniqueId[100] = { 0 }; + char cUniqueIdEx[50] = { 0 }; + rmb_msg_random_uuid (cUniqueIdEx, sizeof (cUniqueIdEx)); + snprintf (cUniqueId, sizeof (cUniqueId), "c/%s", cUniqueIdEx); +// pRmbMsg->cApiType = C_TYPE; + pRmbMsg->cApiType = type; + pRmbMsg->cLogicType = 0; + pRmbMsg->sysHeader.iReceiveMode = 1; + RMB_MEMCPY (pRmbMsg->sysHeader.cConsumerSysId, pConfig->cConsumerSysId); + if (pRmbMsg->sysHeader.iSetSysVersionFlag != 1) + { //没有被用户设置过 + RMB_MEMCPY (pRmbMsg->sysHeader.cConsumerSysVersion, + pConfig->cConsumerSysVersion); + } + RMB_MEMCPY (pRmbMsg->sysHeader.cConsumerSvrId, pConfig->cHostIp); + RMB_MEMCPY (pRmbMsg->sysHeader.cOrgSvrId, pConfig->cHostIp); + RMB_MEMCPY (pRmbMsg->sysHeader.cUniqueId, cUniqueId); + RMB_MEMCPY (pRmbMsg->sysHeader.cConsumerDcn, pConfig->cConsumerDcn); + RMB_MEMCPY (pRmbMsg->sysHeader.cOrgId, pConfig->strOrgId); + RMB_MEMCPY (pRmbMsg->sysHeader.cRmbVersion, RMBVERSION); + + char cAppHeaderClassName[50] = "cn.webank.rmb.message.AppHeader"; + RMB_MEMCPY (pRmbMsg->sysHeader.cAppHeaderClass, cAppHeaderClassName); + + //RMB_MEMSET(pRmbMsg->strScenarioId); + //RMB_MEMSET(pRmbMsg->strServiceId); + //RMB_MEMSET(pRmbMsg->strTargetDcn); + //pRmbMsg->iEventOrService = 0; + + GetRmbNowLongTime (); + pRmbMsg->sysHeader.ulTranTimeStamp = pRmbStConfig->ulNowTtime; + pRmbMsg->sysHeader.ulMessageDate = pRmbStConfig->ulNowTtime; + + //for wemq + + return 0; +} + +//you must fill in under fields +int rmb_msg_set_bizSeqNo (StRmbMsg * pRmbMsg, const char *cBizSeqNo) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (cBizSeqNo, "cBizSeqNo"); + RMB_LEN_CHECK (cBizSeqNo, 32); + + RMB_MEMCPY (pRmbMsg->sysHeader.cBizSeqNo, cBizSeqNo); + return 0; +} + +int rmb_msg_set_consumerSysVersion (StRmbMsg * pRmbMsg, + const char *cConsumerSysVersion) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (cConsumerSysVersion, "cConsumerSysVersion"); + //RMB_LEN_CHECK(cBizSeqNo,32); + + RMB_MEMCPY (pRmbMsg->sysHeader.cConsumerSysVersion, cConsumerSysVersion); + pRmbMsg->sysHeader.iSetSysVersionFlag = 1; + return 0; +} + +int rmb_msg_set_dyedMsg (StRmbMsg * pRmbMsg, const char *sign) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_MEMCPY (pRmbMsg->isDyedMsg, sign); + return 0; +} + +int rmb_msg_set_consumerSeqNo (StRmbMsg * pRmbMsg, const char *cConsumerSeqNo) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (cConsumerSeqNo, "cConsumerSeqNo"); + RMB_LEN_CHECK (cConsumerSeqNo, 32); + + RMB_MEMCPY (pRmbMsg->sysHeader.cConsumerSeqNo, cConsumerSeqNo); + return 0; +} + +int rmb_msg_set_orgSysId (StRmbMsg * pRmbMsg, const char *cOrgSysId) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (cOrgSysId, "cOrgSysId"); + RMB_LEN_CHECK (cOrgSysId, 4) + RMB_MEMCPY (pRmbMsg->sysHeader.cOrgSysId, cOrgSysId); + return 0; +} + +//*********************** + +int rmb_msg_set_dest (StRmbMsg * pRmbMsg, int desType, const char *cTargetDcn, + int iServiceOrEven, const char *cServiceId, + const char *cScenario) +{ + return rmb_msg_set_dest_v2 (pRmbMsg, cTargetDcn, cServiceId, cScenario); + +} + +int rmb_msg_set_dest_v2 (StRmbMsg * pRmbMsg, const char *cTargetDcn, + const char *cServiceId, const char *cScenario) +{ + return rmb_msg_set_dest_v2_1 (pRmbMsg, cTargetDcn, cServiceId, cScenario, + (char *) NULL); +} + +int rmb_msg_set_dest_v2_1 (StRmbMsg * pRmbMsg, const char *cTargetDcn, + const char *cServiceId, const char *cScenario, + const char *cTargetOrgId) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + //RMB_CHECK_POINT_NULL(cTargetDcn, "cTargetDcn"); + RMB_CHECK_POINT_NULL (cServiceId, "cServiceId"); + RMB_CHECK_POINT_NULL (cScenario, "cScenario"); + + if (cTargetDcn == NULL || strlen (cTargetDcn) == 0) + { + pRmbMsg->strTargetDcn[0] = 0; + } + else + { + if (strlen (cTargetDcn) != DEFAULT_DCN_LENGTH) + { + LOGRMB (RMB_LOG_ERROR, "destination dcn must be 3 length!input=%lu", + strlen (cTargetDcn)); + rmb_errno = RMB_ERROR_ARGV_LEN_ERROR; + return -2; + } + strncpy (pRmbMsg->strTargetDcn, cTargetDcn, + sizeof (pRmbMsg->strTargetDcn) - 1); + } + + if (strlen (cServiceId) != DEFAULT_SERVICE_ID_LENGTH) + { + LOGRMB (RMB_LOG_ERROR, + "destination service_id must be 8 length!input=%lu", + strlen (cServiceId)); + rmb_errno = RMB_ERROR_ARGV_LEN_ERROR; + return -2; + } + if (strlen (cScenario) != DEFAULT_SCENE_ID_LENGTH) + { + LOGRMB (RMB_LOG_ERROR, "destination scene_id must be 2 length!input=%lu", + strlen (cScenario)); + rmb_errno = RMB_ERROR_ARGV_LEN_ERROR; + return -2; + } + + pRmbMsg->iEventOrService = + (*(cServiceId + 3) == '0') ? RMB_SERVICE_CALL : RMB_EVENT_CALL; + + strncpy (pRmbMsg->strServiceId, cServiceId, + sizeof (pRmbMsg->strServiceId) - 1); + strncpy (pRmbMsg->strScenarioId, cScenario, + sizeof (pRmbMsg->strScenarioId) - 1); + if (cTargetOrgId == NULL) + { + pRmbMsg->iFLagForOrgId = RMB_COMMIT_BY_API; + } + else + { + pRmbMsg->iFLagForOrgId = RMB_COMMIT_BY_OWN; + strncpy (pRmbMsg->strTargetOrgId, cTargetOrgId, + sizeof (pRmbMsg->strTargetOrgId) - 1); + } + //modify 2016-09-26 + //pRmbMsg->flag = pRmbMsg->flag & (1 << RMBMSG_DEST_HAS_SET); + pRmbMsg->flag = pRmbMsg->flag | (1 << RMBMSG_DEST_HAS_SET); + + return 0; +} + +//////////////////1.7.3 add ////////////////////////////////////////////////////// + +//get dest +int rmb_msg_get_dest (StRmbMsg * pRmbMsg, char *dest, unsigned int *uiLen) +{ + if (pRmbMsg == NULL || dest == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg or dest is null"); + return -1; + } + + if (*uiLen < strlen (pRmbMsg->dest.cDestName)) + { + LOGRMB (RMB_LOG_ERROR, "dest is too small, len=%u, but msg_dest_len=%u\n", + *uiLen, strlen (pRmbMsg->dest.cDestName)); + return -2; + } + + memcpy (dest, pRmbMsg->dest.cDestName, strlen (pRmbMsg->dest.cDestName)); + *uiLen = strlen (pRmbMsg->dest.cDestName); + + return 0; +} + +const char *rmb_msg_get_dest_ptr (StRmbMsg * pRmbMsg) +{ + if (pRmbMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg is null"); + return NULL; + } + + return pRmbMsg->dest.cDestName; +} + +//get cConsumerSysId +int rmb_msg_get_consumerSysId (StRmbMsg * pRmbMsg, char *cConsumerSysId, + unsigned int *uiLen) +{ + if (pRmbMsg == NULL || cConsumerSysId == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg or cConsumerSysId is null"); + return -1; + } + + unsigned int uiConsumerLen = + (unsigned int) strlen (pRmbMsg->sysHeader.cConsumerSysId); + + if (*uiLen < uiConsumerLen) + { + LOGRMB (RMB_LOG_ERROR, + "rmb msg consumerSysId len=%u, but arg len=%u(too small)", + uiConsumerLen, *uiLen); + return -2; + } + + memcpy (cConsumerSysId, pRmbMsg->sysHeader.cConsumerSysId, uiConsumerLen); + *uiLen = uiConsumerLen; + + return 0; +} + +const char *rmb_msg_get_consumerSysId_ptr (StRmbMsg * pRmbMsg) +{ + if (pRmbMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg is null"); + return NULL; + } + + return pRmbMsg->sysHeader.cConsumerSysId; +} + +//get cConsumerSvrId +int rmb_msg_get_consumerSvrId (StRmbMsg * pRmbMsg, char *cConsumerSvrId, + unsigned int *uiLen) +{ + if (pRmbMsg == NULL || cConsumerSvrId == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg or cConsumerSvrId is null"); + return -1; + } + + unsigned int uiConsumerLen = + (unsigned int) strlen (pRmbMsg->sysHeader.cConsumerSvrId); + + if (*uiLen < uiConsumerLen) + { + LOGRMB (RMB_LOG_ERROR, + "rmb msg consumerSvrId len=%u, but arg len=%u(too small)", + uiConsumerLen, *uiLen); + return -2; + } + + memcpy (cConsumerSvrId, pRmbMsg->sysHeader.cConsumerSvrId, uiConsumerLen); + *uiLen = uiConsumerLen; + + return 0; +} + +const char *rmb_msg_get_consumerSvrId_ptr (StRmbMsg * pRmbMsg) +{ + if (pRmbMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg is null"); + return NULL; + } + + return pRmbMsg->sysHeader.cConsumerSvrId; +} + +////////////////////////////////////////////////////////////////////////////// + +int rmb_check_msg_valid (StRmbMsg * pStMsg) +{ + //modify in 2016-09-26 + //if (pStMsg->flag | (1 << RMBMSG_DEST_HAS_SET == 0)) + if ((pStMsg->flag & (1 << RMBMSG_DEST_HAS_SET)) == 0) + { + LOGRMB (RMB_LOG_ERROR, "pStMsg=%s must be init first!", + rmb_msg_print (pStMsg)); + rmb_errno = RMB_ERROR_MSG_MISSING_PART; + return -1; + } + return 0; +} + +int rmb_msg_set_live_time (StRmbMsg * pRmbMsg, unsigned long ulLiveTime) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + if (ulLiveTime == 0) + { + LOGRMB (RMB_LOG_ERROR, "ttl time must gt 0"); + rmb_errno = RMB_ERROR_MSG_TTL_0; + return -2; + } + + pRmbMsg->ulMsgLiveTime = ulLiveTime; + return 0; +} + +int rmb_get_fit_size (const unsigned int uiLen, const unsigned int uiMaxLen) +{ +// if (uiLen >= uiMaxLen) + if (uiLen > uiMaxLen) + { + return -1; + } + unsigned int uiCount = 0; + unsigned int uiTmpLen = uiLen; + while ((uiTmpLen = uiTmpLen >> 1) != 0) + { + uiCount++; + } + uiCount++; + uiCount = (uiCount >= 10) ? uiCount : 10; + return (1 << uiCount) + 1; +} + +int rmb_msg_set_app_header (StRmbMsg * pRmbMsg, const char *appHeader, + unsigned int uiLen) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (appHeader, "appHeader"); + +// if (uiLen >= MAX_APPHEADER_LENGTH) +// { +// LOGRMB(RMB_LOG_ERROR, "uiLen=%u too large!max_limit=%u", uiLen, MAX_APPHEADER_LENGTH); +// rmb_errno = RMB_ERROR_MSG_SET_APPHEADER_TOO_LARGE; +// return -2; +// } + if (pRmbMsg->cAppHeader == NULL || pRmbMsg->iMallocAppHeaderLength == 0) + { + pRmbMsg->cAppHeader = (char *) malloc (i1KB); + pRmbMsg->iMallocAppHeaderLength = i1KB; + } + if (uiLen >= pRmbMsg->iMallocAppHeaderLength) + { + int iFitSize = rmb_get_fit_size (uiLen, MAX_APPHEADER_LENGTH); + if (iFitSize < 0) + { + LOGRMB (RMB_LOG_ERROR, "uiLen=%u too large!max_limit=%u\n", uiLen, + MAX_APPHEADER_LENGTH); + rmb_errno = RMB_ERROR_BUF_NOT_ENOUGH; + return -2; + } + free (pRmbMsg->cAppHeader); + pRmbMsg->cAppHeader = NULL; + pRmbMsg->cAppHeader = (char *) malloc (iFitSize); + pRmbMsg->iMallocAppHeaderLength = iFitSize; + } + + memcpy (pRmbMsg->cAppHeader, appHeader, uiLen); + pRmbMsg->cAppHeader[uiLen] = '\0'; + pRmbMsg->iAppHeaderLen = (int) uiLen; + return 0; +} + +int rmb_msg_set_content (StRmbMsg * pRmbMsg, const char *content, + unsigned int uiLen) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (content, "content"); + +// if (uiLen >= sizeof(pRmbMsg->cContent)) +// { +// LOGRMB(RMB_LOG_ERROR, "uiLen=%u too large!max_limit=%lu",uiLen, sizeof(pRmbMsg->cContent)); +// rmb_errno = RMB_ERROR_MSG_SET_CONTENT_TOO_LARGE; +// return -2; +// } + + if (pRmbMsg->cContent == NULL || pRmbMsg->iMallocContentLength == 0) + { + pRmbMsg->cContent = (char *) malloc (i1KB); + pRmbMsg->iMallocContentLength = i1KB; + } + if (uiLen >= pRmbMsg->iMallocContentLength) + { + int iFitSize = rmb_get_fit_size (uiLen, MAX_MSG_CONTENT_SIZE); + if (iFitSize < 0) + { + LOGRMB (RMB_LOG_ERROR, "uiLen=%u too large!max_limit=%u\n", uiLen, + MAX_MSG_CONTENT_SIZE); + rmb_errno = RMB_ERROR_BUF_NOT_ENOUGH; + return rmb_errno; + } + free (pRmbMsg->cContent); + pRmbMsg->cContent = NULL; + pRmbMsg->cContent = (char *) malloc (iFitSize); + pRmbMsg->iMallocContentLength = iFitSize; + } + + memcpy (pRmbMsg->cContent, content, uiLen); + pRmbMsg->cContent[uiLen] = '\0'; + pRmbMsg->iContentLen = (int) uiLen; + pRmbMsg->sysHeader.iContentLength = pRmbMsg->iContentLen; + return 0; +} + +/** + * get msg type + * 0: undefined type + * 1: request in queue + * 2: reply package in RR + * 3: broadcast + * see: C_RMB_PKG_TYPE + */ +int rmb_msg_get_msg_type (StRmbMsg * pRmbMsg) +{ + return (int) pRmbMsg->cPkgType; +} + +const char *rmb_msg_get_uniqueId_ptr (StRmbMsg * pRmbMsg) +{ + return pRmbMsg->sysHeader.cUniqueId; +} + +const char *rmb_msg_get_biz_seq_no_ptr (StRmbMsg * pRmbMsg) +{ + return pRmbMsg->sysHeader.cBizSeqNo; +} + +const char *rmb_msg_get_consumer_seq_no_ptr (StRmbMsg * pRmbMsg) +{ + return pRmbMsg->sysHeader.cConsumerSeqNo; +} + +const char *rmb_msg_get_consumer_dcn_ptr (StRmbMsg * pRmbMsg) +{ + return pRmbMsg->sysHeader.cConsumerDcn; +} + +const char *rmb_msg_get_org_sys_id_ptr (StRmbMsg * pRmbMsg) +{ + return pRmbMsg->sysHeader.cOrgSysId; +} + +const char *rmb_msg_get_org_id_ptr (StRmbMsg * pRmbMsg) +{ + return pRmbMsg->sysHeader.cOrgId; +} + +const char *rmb_msg_get_app_header_ptr (StRmbMsg * pRmbMsg, + unsigned int *pLen) +{ + if (pRmbMsg == NULL || pLen == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg or pLen == NULL"); + } + + *pLen = pRmbMsg->iAppHeaderLen; + return pRmbMsg->cAppHeader; +} + +int rmb_msg_get_app_header (StRmbMsg * pRmbMsg, char *userHeader, + unsigned int *pLen) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (userHeader, "userHeader"); + + if (pRmbMsg->iAppHeaderLen > *pLen) + { + LOGRMB (RMB_LOG_ERROR, " buffer len too small.uiLen=%u,buffSize=%u", + *pLen, pRmbMsg->iAppHeaderLen); + rmb_errno = RMB_ERROR_BUF_NOT_ENOUGH; + return rmb_errno; + } + memcpy (userHeader, pRmbMsg->cAppHeader, pRmbMsg->iAppHeaderLen); + *pLen = pRmbMsg->iAppHeaderLen; + return 0; +} + +const char *rmb_msg_get_content_ptr (StRmbMsg * pRmbMsg, unsigned int *pLen) +{ + if (pRmbMsg == NULL || pLen == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbMsg or pLen == NULL"); + } + + *pLen = pRmbMsg->iContentLen; + return pRmbMsg->cContent; +} + +int rmb_msg_get_content (StRmbMsg * pRmbMsg, char *content, + unsigned int *pLen) +{ + RMB_CHECK_POINT_NULL (pRmbMsg, "pRmbMsg"); + RMB_CHECK_POINT_NULL (content, "content"); + + if (pRmbMsg->iContentLen > *pLen) + { + LOGRMB (RMB_LOG_ERROR, + " content buffer len too small.uiLen=%u,buffSize=%u", *pLen, + pRmbMsg->iContentLen); + rmb_errno = RMB_ERROR_BUF_NOT_ENOUGH; + return rmb_errno; + } + memcpy (content, pRmbMsg->cContent, pRmbMsg->iContentLen); + *pLen = pRmbMsg->iContentLen; + return 0; +} + +int shift_buf_2_msg (StRmbMsg * pStMsg, const char *cBuf, unsigned int uiLen) +{ + //StRmbMsg msg; + const char *p = cBuf; + + unsigned int uiBufLen = + 3 * sizeof (char) + sizeof (pStMsg->sysHeader) + + 2 * sizeof (pStMsg->dest) + 2 * sizeof (unsigned long) + + 3 * sizeof (int) + sizeof (StFlow *) + sizeof (pStMsg->strTargetDcn) + + sizeof (pStMsg->strServiceId) + sizeof (pStMsg->strScenarioId) + + sizeof (int) + sizeof (int); + if (uiBufLen > uiLen) + { + rmb_errno = RMB_ERROR_BUF_2_MSG_FAIL; + return -1; + } + + //copy msg src + memcpy (&pStMsg->iMsgMode, p, sizeof (int)); + p += sizeof (int); + + //copy cPkgType + pStMsg->cPkgType = *p; + p += sizeof (char); + + //copy cLogicType + pStMsg->cLogicType = *p; + p += sizeof (char); + + //copy cApiType + pStMsg->cApiType = *p; + p += sizeof (char); + + //copy sysHeader + memcpy (&pStMsg->sysHeader, p, sizeof (pStMsg->sysHeader)); + p += sizeof (pStMsg->sysHeader); + + //copy dest + memcpy (&pStMsg->dest, p, sizeof (pStMsg->dest)); + p += sizeof (pStMsg->dest); + + //copy replyTo + memcpy (&pStMsg->replyTo, p, sizeof (pStMsg->replyTo)); + p += sizeof (pStMsg->replyTo); + + //copy msgid + memcpy (&pStMsg->ulMsgId, p, sizeof (unsigned long)); + p += sizeof (unsigned long); + + //copy msgLiveTime + memcpy (&pStMsg->ulMsgLiveTime, p, sizeof (unsigned long)); + p += sizeof (unsigned long); + + //copy AppHeader -- len + memcpy (&pStMsg->iAppHeaderLen, p, sizeof (int)); + p += sizeof (int); + + uiBufLen += pStMsg->iAppHeaderLen; + if (pStMsg->iAppHeaderLen >= pStMsg->iMallocAppHeaderLength) + { + int iFitSize = + rmb_get_fit_size (pStMsg->iAppHeaderLen, MAX_APPHEADER_LENGTH); + if (iFitSize < 0) + { + LOGRMB (RMB_LOG_ERROR, "appheader len=%u too large!max_limit=%u\n", + pStMsg->iAppHeaderLen, MAX_APPHEADER_LENGTH); + rmb_errno = RMB_ERROR_BUF_2_MSG_FAIL; + return rmb_errno; + } + free (pStMsg->cAppHeader); + pStMsg->cAppHeader = NULL; + pStMsg->cAppHeader = (char *) malloc (iFitSize); + pStMsg->iMallocAppHeaderLength = iFitSize; + } + if (uiBufLen > uiLen) + { + rmb_errno = RMB_ERROR_BUF_2_MSG_FAIL; + return -2; + } + + //copy AppHeader -- data + memcpy (pStMsg->cAppHeader, p, pStMsg->iAppHeaderLen); + pStMsg->cAppHeader[pStMsg->iAppHeaderLen] = 0; + p += pStMsg->iAppHeaderLen; + + //copy content + memcpy (&pStMsg->iContentLen, p, sizeof (int)); + p += sizeof (int); + + uiBufLen += pStMsg->iContentLen; + if (pStMsg->iContentLen >= pStMsg->iMallocContentLength) + { + int iFitSize = + rmb_get_fit_size (pStMsg->iContentLen, MAX_MSG_CONTENT_SIZE); + if (iFitSize < 0) + { + LOGRMB (RMB_LOG_ERROR, "content len=%u too large!max_limit=%u\n", uiLen, + MAX_MSG_CONTENT_SIZE); + rmb_errno = RMB_ERROR_BUF_2_MSG_FAIL; + return -3; + } + free (pStMsg->cContent); + pStMsg->cContent = NULL; + pStMsg->cContent = (char *) malloc (iFitSize); + pStMsg->iMallocContentLength = iFitSize; + } + + if (uiBufLen > uiLen) + { + rmb_errno = RMB_ERROR_BUF_2_MSG_FAIL; + return -3; + } + + //copy content + memcpy (pStMsg->cContent, p, pStMsg->iContentLen); + pStMsg->cContent[pStMsg->iContentLen] = 0; + p += pStMsg->iContentLen; + + //copy corrid + memcpy (&pStMsg->iCorrLen, p, sizeof (int)); + p += sizeof (int); + + uiBufLen += pStMsg->iCorrLen; + if (uiBufLen > uiLen) + { + rmb_errno = RMB_ERROR_BUF_2_MSG_FAIL; + return -4; + } + + memcpy (pStMsg->cCorrId, p, pStMsg->iCorrLen); + p += pStMsg->iCorrLen; + + memcpy (&pStMsg->iEventOrService, p, sizeof (int)); + p += sizeof (int); + + memcpy (pStMsg->strTargetDcn, p, sizeof (pStMsg->strTargetDcn)); + p += sizeof (pStMsg->strTargetDcn); + + memcpy (pStMsg->strServiceId, p, sizeof (pStMsg->strServiceId)); + p += sizeof (pStMsg->strServiceId); + + memcpy (pStMsg->strScenarioId, p, sizeof (pStMsg->strScenarioId)); + p += sizeof (pStMsg->strScenarioId); + + //memcpy(pStMsg, &msg, sizeof(StRmbMsg)); + + return 0; +} + +int shift_msg_2_buf (char *cBuf, unsigned int *pLen, const StRmbMsg * pStMsg) +{ + unsigned int uiMsgLen = 0; + uiMsgLen = + 3 * sizeof (char) + sizeof (StSystemHeader) + 2 * sizeof (StDestination) + + 2 * sizeof (unsigned long); + uiMsgLen += + 3 * sizeof (int) + sizeof (StFlow *) + sizeof (pStMsg->strTargetDcn) + + sizeof (pStMsg->strServiceId) + sizeof (pStMsg->strScenarioId) + + sizeof (int); + uiMsgLen += pStMsg->iAppHeaderLen + pStMsg->iContentLen + pStMsg->iCorrLen; + uiMsgLen += sizeof (int); + + char *p = cBuf; + + if (*pLen < uiMsgLen) + { + rmb_errno = RMB_ERROR_MSG_2_BUF_FAIL; + return rmb_errno; + } + + *pLen = uiMsgLen; + + //set msg src + memcpy (p, &pStMsg->iMsgMode, sizeof (int)); + p += sizeof (int); + + //copy cPkgType + *p = pStMsg->cPkgType; + p += sizeof (char); + + //copy cLogicType + *p = pStMsg->cLogicType; + p += sizeof (char); + + //copy cApiType + *p = pStMsg->cApiType; + p += sizeof (char); + + //copy sysheader + memcpy (p, &pStMsg->sysHeader, sizeof (pStMsg->sysHeader)); + p += sizeof (pStMsg->sysHeader); + + //copy dest + memcpy (p, &pStMsg->dest, sizeof (pStMsg->dest)); + p += sizeof (pStMsg->dest); + + //copy replyTo + memcpy (p, &pStMsg->replyTo, sizeof (pStMsg->replyTo)); + p += sizeof (pStMsg->replyTo); + + //copy msgid + memcpy (p, &pStMsg->ulMsgId, sizeof (unsigned long)); + p += sizeof (unsigned long); + + //copy msgLiveTime + memcpy (p, &pStMsg->ulMsgLiveTime, sizeof (unsigned long)); + p += sizeof (unsigned long); + + //copy Appheader + memcpy (p, &pStMsg->iAppHeaderLen, sizeof (int)); + p += sizeof (int); + + memcpy (p, pStMsg->cAppHeader, pStMsg->iAppHeaderLen); + p += pStMsg->iAppHeaderLen; + + //copy content + memcpy (p, &pStMsg->iContentLen, sizeof (int)); + p += sizeof (int); + + memcpy (p, pStMsg->cContent, pStMsg->iContentLen); + p += pStMsg->iContentLen; + + //copy corrid + memcpy (p, &pStMsg->iCorrLen, sizeof (int)); + p += sizeof (int); + + memcpy (p, pStMsg->cCorrId, pStMsg->iCorrLen); + p += pStMsg->iCorrLen; + + memcpy (p, &pStMsg->iEventOrService, sizeof (int)); + p += sizeof (int); + + memcpy (p, pStMsg->strTargetDcn, sizeof (pStMsg->strTargetDcn)); + p += sizeof (pStMsg->strTargetDcn); + + memcpy (p, pStMsg->strServiceId, sizeof (pStMsg->strServiceId)); + p += sizeof (pStMsg->strServiceId); + + memcpy (p, pStMsg->strScenarioId, sizeof (pStMsg->strScenarioId)); + p += sizeof (pStMsg->strScenarioId); + + return 0; +} + +int set_extfields_2_rmb_msg (StRmbMsg * pStMsg, const char *command, int iSeq) +{ + char born_time[32]; + char store_time[32]; + char leave_time[32]; + char arrive_time[32]; + + memset (born_time, 0x00, sizeof (born_time)); + memset (store_time, 0x00, sizeof (store_time)); + memset (leave_time, 0x00, sizeof (leave_time)); + memset (arrive_time, 0x00, sizeof (arrive_time)); + + WEMQJSON *jsonDecoder = NULL; + WEMQJSON *jsonExtField = NULL; + WEMQJSON *property = json_tokener_parse (pStMsg->sysHeader.cProperty); + if (NULL != property) + { + if (json_object_object_get_ex + (property, MSG_BODY_PROPERTY_BORN_TIME_STR, &jsonDecoder)) + { + const char *tmpTime = json_object_get_string (jsonDecoder); + snprintf (born_time, sizeof (born_time), "%s", tmpTime); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In property, %s is null!", + MSG_BODY_PROPERTY_BORN_TIME_STR); + } + + if (json_object_object_get_ex + (property, MSG_BODY_PROPERTY_STORE_TIME_STR, &jsonDecoder)) + { + const char *tmpTime = json_object_get_string (jsonDecoder); + snprintf (store_time, sizeof (store_time), "%s", tmpTime); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In property, %s is null!", + MSG_BODY_PROPERTY_STORE_TIME_STR); + } + + if (json_object_object_get_ex + (property, MSG_BODY_PROPERTY_LEAVE_TIME_STR, &jsonDecoder)) + { + const char *tmpTime = json_object_get_string (jsonDecoder); + snprintf (leave_time, sizeof (leave_time), "%s", tmpTime); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In property, %s is null!", + MSG_BODY_PROPERTY_LEAVE_TIME_STR); + } + + if (json_object_object_get_ex + (property, MSG_BODY_PROPERTY_ARRIVE_TIME_STR, &jsonDecoder)) + { + const char *tmpTime = json_object_get_string (jsonDecoder); + snprintf (arrive_time, sizeof (arrive_time), "%s", tmpTime); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In property, %s is null!", + MSG_BODY_PROPERTY_ARRIVE_TIME_STR); + } + } + jsonExtField = json_tokener_parse (pStMsg->sysHeader.cExtFields); + if (jsonExtField == NULL) + { + jsonExtField = json_object_new_object (); + } + + if (strcmp (command, REQUEST_TO_CLIENT) == 0 + || strcmp (command, ASYNC_MESSAGE_TO_CLIENT) == 0 + || strcmp (command, BROADCAST_MESSAGE_TO_CLIENT) == 0) + { + json_object_object_add (jsonExtField, REQ_BORN_TIMESTAMP, + json_object_new_string (born_time)); + json_object_object_add (jsonExtField, REQ_STORE_TIMESTAMP, + json_object_new_string (store_time)); + json_object_object_add (jsonExtField, REQ_LEAVE_TIMESTAMP, + json_object_new_string (leave_time)); + json_object_object_add (jsonExtField, REQ_ARRIVE_TIMESTAMP, + json_object_new_string (arrive_time)); + json_object_object_add (jsonExtField, MSG_BODY_SYSTEM_ACK_SEQ, + json_object_new_int (iSeq)); + } + else if (strcmp (command, RESPONSE_TO_CLIENT) == 0) + { + json_object_object_add (jsonExtField, RSP_BORN_TIMESTAMP, + json_object_new_string (born_time)); + json_object_object_add (jsonExtField, RSP_STORE_TIMESTAMP, + json_object_new_string (store_time)); + json_object_object_add (jsonExtField, RSP_LEAVE_TIMESTAMP, + json_object_new_string (leave_time)); + json_object_object_add (jsonExtField, RSP_ARRIVE_TIMESTAMP, + json_object_new_string (arrive_time)); + } + + const char *extFields = json_object_get_string (jsonExtField); + if (extFields != NULL) + { + int len = (int) strlen (extFields); + if (len >= RMB_SYSTEMHEADER_EXTFIELDS_MAX_LEN) + { + LOGRMB (RMB_LOG_ERROR, "systemHeader len=%d too large!max_limit=%d: %s", + len, RMB_SYSTEMHEADER_EXTFIELDS_MAX_LEN, extFields); + } + else + { + snprintf (pStMsg->sysHeader.cExtFields, + sizeof (pStMsg->sysHeader.cExtFields), "%s", extFields); + } + } + json_object_put (property); + json_object_put (jsonExtField); + return 0; +} + +static WEMQJSON *generate_destination_from_topic (StRmbMsg * pStMsg, + char *pTopic) +{ + + char cDestName[200]; + char strTargetDcn[10]; + char strServiceId[10]; + char strScenarioId[5]; + + //判断分隔符数量是否正确 + int i = 0; + char *ptopic = pTopic; + char *pTemp = NULL; + do + { + pTemp = strchr (ptopic, '-'); + if (pTemp == NULL) + { + break; + } + i++; + ptopic = pTemp + 1; + } + while (ptopic != NULL); + + if (i != 4) + { + if (strstr (pTopic, "reply-topic") == NULL) + { + LOGRMB (RMB_LOG_WARN, "topic:%s formatting is not conformed!", pTopic); + return NULL; + } + } + + WEMQJSON *jsonDest = json_object_new_object (); + if (jsonDest == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object failed"); + return NULL; + } + + memset (cDestName, 0x00, sizeof (cDestName)); + snprintf (cDestName, sizeof (pStMsg->dest.cDestName), "%s", pTopic); + + for (i = 0; i < strlen (cDestName) && cDestName[i] != '\0'; i++) + { + if (cDestName[i] == '-') + { + cDestName[i] = '/'; + } + } + json_object_object_add (jsonDest, MSG_BODY_DEST_NAME_STR, + json_object_new_string (cDestName)); + + pTemp = strrchr (cDestName, '/'); + *pTemp = '\0'; + //copy ScenarioId + pTemp = strrchr (cDestName, '/'); + if (pTemp == NULL) + { + return NULL; + } + snprintf (strScenarioId, sizeof (strScenarioId), "%s", pTemp + 1); + *pTemp = '\0'; + + //copy ServiceId + pTemp = strrchr (cDestName, '/'); + if (pTemp == NULL) + { + return NULL; + } + snprintf (strServiceId, sizeof (strServiceId), "%s", pTemp + 1); + *pTemp = '\0'; + + pTemp = strrchr (cDestName, '/'); + if (pTemp == NULL) + { + return NULL; + } + *pTemp = '\0'; + //copy TargetDcn + snprintf (strTargetDcn, sizeof (strTargetDcn), "%s", cDestName); + + json_object_object_add (jsonDest, MSG_BODY_DEST_TYPE_STR, + json_object_new_string ("se")); + json_object_object_add (jsonDest, MSG_BODY_DEST_SORE_STR, + json_object_new_string (strServiceId)); + json_object_object_add (jsonDest, MSG_BODY_DEST_SCENARIO_STR, + json_object_new_string (strScenarioId)); + json_object_object_add (jsonDest, MSG_BODY_DEST_DCN_STR, + json_object_new_string (strTargetDcn)); + json_object_object_add (jsonDest, MSG_BODY_DEST_ORGID_STR, + json_object_new_string (pStMsg->sysHeader.cOrgId)); + + return jsonDest; +} + +int trans_json_2_rmb_msg (StRmbMsg * pStMsg, const char *bodyJson, + const char *command) +{ + if (pStMsg == NULL || bodyJson == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStMsg or bodyJson is null"); + return -1; + } + + rmb_msg_clear (pStMsg); + + pStMsg->cApiType = C_TYPE_WEMQ; + + WEMQJSON *systemHeader = NULL; + WEMQJSON *dest = NULL; + WEMQJSON *jsonDecoder = NULL; + WEMQJSON *property = NULL; + WEMQJSON *jsonByteBody = NULL; + + WEMQJSON *jsonBody = json_tokener_parse (bodyJson); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_tokener_parse failed!,buf is:%s", bodyJson); + return -1; + } + if (!json_object_object_get_ex + (jsonBody, MSG_BODY_BYTE_BODY_JSON, &jsonByteBody)) + { + LOGRMB (RMB_LOG_ERROR, "body json no byte body!"); + return -2; + } //byte body json + + if (!json_object_object_get_ex + (jsonBody, MSG_BODY_PROPERTY_JSON, &property)) + { + LOGRMB (RMB_LOG_ERROR, "body json no properties!"); + return -2; + } //property json + jsonByteBody = json_tokener_parse (json_object_get_string (jsonByteBody)); + if (!json_object_object_get_ex + (jsonByteBody, MSG_BODY_BYTE_BODY_SYSTEM_HEADER_CONTENT_JSON, + &systemHeader)) + { + LOGRMB (RMB_LOG_ERROR, "byte body json no system header content!"); + return -2; + } //system header json + systemHeader = json_tokener_parse (json_object_get_string (systemHeader)); + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_BIZ_STR, &jsonDecoder)) + { + const char *bizNo = json_object_get_string (jsonDecoder); + if (bizNo != NULL) + { + snprintf (pStMsg->sysHeader.cBizSeqNo, + sizeof (pStMsg->sysHeader.cBizSeqNo), "%s", bizNo); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_BIZ_STR); + } + } //system header bizno + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_SEQNO_STR, &jsonDecoder)) + { + const char *seqNo = json_object_get_string (jsonDecoder); + if (seqNo != NULL) + { + snprintf (pStMsg->sysHeader.cConsumerSeqNo, + sizeof (pStMsg->sysHeader.cConsumerSeqNo), "%s", seqNo); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_SEQNO_STR); + } + } //system header seqNo + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_SVRID_STR, &jsonDecoder)) + { + const char *svrId = json_object_get_string (jsonDecoder); + if (svrId != NULL) + { + snprintf (pStMsg->sysHeader.cConsumerSvrId, + sizeof (pStMsg->sysHeader.cConsumerSvrId), "%s", svrId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_SVRID_STR); + } + } //system header svrId + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_ORGSYS_STR, &jsonDecoder)) + { + const char *orgId = json_object_get_string (jsonDecoder); + if (orgId != NULL) + { + snprintf (pStMsg->sysHeader.cOrgSysId, + sizeof (pStMsg->sysHeader.cOrgSysId), "%s", orgId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_ORGSYS_STR); + } + } //system header orgId + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_CSMID_STR, &jsonDecoder)) + { + const char *csmId = json_object_get_string (jsonDecoder); + if (csmId != NULL) + { + snprintf (pStMsg->sysHeader.cConsumerSysId, + sizeof (pStMsg->sysHeader.cConsumerSysId), "%s", csmId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_CSMID_STR); + } + } //system header csmId + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_TIME_LINT, &jsonDecoder)) + { + pStMsg->sysHeader.ulTranTimeStamp = json_object_get_int64 (jsonDecoder); + } //system header transTime + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_CSMDCN_STR, &jsonDecoder)) + { + const char *csmDcn = json_object_get_string (jsonDecoder); + if (csmDcn != NULL) + { + snprintf (pStMsg->sysHeader.cConsumerDcn, + sizeof (pStMsg->sysHeader.cConsumerDcn), "%s", csmDcn); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_CSMDCN_STR); + } + } //system header csmDcn + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_ORGSVR_STR, &jsonDecoder)) + { + const char *orgSysId = json_object_get_string (jsonDecoder); + if (orgSysId != NULL) + { + snprintf (pStMsg->sysHeader.cOrgSvrId, + sizeof (pStMsg->sysHeader.cOrgSvrId), "%s", orgSysId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_ORGSVR_STR); + } + } //system header orgSysId + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_ORGID_STR, &jsonDecoder)) + { + const char *cOrgId = json_object_get_string (jsonDecoder); + if (cOrgId != NULL) + { + snprintf (pStMsg->sysHeader.cOrgId, sizeof (pStMsg->sysHeader.cOrgId), + "%s", cOrgId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_ORGID_STR); + } + } //system header cOrgId + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_UNIID_STR, &jsonDecoder)) + { + const char *cUniqueId = json_object_get_string (jsonDecoder); + if (cUniqueId != NULL) + { + snprintf (pStMsg->sysHeader.cUniqueId, + sizeof (pStMsg->sysHeader.cUniqueId), "%s", cUniqueId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_UNIID_STR); + } + } //system header cUniqueId + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_CONLEN_INT, &jsonDecoder)) + { + pStMsg->sysHeader.iContentLength = json_object_get_int (jsonDecoder); + } //system header iContentLength + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_SENDTIME_LINT, &jsonDecoder)) + { + pStMsg->sysHeader.ulSendTime = json_object_get_int64 (jsonDecoder); + } //system header ulSendTime + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_RECVTIME_LINT, &jsonDecoder)) + { + pStMsg->sysHeader.ulReceiveTime = json_object_get_int64 (jsonDecoder); + } + if (pStMsg->sysHeader.ulReceiveTime == 0) + { + GetRmbNowLongTime (); + pStMsg->sysHeader.ulReceiveTime = pRmbStConfig->ulNowTtime; + } + //system header ulReceiveTime + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_REPLYTIME_LINT, &jsonDecoder)) + { + pStMsg->sysHeader.ulReplyTime = json_object_get_int64 (jsonDecoder); + } //system header ulReplyTime + + if (json_object_object_get_ex + (jsonByteBody, MSG_BODY_BYTE_BODY_APPHEADER_NAME_STR, &jsonDecoder)) + { + const char *pAppheaderClass = json_object_get_string (jsonDecoder); + if (pAppheaderClass != NULL) + { + snprintf (pStMsg->sysHeader.cAppHeaderClass, + sizeof (pStMsg->sysHeader.cAppHeaderClass), "%s", + pAppheaderClass); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_BYTE_BODY_APPHEADER_NAME_STR); + } + } // system header cAppHeaderClass + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_VER_STR, &jsonDecoder)) + { + const char *pConsumerSysVersion = json_object_get_string (jsonDecoder); + if (pConsumerSysVersion != NULL) + { + snprintf (pStMsg->sysHeader.cConsumerSysVersion, + sizeof (pStMsg->sysHeader.cConsumerSysVersion), "%s", + pConsumerSysVersion); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_VER_STR); + } + } + //system consumerSysVersion + + const char *cProperty = json_object_get_string (property); + if (cProperty != NULL) + { + int len = (int) strlen (property); + if (len >= RMB_SYSTEMHEADER_PROPERTY_MAX_LEN) + { + LOGRMB (RMB_LOG_ERROR, "property len=%d too large!max_limit=%d: %s", + len, RMB_SYSTEMHEADER_PROPERTY_MAX_LEN, cProperty); + } + else + { + snprintf (pStMsg->sysHeader.cProperty, + sizeof (pStMsg->sysHeader.cProperty), "%s", cProperty); + } + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_PROPERTY_JSON); + } + + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_EXTFIELDS_STR, &jsonDecoder)) + { + const char *extFields = json_object_get_string (jsonDecoder); + if (extFields != NULL) + { + int len = (int) strlen (extFields); + if (len >= RMB_SYSTEMHEADER_EXTFIELDS_MAX_LEN) + { + LOGRMB (RMB_LOG_ERROR, + "systemHeader len=%d too large!max_limit=%d: %s", len, + RMB_SYSTEMHEADER_EXTFIELDS_MAX_LEN, extFields); + } + else + { + snprintf (pStMsg->sysHeader.cExtFields, + sizeof (pStMsg->sysHeader.cExtFields), "%s", extFields); + } + if (strstr (extFields, "\"IS_DYED_MSG\": \"true\"") != NULL) + { + LOGRMB (RMB_LOG_DEBUG, "trans msg, extfield is %s", extFields); + strcpy (pStMsg->isDyedMsg, "true"); + } + else + { + strcpy (pStMsg->isDyedMsg, "false"); + } + } + else + { + LOGRMB (RMB_LOG_ERROR, "In systemHeader, %s is null!", + MSG_BODY_SYSTEM_EXTFIELDS_STR); + } + + } //system header extFields + + if (json_object_object_get_ex + (jsonByteBody, MSG_BODY_BYTE_BODY_APPHEADER_CONTENT_JSON, &jsonDecoder)) + { + const char *appHeader = json_object_get_string (jsonDecoder); + if (appHeader != NULL) + { + //get appHeader len + unsigned int uiAppHeaderLen = json_object_get_string_len (jsonDecoder); + if (uiAppHeaderLen >= pStMsg->iMallocAppHeaderLength) + { + int iFitSize = + rmb_get_fit_size (uiAppHeaderLen, MAX_APPHEADER_LENGTH); + if (iFitSize < 0) + { + LOGRMB (RMB_LOG_ERROR, "appHeader len=%d too large!max_limit=%u", + uiAppHeaderLen, MAX_APPHEADER_LENGTH); + return -1; + } + free (pStMsg->cAppHeader); + pStMsg->cAppHeader = NULL; + pStMsg->cAppHeader = (char *) malloc (iFitSize); + pStMsg->iMallocAppHeaderLength = iFitSize; + } + pStMsg->iAppHeaderLen = uiAppHeaderLen; + memcpy (pStMsg->cAppHeader, json_object_get_string (jsonDecoder), + uiAppHeaderLen); + pStMsg->cAppHeader[pStMsg->iAppHeaderLen] = '\0'; + } + else + { + LOGRMB (RMB_LOG_ERROR, "In body, %s is null!", MSG_BODY_APP_JSON); + } + } //appHeader + + if (json_object_object_get_ex + (property, MSG_BODY_PROPERTY_TTL_INT, &jsonDecoder)) + { + pStMsg->ulMsgLiveTime = json_object_get_int64 (jsonDecoder); + } //header ulMsgLiveTime + + //if (json_object_object_get_ex(jsonBody, MSG_BODY_TOPIC_STR, &jsonDecoder)) + //{ + // const char *topic = json_object_get_string(jsonDecoder); + + // dest = generate_destination_from_topic(pStMsg,topic); + if (json_object_object_get_ex (jsonByteBody, MSG_BODY_DEST_JSON, &dest)) + { + dest = json_tokener_parse (json_object_get_string (dest)); + } + else + { + if (json_object_object_get_ex + (jsonBody, MSG_BODY_TOPIC_STR, &jsonDecoder)) + { + const char *topic = json_object_get_string (jsonDecoder); + dest = generate_destination_from_topic (pStMsg, topic); + } + + } + if (NULL != dest) + { + if (json_object_object_get_ex + (dest, MSG_BODY_DEST_NAME_STR, &jsonDecoder)) + { + //get name + const char *destTmp = json_object_get_string (jsonDecoder); + if (destTmp != NULL) + { + snprintf (pStMsg->dest.cDestName, sizeof (pStMsg->dest.cDestName), + "%s", destTmp); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In destination, %s is null", + MSG_BODY_DEST_NAME_STR); + } + } //get name + + if (json_object_object_get_ex + (dest, MSG_BODY_DEST_SORE_STR, &jsonDecoder)) + { + const char *pServiceId = json_object_get_string (jsonDecoder); + if (pServiceId != NULL) + { + snprintf (pStMsg->strServiceId, sizeof (pStMsg->strServiceId), "%s", + pServiceId); + pStMsg->iEventOrService = + (*(pServiceId + 3) == '0') ? RMB_SERVICE_CALL : RMB_EVENT_CALL; + } + else + { + LOGRMB (RMB_LOG_ERROR, "In destination, %s is null", + MSG_BODY_DEST_SORE_STR); + } + } //get serviceOrEventId + + if (json_object_object_get_ex + (dest, MSG_BODY_DEST_SCENARIO_STR, &jsonDecoder)) + { + const char *pScenarioId = json_object_get_string (jsonDecoder); + if (pScenarioId != NULL) + { + snprintf (pStMsg->strScenarioId, sizeof (pStMsg->strScenarioId), "%s", + pScenarioId); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In destination, %s is null!", + MSG_BODY_DEST_SCENARIO_STR); + } + } //get scenario + + if (json_object_object_get_ex (dest, MSG_BODY_DEST_DCN_STR, &jsonDecoder)) + { + const char *pDcn = json_object_get_string (jsonDecoder); + if (pDcn != NULL) + { + snprintf (pStMsg->strTargetDcn, sizeof (pStMsg->strTargetDcn), "%s", + pDcn); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In destination, %s is null!", + MSG_BODY_DEST_DCN_STR); + } + } //get dcn + + if (json_object_object_get_ex + (dest, MSG_BODY_DEST_ORGID_STR, &jsonDecoder)) + { + const char *pOrganization = json_object_get_string (jsonDecoder); + if (pOrganization != NULL) + { + snprintf (pStMsg->strTargetOrgId, sizeof (pStMsg->strTargetOrgId), + "%s", pOrganization); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In destination, %s is null", + MSG_BODY_DEST_ORGID_STR); + } + } //get organization + //header dest + } + //topic + + if (json_object_object_get_ex + (property, MSG_BODY_PROPERTY_REPLYTO_STR, &jsonDecoder)) + { + const char *replyTo = json_object_get_string (jsonDecoder); + if (replyTo != NULL) + { + snprintf (pStMsg->replyTo.cDestName, sizeof (pStMsg->replyTo.cDestName), + "%s", replyTo); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In bodyjson, %s is null", MSG_BODY_REPLYTO_STR); + } + } //header replyTo + + if (json_object_object_get_ex + (jsonByteBody, MSG_BODY_BYTE_BODY_CONTENT_STR, &jsonDecoder)) + { + const char *cContent = json_object_get_string (jsonDecoder); + if (cContent != NULL) + { +// pStMsg->iContentLen = strlen(cContent); + pStMsg->iContentLen = json_object_get_string_len (jsonDecoder); + LOGRMB (RMB_LOG_DEBUG, "get content len:%d", pStMsg->iContentLen); + if (pStMsg->iContentLen >= pStMsg->iMallocContentLength) + { + int iFitSize = + rmb_get_fit_size (pStMsg->iContentLen, MAX_MSG_CONTENT_SIZE); + if (iFitSize < 0) + { + LOGRMB (RMB_LOG_ERROR, "content len=%d too large!max_limit=%u", + pStMsg->iContentLen, MAX_MSG_CONTENT_SIZE); + return -1; + } + free (pStMsg->cContent); + pStMsg->cContent = NULL; + pStMsg->cContent = (char *) malloc (iFitSize); + pStMsg->iMallocContentLength = iFitSize; + } + //strncpy(pStMsg->cContent, cContent, pStMsg->iContentLen); + memcpy (pStMsg->cContent, cContent, pStMsg->iContentLen); + pStMsg->cContent[pStMsg->iContentLen] = '\0'; + LOGRMB (RMB_LOG_DEBUG, "get content:%d - %s", pStMsg->iContentLen, + pStMsg->cContent); + } + else + { + LOGRMB (RMB_LOG_ERROR, "In bodyjson, %s is null", MSG_BODY_CONTENT_STR); + } + } //header cContent + + json_object_put (dest); + json_object_put (systemHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + + return 0; +} + +int rmb_msg_print_v (StRmbMsg * pRmbMsg) +{ + LOGRMB (RMB_LOG_DEBUG, + "[type=%s,send=%lu,rev=%lu,dest=%s,bizSeqNo=%s,cSeqNo=%s,replyTo=%s,len=%d,content=%s]", + (int) pRmbMsg->cLogicType <= + 6 ? strLogicType[(int) (pRmbMsg->cLogicType)] : "null", + pRmbMsg->sysHeader.ulSendTime, pRmbMsg->sysHeader.ulReceiveTime, + pRmbMsg->dest.cDestName, pRmbMsg->sysHeader.cBizSeqNo, + pRmbMsg->sysHeader.cConsumerSeqNo, pRmbMsg->replyTo.cDestName, + pRmbMsg->iContentLen, pRmbMsg->cContent); + return 0; +} + +const char *rmb_msg_print (StRmbMsg * pRmbMsg) +{ + if (pRmbMsg->cLogicType == REQ_PKG_IN + || pRmbMsg->cLogicType == EVENT_PKG_IN) + { + snprintf (pRmbMsg->strLogBuf, sizeof (pRmbMsg->strLogBuf) - 1, + "[type=%s,send=%lu,rev=%lu,dest=%s,bizSeqNo=%s,cSeqNo=%s,replyTo=%s,len=%d,content=%s]", + (int) pRmbMsg->cLogicType <= + 6 ? strLogicType[(int) (pRmbMsg->cLogicType)] : "null", + pRmbMsg->sysHeader.ulSendTime, pRmbMsg->sysHeader.ulReceiveTime, + pRmbMsg->dest.cDestName, pRmbMsg->sysHeader.cBizSeqNo, + pRmbMsg->sysHeader.cConsumerSeqNo, pRmbMsg->replyTo.cDestName, + pRmbMsg->iContentLen, pRmbMsg->cContent); + } + else if (pRmbMsg->cLogicType == RSP_PKG_IN + || pRmbMsg->cLogicType == RSP_PKG_OUT) + { + snprintf (pRmbMsg->strLogBuf, sizeof (pRmbMsg->strLogBuf) - 1, + "[type=%s,send=%lu,rev=%lu,reply=%lu,dest=%s,bizSeqNo=%s,cSeqNo=%s,replyTo=%s,len=%d,content=%s]", + (int) pRmbMsg->cLogicType <= + 6 ? strLogicType[(int) (pRmbMsg->cLogicType)] : "null", + pRmbMsg->sysHeader.ulSendTime, pRmbMsg->sysHeader.ulReceiveTime, + pRmbMsg->sysHeader.ulReplyTime, pRmbMsg->dest.cDestName, + pRmbMsg->sysHeader.cBizSeqNo, pRmbMsg->sysHeader.cConsumerSeqNo, + pRmbMsg->replyTo.cDestName, pRmbMsg->iContentLen, + pRmbMsg->cContent); + } + else + { + snprintf (pRmbMsg->strLogBuf, sizeof (pRmbMsg->strLogBuf) - 1, + "[type=%s,send=%lu,dest=%s,bizSeqNo=%s,cSeqNo=%s,replyTo=%s,len=%d,content=%s]", + (int) pRmbMsg->cLogicType <= + 6 ? strLogicType[(int) (pRmbMsg->cLogicType)] : "null", + pRmbMsg->sysHeader.ulSendTime, pRmbMsg->dest.cDestName, + pRmbMsg->sysHeader.cBizSeqNo, pRmbMsg->sysHeader.cConsumerSeqNo, + pRmbMsg->replyTo.cDestName, pRmbMsg->iContentLen, + pRmbMsg->cContent); + } + + pRmbMsg->strLogBuf[sizeof (pRmbMsg->strLogBuf) - 1] = 0; + return pRmbMsg->strLogBuf; +} + +//消息初始化 +StRmbMsg *rmb_msg_malloc () +{ + StRmbMsg *rmbMsg = (StRmbMsg *) malloc (sizeof (StRmbMsg)); + if (rmbMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for rmbMsg error!\n"); + return NULL; + } + memset (rmbMsg, 0, sizeof (StRmbMsg)); + + rmbMsg->cContent = (char *) malloc (i1KB); + if (rmbMsg->cContent == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for rmbMsg->cContent error!\n"); + free (rmbMsg); + rmbMsg = NULL; + return NULL; + } + memset (rmbMsg->cContent, 0x00, sizeof (char) * i1KB); + rmbMsg->iMallocContentLength = i1KB; + + rmbMsg->cAppHeader = (char *) malloc (i1KB); + if (rmbMsg->cAppHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for rmbMsg->cAppHeader error!\n"); + free (rmbMsg->cContent); + rmbMsg->cContent = NULL; + free (rmbMsg); + rmbMsg = NULL; + return NULL; + } + memset (rmbMsg->cAppHeader, 0x00, sizeof (char) * i1KB); + rmbMsg->iMallocAppHeaderLength = i1KB; + + return rmbMsg; +} + +//消息释放 +int rmb_msg_free (StRmbMsg * pRmbMsg) +{ + if (pRmbMsg == NULL) + { + return 0; + } + if (pRmbMsg->cContent != NULL && pRmbMsg->iMallocContentLength != 0) + { + free (pRmbMsg->cContent); + pRmbMsg->cContent = NULL; + } + if (pRmbMsg->cAppHeader != NULL && pRmbMsg->iMallocAppHeaderLength != 0) + { + free (pRmbMsg->cAppHeader); + pRmbMsg->cAppHeader = NULL; + } + + free (pRmbMsg); + return 0; +} + +int rmb_msg_random_uuid (char *puuid, size_t size) +{ + char cUniqueIdEx[50] = { 0 }; + uuid_t uuidout; + uuid_generate_random (uuidout); + uuid_unparse (uuidout, cUniqueIdEx); + snprintf (puuid, size, "%s", cUniqueIdEx); + return 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_pub.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_pub.c new file mode 100644 index 0000000000..784ce498cc --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_pub.c @@ -0,0 +1,2453 @@ +// 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. + +#include +#include +#include +#include +#include "common.h" +#include "rmb_pub.h" +#include "rmb_context.h" +#include "rmb_udp.h" +#include "rmb_common.h" +#include "rmb_errno.h" +#include "wemq_thread.h" + +static int g_iSendReq = 0; +static unsigned long g_iSendReqForEvent = 100000000; +static StRmbPub *pRmbGlobalPub; + +unsigned int g_uiSendMsgSeq = 0; +unsigned int g_uiRecvMsgSeq = 0; +unsigned int DEFAULT_WINDOW_SIZE = 100; + +typedef struct gsl_err +{ + char result; + const char *err_msg; +} gsl_err; + +gsl_err gsl_error[] = { + {0x01, NULL}, + {0x11, "query ckv null"}, + {0x21, "chvvalue.orgid_list_size() = 0"}, + {0x31, "orgid for query rules is null"}, + {0x41, "no available rules for service"}, + {0x51, "ckvvalue.org.dcn_list_size() = 0"}, + {0x61, "target dcn is null according to query rules for event"}, + {0x71, NULL}, + {0x81, NULL}, + {0x91, NULL}, + {0xA1, NULL}, + {0xB1, NULL}, + {0xC1, NULL}, + {0xD1, NULL}, + {0xE1, NULL}, + {0xF1, NULL}, + {0x02, NULL}, + {0x12, + "CommonOrgid points to SingleOrgid, service cannot be deployed in more than one ADM or C-DCN"}, + {0x22, + "CommonOrgid points to SingleOrgid, service cannot be found in either ADM or C-DCN"}, + {0x32, + "public service id is deployed in multiple regions causing conflicts"}, + {0x42, + "service is poly-active in one area(R-DCN/C-DCN/ADM/Common), but dcn matching IDC of clientDcn not found"}, + {0x52, + "event subscriptors belong to one area(CS/DMZ/ECN), but dcn matching IDC of clientDcn not found"}, + {0x62, NULL}, + {0x72, NULL}, + {0x82, NULL}, + {0x92, NULL}, + {0xA2, NULL}, + {0xB2, NULL}, + {0xC2, NULL}, + {0xD2, NULL}, + {0xE2, NULL}, + {0xF2, NULL}, + {0x03, NULL}, + {0x13, "DecodeBuf error or ParseFromString error"}, + {0x23, "query ckv error"}, + {0x33, NULL}, + {0x43, NULL}, + {0x53, NULL}, + {0x63, NULL}, + {0x73, NULL}, + {0x83, NULL}, + {0x93, NULL}, + {0xA3, NULL}, + {0xB3, NULL}, + {0xC3, NULL}, + {0xD3, NULL}, + {0xE3, NULL}, + {0xF3, NULL} +}; + +//#define TCP_BUF_SIZE 5<<01 +static int rmb_pub_encode_header_for_wemq (unsigned int uiCmd, + StWemqThreadMsg * ptThreadMsg, + StRmbMsg * ptSendMsg) +{ + if (ptThreadMsg == NULL || ptSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptThreadMsg is null or ptSendMsg is null"); + return -1; + } + + switch (uiCmd) + { + case THREAD_MSG_CMD_SEND_MSG: + { + ptThreadMsg->m_iCmd = THREAD_MSG_CMD_SEND_MSG; + + WEMQJSON *jsonHeader = json_object_new_object (); + + // ptSendMsg->strServiceId[3] == '3' 多播使用ASYNC_MESSAGE_TO_SERVER + if (ptSendMsg->strServiceId[3] == '4') + { + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string + (BROADCAST_MESSAGE_TO_SERVER)); + } + else + { + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string + (ASYNC_MESSAGE_TO_SERVER)); + } + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (++g_iSendReqForEvent)); + LOGRMB (RMB_LOG_DEBUG, "put seq:%ld in pkg", g_iSendReqForEvent); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "get thread msg header failed"); + json_object_put (jsonHeader); + return -1; + } + ptThreadMsg->m_iHeaderLen = strlen (header_str); + + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%d,%s\n", + ptThreadMsg->m_iHeaderLen, header_str); + ptThreadMsg->m_pHeader = + (char *) malloc ((ptThreadMsg->m_iHeaderLen + 1) * sizeof (char)); + if (ptThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for ptThreadMsg->m_pHeader failed"); + json_object_put (jsonHeader); + return -2; + } + memcpy (ptThreadMsg->m_pHeader, header_str, ptThreadMsg->m_iHeaderLen); + ptThreadMsg->m_pHeader[ptThreadMsg->m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + return 0; + } + case THREAD_MSG_CMD_SEND_REQUEST: + { + ptThreadMsg->m_iCmd = THREAD_MSG_CMD_SEND_REQUEST; + + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (REQUEST_TO_SERVER)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (g_iSendReq++)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg header failed"); + json_object_put (jsonHeader); + return -1; + } + ptThreadMsg->m_iHeaderLen = strlen (header_str); + + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%d,%s\n", + ptThreadMsg->m_iHeaderLen, header_str); + ptThreadMsg->m_pHeader = + (char *) malloc ((ptThreadMsg->m_iHeaderLen + 1) * sizeof (char)); + if (ptThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for ptThreadMsg->m_pHeader failed\n"); + json_object_put (jsonHeader); + return -2; + } + memcpy (ptThreadMsg->m_pHeader, header_str, ptThreadMsg->m_iHeaderLen); + ptThreadMsg->m_pHeader[ptThreadMsg->m_iHeaderLen] = '\0'; + json_object_put (jsonHeader); + return 0; + } + case THREAD_MSG_CMD_SEND_REQUEST_ASYNC: + { + ptThreadMsg->m_iCmd = THREAD_MSG_CMD_SEND_REQUEST_ASYNC; + + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (REQUEST_TO_SERVER)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (g_iSendReq++)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg header failed"); + json_object_put (jsonHeader); + return -1; + } + ptThreadMsg->m_iHeaderLen = strlen (header_str); + + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%d,%s\n", + ptThreadMsg->m_iHeaderLen, header_str); + ptThreadMsg->m_pHeader = + (char *) malloc ((ptThreadMsg->m_iHeaderLen + 1) * sizeof (char)); + if (ptThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for ptThreadMsg->m_pHeader failed\n"); + json_object_put (jsonHeader); + return -2; + } + memcpy (ptThreadMsg->m_pHeader, header_str, ptThreadMsg->m_iHeaderLen); + ptThreadMsg->m_pHeader[ptThreadMsg->m_iHeaderLen] = '\0'; + json_object_put (jsonHeader); + return 0; + } + case THREAD_MSG_CMD_SEND_REPLY: + { + ptThreadMsg->m_iCmd = THREAD_MSG_CMD_SEND_REPLY; + + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (RESPONSE_TO_SERVER)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (g_iSendReq++)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg header failed"); + json_object_put (jsonHeader); + return -1; + } + ptThreadMsg->m_iHeaderLen = strlen (header_str); + + //LOGRMB(RMB_LOG_DEBUG, "Get thread msg header succ, len=%d,%s\n", ptThreadMsg->m_iHeaderLen, header_str); + ptThreadMsg->m_pHeader = + (char *) malloc ((ptThreadMsg->m_iHeaderLen + 1) * sizeof (char)); + if (ptThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for ptThreadMsg->m_pHeader failed\n"); + json_object_put (jsonHeader); + return -2; + } + memcpy (ptThreadMsg->m_pHeader, header_str, ptThreadMsg->m_iHeaderLen); + ptThreadMsg->m_pHeader[ptThreadMsg->m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + return 0; + } + case THREAD_MSG_CMD_SEND_MSG_ACK: + { + ptThreadMsg->m_iCmd = THREAD_MSG_CMD_SEND_MSG_ACK; + + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (MSG_ACK)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (g_iSendReq++)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg header failed"); + json_object_put (jsonHeader); + return -1; + } + ptThreadMsg->m_iHeaderLen = strlen (header_str); + + //LOGRMB(RMB_LOG_DEBUG, "Get thread msg header succ, len=%d,%s\n", ptThreadMsg->m_iHeaderLen, header_str); + ptThreadMsg->m_pHeader = + (char *) malloc ((ptThreadMsg->m_iHeaderLen + 1) * sizeof (char)); + if (ptThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for ptThreadMsg->m_pHeader failed\n"); + json_object_put (jsonHeader); + return -2; + } + memcpy (ptThreadMsg->m_pHeader, header_str, ptThreadMsg->m_iHeaderLen); + ptThreadMsg->m_pHeader[ptThreadMsg->m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + return 0; + } + default: + LOGRMB (RMB_LOG_ERROR, "unknown cmd:%u", uiCmd); + return -1; + } + + return 0; +} + +static WEMQJSON *rmb_pub_encode_system_header_for_wemq (unsigned int uiCmd, + StRmbMsg * ptSendMsg) +{ + if (ptSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptSendMsg is null"); + return NULL; + } + + WEMQJSON *jsonSystem = json_object_new_object (); + + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_BIZ_STR, + json_object_new_string (ptSendMsg->sysHeader. + cBizSeqNo)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_SEQNO_STR, + json_object_new_string (ptSendMsg->sysHeader. + cConsumerSeqNo)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_SVRID_STR, + json_object_new_string (ptSendMsg->sysHeader. + cConsumerSvrId)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_ORGSYS_STR, + json_object_new_string (ptSendMsg->sysHeader. + cOrgSysId)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_CSMID_STR, + json_object_new_string (ptSendMsg->sysHeader. + cConsumerSysId)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_TIME_LINT, + json_object_new_int64 (ptSendMsg->sysHeader. + ulTranTimeStamp)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_CSMDCN_STR, + json_object_new_string (ptSendMsg->sysHeader. + cConsumerDcn)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_ORGSVR_STR, + json_object_new_string (ptSendMsg->sysHeader. + cOrgSvrId)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_ORGID_STR, + json_object_new_string (ptSendMsg->sysHeader. + cOrgId)); + //发送消息时,version为consumerSysVersion,且必须为1.0.0 + //json_object_object_add(jsonSystem, MSG_BODY_SYSTEM_VER_STR, json_object_new_string("weq_c_1_0_0")); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_VER_STR, + json_object_new_string (ptSendMsg->sysHeader. + cConsumerSysVersion)); + //add rmb api version + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_API_VERSION, + json_object_new_string (RMBVERSION)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_UNIID_STR, + json_object_new_string (ptSendMsg->sysHeader. + cUniqueId)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_CONLEN_INT, + json_object_new_int (ptSendMsg->sysHeader. + iContentLength)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_MSGTYPE_INT, + json_object_new_int (1)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_RECVTYPE_INT, + json_object_new_int (1)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_SENDTIME_LINT, + json_object_new_int64 (ptSendMsg->sysHeader. + ulSendTime)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_RECVTIME_LINT, + json_object_new_int64 (ptSendMsg->sysHeader. + ulReceiveTime)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_REPLYTIME_LINT, + json_object_new_int64 (ptSendMsg->sysHeader. + ulReplyTime)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_REPLYRECEIVETIME_LINT, + json_object_new_int64 (ptSendMsg->sysHeader. + ulReplyReceiveTime)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_APITYPE_INT, + json_object_new_int (ptSendMsg->cApiType)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_LOGICTYPE_INT, + json_object_new_int ((int32_t) ptSendMsg-> + cLogicType)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_SOCOID_STR, + json_object_new_string ("#C")); + + if (uiCmd == THREAD_MSG_CMD_SEND_REPLY || uiCmd == THREAD_MSG_CMD_RECV_MSG_ACK || uiCmd == THREAD_MSG_CMD_SEND_MSG_ACK) //一般发回包时候、单播回ack,需要rsp_ip + { + WEMQJSON *extFields = + json_tokener_parse (ptSendMsg->sysHeader.cExtFields); + if (extFields == NULL) + { + extFields = json_object_new_object (); + } + json_object_object_add (extFields, MSG_BODY_SYSTEM_RSP_IP, + json_object_new_string (pRmbStConfig->cHostIp)); + json_object_object_add (extFields, MSG_BODY_SYSTEM_RSP_SYS, + json_object_new_string (pRmbStConfig-> + cConsumerSysId)); + json_object_object_add (extFields, MSG_BODY_SYSTEM_RSP_DCN, + json_object_new_string (pRmbStConfig-> + cConsumerDcn)); + json_object_object_add (extFields, MSG_BODY_SYSTEM_RSP_IDC, + json_object_new_string (pRmbStConfig->cRegion)); + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_EXTFIELDS_STR, + extFields); + const char *systemStr = json_object_get_string (jsonSystem); + WEMQJSON *jsonSystemHeader = json_tokener_parse (systemStr); + json_object_put (jsonSystem); + return jsonSystemHeader; + } + else //发包时候 + { + WEMQJSON *extFields = + json_tokener_parse (ptSendMsg->sysHeader.cExtFields); + if (extFields == NULL) + { + extFields = json_object_new_object (); + } + json_object_object_add (extFields, MSG_BODY_SYSTEM_REQ_IP, + json_object_new_string (pRmbStConfig->cHostIp)); + json_object_object_add (extFields, MSG_BODY_SYSTEM_REQ_SYS, + json_object_new_string (pRmbStConfig-> + cConsumerSysId)); + json_object_object_add (extFields, MSG_BODY_SYSTEM_REQ_DCN, + json_object_new_string (pRmbStConfig-> + cConsumerDcn)); + json_object_object_add (extFields, MSG_BODY_SYSTEM_REQ_IDC, + json_object_new_string (pRmbStConfig->cRegion)); + if (strcmp (ptSendMsg->isDyedMsg, "true") == 0) + { + json_object_object_add (extFields, IS_DYED_MSG, + json_object_new_string ("true")); + } + json_object_object_add (jsonSystem, MSG_BODY_SYSTEM_EXTFIELDS_STR, + extFields); + const char *systemStr = json_object_get_string (jsonSystem); + WEMQJSON *jsonSystemHeader = json_tokener_parse (systemStr); + json_object_put (jsonSystem); + return jsonSystemHeader; + } +} + +/** + * set destination proto, like: + * "destination" : { + * "name" : "A00/s/10000000/01/0", + * "type" : "se", + * "serviceOrEventId" : "10000000", + * "scenario" : "01", + * "dcnNo" : "A00", -- not support 000 + * "organizationId" : "99996", + * "organizationIdInputFlag" : 0, + * } + * 其中,type固定为"se",wemq java历史遗留问题 + */ +static WEMQJSON *rmb_pub_encode_body_dest_for_wemq (StRmbMsg * ptSendMsg) +{ + if (ptSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptSendMsg is null"); + return NULL; + } + + WEMQJSON *jsonDest = json_object_new_object (); + if (jsonDest == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object failed"); + return NULL; + } + + json_object_object_add (jsonDest, MSG_BODY_DEST_NAME_STR, + json_object_new_string (ptSendMsg->dest.cDestName)); + json_object_object_add (jsonDest, MSG_BODY_DEST_TYPE_STR, + json_object_new_string ("se")); + json_object_object_add (jsonDest, MSG_BODY_DEST_SORE_STR, + json_object_new_string (ptSendMsg->strServiceId)); + json_object_object_add (jsonDest, MSG_BODY_DEST_SCENARIO_STR, + json_object_new_string (ptSendMsg->strScenarioId)); + json_object_object_add (jsonDest, MSG_BODY_DEST_DCN_STR, + json_object_new_string (ptSendMsg->strTargetDcn)); + json_object_object_add (jsonDest, MSG_BODY_DEST_ANY_DCN_STR, + json_object_new_boolean (0)); + + json_object_object_add (jsonDest, MSG_BODY_DEST_ORGID_STR, + json_object_new_string (ptSendMsg->strTargetOrgId)); + json_object_object_add (jsonDest, MSG_BODY_DEST_ORGFLAG_INT, + json_object_new_int (ptSendMsg->iFLagForOrgId)); + + return jsonDest; +} + +WEMQJSON *rmb_pub_encode_property_for_wemq (unsigned int uiCmd, + StRmbMsg * ptSendMsg) +{ + if (ptSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptSendMsg is null"); + return NULL; + } + + WEMQJSON *jsonProperty = NULL; + + if (uiCmd == THREAD_MSG_CMD_SEND_REPLY + || uiCmd == THREAD_MSG_CMD_RECV_MSG_ACK + || uiCmd == THREAD_MSG_CMD_SEND_MSG_ACK) + { + jsonProperty = json_tokener_parse (ptSendMsg->sysHeader.cProperty); + if (jsonProperty == NULL) + { + jsonProperty = json_object_new_object (); + } + } + else + { + jsonProperty = json_object_new_object (); + json_object_object_add (jsonProperty, MSG_BODY_PROPERTY_REPLYTO_STR, + json_object_new_string (ptSendMsg->replyTo. + cDestName)); + json_object_object_add (jsonProperty, + MSG_BODY_PROPERTY_RR_REQUEST_UNIQ_ID_STR, + json_object_new_string (ptSendMsg->sysHeader. + cUniqueId)); + json_object_object_add (jsonProperty, MSG_BODY_PROPERTY_KEYS_STR, + json_object_new_string (ptSendMsg->sysHeader. + cConsumerSeqNo)); + json_object_object_add (jsonProperty, MSG_BODY_PROPERTY_MSG_TYPE_STR, + json_object_new_string ("persistent")); + json_object_object_add (jsonProperty, MSG_BODY_PROPERTY_TTL_INT, + json_object_new_int64 (ptSendMsg->ulMsgLiveTime)); + json_object_object_add (jsonProperty, MSG_BODY_PROPERTY_SEQ_STR, + json_object_new_string (ptSendMsg->sysHeader. + cBizSeqNo)); + } + return jsonProperty; +} + +WEMQJSON *rmb_pub_encode_byte_body_for_wemq (unsigned int uiCmd, + StRmbMsg * ptSendMsg) +{ + if (ptSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptSendMsg is null"); + return NULL; + } + + WEMQJSON *jsonByteBody = json_object_new_object (); + json_object_object_add (jsonByteBody, + MSG_BODY_BYTE_BODY_APPHEADER_CONTENT_JSON, + json_object_new_string (ptSendMsg->cAppHeader)); + json_object_object_add (jsonByteBody, MSG_BODY_BYTE_BODY_APPHEADER_NAME_STR, + json_object_new_string (ptSendMsg->sysHeader. + cAppHeaderClass)); + json_object_object_add (jsonByteBody, MSG_BODY_BYTE_BODY_CONTENT_STR, + json_object_new_string_len (ptSendMsg->cContent, + ptSendMsg-> + iContentLen)); + json_object_object_add (jsonByteBody, MSG_BODY_BYTE_BODY_CREATETIME_LINT, + json_object_new_int64 (pRmbStConfig->ulNowTtime)); + json_object_object_add (jsonByteBody, MSG_BODY_COID_STR, + json_object_new_string ("#c")); + json_object_object_add (jsonByteBody, MSG_BODY_DELIVERYTIME_INT, + json_object_new_int (1)); + json_object_object_add (jsonByteBody, MSG_BODY_TTL_LINT, + json_object_new_int64 (ptSendMsg->ulMsgLiveTime)); + if (uiCmd == THREAD_MSG_CMD_SEND_REQUEST + || uiCmd == THREAD_MSG_CMD_SEND_REQUEST_ASYNC + || uiCmd == THREAD_MSG_CMD_SEND_REPLY) + { + json_object_object_add (jsonByteBody, MSG_BODY_SYN_BOOL, + json_object_new_boolean (1)); + } + else + { + json_object_object_add (jsonByteBody, MSG_BODY_SYN_BOOL, + json_object_new_boolean (0)); + } + + WEMQJSON *jsonSystemHeaderContent = + rmb_pub_encode_system_header_for_wemq (uiCmd, ptSendMsg); + if (jsonSystemHeaderContent == NULL) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_system_header return null"); + return NULL; + } + const char *systemHeaderContentStr = + json_object_get_string (jsonSystemHeaderContent); + json_object_object_add (jsonByteBody, + MSG_BODY_BYTE_BODY_SYSTEM_HEADER_CONTENT_JSON, + json_object_new_string (systemHeaderContentStr)); + + WEMQJSON *jsonBodyDest = rmb_pub_encode_body_dest_for_wemq (ptSendMsg); + if (jsonBodyDest == NULL) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_body_dest return null"); + return NULL; + } + const char *jsonBodyDestStr = json_object_get_string (jsonBodyDest); + json_object_object_add (jsonByteBody, MSG_BODY_DEST_JSON, + json_object_new_string (jsonBodyDestStr)); + + const char *byteBodyStr = json_object_get_string (jsonByteBody); + if (byteBodyStr == NULL) + { + json_object_put (jsonByteBody); + return NULL; + } + + int sysLen = strlen (byteBodyStr); + //LOGRMB(RMB_LOG_DEBUG, "Gen thread msg json byte body succ, len %d, %s\n", sysLen, byteBodyStr); + json_object_put (jsonSystemHeaderContent); + json_object_put (jsonBodyDest); + return jsonByteBody; +} + +//根据最新协议解析 +int rmb_pub_encode_body_for_wemq (unsigned int uiCmd, + StWemqThreadMsg * ptThreadMsg, + StRmbMsg * ptSendMsg, + unsigned long ulTimeToAlive) +{ + if (ptThreadMsg == NULL || ptSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptThreadMsg or ptSendMsg is null"); + return -1; + } + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + return -1; + } + char cTopic[128]; + char serviceOrEvent = (*(ptSendMsg->strServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + ptSendMsg->strTargetDcn, serviceOrEvent, ptSendMsg->strServiceId, + ptSendMsg->strScenarioId, *(ptSendMsg->strServiceId + 3)); + json_object_object_add (jsonBody, MSG_BODY_TOPIC_STR, + json_object_new_string (cTopic)); + + if (THREAD_MSG_CMD_SEND_REQUEST_ASYNC == uiCmd) + { + snprintf (ptSendMsg->sysHeader.cExtFields, sizeof ("{\"rrType\": 1 }"), + "%s", "{\"rrType\": 1 }"); + } + WEMQJSON *jsonBodyProperty = + rmb_pub_encode_property_for_wemq (uiCmd, ptSendMsg); + if (jsonBodyProperty == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_property_for_wemq return null"); + json_object_put (jsonBody); + return -1; + } + + json_object_object_add (jsonBody, MSG_BODY_PROPERTY_JSON, jsonBodyProperty); + + WEMQJSON *jsonByteBody = + rmb_pub_encode_byte_body_for_wemq (uiCmd, ptSendMsg); + if (jsonByteBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_byte_body_for_wemq return null"); + json_object_put (jsonBody); + return -1; + } + const char *byteBodyStr = json_object_get_string (jsonByteBody); + + json_object_object_add (jsonBody, MSG_BODY_BYTE_BODY_JSON, + json_object_new_string (byteBodyStr)); + //json_object_object_add(jsonBody, MSG_BODY_BYTE_BODY_JSON, jsonByteBody); + + const char *bodyStr = json_object_get_string (jsonBody); + if (bodyStr == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + return -1; + } + ptThreadMsg->m_iBodyLen = strlen (bodyStr); + + //LOGRMB(RMB_LOG_DEBUG, "Get thread msg body succ, len=%d,%s", ptThreadMsg->m_iBodyLen, bodyStr); + ptThreadMsg->m_pBody = + (char *) malloc ((ptThreadMsg->m_iBodyLen + 1) * sizeof (char)); + if (ptThreadMsg->m_pBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for ptThreadMsg->m_pBody failed"); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + return -1; + } +// strncpy(ptThreadMsg->m_pBody, bodyStr, ptThreadMsg->m_iBodyLen); + memcpy (ptThreadMsg->m_pBody, bodyStr, ptThreadMsg->m_iBodyLen); + ptThreadMsg->m_pBody[ptThreadMsg->m_iBodyLen] = '\0'; + json_object_put (jsonBody); + json_object_put (jsonByteBody); + + return 0; +} + +int rmb_pub_encode_thread_msg (unsigned int uiCmd, + StWemqThreadMsg * ptThreadMsg, + StRmbMsg * ptSendMsg, + unsigned long ulTimeToAlive) +{ + int iRet = -1; + + if (ptSendMsg == NULL || ptThreadMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "ptThreadMsg or ptSendMsg is null"); + return -1; + } + + iRet = rmb_pub_encode_header_for_wemq (uiCmd, ptThreadMsg, ptSendMsg); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_header_for_wemq failed"); + return iRet; + } + + iRet = + rmb_pub_encode_body_for_wemq (uiCmd, ptThreadMsg, ptSendMsg, + ulTimeToAlive); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_body_for_wemq failed"); + return iRet; + } + LOGRMB (RMB_LOG_INFO, + "Get thread msg header succ, headerLen=%d,%s Get thread msg body succ, bodyLen=%d,%s\n", + ptThreadMsg->m_iHeaderLen, ptThreadMsg->m_pHeader, + ptThreadMsg->m_iBodyLen, ptThreadMsg->m_pBody); + + return 0; + +} + +char *rmb_printf_service_status (StRmbPub * pStPub, + StServiceStatus * pTmpService) +{ + //if ((int)pTmpService->cResult == 1) + if ((pTmpService->cResult & 0x0F) == 0x01) + { + snprintf (pStPub->printGslBuf, sizeof (pStPub->printGslBuf) - 1, + "service[%s,%s,%s,%d] null,gettime=%lu,InvalidTime=%lu pls check!", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pTmpService->ulGetTimes, pTmpService->ulInvalidTime); + } + //else if ((int)pTmpService->cResult == 2) + else if ((pTmpService->cResult & 0x0F) == 0x02) + { + snprintf (pStPub->printGslBuf, sizeof (pStPub->printGslBuf) - 1, + "service[%s,%s,%s,%d] route error,gettime=%lu,InvalidTime=%lu pls check!", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pTmpService->ulGetTimes, pTmpService->ulInvalidTime); + } + //else if ((int)pTmpService->cResult == 3) + else if ((pTmpService->cResult & 0x0F) == 0x03) + { + snprintf (pStPub->printGslBuf, sizeof (pStPub->printGslBuf) - 1, + "service[%s,%s,%s,%d] gsl_svr error,gettime=%lu,InvalidTime=%lu pls retry!", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pTmpService->ulGetTimes, pTmpService->ulInvalidTime); + } + else if ((int) pTmpService->cResult == 0) + { + if ((int) pTmpService->cRouteFlag == 2) + { + snprintf (pStPub->printGslBuf, sizeof (pStPub->printGslBuf) - 1, + "service[%s,%s,%s,%d] routeFlag=%d,dcn=%s,time=%lu,InvalidTime=%lu", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + (int) pTmpService->cRouteFlag, pTmpService->strTargetDcn, + pTmpService->ulGetTimes, pTmpService->ulInvalidTime); + } + else + { + snprintf (pStPub->printGslBuf, sizeof (pStPub->printGslBuf) - 1, + "service[%s,%s,%s,%d] routeFlag=%d,time=%lu,InvalidTime=%lu", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + (int) pTmpService->cRouteFlag, pTmpService->ulGetTimes, + pTmpService->ulInvalidTime); + } + + } + pStPub->printGslBuf[sizeof (pStPub->printGslBuf) - 1] = 0; + return pStPub->printGslBuf; +} + +/** + * 将字符串中的'/'替换为'-' + */ +static void rmb_change_slash_to_hyphen (char *str, int iLen) +{ + int i = 0; + for (i = 0; i < iLen && str[i] != '\0'; i++) + { + if (str[i] == '/') + { + str[i] = '-'; + } + } +} + +/** + * 用于判断消息发往wemq + */ +static int rmb_pub_send_mode (StRmbPub * pPub, StRmbMsg * pMsg) +{ + if (pPub == NULL || pMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pPub or pMsg is null"); + return -1; + } + + pMsg->iMsgMode = RMB_MSG_WEMQ; + + return 0; +} + +/** + * private func, request gsl for route and dcn + * 参见 + * api cache需求: + * 1. api使用同步的方式更新本地gsl cache,不做全量缓存 + * 2. api请求gsl服务的超时时间默认为1000ms + * 3. cache数据初始的超时时间为600s + * 4. cache数据更新逻辑如下: + * 1) cache中没有本次查询的数据, 则: + * result字段为0,则查询结果存入缓存,失效时间为600s + * result字段低4位为1,则查询结果存入缓存,失效时间为600s,向调用方返错 + * result字段低4位为2,则查询结果不存入缓存,向调用方返错 + * result字段低4位为3或者查询超时,查询结果不存入缓存,向调用方返错 + * 2) api发送消息时发现cache中数据已失效,则去gsl拉取数据: + * result字段为0,更新本地cache,同时将失效时间延后600s,使用最新查询到的数据发送rmb消息 + * result字段低4位为1,则查询结果存入缓存,失效时间为600s,向调用方返错 + * result字段低4位为2,则删除本地缓存数据,向调用方返错 + * result字段低4位为3或者查询超时,如果cache原数据的result字段为0,更新本地数据的失效时间,延后30s + */ +static int rmb_pub_send_gsl (StRmbPub * pStPub, StServiceStatus * pTmpService, + const char *cBizSeqNo, + const char *cConsumerSeqNo) +{ + //get dcn + //char pkgBuf[MAX_GSL_REQ_BUF_SIZE]; + char *p = pStPub->pkgBuf; + int iPkgLen = 0; + //*p = GSL_SUBCMD_QUERY_SERVICE; + *p = GSL_SUBCMD_NEW_QUERY_SERVICE; + p += 1; + iPkgLen += 1; + + int tmp = strlen (pTmpService->strTargetOrgId); + *p = tmp; + p += 1; + iPkgLen += 1; + memcpy (p, pTmpService->strTargetOrgId, tmp); + p += tmp; + iPkgLen += tmp; + + tmp = strlen (pRmbStConfig->cConsumerDcn); + *p = tmp; + p += 1; + iPkgLen += 1; + memcpy (p, pRmbStConfig->cConsumerDcn, tmp); + p += tmp; + iPkgLen += tmp; + + tmp = strlen (pTmpService->strServiceId); + *p = tmp; + p += 1; + iPkgLen += 1; + memcpy (p, pTmpService->strServiceId, tmp); + p += tmp; + iPkgLen += tmp; + + tmp = strlen (pTmpService->strScenarioId); + *p = tmp; + p += 1; + iPkgLen += 1; + memcpy (p, pTmpService->strScenarioId, tmp); + p += tmp; + iPkgLen += tmp; + + *p = pTmpService->cFlagForOrgId; + iPkgLen += 1; + + rmb_msg_set_bizSeqNo (pStPub->pSendMsg, cBizSeqNo); + rmb_msg_set_consumerSeqNo (pStPub->pSendMsg, cConsumerSeqNo); + rmb_msg_set_orgSysId (pStPub->pSendMsg, pRmbStConfig->cConsumerSysId); + rmb_msg_set_dest_v2_1 (pStPub->pSendMsg, GSL_DEFAULT_DCN, + GSL_DEFAULT_SERVICE_ID, GSL_DEFAULT_SCENE_ID, + GSL_DEFAULT_COMMON_ORGID); + + rmb_msg_set_content (pStPub->pSendMsg, pStPub->pkgBuf, iPkgLen); + char appHeader[5] = "{}"; + rmb_msg_set_app_header (pStPub->pSendMsg, appHeader, strlen (appHeader)); + + int iRet = + rmb_pub_send_and_receive (pStPub, pStPub->pSendMsg, pStPub->pRcvMsg, + pRmbStConfig->iQueryTimeout); + if (iRet == 0) + { + char receiveBuf[MAX_GSL_RSP_BUF_SIZE]; + unsigned int receiveLen = sizeof (receiveBuf); + rmb_msg_get_content (pStPub->pRcvMsg, receiveBuf, &receiveLen); + if (receiveLen == 0) + { + LOGRMB (RMB_LOG_ERROR, "GSL reply len=0, req=%s\n", + rmb_msg_print (pStPub->pSendMsg)); + rmb_errno = RMB_ERROR_GSL_SVR_ERROR; + return 3; + } + // result(char) + routeFlag(char) + targetDcn(cStr) + char result = *(receiveBuf + 1); + pTmpService->cResult = result; + + if (result == 0) + { + pTmpService->cRouteFlag = *(receiveBuf + 2); + if (pTmpService->cRouteFlag == 0 || pTmpService->cRouteFlag == 1) + { + LOGRMB (RMB_LOG_INFO, "GSL:[%s-%s-%s-%d] routeFlag=%d\n", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId, + (int) pTmpService->cRouteFlag); + return 0; + } + unsigned int uiDcnLen = *(receiveBuf + 3); + memcpy (pTmpService->strTargetDcn, receiveBuf + 4, uiDcnLen); + pTmpService->strTargetDcn[uiDcnLen] = 0; + + LOGRMB (RMB_LOG_INFO, + "GSL:[%s-%s-%s-%d],get succ!routeFlag=2,targetDcn=%s \n", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pTmpService->strTargetDcn); + return 0; + } + //兼容老的gsl的错误返回码 + else if (result == 1) + { + LOGRMB (RMB_LOG_INFO, + "GSL:[%s-%s-%s-%d] service=NULL,result=1, uniqueID=%s\n", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pStPub->pRcvMsg->sysHeader.cUniqueId); + //pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_NULL; + return 1; + } + else if (result == 2) + { + + LOGRMB (RMB_LOG_INFO, + "GSL:[%s-%s-%s-%d] service error,result=2, uniqueID=%s\n", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pStPub->pRcvMsg->sysHeader.cUniqueId); + //pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_ERROR; + return 2; + } + else if (result == 3) + { + LOGRMB (RMB_LOG_INFO, + "GSL:[%s-%s-%s-%d] gsl svr error,result=3, uniqueID=%s\n", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + pStPub->pRcvMsg->sysHeader.cUniqueId); + //pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + rmb_errno = RMB_ERROR_GSL_SVR_ERROR; + //return 3; + return 4; + } + ////////////////////////////// + else if ((result & 0x0F) == 0x01) + { + int index = (result & 0xF0) >> 4; + LOGRMB (RMB_LOG_INFO, "GSL:[%s-%s-%s-%d] uId=%s, result=0x%02x, %s\n", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId, + pStPub->pRcvMsg->sysHeader.cUniqueId, + gsl_error[index].result, gsl_error[index].err_msg); + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_NULL; + return 1; + } + else if ((result & 0x0F) == 0x02) + { + int index = ((result & 0xF0) >> 4) + 16; + LOGRMB (RMB_LOG_INFO, "GSL:[%s-%s-%s-%d] uId=%s, result=0x%02x, %s\n", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId, + pStPub->pRcvMsg->sysHeader.cUniqueId, + gsl_error[index].result, gsl_error[index].err_msg); + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_ERROR; + return 2; + } + else if ((result & 0x0F) == 0x03) + { + int index = ((result & 0xF0) >> 4) + 32; + LOGRMB (RMB_LOG_INFO, "GSL:[%s-%s-%s-%d] uId=%s, result=0x%02x, %s\n", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId, + pStPub->pRcvMsg->sysHeader.cUniqueId, + gsl_error[index].result, gsl_error[index].err_msg); + rmb_errno = RMB_ERROR_GSL_SVR_ERROR; + return 4; + } + } + else + { + if (rmb_errno == RMB_ERROR_SEND_RR_MSG_TIMEOUT) + { + LOGRMB (RMB_LOG_ERROR, + "GSL:[%s-%s-%s-%d],send and receive from GSL timeout.\n", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId); + pTmpService->cResult = 3; + return 4; + } + + LOGRMB (RMB_LOG_ERROR, + "GSL:[%s-%s-%s-%d],send and recevie from GSL error,iRet=%d!\n", + pTmpService->strServiceId, pTmpService->strScenarioId, + pTmpService->strTargetOrgId, (int) pTmpService->cFlagForOrgId, + iRet); + //pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + pTmpService->cResult = 3; + rmb_errno = RMB_ERROR_REQ_GSL_ERROR; + return 3; + } + return 0; +} + +/** + * 给gsl发染色消息 + */ + +int rmb_pub_send_dyed_msg_to_gsl (StRmbPub * pStPub) +{ + char cBizSeqNo[50] = ""; + char cConsumerSeqNo[50] = ""; + rmb_msg_random_uuid (cBizSeqNo, 32); + rmb_msg_random_uuid (cConsumerSeqNo, 32); + + rmb_msg_set_bizSeqNo (pStPub->pSendMsg, cBizSeqNo); + rmb_msg_set_consumerSeqNo (pStPub->pSendMsg, cConsumerSeqNo); + rmb_msg_set_orgSysId (pStPub->pSendMsg, pRmbStConfig->cConsumerSysId); + rmb_msg_set_dest_v2_1 (pStPub->pSendMsg, GSL_DEFAULT_DCN, + GSL_DEFAULT_SERVICE_ID, GSL_DEFAULT_SCENE_ID, + GSL_DEFAULT_COMMON_ORGID); + + rmb_msg_set_content (pStPub->pSendMsg, "", 0); + char appHeader[5] = "{}"; + rmb_msg_set_app_header (pStPub->pSendMsg, appHeader, strlen (appHeader)); + rmb_msg_set_dyedMsg (pStPub->pSendMsg, "true"); + + int iRet = + rmb_pub_send_and_receive (pStPub, pStPub->pSendMsg, pStPub->pRcvMsg, + pRmbStConfig->iQueryTimeout); + if (iRet == 1) + { + LOGRMB (RMB_LOG_DEBUG, "send dyed msg to GSL success,ret code is %d", + iRet); + } + rmb_msg_clear (pStPub->pSendMsg); + return iRet; +} + +//0:succ +//1:GSL服务id为空 +//2:GSL服务id路由错误 +//3:GSL服务器错误 +//-1:服务错误 + +int rmb_pub_send_gsl_and_insert_cache (StRmbPub * pStPub, StRmbMsg * pStMsg, + StServiceStatus * pTmpService, + StServiceStatus * hasCachedService) +{ + //pthread_mutex_lock(&pStPub->pubMutex); + if (hasCachedService != NULL) + { + //if (hasCachedService->ulGetTimes + pRmbStConfig->iCacheTimeoutTime * 1000 >= pRmbStConfig->ulNowTtime) + if (hasCachedService->ulInvalidTime >= pRmbStConfig->ulNowTtime) + { + //if (hasCachedService->cResult == 1) + if ((hasCachedService->cResult & 0x0F) == 0x01) + { + LOGRMB (RMB_LOG_ERROR, "Cache:[%s-%s-%s-%d] service=NULL", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId); + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_NULL; + return 1; + } +// else if (hasCachedService->cResult == 2) +// { +// LOGRMB(RMB_LOG_ERROR, "Cache:[%s-%s-%s-%d] service error", +// pTmpService->strServiceId, +// pTmpService->strScenarioId, +// pTmpService->strTargetOrgId, +// (int)pTmpService->cFlagForOrgId +// ); +// rmb_errno = RMB_ERROR_GSL_SERVICE_ID_ERROR; +// return 2; +// } + else if (hasCachedService->cResult == 0) + { + if (hasCachedService->cRouteFlag == 0 + || hasCachedService->cRouteFlag == 1) + { + return 0; + } + else + { + //LOGRMB(RMB_LOG_DEBUG, "nowTime=%lu,Cache:[%s]", pRmbStConfig->ulNowTtime, rmb_printf_service_status(pStPub, tmpService)); + if (strcmp (pStMsg->strTargetDcn, hasCachedService->strTargetDcn) != + 0) + { + LOGRMB (RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", + hasCachedService->strTargetDcn, pStMsg->strTargetDcn); + strncpy (pStMsg->strTargetDcn, hasCachedService->strTargetDcn, + sizeof (pStMsg->strTargetDcn) - 1); + //LOGRMB(RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", hasCachedService->strTargetDcn, pStMsg->strTargetDcn); + } + return 0; + } + } + } + } + else + { + hasCachedService = + bsearch (pTmpService, pRmbStConfig->serviceStatusList, + pRmbStConfig->iCacheServiceNums, sizeof (StServiceStatus), + cmpServiceStatusStr); + if (hasCachedService != NULL) + { + //if (hasCachedService->ulGetTimes + pRmbStConfig->iCacheTimeoutTime * 1000 >= pRmbStConfig->ulNowTtime) + if (hasCachedService->ulInvalidTime >= pRmbStConfig->ulNowTtime) + { + //if (hasCachedService->cResult == 1) + if ((hasCachedService->cResult & 0x0F) == 0x01) + { + LOGRMB (RMB_LOG_ERROR, "Cache:[%s-%s-%s-%d] service=NULL", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId); + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_NULL; + return 1; + } +// else if (hasCachedService->cResult == 2) +// { +// LOGRMB(RMB_LOG_ERROR, "Cache:[%s-%s-%s-%d] service error", +// pTmpService->strServiceId, +// pTmpService->strScenarioId, +// pTmpService->strTargetOrgId, +// (int)pTmpService->cFlagForOrgId +// ); +// rmb_errno = RMB_ERROR_GSL_SERVICE_ID_ERROR; +// return 2; +// } + else if (hasCachedService->cResult == 0) + { + if (hasCachedService->cRouteFlag == 0 + || hasCachedService->cRouteFlag == 1) + { + return 0; + } + else + { + //LOGRMB(RMB_LOG_DEBUG, "nowTime=%lu,Cache:[%s]", pRmbStConfig->ulNowTtime, rmb_printf_service_status(pStPub, tmpService)); + if (strcmp (pStMsg->strTargetDcn, hasCachedService->strTargetDcn) + != 0) + { + LOGRMB (RMB_LOG_INFO, + "GSL DCN=%s is diffrent with input DCN=%s", + hasCachedService->strTargetDcn, pStMsg->strTargetDcn); + strncpy (pStMsg->strTargetDcn, hasCachedService->strTargetDcn, + sizeof (pStMsg->strTargetDcn) - 1); + } + return 0; + } + } + } + } + } + int iRet = + rmb_pub_send_gsl (pStPub, pTmpService, pStMsg->sysHeader.cBizSeqNo, + pStMsg->sysHeader.cConsumerSeqNo); + if (iRet == 2 || iRet == 3) + { + pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + if (hasCachedService != NULL) + { + hasCachedService->cResult = pTmpService->cResult; + hasCachedService->cRouteFlag = pTmpService->cRouteFlag; + } + return iRet; + } +// if (iRet == 3) +// { +// pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; +// pTmpService->ulInvalidTime = pRmbStConfig->ulNowTtime + pRmbStConfig->iCacheFailedTimeoutTime * 1000; +// //pthread_mutex_unlock(&pStPub->pubMutex); +// return 3; +// } + + if (iRet == 4) + { + pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + pTmpService->ulInvalidTime = + pRmbStConfig->ulNowTtime + pRmbStConfig->iCacheFailedTimeoutTime * 1000; + if (hasCachedService != NULL) + { + if ((hasCachedService->cResult == 0) + || ((hasCachedService->cResult & 0x0F) == 0x01)) + { + hasCachedService->ulInvalidTime = + pRmbStConfig->ulNowTtime + + pRmbStConfig->iCacheFailedTimeoutTime * 1000; + } + } + return 4; + } + + //cache过期,且在本地存在 + if (hasCachedService != NULL) + { + pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + + hasCachedService->cResult = pTmpService->cResult; + hasCachedService->cRouteFlag = pTmpService->cRouteFlag; + hasCachedService->ulGetTimes = pRmbStConfig->ulNowTtime; + if (hasCachedService->cResult == 0) + { + memcpy (hasCachedService->strTargetDcn, pTmpService->strTargetDcn, + sizeof (hasCachedService->strTargetDcn)); + } + if (iRet == 0 || iRet == 1) + { + hasCachedService->ulInvalidTime = + pRmbStConfig->ulNowTtime + pRmbStConfig->iCacheSuccTimeoutTime * 1000; + } + else + { + hasCachedService->ulInvalidTime = + pRmbStConfig->ulNowTtime + + pRmbStConfig->iCacheFailedTimeoutTime * 1000; + } + } + else + { //本地无cach + //本地无cache,且返回结果为2或3,则不缓存 + if (iRet == 2 || iRet == 3 || iRet == 4) + return iRet; + + pTmpService->ulGetTimes = pRmbStConfig->ulNowTtime; + if (iRet == 0 || iRet == 1) + { + pTmpService->ulInvalidTime = + pRmbStConfig->ulNowTtime + pRmbStConfig->iCacheSuccTimeoutTime * 1000; + } + else + { + pTmpService->ulInvalidTime = + pRmbStConfig->ulNowTtime + + pRmbStConfig->iCacheFailedTimeoutTime * 1000; + } + //select + StServiceStatus *pTmp = NULL; + if (pRmbStConfig->iCacheServiceNums >= MAX_SERVICE_STATUS_CACHE_NUMS) + { + //find the oldest cache + int i = 0; + //unsigned long ulMinTimestamp = 1 << (sizeof(unsigned long)-1); + unsigned long ulMinTimestamp = + pRmbStConfig->serviceStatusList[0].ulGetTimes; + for (; i < MAX_SERVICE_STATUS_CACHE_NUMS; i++) + { + if (ulMinTimestamp > pRmbStConfig->serviceStatusList[i].ulGetTimes) + { + ulMinTimestamp = pRmbStConfig->serviceStatusList[i].ulGetTimes; + pTmp = &pRmbStConfig->serviceStatusList[i]; + } + } + pRmbStConfig->iCacheServiceNums -= 1; + } + else + { + pTmp = + &pRmbStConfig->serviceStatusList[pRmbStConfig->iCacheServiceNums]; + } + memcpy (pTmp, pTmpService, sizeof (StServiceStatus)); + pRmbStConfig->iCacheServiceNums += 1; + //sort + qsort (pRmbStConfig->serviceStatusList, pRmbStConfig->iCacheServiceNums, + sizeof (StServiceStatus), cmpServiceStatusStr); + } + int i = 0; + for (; i < pRmbStConfig->iCacheServiceNums; i++) + { + LOGRMB (RMB_LOG_INFO, "cache%dth:[%s]", i, + rmb_printf_service_status (pStPub, + &pRmbStConfig->serviceStatusList[i])); + } + //pthread_mutex_unlock(&pStPub->pubMutex); + //return pTmpService->cResult; + return iRet; +} + +/** + * before 0.9.15 version + * req: subcmd(char) + targetOrgId(cStr) + selfDcn(cStr) + serverId(cStr) + scenseId(cStr) + flag(char)(0: user 1: api) + * rsp: subcmd(char) + result(char) + routeFlag(char) + targetDcn(cStr) + * + * 0.9.15: + * req: subcmd -- 0x11 + * rsp: result -- 0x11 0x21 ... + * result 0x1x -- cache 600s + * result 0x2x -- clean cache + * return: + * 0:success + * 1:null + * 2:serverId error + * 3:GSL server error + */ +int rmb_pub_get_target_dcn (StRmbPub * pStPub, StRmbMsg * pStMsg) +{ + //search cache + //int iFLagForReqGsl = 1; + StServiceStatus tmpStatus; + tmpStatus.ulInvalidTime = 0; + StServiceStatus *pTmpService = &tmpStatus; + + pTmpService->cFlagForOrgId = pStMsg->iFLagForOrgId; + if (pStMsg->iFLagForOrgId == RMB_COMMIT_BY_OWN) + { + strncpy (pTmpService->strTargetOrgId, pStMsg->strTargetOrgId, + sizeof (pTmpService->strTargetOrgId) - 1); + } + else + { + strncpy (pTmpService->strTargetOrgId, pRmbStConfig->strOrgId, + sizeof (pTmpService->strTargetOrgId) - 1); + } + strncpy (pTmpService->strServiceId, pStMsg->strServiceId, + sizeof (pTmpService->strServiceId) - 1); + strncpy (pTmpService->strScenarioId, pStMsg->strScenarioId, + sizeof (pTmpService->strScenarioId) - 1); + + StServiceStatus *tmpService = + bsearch (pTmpService, pRmbStConfig->serviceStatusList, + pRmbStConfig->iCacheServiceNums, sizeof (StServiceStatus), + cmpServiceStatusStr); + if (tmpService != NULL) + { + //if (tmpService->ulGetTimes + pRmbStConfig->iCacheTimeoutTime * 1000 >= pRmbStConfig->ulNowTtime) + if (tmpService->ulInvalidTime >= pRmbStConfig->ulNowTtime) + { + //if (tmpService->cResult == 1) +// if (tmpService->cResult == 0x11 || tmpService->cResult == 0x21 || tmpService->cResult == 0x31 || +// tmpService->cResult == 0x41 || tmpService->cResult == 0x51 || tmpService->cResult == 0x61) + if ((tmpService->cResult & 0x0F) == 0x01) + { + LOGRMB (RMB_LOG_ERROR, "Cache:[%s-%s-%s-%d] service=NULL", + pTmpService->strServiceId, + pTmpService->strScenarioId, + pTmpService->strTargetOrgId, + (int) pTmpService->cFlagForOrgId); + rmb_errno = RMB_ERROR_GSL_SERVICE_ID_NULL; + return 1; + } +// else if (tmpService->cResult == 2) +// { +// LOGRMB(RMB_LOG_ERROR, "Cache:[%s-%s-%s-%d] service error", +// pTmpService->strServiceId, +// pTmpService->strScenarioId, +// pTmpService->strTargetOrgId, +// (int)pTmpService->cFlagForOrgId +// ); +// rmb_errno = RMB_ERROR_GSL_SERVICE_ID_ERROR; +// return 2; +// } + else if (tmpService->cResult == 0) + { + if (tmpService->cRouteFlag == 0 || tmpService->cRouteFlag == 1) + { + return 0; + } + else + { + //LOGRMB(RMB_LOG_DEBUG, "nowTime=%lu,Cache:[%s]", pRmbStConfig->ulNowTtime, rmb_printf_service_status(pStPub, tmpService)); + if (strcmp (pStMsg->strTargetDcn, tmpService->strTargetDcn) != 0) + { + LOGRMB (RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", + tmpService->strTargetDcn, pStMsg->strTargetDcn); + strncpy (pStMsg->strTargetDcn, tmpService->strTargetDcn, + sizeof (pStMsg->strTargetDcn) - 1); + //LOGRMB(RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", tmpService->strTargetDcn, pStMsg->strTargetDcn); + } + return 0; + } + } + } + else + { + LOGRMB (RMB_LOG_INFO, "cache time out!nowTime=%lu, Cache:[%s] ", + pRmbStConfig->ulNowTtime, rmb_printf_service_status (pStPub, + tmpService)); + } + } + pthread_mutex_lock (&pStPub->pubMutex); + int iRet = + rmb_pub_send_gsl_and_insert_cache (pStPub, pStMsg, pTmpService, + tmpService); + pthread_mutex_unlock (&pStPub->pubMutex); + if (iRet != 0) + { +// if (iRet == 3 && tmpService != NULL) + if (iRet == 4 && tmpService != NULL && tmpService->cResult == 0) + { + //copy dcn to msg + if (tmpService->cRouteFlag == 2) + { + if (strcmp (pStMsg->strTargetDcn, tmpService->strTargetDcn) != 0) + { + LOGRMB (RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", + tmpService->strTargetDcn, pStMsg->strTargetDcn); + strncpy (pStMsg->strTargetDcn, tmpService->strTargetDcn, + sizeof (pStMsg->strTargetDcn) - 1); + //LOGRMB(RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", tmpService->strTargetDcn, pStMsg->strTargetDcn); + } + } + LOGRMB (RMB_LOG_ERROR, "ReqGsl error,but use cache! gsl=[%s],cache=%s", + rmb_printf_service_status (pStPub, pTmpService), + rmb_printf_service_status (pStPub, tmpService)); + return 0; + } + LOGRMB (RMB_LOG_ERROR, "ReqGsl gsl=[%s]", + rmb_printf_service_status (pStPub, pTmpService)); + return iRet; + } + else + { + //copy dcn to msg + // + if (pTmpService->cResult == 0 && pTmpService->cRouteFlag == 2) + { + if (strcmp (pStMsg->strTargetDcn, pTmpService->strTargetDcn) != 0) + { + LOGRMB (RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", + pTmpService->strTargetDcn, pStMsg->strTargetDcn); + strncpy (pStMsg->strTargetDcn, pTmpService->strTargetDcn, + sizeof (pStMsg->strTargetDcn) - 1); + //LOGRMB(RMB_LOG_INFO, "GSL DCN=%s is diffrent with input DCN=%s", pTmpService->strTargetDcn, pStMsg->strTargetDcn); + } + } + LOGRMB (RMB_LOG_INFO, "ReqGsl succ! gsl=[%s]", + rmb_printf_service_status (pStPub, pTmpService)); + } + return 0; +} + +int rmb_pub_set_destination_Interval (StRmbPub * pStPub, StRmbMsg * pStMsg) +{ + //req gsl control + if (pRmbStConfig->iReqGsl == 1) + { + if (!strcmp (pStMsg->strServiceId, GSL_DEFAULT_SERVICE_ID)) + { + strncpy (pStMsg->strTargetDcn, GSL_DEFAULT_DCN, + sizeof (pStMsg->strTargetDcn) - 1); + } + else + { + int iRet = rmb_pub_get_target_dcn (pStPub, pStMsg); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_get_target_dcn error!iRet=%d", iRet); + return iRet; + } + } + } + + if (pStMsg->iEventOrService == RMB_EVENT_CALL) + { + snprintf (pStMsg->dest.cDestName, sizeof (pStMsg->dest.cDestName), + "%s/e/%s/%s/%c", pStMsg->strTargetDcn, pStMsg->strServiceId, + pStMsg->strScenarioId, *(pStMsg->strServiceId + 3)); + } + else + { + snprintf (pStMsg->dest.cDestName, sizeof (pStMsg->dest.cDestName), + "%s/s/%s/%s/%c", pStMsg->strTargetDcn, pStMsg->strServiceId, + pStMsg->strScenarioId, *(pStMsg->strServiceId + 3)); + } + pStMsg->dest.iDestType = RMB_DEST_TOPIC; + + //set pub message to wemq + rmb_pub_send_mode (pStPub, pStMsg); + + return 0; +} + +/** + * Function: rmb_pub_init + * Description: rmb pub initialize + * Return: + * 0: success + * -1: failed + */ +int rmb_pub_init (StRmbPub * pRmbPub) +{ + if (pRmbPub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub arg is null\n"); + rmb_errno = RMB_ERROR_ARGV_NULL; + return -1; + } + + if (pRmbPub->uiContextNum == 1) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub has already init!"); + return 0; + } + pRmbPub->pContext = (StContext *) malloc (sizeof (StContext)); + if (pRmbPub->pContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub->pContext malloc error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + pRmbStConfig->uiPid = (unsigned int) getpid (); + memset (pRmbPub->pContext, 0, sizeof (StContext)); + pRmbPub->pContext->contextType = RMB_CONTEXT_TYPE_PUB; + + int iRet = rmb_context_init (pRmbPub->pContext); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_init failed!iRet=%d,error=%s", iRet, + get_rmb_last_error ()); + rmb_errno = RMB_ERROR_INIT_CONTEXT_FAIL; + return -3; + } + pRmbPub->uiContextNum = 1; + pRmbPub->pContext->pFather = (void *) pRmbPub; + + pRmbPub->ulLastTime = 0; + //rmb_pub_rand(pRmbPub); + + pRmbPub->pSendMsg = rmb_msg_malloc (); + if (pRmbPub->pSendMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_init malloc failed!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + + //pRmbPub->pRcvMsg = (StRmbMsg*)malloc(sizeof(StRmbMsg)); + pRmbPub->pRcvMsg = rmb_msg_malloc (); + if (pRmbPub->pRcvMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_init malloc failed!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + pthread_mutex_init (&pRmbPub->pubMutex, NULL); + rmb_pub_send_dyed_msg_to_gsl (pRmbPub); + + return 0; +} + +/** + * Function: rmb_pub_init_python + * Description: rmb pub initialize + * Return: + * 0: success + * -1: failed + */ +int rmb_pub_init_python () +{ + pRmbGlobalPub = (StRmbPub *) calloc (1, sizeof (StRmbPub)); + if (pRmbGlobalPub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbGlobalPub arg is null\n"); + rmb_errno = RMB_ERROR_ARGV_NULL; + return -1; + } + + rmb_pub_init (pRmbGlobalPub); + + return 0; +} + +int rmb_pub_send_msg_to_wemq (StRmbPub * pRmbPub, StRmbMsg * pMsg) +{ + if (pRmbPub == NULL || pMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub or pMsg is null"); + return -1; + } + + //check dest is set + if (rmb_check_msg_valid (pMsg) != 0) + { + rmb_errno = RMB_ERROR_MSG_MISSING_PART; + return -2; + } + + if (pMsg->iEventOrService == (int) RMB_SERVICE_CALL) + { + LOGRMB (RMB_LOG_ERROR, + "rmb pub event interface can't send rr msg,serviceId=%s!\n", + pMsg->strServiceId); + rmb_errno = RMB_ERROR_EVENT_INTERFACE_CAN_NOT_SEND_RR_MSG; + return -3; + } + + int iRet = 0; + + iRet = rmb_msg_init (pMsg, pRmbStConfig, C_TYPE_WEMQ); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_msg_init failed!iRet=%d\n", iRet); + return -5; + } + + if (pMsg->ulMsgLiveTime == 0 + || pMsg->ulMsgLiveTime > DEFAULT_MSG_MAX_LIVE_TIME) + { + pMsg->ulMsgLiveTime = DEFAULT_MSG_MAX_LIVE_TIME; + } + + pMsg->cLogicType = EVENT_PKG_IN_WEMQ; + GetRmbNowLongTime (); + pMsg->sysHeader.ulSendTime = pRmbStConfig->ulNowTtime; + + StContext *pStContext = pRmbPub->pContext; + pStContext->uiPkgLen = MAX_LENTH_IN_A_MSG; + + if (pMsg->ulMsgLiveTime == 0 + || pMsg->ulMsgLiveTime > DEFAULT_MSG_MAX_LIVE_TIME) + { + pMsg->ulMsgLiveTime = DEFAULT_MSG_MAX_LIVE_TIME; + } + + stContextProxy *pContextProxy = pStContext->pContextProxy; + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_MSG; + iRet = + rmb_pub_encode_thread_msg (stThreadMsg.m_iCmd, &stThreadMsg, pMsg, + pMsg->ulMsgLiveTime); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_thread_msg error!"); + rmb_send_log_for_error (pStContext->pContextProxy, RMB_ERROR_ENCODE_FAIL, + "wemq_pub_encode_thread_msg error", pMsg); + return iRet; + } + + pthread_mutex_lock (&pContextProxy->eventMutex); + iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!,iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_WORKER_PUT_FIFO_ERROR, + "wemq_kfifo_put error", pMsg); + return -5; + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts_timeout; + ts_timeout.tv_sec = + tv.tv_sec + (tv.tv_usec / 1000 + pRmbStConfig->accessAckTimeOut) / 1000; + ts_timeout.tv_nsec = + ((tv.tv_usec / 1000 + + pRmbStConfig->accessAckTimeOut) % 1000) * 1000 * 1000; + + pContextProxy->iFlagForEvent = -1; + if (pContextProxy->iFlagForEvent == -1) + { + //reset seq + pContextProxy->iSeqForEvent = g_iSendReqForEvent; + LOGRMB (RMB_LOG_DEBUG, "reset seq:%ld, pContextProxy->iSeqForEvent:%ld", + g_iSendReqForEvent, pContextProxy->iSeqForEvent); + + pthread_cond_timedwait (&pContextProxy->eventCond, + &pContextProxy->eventMutex, &ts_timeout); + + } + pthread_mutex_unlock (&pContextProxy->eventMutex); + + switch (pContextProxy->iFlagForEvent) + { + case RMB_CODE_TIME_OUT: + LOGRMB (RMB_LOG_ERROR, "time out!req=%s", rmb_msg_print (pMsg)); + rmb_errno = RMB_ERROR_SEND_EVENT_MSG_FAIL; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_SEND_EVENT_MSG_FAIL, + "wemq send event msg ack timeout", pMsg); + return -6; + case RMB_CODE_SUSS: + LOGRMB (RMB_LOG_DEBUG, "send msg succ!req=%s\n", rmb_msg_print (pMsg)); + return 0; + case RMB_CODE_OTHER_FAIL: + LOGRMB (RMB_LOG_ERROR, "send msg failed!req=%s", rmb_msg_print (pMsg)); + return -6; + case RMB_CODE_AUT_FAIL: + LOGRMB (RMB_LOG_ERROR, "Authentication failed!req=%s", + rmb_msg_print (pMsg)); + return -5; + } + +} + +static int rmb_pub_send_and_receive_to_wemq (StRmbPub * pRmbPub, + StRmbMsg * pSendMsg, + StRmbMsg * pRevMsg, + unsigned int uiTimeOut) +{ + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + RMB_CHECK_POINT_NULL (pSendMsg, "pSendMsg"); + RMB_CHECK_POINT_NULL (pRevMsg, "pRevMsg"); + + if (pSendMsg->iEventOrService == (int) RMB_EVENT_CALL) + { + LOGRMB (RMB_LOG_ERROR, "rr interface can't send event msg!"); + rmb_errno = RMB_ERROR_RR_INTERFACE_CAN_NOT_SEND_EVENT_MSG; + return -1; + } + + int iRet = 0; + + iRet = rmb_msg_init (pSendMsg, pRmbStConfig, C_TYPE_WEMQ); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_msg_init failed!iRet=%d", iRet); + return -3; + } + + if (pSendMsg->ulMsgLiveTime == 0 + || pSendMsg->ulMsgLiveTime > DEFAULT_MSG_MAX_LIVE_TIME) + { + pSendMsg->ulMsgLiveTime = uiTimeOut; + } + + pSendMsg->cLogicType = REQ_PKG_IN_WEMQ; + GetRmbNowLongTime (); + pSendMsg->sysHeader.ulSendTime = pRmbStConfig->ulNowTtime; + + StContext *pStContext = pRmbPub->pContext; + pStContext->uiPkgLen = MAX_LENTH_IN_A_MSG; + stContextProxy *pContextProxy = pStContext->pContextProxy; + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_REQUEST; + iRet = + rmb_pub_encode_thread_msg (stThreadMsg.m_iCmd, &stThreadMsg, pSendMsg, + uiTimeOut); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_thread_msg error!"); + rmb_send_log_for_error (pStContext->pContextProxy, RMB_ERROR_ENCODE_FAIL, + "wemq_pub_encode_thread_msg error", pSendMsg); + return -4; + } + + pthread_mutex_lock (&pContextProxy->rrMutex); + iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_WORKER_PUT_FIFO_ERROR, + "wemq_kfifo_put error", pSendMsg); + return -5; + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts_timeout; + ts_timeout.tv_sec = tv.tv_sec + (tv.tv_usec / 1000 + uiTimeOut) / 1000; + ts_timeout.tv_nsec = ((tv.tv_usec / 1000 + uiTimeOut) % 1000) * 1000 * 1000; + + int i = 0; + unsigned int uiUniqueLen = strlen (pSendMsg->sysHeader.cUniqueId); + pContextProxy->iFlagForRR = -1; + + if (pContextProxy->iFlagForRR == -1) + { + //add uniqueId + strncpy (pContextProxy->stUnique.unique_id, pSendMsg->sysHeader.cUniqueId, + uiUniqueLen); + pContextProxy->stUnique.unique_id[uiUniqueLen] = '\0'; + pContextProxy->stUnique.flag = 1; + + } + + pthread_cond_timedwait (&pContextProxy->rrCond, &pContextProxy->rrMutex, + &ts_timeout); + + if (pContextProxy->iFlagForRR == RMB_CODE_TIME_OUT) + { + pContextProxy->stUnique.flag = 0; + + } + pthread_mutex_unlock (&pContextProxy->rrMutex); + + switch (pContextProxy->iFlagForRR) + { + case RMB_CODE_TIME_OUT: + LOGRMB (RMB_LOG_ERROR, "time out!req=%s", rmb_msg_print (pSendMsg)); + rmb_errno = RMB_ERROR_SEND_RR_MSG_TIMEOUT; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_SEND_RR_MSG_TIMEOUT, + "wemq send rr msg timeout", pSendMsg); + return -6; + case RMB_CODE_SUSS: + trans_json_2_rmb_msg (pRevMsg, pContextProxy->mPubRRBuf, + RESPONSE_TO_CLIENT); + LOGRMB (RMB_LOG_DEBUG, "receive reply succ,buf:%s", + pContextProxy->mPubRRBuf); + pRevMsg->cPkgType = RR_TOPIC_PKG; + return 0; + case RMB_CODE_OTHER_FAIL: + LOGRMB (RMB_LOG_ERROR, "receive reply failed!req=%s", + rmb_msg_print (pSendMsg)); + rmb_errno = RMB_ERROR_SEND_RR_MSG_TIMEOUT; + return -4; + case RMB_CODE_AUT_FAIL: + LOGRMB (RMB_LOG_ERROR, "receive reply Authentication failed!req=%s", + rmb_msg_print (pSendMsg)); + rmb_errno = RMB_ERROR_SEND_RR_MSG_TIMEOUT; + return -5; + case RMB_CODE_DYED_MSG: + LOGRMB (RMB_LOG_INFO, "receive dyed msg:%s", pContextProxy->mPubRRBuf); + return 1; + } + +} + +int rmb_pub_send_rr_msg_async_to_wemq (StRmbPub * pRmbPub, + StRmbMsg * pSendMsg, + unsigned int uiTimeOut) +{ + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + RMB_CHECK_POINT_NULL (pSendMsg, "pSendMsg"); + + if (pSendMsg->iEventOrService == (int) RMB_EVENT_CALL) + { + LOGRMB (RMB_LOG_ERROR, "async rr interface can't send event msg!"); + rmb_errno = RMB_ERROR_RR_INTERFACE_CAN_NOT_SEND_EVENT_MSG; + return -1; + } + + //pub connect status error + //if (pRmbPub->pContext->pContextProxy->iFlagForPublish == 0) { + // LOGRMB(RMB_LOG_ERROR, "rmb pub not connect to access!!!"); + // return -4; + //} + + int iRet = 0; +// iRet = rmb_pub_set_destination_Interval(pRmbPub, pSendMsg); +// if (iRet != 0) { +// LOGRMB(RMB_LOG_ERROR, "rmb set destination error!serviceId=%s,sceneId=%s,iRet=%d", pSendMsg->strServiceId, pSendMsg->strScenarioId, iRet); +// return -2; +// } + LOGRMB (RMB_LOG_DEBUG, "pubMsg dest=%d,%s,replyTo=%s", + pSendMsg->dest.iDestType, pSendMsg->dest.cDestName, + pSendMsg->replyTo.cDestName); + + iRet = rmb_msg_init (pSendMsg, pRmbStConfig, C_TYPE_WEMQ); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_msg_init failed!iRet=%d", iRet); + return -3; + } + + if (uiTimeOut > RR_ASYNC_MSG_MAX_LIVE_TIME) + { + LOGRMB (RMB_LOG_ERROR, "RR sync ttl too large, max value is:%ld", + RR_ASYNC_MSG_MAX_LIVE_TIME); + return -4; + } + + if (pSendMsg->ulMsgLiveTime == 0 + || pSendMsg->ulMsgLiveTime > DEFAULT_MSG_MAX_LIVE_TIME) + { + pSendMsg->ulMsgLiveTime = uiTimeOut; + } + + GetRmbNowLongTime (); + pSendMsg->sysHeader.ulSendTime = pRmbStConfig->ulNowTtime; + pSendMsg->replyTo.iDestType = RMB_DEST_TOPIC; + + StContext *pStContext = pRmbPub->pContext; + pStContext->uiPkgLen = MAX_LENTH_IN_A_MSG; + stContextProxy *pContextProxy = pStContext->pContextProxy; + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_REQUEST_ASYNC; + iRet = + rmb_pub_encode_thread_msg (stThreadMsg.m_iCmd, &stThreadMsg, pSendMsg, 0); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_thread_msg error!"); + rmb_send_log_for_error (pStContext->pContextProxy, RMB_ERROR_ENCODE_FAIL, + "wemq_pub_encode_thread_msg error", pSendMsg); + return iRet; + } + unsigned int uiUniqueLen = strlen (pSendMsg->sysHeader.cUniqueId); + int i = 0; + struct timeval tv_now; + gettimeofday (&tv_now, NULL); + unsigned long ulNowTime = tv_now.tv_sec * 1000 + tv_now.tv_usec / 1000; + int iFlagForList = 0; + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncNew. + get_array_size (&pContextProxy->pUniqueListForRRAsyncNew); i++) + { + + if (pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag == 0) + { + pthread_mutex_lock (&pContextProxy->rrMutex); + snprintf (pContextProxy->pUniqueListForRRAsyncNew.Data[i].unique_id, + sizeof (pContextProxy->pUniqueListForRRAsyncNew.Data[i]. + unique_id), "%s", pSendMsg->sysHeader.cUniqueId); + snprintf (pContextProxy->pUniqueListForRRAsyncNew.Data[i].biz_seq, + sizeof (pContextProxy->pUniqueListForRRAsyncNew.Data[i]. + biz_seq), "%s", pSendMsg->sysHeader.cBizSeqNo); + pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag = 1; + pContextProxy->pUniqueListForRRAsyncNew.Data[i].timeStamp = ulNowTime; + pContextProxy->pUniqueListForRRAsyncNew.Data[i].timeout = uiTimeOut; + iFlagForList = 1; + pthread_mutex_unlock (&pContextProxy->rrMutex); + break; + } + } + //已有空间已装满 + if (iFlagForList == 0) + { + LOGRMB (RMB_LOG_INFO, "local list for rr async push back"); + StUniqueIdList uniqueIdList; + strncpy (uniqueIdList.unique_id, pSendMsg->sysHeader.cUniqueId, + uiUniqueLen); + uniqueIdList.unique_id[uiUniqueLen] = '\0'; + uniqueIdList.flag = 1; + uniqueIdList.timeStamp = ulNowTime; + uniqueIdList.timeout = uiTimeOut; + pthread_mutex_lock (&pContextProxy->rrMutex); + pContextProxy->pUniqueListForRRAsyncNew.Input (uniqueIdList, + &pContextProxy-> + pUniqueListForRRAsyncNew); + pthread_mutex_unlock (&pContextProxy->rrMutex); + } + iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_WORKER_PUT_FIFO_ERROR, + "wemq_kfifo_put error", pSendMsg); + return -4; + } + + pContextProxy->iFlagForRRAsync = 1; + return 0; +} + +/** +Function: wemq_pub_reply_msg +Description:send report packet +Retrun: + 0 --success + -1 --failed +*/ +int rmb_pub_reply_msg_for_wemq (StRmbPub * pRmbPub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg) +{ + if (pRmbPub == NULL || pStReceiveMsg == NULL || pStReplyMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub or pStReceiveMsg or pStReplyMsg is null"); + return -1; + } + + if (strlen (pStReceiveMsg->replyTo.cDestName) == 0) + { + LOGRMB (RMB_LOG_ERROR, "receiveMsg has no replyTo,can't reply!\n"); + return -2; + } + + //pub connect status error + //if (pRmbPub->pContext->pContextProxy->iFlagForPublish == 0) { + // LOGRMB(RMB_LOG_ERROR, "rmb pub not connect to access!!!"); + // return -4; + //} + + memcpy (&pStReplyMsg->sysHeader, &pStReceiveMsg->sysHeader, + sizeof (pStReceiveMsg->sysHeader)); + memcpy (&pStReplyMsg->dest, &pStReceiveMsg->replyTo, + sizeof (pStReceiveMsg->replyTo)); + + //serviceId + memcpy (pStReplyMsg->strServiceId, pStReceiveMsg->strServiceId, + sizeof (pStReceiveMsg->strServiceId)); + //scenarioId + memcpy (pStReplyMsg->strScenarioId, pStReceiveMsg->strScenarioId, + sizeof (pStReceiveMsg->strScenarioId)); + //dcn + memcpy (pStReplyMsg->strTargetDcn, pStReceiveMsg->strTargetDcn, + sizeof (pStReceiveMsg->strTargetDcn)); + //organization + memcpy (pStReplyMsg->strTargetOrgId, pStReceiveMsg->strTargetOrgId, + sizeof (pStReceiveMsg->strTargetOrgId)); + //ttl + pStReplyMsg->ulMsgLiveTime = pStReceiveMsg->ulMsgLiveTime; + + strncpy (pStReplyMsg->cCorrId, pStReceiveMsg->cCorrId, + sizeof (pStReceiveMsg->cCorrId)); + pStReplyMsg->iCorrLen = pStReceiveMsg->iCorrLen; + pStReplyMsg->cApiType = C_TYPE_WEMQ; + pStReplyMsg->cLogicType = RSP_PKG_OUT_WEMQ; + + GetRmbNowLongTime (); + pStReplyMsg->sysHeader.ulReplyTime = pRmbStConfig->ulNowTtime; +/* + while (CURRENT_WINDOW_SIZE >= DEFAULT_WINDOW_SIZE) { + LOGRMB(RMB_LOG_ERROR, "Send Window Full, recvSeq=%u,sendSeq=%u", g_uiRecvMsgSeq, g_uiSendMsgSeq); + usleep(1000); + } +*/ + StContext *pStContext = pRmbPub->pContext; + pStContext->uiPkgLen = MAX_LENTH_IN_A_MSG; + stContextProxy *pContextProxy = pStContext->pContextProxy; + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_REPLY; + int iRet = 0; + iRet = + rmb_pub_encode_thread_msg (stThreadMsg.m_iCmd, &stThreadMsg, pStReplyMsg, + 0); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_thread_msg error!"); + rmb_send_log_for_error (pStContext->pContextProxy, RMB_ERROR_ENCODE_FAIL, + "wemq_reply_encode_thread_msg error", + pStReplyMsg); + return iRet; + } + + iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_WORKER_PUT_FIFO_ERROR, + "reply message wemq_kfifo_put error", + pStReplyMsg); + return rmb_errno; + } + + return 0; +} + +/** + * Function: rmb_pub_send_msg + * Description: send event msg + * Return: + * 0: success + * -1: failed + * -2: queue full + */ +int rmb_pub_send_msg (StRmbPub * pRmbPub, StRmbMsg * pStMsg) +{ + + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + RMB_CHECK_POINT_NULL (pStMsg, "pStMsg"); + + if (rmb_check_msg_valid (pStMsg) != 0) + { + rmb_errno = RMB_ERROR_MSG_MISSING_PART; + return rmb_errno; + } + + if (pStMsg->iEventOrService == (int) RMB_SERVICE_CALL) + { + LOGRMB (RMB_LOG_ERROR, "event interface can't send rr msg,serviceId=%s!", + pStMsg->strServiceId); + rmb_errno = RMB_ERROR_EVENT_INTERFACE_CAN_NOT_SEND_RR_MSG; + return rmb_errno; + } + + int iRet = rmb_pub_set_destination_Interval (pRmbPub, pStMsg); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb set destination error!serviceId=%s,sceneId=%s,iRet=%d,error=%s", + pStMsg->strServiceId, pStMsg->strScenarioId, iRet, + get_rmb_last_error ()); + return rmb_errno; + } + + return rmb_pub_send_msg_to_wemq (pRmbPub, pStMsg); + +} + +/** + * Function: rmb_pub_send_msg_python + * Description: send event msg_python + * Return: + * 0: success + * -1: failed + * -2: queue full + */ +int rmb_pub_send_msg_python (StRmbMsg * pStMsg) +{ + StRmbPub *pRmbPub = pRmbGlobalPub; + + return rmb_pub_send_msg (pRmbPub, pStMsg); + +} + +/** +Function: rmb_pub_send_rr_msg +Description:send RR asynchronous message +Retrun: + 0 --success + -1 --failed + -2 --queue full +*/ +int rmb_pub_send_rr_msg_async (StRmbPub * pRmbPub, StRmbMsg * pStMsg, + unsigned int uiTimeOut) +{ + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + RMB_CHECK_POINT_NULL (pStMsg, "pStMsg"); + + if (pStMsg->iEventOrService == (int) RMB_EVENT_CALL) + { + LOGRMB (RMB_LOG_ERROR, "aync RR interface can't send event msg!"); + rmb_errno = RMB_ERROR_RR_INTERFACE_CAN_NOT_SEND_EVENT_MSG; + return rmb_errno; + } + + //set destination + int iRet = rmb_pub_set_destination_Interval (pRmbPub, pStMsg); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb set destination error!serviceId=%s,sceneId=%s,iRet=%d", + pStMsg->strServiceId, pStMsg->strScenarioId, iRet); + return rmb_errno; + } + + return rmb_pub_send_rr_msg_async_to_wemq (pRmbPub, pStMsg, uiTimeOut); + +} + +/** +Function: rmb_pub_send_rr_msg_async_python +Description:send RR asynchronous message +Retrun: + 0 --success + -1 --failed + -2 --queue full +*/ +int rmb_pub_send_rr_msg_async_python (StRmbMsg * pStMsg, + unsigned int uiTimeOut) +{ + StRmbPub *pRmbPub = pRmbGlobalPub; + + return rmb_pub_send_rr_msg_async (pRmbPub, pStMsg, uiTimeOut); +} + +/** +Function: rmb_pub_send_and_receive +Description:send message and wait for report +Retrun: + 0 --success + -1 --timeout + -2 --error +*/ +int rmb_pub_send_and_receive (StRmbPub * pRmbPub, StRmbMsg * pSendMsg, + StRmbMsg * pRevMsg, unsigned int uiTimeOut) +{ + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + RMB_CHECK_POINT_NULL (pSendMsg, "pSendMsg"); + RMB_CHECK_POINT_NULL (pRevMsg, "pRevMsg"); + + if (pSendMsg->iEventOrService == (int) RMB_EVENT_CALL) + { + LOGRMB (RMB_LOG_ERROR, "RR interface can't send event msg!"); + rmb_errno = RMB_ERROR_RR_INTERFACE_CAN_NOT_SEND_EVENT_MSG; + return rmb_errno; + } + + //set destination + int iRet = rmb_pub_set_destination_Interval (pRmbPub, pSendMsg); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "rmb set destination error!serviceId=%s,sceneId=%s,iRet=%d", + pSendMsg->strServiceId, pSendMsg->strScenarioId, iRet); + return rmb_errno; + } + + return rmb_pub_send_and_receive_to_wemq (pRmbPub, pSendMsg, pRevMsg, + uiTimeOut); + +} + +int rmb_pub_send_and_receive_python (StRmbMsg * pSendMsg, StRmbMsg * pRevMsg, + unsigned int uiTimeOut) +{ + StRmbPub *pRmbPub = pRmbGlobalPub; + + return rmb_pub_send_and_receive (pRmbPub, pSendMsg, pRevMsg, uiTimeOut); +} + +/** +Function: rmb_pub_reply_msg +Description:send report packet +Retrun: + 0 --success + -1 --failed +*/ +int rmb_pub_reply_msg (StRmbPub * pRmbPub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg) +{ + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + RMB_CHECK_POINT_NULL (pStReceiveMsg, "pStReceiveMsg"); + RMB_CHECK_POINT_NULL (pStReplyMsg, "pStReplyMsg"); + if (strlen (pStReceiveMsg->replyTo.cDestName) == 0) + { + //LOGRMB(RMB_LOG_INFO, "rmb receivemsg reply destname empty"); + LOGRMB (RMB_LOG_WARN, "pStReceiveMsg->replyTo.cDestName=%s", + pStReceiveMsg->replyTo.cDestName); + return 0; + } + return rmb_pub_reply_msg_for_wemq (pRmbPub, pStReceiveMsg, pStReplyMsg); + +} + +/** +Function: rmb_pub_close +Description:close pub +Retrun: + 0 --success + -1 --failed +*/ +int rmb_pub_close (StRmbPub * pRmbPub) +{ + if (pRmbPub == NULL || pRmbPub->pContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub or pRmbPub->pContext is null"); + return 0; + } + + //wemq + if (pRmbStConfig->iConnWemq == 1 || pRmbStConfig->iApiLogserverSwitch == 1) + { + if (pRmbPub->pContext->pContextProxy != NULL) + { + stContextProxy *pContextProxy = pRmbPub->pContext->pContextProxy; + + //pContextProxy->iFlagForRun = 0; + if (rmb_pub_send_client_goodbye_to_wemq (pRmbPub) != 0) + { + LOGRMB (RMB_LOG_DEBUG, "rmb_pub_send_client_goodbye_to_wemq failed"); + } + pContextProxy->iFlagForRun = 0; + GetRmbNowLongTime (); + pContextProxy->ulGoodByeTime = pRmbStConfig->ulNowTtime; + LOGRMB (RMB_LOG_DEBUG, "pthread_join mainThreadId"); + if (pContextProxy->mainThreadId != 0) + { + pthread_join (pContextProxy->mainThreadId, NULL); + } + + LOGRMB (RMB_LOG_DEBUG, "pthread_join coThreadId"); + if (pContextProxy->coThreadId != 0) + { + pthread_join (pContextProxy->coThreadId, NULL); + } + } + } + return 0; +} + +int rmb_pub_close_python () +{ + StRmbPub *pRmbPub = pRmbGlobalPub; + + int ret = rmb_pub_close_v2 (pRmbPub); + free (pRmbPub); + return ret; +} + +/** +Function: rmb_pub_close_v2 +Description:close pub +Retrun: + 0 --success + -1 --failed +*/ +int rmb_pub_close_v2 (StRmbPub * pRmbPub) +{ + if (pRmbPub == NULL || pRmbPub->pContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbPub or pRmbPub->pContext is null"); + return 0; + } + + //wemq + if (pRmbStConfig->iConnWemq == 1 || pRmbStConfig->iApiLogserverSwitch == 1) + { + if (pRmbPub->pContext->pContextProxy != NULL) + { + stContextProxy *pContextProxy = pRmbPub->pContext->pContextProxy; + + pContextProxy->iFlagForRun = 0; + GetRmbNowLongTime (); + pContextProxy->ulGoodByeTime = pRmbStConfig->ulNowTtime; + LOGRMB (RMB_LOG_DEBUG, "pthread_join mainThreadId"); + if (pContextProxy->mainThreadId != 0) + { + pthread_join (pContextProxy->mainThreadId, NULL); + } + + LOGRMB (RMB_LOG_DEBUG, "pthread_join coThreadId"); + if (pContextProxy->coThreadId != 0) + { + pthread_join (pContextProxy->coThreadId, NULL); + } + } + } + + return 0; +} + +int rmb_pub_send_client_goodbye_to_wemq (StRmbPub * pRmbPub) +{ + RMB_CHECK_POINT_NULL (pRmbPub, "pRmbPub"); + + stContextProxy *pContextProxy = pRmbPub->pContext->pContextProxy; + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_CLIENT_GOODBYE; + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object failed"); + return -2; + } + //add type + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (CLIENT_GOODBYE_REQUEST)); + //add seq + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + //add status + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "header is null"); + json_object_put (jsonHeader); + return -2; + } + + stThreadMsg.m_iHeaderLen = strlen (header_str); + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%u, %s", + stThreadMsg.m_iHeaderLen, header_str) stThreadMsg.m_pHeader = + (char *) malloc ((stThreadMsg.m_iHeaderLen + 1) * sizeof (char)); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for stThreadMsg.m_pHeader failed"); + json_object_put (jsonHeader); + return -2; + } + memcpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + stThreadMsg.m_iBodyLen = 0; + stThreadMsg.m_pBody = NULL; + + int iRet = wemq_kfifo_put (&pContextProxy->pubFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error,iRet=%d!\n", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + return rmb_errno; + } + + struct timeval nowTimeVal; + gettimeofday (&nowTimeVal, NULL); + struct timespec timeout; + timeout.tv_sec = + nowTimeVal.tv_sec + (nowTimeVal.tv_usec / 1000 + + pRmbStConfig->goodByeTimeOut) / 1000; + timeout.tv_nsec = + ((nowTimeVal.tv_usec / 1000 + + pRmbStConfig->goodByeTimeOut) % 1000) * 1000 * 1000; + + pContextProxy->iFlagForGoodBye = 0; + pthread_mutex_lock (&pContextProxy->goodByeMutex); + if (pContextProxy->iFlagForGoodBye == 0) + { + pthread_cond_timedwait (&pContextProxy->goodByeCond, + &pContextProxy->goodByeMutex, &timeout); + } + pthread_mutex_unlock (&pContextProxy->goodByeMutex); + + if (pContextProxy->iFlagForGoodBye != 1) + { + LOGRMB (RMB_LOG_ERROR, "send pub client goodBye timeout!"); + rmb_errno = RMB_ERROR_CLIENT_GOODBYE_TIMEOUT; + return rmb_errno; + } + + LOGRMB (RMB_LOG_DEBUG, "send and recv sub client goodbye succ"); + + return 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_sub.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_sub.c new file mode 100644 index 0000000000..7ca7ea4b73 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_sub.c @@ -0,0 +1,1379 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "rmb_common.h" +#include "rmb_errno.h" +#include "rmb_sub.h" +#include "rmb_udp.h" +#include "rmb_pub.h" +#include "rmb_list.h" +#include "rmb_context.h" +#include "wemq_thread.h" + +#define SRV_GOV_DATA_LVQ "SRV_GOV_DATA_LVQ" +#define SRV_BROADCAST_LVQ "BROADCAST_DATA_LVQ" + +#define atomic_set(x, y) __sync_lock_test_and_set((x), (y)) + +static StRmbPub *pRmbGlobalSub; + +//****************************************private************************************************ + +//根据类型获取mq +StMqInfo *rmb_sub_get_mq_by_type (StRmbSub * stRmbSub, int iType); + +void rmb_get_topic_group (void *args); + +int rmb_sub_add_rr_topic_v2 (StRmbSub * pStRmbSub); +int rmb_sub_add_listen_to_wemq (StRmbSub * pRmbSub, + const st_rmb_queue_info * pQueueInfo, + unsigned int uiQueueSize, const char *cDcn, + const char *cSysId); +int wemq_sub_reply_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg); +int wemq_sub_ack_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg); + +//int wemq_sub_add_listen_topic_bypass(StRmbSub *pStRmbSub, const char *cTopic); +int wemq_sub_add_listen_topic_bypass (StRmbSub * pStRmbSub, + const char **cTopic, + unsigned int uiTopicSize); + +int wemq_sub_add_start_to_access (StRmbSub * pStRmbSub); + +//************************************************************************************************* + +static unsigned long ulGetTopicGroupPthreadId = 0; + +static StRmbTopicInfo rmbTopicInfo[1024]; +static volatile int rmbTopicIndex = -1; + +unsigned long rmb_get_topic_thread_id () +{ + return ulGetTopicGroupPthreadId; +} + +/** + * Function: rmb_sub_init + * Description: rmb sub initialize + * Return: + * 0: success + * other: failed + */ +int rmb_sub_init (StRmbSub * pStRmbSub) +{ + if (pStRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub is null"); + return -1; + } + + if (pStRmbSub->uiContextNum == 1) + { + LOGRMB (RMB_LOG_ERROR, + " sub had inited. uiContextNum is :%u, max context is : %u", + pStRmbSub->uiContextNum, 1); + return 0; + } + + pStRmbSub->pStContext = (StContext *) malloc (sizeof (StContext)); + if (pStRmbSub->pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub->pContext malloc error!"); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -1; + } + pRmbStConfig->uiPid = (unsigned int) getpid (); + memset (pStRmbSub->pStContext, 0, sizeof (StContext)); + + pStRmbSub->pQueueInfo = + (st_rmb_queue_info *) malloc (sizeof (st_rmb_queue_info) * + MAX_LISTEN_TOPIC_NUM); + if (pStRmbSub->pQueueInfo == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub->pQueueInfo malloc error!"); + return -1; + } + memset (pStRmbSub->pQueueInfo, 0x00, + (sizeof (st_rmb_queue_info) * MAX_LISTEN_TOPIC_NUM)); + pStRmbSub->iQueueNum = 0; + + //pStRmbSub->uiFlagForFilter = RMB_FILTER_FLAG_FOR_RR_ASYNC; + + pStRmbSub->pStContext->contextType = RMB_CONTEXT_TYPE_SUB; + + //init context + int iRet = rmb_context_init (pStRmbSub->pStContext); + if (iRet < 0) + { + rmb_errno = RMB_ERROR_INIT_CONTEXT_FAIL; + return -2; + } + + //init notify, from init_context to here, 1.8.0 + iRet = rmb_notify_init (&(pStRmbSub->pStContext->fifoMq)); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "rmb_notify_init error!iRet=%u", iRet); + return -3; + } + + pStRmbSub->pStContext->pFather = (void *) pStRmbSub; + + pStRmbSub->uiContextNum = 1; + + return 0; +} + +/** + * Function: rmb_sub_init_python + * Description: rmb sub initialize + * Return: + * 0: success + * -1: failed + */ +int rmb_sub_init_python () +{ + + pRmbGlobalSub = (StRmbSub *) calloc (1, sizeof (StRmbSub)); + if (pRmbGlobalSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pRmbGlobalSub arg is null\n"); + rmb_errno = RMB_ERROR_ARGV_NULL; + return -1; + } + rmb_sub_init (pRmbGlobalSub); +} + +/** + * Function: rmb_sub_add_reveive_rsp + * Description: init, sub add receive RR async report packages + * Return: + * 0: success + * other: failed + */ +int rmb_sub_add_reveive_rsp (StRmbSub * pStRmbSub, unsigned short usRspPort) +{ + int iRet = 0; + + iRet = + rmb_context_add_rsp_socket (pStRmbSub->pStContext, pRmbStConfig->cHostIp, + usRspPort); + if (iRet != 0) + { + rmb_errno = RMB_ERROR_INIT_UDP_FAIL; + return rmb_errno; + } + return 0; +} + +int rmb_sub_add_reveive_rsp_by_mq (StRmbSub * pStRmbSub, + rmb_callback_func func, void *func_argv) +{ + + int iRet = 0; + iRet = + rmb_context_add_rr_rsp_mq_fifo (pStRmbSub->pStContext, + pRmbStConfig->strFifoPathForRRrsp, + pRmbStConfig->uiShmKeyForRRrsp, + pRmbStConfig->uiShmSizeForRRrsp, func, + func_argv); + if (iRet != 0) + { + return rmb_errno; + } + return 0; +} + +int rmb_sub_add_reveive_rsp_by_mq_v2 (StRmbSub * pStRmbSub, + const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, void *func_argv) +{ + int iRet = 0; + + iRet = + rmb_context_add_rr_rsp_mq_fifo (pStRmbSub->pStContext, strFifoPath, + uiShmKey, uiShmSize, func, func_argv); + if (iRet != 0) + { + return rmb_errno; + } + return 0; +} + +int rmb_sub_add_reveive_rsp_by_mq_python (const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv) +{ + int iRet = 0; + StRmbSub *pStRmbSub = pRmbGlobalSub; + + iRet = + rmb_context_add_rr_rsp_mq_fifo (pStRmbSub->pStContext, strFifoPath, + uiShmKey, uiShmSize, func, func_argv); + if (iRet != 0) + { + return rmb_errno; + } + return 0; +} + +/** + * Function: rmb_sub_add_reveive_req + * Description: init, sub add receive queue request package + * Return: + * 0: success + * other: failed + */ +int rmb_sub_add_reveive_req (StRmbSub * pStRmbSub, unsigned short usReqPort) +{ + + int iRet = + rmb_context_add_req_socket (pStRmbSub->pStContext, pRmbStConfig->cHostIp, + usReqPort); + if (iRet != 0) + { + rmb_errno = RMB_ERROR_INIT_UDP_FAIL; + return rmb_errno; + } + return 0; +} + +int rmb_sub_add_reveive_req_by_mq (StRmbSub * pStRmbSub, + rmb_callback_func func, void *func_argv) +{ + + int iRet = 0; + + iRet = + rmb_context_add_req_mq_fifo (pStRmbSub->pStContext, + pRmbStConfig->strFifoPathForReq, + pRmbStConfig->uiShmKeyForReq, + pRmbStConfig->uiShmSizeForReq, func, + func_argv); + if (iRet != 0) + { + return -1; + } + + return 0; +} + +int rmb_sub_add_reveive_req_by_mq_v2 (StRmbSub * pStRmbSub, + const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, void *func_argv) +{ + + int iRet = 0; + + iRet = + rmb_context_add_req_mq_fifo (pStRmbSub->pStContext, strFifoPath, uiShmKey, + uiShmSize, func, func_argv); + if (iRet != 0) + { + return -1; + } + + return 0; +} + +int rmb_sub_add_reveive_req_by_mq_python (const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv) +{ + + int iRet = 0; + StRmbSub *pStRmbSub = pRmbGlobalSub; + iRet = + rmb_context_add_req_mq_fifo (pStRmbSub->pStContext, strFifoPath, uiShmKey, + uiShmSize, func, func_argv); + if (iRet != 0) + { + return -1; + } + + return 0; +} + +int rmb_sub_add_reveive_broadcast (StRmbSub * pStRmbSub, + unsigned short usRevBroadcastPort) +{ + + int iRet = + rmb_context_add_broadcast_socket (pStRmbSub->pStContext, + pRmbStConfig->cHostIp, + usRevBroadcastPort); + if (iRet != 0) + { + rmb_errno = RMB_ERROR_INIT_UDP_FAIL; + return rmb_errno; + } + return 0; +} + +/** + * Function: rmb_sub_add_reveive_broadcast_by_mq + * Description: init, sub add receive broadcast package + * Return: + * 0: success + * other: failed + */ +int rmb_sub_add_reveive_broadcast_by_mq (StRmbSub * pStRmbSub, + rmb_callback_func func, + void *func_argv) +{ + + int iRet = 0; + + iRet = + rmb_context_add_broadcast_mq_fifo (pStRmbSub->pStContext, + pRmbStConfig->strFifoPathForBroadcast, + pRmbStConfig->uiShmKeyForBroadcast, + pRmbStConfig->uiShmSizeForBroadcast, + func, func_argv); + if (iRet != 0) + { + return -1; + } + + return 0; +} + +int rmb_sub_add_reveive_broadcast_by_mq_v2 (StRmbSub * pStRmbSub, + const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv) +{ + + int iRet = 0; + + iRet = + rmb_context_add_broadcast_mq_fifo (pStRmbSub->pStContext, strFifoPath, + uiShmKey, uiShmSize, func, func_argv); + if (iRet != 0) + { + return -1; + } + + return 0; +} + +int rmb_sub_add_reveive_broadcast_by_mq_python (const char *strFifoPath, + const unsigned int uiShmKey, + const unsigned int uiShmSize, + rmb_callback_func func, + void *func_argv) +{ + + int iRet = 0; + StRmbSub *pStRmbSub = pRmbGlobalSub; + iRet = + rmb_context_add_broadcast_mq_fifo (pStRmbSub->pStContext, strFifoPath, + uiShmKey, uiShmSize, func, func_argv); + if (iRet != 0) + { + return -1; + } + + return 0; +} + +int rmb_sub_add_listen (StRmbSub * pStRmbSub, + const st_rmb_queue_info * pQueueInfo, + unsigned int uiQueueSize) +{ + if (pStRmbSub == NULL || pQueueInfo == NULL || uiQueueSize == 0) + { + LOGRMB (RMB_LOG_ERROR, + "pStRmbSub or pQueueInfo is null or uiQueueSize=%u", uiQueueSize); + return -1; + } + st_rmb_queue_info *p = pQueueInfo; + + pStRmbSub->pQueueInfo = pQueueInfo; + pStRmbSub->iQueueNum = uiQueueSize; + //pStRmbSub->uiFlagForFilter = RMB_FILTER_FLAG_FOR_SUB; + + int i = 0; + int iRet = 0; + iRet = + rmb_sub_add_listen_to_wemq (pStRmbSub, pQueueInfo, uiQueueSize, + pRmbStConfig->cConsumerDcn, + pRmbStConfig->cConsumerSysId); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "sub add listen to wemq failed, dcn=%s", + pRmbStConfig->cConsumerDcn); + return iRet; + } + + return wemq_sub_add_start_to_access (pStRmbSub); +} + +int rmb_sub_add_listen_python (const st_rmb_queue_info * pQueueInfo, + unsigned int uiQueueSize) +{ + StRmbSub *pStRmbSub = pRmbGlobalSub; + + return rmb_sub_add_listen (pStRmbSub, pQueueInfo, uiQueueSize); +} + +/** + * Function: rmb_sub_do_receive + * Description: add epoll + * Return: + * 0: success + * other: failed + */ +int rmb_sub_do_receive (StRmbSub * pStRmbSub, int iTimeout) +{ + int iRet = rmb_notify_epoll (pStRmbSub, iTimeout); + + return iRet; + +} + +int rmb_sub_do_receive_python () +{ + StRmbSub *pStRmbSub = pRmbGlobalSub; + int iRet = rmb_notify_epoll (pStRmbSub, 1); + + return iRet; + +} + +/** + * Function: rmb_sub_reply_msg + * Description: report message + * Return: + * 0: success + * -1: failed + */ +int rmb_sub_reply_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg) +{ + RMB_CHECK_POINT_NULL (pStRmbSub, "pStRmbSub"); + RMB_CHECK_POINT_NULL (pStReceiveMsg, "pStReceiveMsg"); + RMB_CHECK_POINT_NULL (pStReplyMsg, "pStReplyMsg"); + + if (strlen (pStReceiveMsg->replyTo.cDestName) == 0) + { + LOGRMB (RMB_LOG_WARN, "pStReceiveMsg->replyTo.cDestName=%s", + pStReceiveMsg->replyTo.cDestName); + return 0; + } + + return wemq_sub_reply_msg (pStRmbSub, pStReceiveMsg, pStReplyMsg); + +} + +int rmb_sub_reply_msg_python (StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg) +{ + StRmbSub *pStRmbSub = pRmbGlobalSub; + + return rmb_sub_reply_msg (pStRmbSub, pStReceiveMsg, pStReplyMsg); +} + +/** + * Function: rmb_sub_ack_msg + * Description: ack received message + * Return: + * 0: success + * -1: failed + */ +int rmb_sub_ack_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg) +{ + RMB_CHECK_POINT_NULL (pStRmbSub, "pStRmbSub"); + RMB_CHECK_POINT_NULL (pStReceiveMsg, "pStReceiveMsg"); + + return 0; +} + +/** + * Function: rmb_sub_close + * Description:close sub + */ +int rmb_sub_close (StRmbSub * pStRmbSub) +{ + if (pStRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub is null"); + return 0; + } + + //wemq + if (pRmbStConfig->iConnWemq == 1 || pRmbStConfig->iApiLogserverSwitch == 1) + { + if (pStRmbSub->pStContext != NULL + && pStRmbSub->pStContext->pContextProxy != NULL) + { + stContextProxy *pContextProxy = pStRmbSub->pStContext->pContextProxy; + + if (rmb_sub_send_client_goodbye_to_wemq (pStRmbSub) != 0) + { + LOGRMB (RMB_LOG_ERROR, "send sub client goodbye to wemq fail"); + } + pContextProxy->iFlagForRun = 0; + GetRmbNowLongTime (); + pContextProxy->ulGoodByeTime = pRmbStConfig->ulNowTtime; + LOGRMB (RMB_LOG_DEBUG, "pthread_join mainThreadId"); + if (pContextProxy->mainThreadId != 0) + { + pthread_join (pContextProxy->mainThreadId, NULL); + } + + LOGRMB (RMB_LOG_DEBUG, "pthread_join coThreadId"); + if (pContextProxy->coThreadId != 0) + { + pthread_join (pContextProxy->coThreadId, NULL); + } + + rmb_msg_free (pStRmbSub->pStContext->pReceiveWemqMsg); + rmb_msg_free (pStRmbSub->pStContext->pReceiveWemqMsgForRR); + rmb_msg_free (pStRmbSub->pStContext->pReceiveWemqMsgForBroadCast); + free (pStRmbSub->pStContext->pWemqPkg); + free (pStRmbSub->pStContext->pWemqPkgForRRAsync); + + } + } + + LOGRMB (RMB_LOG_DEBUG, "call rmb_sub_close for over"); + + return 0; +} + +int rmb_sub_close_python () +{ + StRmbSub *pStRmbSub = pRmbGlobalSub; + while (rmb_sub_check_req_mq_is_null (pStRmbSub) != 0) //本地的共享内存还有未处理完的消息 + { + rmb_sub_do_receive (pStRmbSub, 1); + } + + int ret = rmb_sub_close_v2 (pStRmbSub); + free (pStRmbSub); + return ret; +} + +/** + * Function: rmb_sub_close_v2 + * Description:close sub + */ +int rmb_sub_close_v2 (StRmbSub * pStRmbSub) +{ + if (pStRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub is null"); + return 0; + } + + //wemq + if (pRmbStConfig->iConnWemq == 1 || pRmbStConfig->iApiLogserverSwitch == 1) + { + if (pStRmbSub->pStContext != NULL + && pStRmbSub->pStContext->pContextProxy != NULL) + { + stContextProxy *pContextProxy = pStRmbSub->pStContext->pContextProxy; + + pContextProxy->iFlagForRun = 0; + GetRmbNowLongTime (); + pContextProxy->ulGoodByeTime = pRmbStConfig->ulNowTtime; + LOGRMB (RMB_LOG_DEBUG, "pthread_join mainThreadId"); + if (pContextProxy->mainThreadId != 0) + { + pthread_join (pContextProxy->mainThreadId, NULL); + } + + LOGRMB (RMB_LOG_DEBUG, "pthread_join coThreadId"); + if (pContextProxy->coThreadId != 0) + { + pthread_join (pContextProxy->coThreadId, NULL); + } + + rmb_msg_free (pStRmbSub->pStContext->pReceiveWemqMsg); + rmb_msg_free (pStRmbSub->pStContext->pReceiveWemqMsgForRR); + rmb_msg_free (pStRmbSub->pStContext->pReceiveWemqMsgForBroadCast); + free (pStRmbSub->pStContext->pWemqPkg); + free (pStRmbSub->pStContext->pWemqPkgForRRAsync); + } + } + + LOGRMB (RMB_LOG_DEBUG, "call rmb_sub_close for over"); + + return 0; +} + +int rmb_sub_send_client_goodbye_to_wemq (StRmbSub * pRmbSub) +{ + RMB_CHECK_POINT_NULL (pRmbSub, "pStRmbSub"); + + stContextProxy *pContextProxy = pRmbSub->pStContext->pContextProxy; + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_CLIENT_GOODBYE; + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object failed"); + return -2; + } + //add command + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (CLIENT_GOODBYE_REQUEST)); + //add seq + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + //add code + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "header is null"); + json_object_put (jsonHeader); + return -2; + } + + stThreadMsg.m_iHeaderLen = strlen (header_str); + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%u, %s", + stThreadMsg.m_iHeaderLen, header_str) stThreadMsg.m_pHeader = + (char *) malloc ((stThreadMsg.m_iHeaderLen + 1) * sizeof (char)); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for stThreadMsg.m_pHeader failed"); + json_object_put (jsonHeader); + return -2; + } + memcpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + stThreadMsg.m_iBodyLen = 0; + stThreadMsg.m_pBody = NULL; + pthread_mutex_lock (&pContextProxy->goodByeMutex); + int iRet = wemq_kfifo_put (&pContextProxy->subFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error,iRet=%d!\n", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + return rmb_errno; + } + + struct timeval nowTimeVal; + gettimeofday (&nowTimeVal, NULL); + struct timespec timeout; + timeout.tv_sec = + nowTimeVal.tv_sec + (nowTimeVal.tv_usec / 1000 + + pRmbStConfig->goodByeTimeOut) / 1000; + timeout.tv_nsec = + ((nowTimeVal.tv_usec / 1000 + + pRmbStConfig->goodByeTimeOut) % 1000) * 1000 * 1000; + + pContextProxy->iFlagForGoodBye = 0; + + if (pContextProxy->iFlagForGoodBye == 0) + { + pthread_cond_timedwait (&pContextProxy->goodByeCond, + &pContextProxy->goodByeMutex, &timeout); + } + pthread_mutex_unlock (&pContextProxy->goodByeMutex); + + if (pContextProxy->iFlagForGoodBye != 1) + { + LOGRMB (RMB_LOG_ERROR, "send sub client goodBye timeout!"); + rmb_errno = RMB_ERROR_CLIENT_GOODBYE_TIMEOUT; + return rmb_errno; + } + + LOGRMB (RMB_LOG_DEBUG, "send and recv sub client goodBye succ"); + + return 0; +} + +/* +Function: rmb_sub_stop_receive +Description:rmb_sub停止接受queue消息 +* Return: +* 见rmb_errno.h文件 +*/ +int rmb_sub_stop_receive (StRmbSub * pStRmbSub) +{ + int iRet = 0; + if (pRmbStConfig->iConnWemq == 1 || pRmbStConfig->iApiLogserverSwitch == 1) + { + if (pStRmbSub->pStContext != NULL + && pStRmbSub->pStContext->pContextProxy != NULL) + { + stContextProxy *pContextProxy = pStRmbSub->pStContext->pContextProxy; + if (rmb_sub_send_client_goodbye_to_wemq (pStRmbSub) == 0) + { + //pContextProxy->iFlagForRun = 0; + return 0; + } + else + { + LOGRMB (RMB_LOG_ERROR, "send client goodbye to wemq fail"); + //pContextProxy->iFlagForRun = 0; + return -1; + } + } + else + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub->pStContext null"); + return -2; + } + } + return 0; +} + +/* +Function: rmb_sub_stop_receive_python +Description:rmb_sub停止接受queue消息 +* Return: +* 见rmb_errno.h文件 +*/ +int rmb_sub_stop_receive_python () +{ + StRmbSub *pStRmbSub = pRmbGlobalSub; + + return rmb_sub_stop_receive (pStRmbSub); +} + +//add 2015-02-10 +StMqInfo *rmb_sub_get_mq_by_type (StRmbSub * stRmbSub, int iType) +{ + return stRmbSub->pStContext->fifoMq.mqIndex[iType]; +} + +StMqInfo *rmb_sub_get_receve_req_mq (StRmbSub * stRmbSub) +{ + if (stRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "stRmb==NULL"); + return NULL; + } + return rmb_sub_get_mq_by_type (stRmbSub, (int) req_mq_index); +} + +StMqInfo *rmb_sub_get_rr_rsp_mq (StRmbSub * stRmbSub) +{ + if (stRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "stRmb==NULL"); + return NULL; + } + return rmb_sub_get_mq_by_type (stRmbSub, (int) rr_rsp_mq_index); +} + +StMqInfo *rmb_sub_get_broadcast_mq (StRmbSub * stRmbSub) +{ + if (stRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "stRmb==NULL"); + return NULL; + } + return rmb_sub_get_mq_by_type (stRmbSub, (int) broadcast_mq_index); +} + +StMqInfo *rmb_sub_get_receve_rsp_mq (StRmbSub * stRmbSub) +{ + if (stRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "stRmb==NULL"); + return NULL; + } + return rmb_sub_get_mq_by_type (stRmbSub, (int) rr_rsp_mq_index); +} + +StMqInfo *rmb_sub_get_receve_broadcast_mq (StRmbSub * stRmbSub) +{ + if (stRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "stRmb==NULL"); + return NULL; + } + return rmb_sub_get_mq_by_type (stRmbSub, (int) broadcast_mq_index); +} + +int rmb_sub_get_fd (StMqInfo * pMqInfo) +{ + RMB_CHECK_POINT_NULL (pMqInfo, "pMqInfo"); + + return pMqInfo->fifo->iFd; +} + +int rmb_sub_receive_from_mq (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen) +{ + RMB_CHECK_POINT_NULL (pMqInfo, "pMqInfo"); + + return rmb_notify_dequeue (pMqInfo, buf, uiBufSize, pDataLen); +} + +int rmb_sub_try_receive_from_mq (StMqInfo * pMqInfo, char *buf, + const unsigned int uiBufSize, + unsigned int *pDataLen) +{ + RMB_CHECK_POINT_NULL (pMqInfo, "pMqInfo"); + + return rmb_notify_try_dequeue (pMqInfo, buf, uiBufSize, pDataLen); +} + +/* +Function: rmb_sub_check_mq_is_null +Description:校验所有队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int rmb_sub_check_mq_is_null (StRmbSub * pStRmbSub) +{ + if (pStRmbSub == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub==NULL"); + return NULL; + } + int result = rmb_sub_check_req_mq_is_null (pStRmbSub) + && rmb_sub_check_rr_rsp_mq_is_null (pStRmbSub) + && rmb_sub_check_broadcast_mq_is_null (pStRmbSub); + return result; +} + +/* +Function: rmb_sub_check_req_mq_is_null +Description:校验是否请求队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int rmb_sub_check_req_mq_is_null (StRmbSub * pStRmbSub) +{ + StMqInfo *p = rmb_sub_get_receve_req_mq (pStRmbSub); + if (p == NULL) + { + return 0; + } + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + usleep (1000); + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + return 0; +} + +/* +Function: rmb_sub_check_rr_rsp_mq_is_null +Description:校验rr_rsp队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int rmb_sub_check_rr_rsp_mq_is_null (StRmbSub * pStRmbSub) +{ + StMqInfo *p = rmb_sub_get_rr_rsp_mq (pStRmbSub); + if (p == NULL) + { + return 0; + } + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + usleep (1000); + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + return 0; +} + +/* +Function: rmb_sub_check_broadcast_mq_is_null +Description:校验broadcast队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int rmb_sub_check_broadcast_mq_is_null (StRmbSub * pStRmbSub) +{ + StMqInfo *p = rmb_sub_get_broadcast_mq (pStRmbSub); + if (p == NULL) + { + return 0; + } + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + usleep (1000); + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * Description: add bind to wemq + * Return: + * 0: success + * -1: arg error + * -2: error + * json: + * send: + * headerJson={"code":0,"seq":"1333580037","command":"SUBSCRIBE_REQUEST"} + * |bodyJson={"topicList":["PRX-e-10030002-05-3","PRX-e-10020002-02-2","PRX-s-10000002-01-0","PRX-e-10020002-06-2"]} + * 例如: + * success: -- code为0 + * headerJson={"code":0,"seq":"1333580037","command":"SUBSCRIBE_RESPONSE", "message":"ok"}|bodyJson=null + * failed: -- code非0 + headerJson={"code":0,"seq":"1333580037","command":"SUBSCRIBE_RESPONSE", "message":"no topic route"}|bodyJson=null + * + */ +int rmb_sub_add_listen_to_wemq (StRmbSub * pRmbSub, + const st_rmb_queue_info * pQueueInfo, + unsigned int uiQueueSize, const char *cDcn, + const char *cSysId) +{ + RMB_CHECK_POINT_NULL (pRmbSub, "pStRmbSub"); + RMB_CHECK_POINT_NULL (pRmbSub->pStContext, "pStRmbSub->pStContext"); + RMB_CHECK_POINT_NULL (pRmbSub->pStContext->pContextProxy, + "pStRmbSub->pStContext->pContextProxy"); + RMB_CHECK_POINT_NULL (cDcn, "cDcn"); + RMB_CHECK_POINT_NULL (cSysId, "cSysId"); + + stContextProxy *pContextProxy = pRmbSub->pStContext->pContextProxy; + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_ADD_LISTEN; + WEMQJSON *jsonTopicList = json_object_new_array (); + st_rmb_queue_info *p = pQueueInfo; + int i; + char cBroadcastDcn[10] = "000"; + for (i = 0; i < uiQueueSize; i++) + { + char cTopic[200] = { 0 }; + char serviceOrEvent = (*(p->cServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", cDcn, serviceOrEvent, + p->cServiceId, p->cScenarioId, *(p->cServiceId + 3)); + json_object_array_add (jsonTopicList, json_object_new_string (cTopic)); + //自动监听广播topic + if (serviceOrEvent == 'e') + { + memset (cTopic, 0x00, sizeof (cTopic)); + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", cBroadcastDcn, + serviceOrEvent, p->cServiceId, p->cScenarioId, + *(p->cServiceId + 3)); + json_object_array_add (jsonTopicList, json_object_new_string (cTopic)); + } + p += 1; + } + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object for jsonHeader failed"); + return -1; + } + + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (SUBSCRIBE_REQUEST)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object for jsonBody failed"); + json_object_put (jsonHeader); + json_object_put (jsonTopicList); + return -1; + } + + json_object_object_add (jsonBody, MSG_BODY_TOPIC_LIST_JSON, jsonTopicList); + + const char *header_str = json_object_get_string (jsonHeader); + + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_get_string for header is null"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -2; + } + stThreadMsg.m_iHeaderLen = strlen (header_str); + + LOGRMB (RMB_LOG_INFO, "Gen thread msg header succ, len=%d, %s", + stThreadMsg.m_iHeaderLen, header_str); + stThreadMsg.m_pHeader = + (char *) malloc (stThreadMsg.m_iHeaderLen * sizeof (char) + 1); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for m_pHeader failed, errno=%d", errno); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + strncpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + json_object_put (jsonBody); + return -1; + } + + stThreadMsg.m_iBodyLen = strlen (body_str); + stThreadMsg.m_pBody = + (char *) malloc (stThreadMsg.m_iBodyLen * sizeof (char) + 1); + if (stThreadMsg.m_pBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for hello body failed"); + json_object_put (jsonBody); + return -1; + } + memcpy (stThreadMsg.m_pBody, body_str, stThreadMsg.m_iBodyLen); + stThreadMsg.m_pBody[stThreadMsg.m_iBodyLen] = '\0'; + + json_object_put (jsonBody); + pthread_mutex_lock (&pContextProxy->regMutex); + int iRet = wemq_kfifo_put (&pContextProxy->subFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error,iRet=%d!\n", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + return -3; + } + + struct timeval nowTimeVal; + gettimeofday (&nowTimeVal, NULL); + struct timespec timeout; + timeout.tv_sec = + nowTimeVal.tv_sec + (nowTimeVal.tv_usec / 1000 + + pRmbStConfig->iNormalTimeout) / 1000; + timeout.tv_nsec = + ((nowTimeVal.tv_usec / 1000 + + pRmbStConfig->iNormalTimeout) % 1000) * 1000 * 1000; + + pContextProxy->iFlagForReg = 0; + pContextProxy->iResultForReg = -1; + if (pContextProxy->iFlagForReg == 0) + { + pthread_cond_timedwait (&pContextProxy->regCond, &pContextProxy->regMutex, + &timeout); + } + pthread_mutex_unlock (&pContextProxy->regMutex); + + if (pContextProxy->iFlagForReg == 1 && pContextProxy->iResultForReg != 0) + { + LOGRMB (RMB_LOG_ERROR, "add listen failed,iRet=%d,dcn=%s", + pContextProxy->iResultForReg, cDcn); + rmb_errno = RMB_ERROR_WORKER_REGISTER_ERROR; + return rmb_errno; + } + + if (pContextProxy->iFlagForReg != 1) + { + LOGRMB (RMB_LOG_ERROR, "add listen timeout!dcn=%s", cDcn); + rmb_errno = RMB_ERROR_WORKER_REGISTER_ERROR; + return rmb_errno; + } + + LOGRMB (RMB_LOG_DEBUG, "add listen succ!dcn=%s", cDcn); + //cache sub topic; + p = pQueueInfo; + for (i = 0; i < uiQueueSize; i++) + { + StWemqTopicProp stTopicProp; + memset (&stTopicProp, 0, sizeof (stTopicProp)); + stTopicProp.flag = 0; + strncpy (stTopicProp.cServiceId, p->cServiceId, strlen (p->cServiceId)); + stTopicProp.cServiceId[8] = '\0'; + strncpy (stTopicProp.cScenario, p->cScenarioId, strlen (p->cScenarioId)); + stTopicProp.cScenario[2] = '\0'; + wemq_topic_list_add_node (&pContextProxy->stTopicList, &stTopicProp); + p += 1; + } + + return 0; +} + +int wemq_sub_add_start_to_access (StRmbSub * pStRmbSub) +{ + if (pStRmbSub == NULL || pStRmbSub->pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub or pStRmbSub->pStContext is null"); + return -1; + } + + stContextProxy *pContextProxy = pStRmbSub->pStContext->pContextProxy; + if (pContextProxy == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmbSub->pStContext->pContextProxy is null"); + return -1; + } + + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_START; + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object failed"); + return -2; + } + //add command + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (LISTEN_REQUEST)); + //add seq + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + //add code + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "header is null"); + json_object_put (jsonHeader); + return -2; + } + + stThreadMsg.m_iHeaderLen = strlen (header_str); + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%u, %s", + stThreadMsg.m_iHeaderLen, header_str); + stThreadMsg.m_pHeader = + (char *) malloc ((stThreadMsg.m_iHeaderLen + 1) * sizeof (char)); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for stThreadMsg.m_pHeader failed"); + json_object_put (jsonHeader); + return -2; + } + memcpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + stThreadMsg.m_iBodyLen = 0; + stThreadMsg.m_pBody = NULL; + + int iRet = 0; + struct timeval nowTimeVal; + struct timespec timeout; + pthread_mutex_lock (&pContextProxy->regMutex); + iRet = wemq_kfifo_put (&pContextProxy->subFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put for listen comman error"); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + return -3; + } + + gettimeofday (&nowTimeVal, NULL); + timeout.tv_sec = + nowTimeVal.tv_sec + (nowTimeVal.tv_usec / 1000 + + pRmbStConfig->iNormalTimeout) / 1000; + timeout.tv_nsec = + ((nowTimeVal.tv_usec / 1000 + + pRmbStConfig->iNormalTimeout) % 1000) * 1000 * 1000; + + pContextProxy->iResultForReg = -1; + pContextProxy->iFlagForReg = 0; + if (pContextProxy->iFlagForReg == 0) + { + pthread_cond_timedwait (&pContextProxy->regCond, &pContextProxy->regMutex, + &timeout); + } + pthread_mutex_unlock (&pContextProxy->regMutex); + + switch (pContextProxy->iResultForReg) + { + case RMB_CODE_TIME_OUT: + LOGRMB (RMB_LOG_ERROR, "send start command timeout"); + return -6; + case RMB_CODE_SUSS: + LOGRMB (RMB_LOG_INFO, "send start command to access succ"); + return 0; + case RMB_CODE_OTHER_FAIL: + LOGRMB (RMB_LOG_ERROR, "send start command failed,iRet=%d", + pContextProxy->iResultForReg); + return -4; + case RMB_CODE_AUT_FAIL: + LOGRMB (RMB_LOG_ERROR, "send start command authentication failed,iRet=%d", + pContextProxy->iResultForReg); + return -5; + default: + return 0; + } + +} + +int wemq_sub_reply_msg (StRmbSub * pStRmbSub, StRmbMsg * pStReceiveMsg, + StRmbMsg * pStReplyMsg) +{ + if (pStRmbSub == NULL || pStReceiveMsg == NULL || pStReplyMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmb or pStReceiveMsg or pStReplyMsg is null"); + return -1; + } + + memcpy (&pStReplyMsg->sysHeader, &pStReceiveMsg->sysHeader, + sizeof (pStReceiveMsg->sysHeader)); + memcpy (&pStReplyMsg->dest, &pStReceiveMsg->replyTo, + sizeof (pStReceiveMsg->replyTo)); + if (strlen (pStReplyMsg->dest.cDestName) == 0) + { + LOGRMB (RMB_LOG_ERROR, "receiveMsg has no replyTo, can't reply!"); + return -2; + } + LOGRMB (RMB_LOG_DEBUG, "receive msg property: %s", + pStReceiveMsg->sysHeader.cProperty); + memcpy (&pStReplyMsg->sysHeader.cProperty, + &pStReceiveMsg->sysHeader.cProperty, + sizeof (pStReceiveMsg->sysHeader.cProperty)); + + //serviceId + memcpy (pStReplyMsg->strServiceId, pStReceiveMsg->strServiceId, + sizeof (pStReceiveMsg->strServiceId)); + //scenarioId + memcpy (pStReplyMsg->strScenarioId, pStReceiveMsg->strScenarioId, + sizeof (pStReceiveMsg->strScenarioId)); + //dcn + memcpy (pStReplyMsg->strTargetDcn, pStReceiveMsg->strTargetDcn, + sizeof (pStReceiveMsg->strTargetDcn)); + //organization + memcpy (pStReplyMsg->strTargetOrgId, pStReceiveMsg->strTargetOrgId, + sizeof (pStReceiveMsg->strTargetOrgId)); + //ttl + pStReplyMsg->ulMsgLiveTime = pStReceiveMsg->ulMsgLiveTime; + + strncpy (pStReplyMsg->cCorrId, pStReceiveMsg->cCorrId, + sizeof (pStReceiveMsg->cCorrId)); + pStReplyMsg->iCorrLen = pStReceiveMsg->iCorrLen; + pStReplyMsg->cApiType = C_TYPE_WEMQ; + pStReplyMsg->cLogicType = RSP_PKG_OUT_WEMQ; + GetRmbNowLongTime (); + pStReplyMsg->sysHeader.ulReplyTime = pRmbStConfig->ulNowTtime; + + StContext *pStContext = pStRmbSub->pStContext; + pStContext->uiPkgLen = MAX_LENTH_IN_A_MSG; + stContextProxy *pContextProxy = pStContext->pContextProxy; + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_REPLY; + int iRet = + rmb_pub_encode_thread_msg (stThreadMsg.m_iCmd, &stThreadMsg, pStReplyMsg, + 3000); + //LOGRMB(RMB_LOG_DEBUG, "encode succ header %s, body %s\n",stThreadMsg.m_pHeader, stThreadMsg.m_pBody); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_thread_msg error!\n"); + return iRet; + } + + iRet = wemq_kfifo_put (&pContextProxy->subFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_WORKER_PUT_FIFO_ERROR, + "sub reply wemq_kfifo_put error", pStReplyMsg); + return rmb_errno; + } + + return 0; +} + +int wemq_sub_ack_msg (StRmbSub * pStRmbSub, StRmbMsg * pStAckMsg) +{ + if (pStRmbSub == NULL || pStAckMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStRmb or pStReplyMsg is null"); + return -1; + } + + if (pStAckMsg->cPkgType == RR_TOPIC_PKG) + { + return 0; + } + + LOGRMB (RMB_LOG_DEBUG, "receive msg property: %s", + pStAckMsg->sysHeader.cProperty); + + StContext *pStContext = pStRmbSub->pStContext; + pStContext->uiPkgLen = MAX_LENTH_IN_A_MSG; + stContextProxy *pContextProxy = pStContext->pContextProxy; + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_SEND_MSG_ACK; + int iRet = + rmb_pub_encode_thread_msg (stThreadMsg.m_iCmd, &stThreadMsg, pStAckMsg, + 3000); + //LOGRMB(RMB_LOG_DEBUG, "encode succ header %s, body %s\n",stThreadMsg.m_pHeader, stThreadMsg.m_pBody); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_pub_encode_thread_msg error!\n"); + return iRet; + } + + iRet = wemq_kfifo_put (&pContextProxy->subFifo, stThreadMsg); + if (iRet <= 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_kfifo_put error!iRet=%d", iRet); + rmb_errno = RMB_ERROR_WORKER_PUT_FIFO_ERROR; + rmb_send_log_for_error (pStContext->pContextProxy, + RMB_ERROR_WORKER_PUT_FIFO_ERROR, + "sub ack wemq_kfifo_put error", pStAckMsg); + return rmb_errno; + } + + return 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_udp.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_udp.c new file mode 100644 index 0000000000..76fd187ed1 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_udp.c @@ -0,0 +1,383 @@ +// 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. + +#include "rmb_udp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int udp_get_socket (const char *host, const char *serv, socklen_t * addrlenp) +{ + int iUDPSocket; + int iRet; + + struct addrinfo hints; + struct addrinfo *res, *ressave; + + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if ((iRet = getaddrinfo (host, serv, &hints, &res)) != 0) + { + return -1; + } + ressave = res; + + do + { + iUDPSocket = socket (res->ai_family, res->ai_socktype, res->ai_protocol); + if (iUDPSocket < 0) + continue; /* error, try next one */ + + if (bind (iUDPSocket, res->ai_addr, res->ai_addrlen) == 0) + break; /* success */ + + close (iUDPSocket); /* bind error, close and try next one */ + } + while ((res = res->ai_next) != NULL); + + if (res == NULL) /* errno from final socket() or bind() */ + return -1; + //err_sys("udp_server error for %s, %s", host, serv); + + if (addrlenp) + *addrlenp = res->ai_addrlen; /* return size of protocol address */ + + freeaddrinfo (ressave); + + if (iUDPSocket < 0) + { + return -1; + //err_sys("UDP_GetSocket error : %s", strerror(errno)); + } + return iUDPSocket; +} + +int udp_server (const char *pszHost, unsigned short usPort) +{ + int udpsock; + struct hostent *hostinfo; + struct in_addr *addp; + struct sockaddr_in sockname; + + memset ((char *) &sockname, 0, sizeof (sockname)); + if (pszHost == NULL) + { + hostinfo = NULL; + } + else if ((hostinfo = gethostbyname (pszHost)) == NULL) + { + //err_msg("Cannot find %s - %s",pszHost,strerror(errno)); + return -1; + } + + udpsock = socket (AF_INET, SOCK_DGRAM, 0); + if (udpsock < 0) + { + //err_msg("Error opening socket - %s",strerror(errno)); + return -1; + } + //setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (hostinfo != NULL) + { + addp = (struct in_addr *) *(hostinfo->h_addr_list); + sockname.sin_addr = *addp; + } + else + { + sockname.sin_addr.s_addr = INADDR_ANY; + } + sockname.sin_family = AF_INET; + sockname.sin_port = htons (usPort); + + if ((bind (udpsock, (struct sockaddr *) &sockname, sizeof (sockname))) == + -1) + { + close (udpsock); + //err_msg("Cannot bind port %i at %s -%s",usPort,pszHost,strerror(errno)); + return -1; + } + + return (udpsock); +} + +int check_socket (int iSocket, fd_set * pStReadFds, int iNfd) +{ + struct timeval stTimeVal; + + FD_ZERO (pStReadFds); + FD_SET (iSocket, pStReadFds); + stTimeVal.tv_sec = 0; + stTimeVal.tv_usec = 5000; + + if (select (iNfd, pStReadFds, NULL, NULL, &stTimeVal) > 0) + { + return 0; + } + return -1; +} + +int check_socket_with_timeout (int iSocket, fd_set * pStReadFds, int iNfd, + int sec, int usec) +{ + struct timeval stTimeVal; + + FD_ZERO (pStReadFds); + FD_SET (iSocket, pStReadFds); + stTimeVal.tv_sec = sec; + stTimeVal.tv_usec = usec; + + if (select (iNfd, pStReadFds, NULL, NULL, &stTimeVal) > 0) + { + return 0; + } + return -1; +} + +int check_and_process_socket (int iSocket, fd_set * pStReadFds, char *cPkgBuf, + const unsigned int uiMaxLen, + unsigned int *pPkgLen) +{ + if (FD_ISSET (iSocket, pStReadFds)) + { + struct sockaddr_in stFromAddr; + socklen_t iAddrLength = sizeof (stFromAddr); + *pPkgLen = 0; + //LOGSYS(RMB_LOG_DEBUG, " sizeof(cPkgBuf)=%lu", sizeof(cPkgBuf)); + + int iRet = recvfrom (iSocket, cPkgBuf, uiMaxLen, + 0, (struct sockaddr *) &stFromAddr, &iAddrLength); + if (iRet > 0) + { + *pPkgLen = iRet; + } + return iRet; + } + return 0; +} + +int tcp_nodelay (int iSockfd) +{ + int i; + + if ((i = fcntl (iSockfd, F_GETFL, 0)) == -1) + return (-1); + else if (fcntl (iSockfd, F_SETFL, i | FNDELAY) == -1) + return (-1); + return 0; +} + +int get_host_name (char *hostName, unsigned int uiHostNameLen) +{ + struct hostent *host; //���������Ϣ +// while () +// { +// +// } + + if ((host = gethostent ()) == NULL) + { + LOGRMB (RMB_LOG_ERROR, " fail to get host's information"); + return -1; + } + strncpy (hostName, host->h_name, uiHostNameLen); + + while ((host = gethostent ()) != NULL) + { + } + endhostent (); + //LOGSYS(LOG_ERROR, "%s hostName: %s,%s,uiHostName=%u" , __func__, hostName, host->h_name, uiHostNameLen); + return 0; +} + +int get_local_ip (char *addr, unsigned int uiAddrLen) +{ + int i = 0; + int sockfd; + struct ifconf ifconf; + char buf[512]; + struct ifreq *ifreq; + char *ip; + + ifconf.ifc_len = 512; + ifconf.ifc_buf = buf; + + if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) + { + return -1; + } + ioctl (sockfd, SIOCGIFCONF, &ifconf); + close (sockfd); + + ifreq = (struct ifreq *) buf; + for (i = (ifconf.ifc_len / sizeof (struct ifreq)); i > 0; i--) + { + ip = inet_ntoa (((struct sockaddr_in *) &(ifreq->ifr_addr))->sin_addr); + + if (strcmp (ip, "127.0.0.1") == 0) + { + ifreq++; + continue; + } + + strncpy (addr, ip, uiAddrLen); + //LOGSYS(LOG_ERROR, "%s HostIp: %s,%s,len=%u" , __func__, addr,ip, uiAddrLen); + return 0; + } + + return -1; +} + +/** + * 2.0.10版本增加,逻辑为: + * 通过获取环境变量networkInterface的值,来获取对应的ip + * 如果失败,则返回默认值 + * 默认获取方式: bond1 > eth1 > eth0 + */ +int get_local_ip_v2 (char *addr, unsigned int uiAddrLen) +{ + char *val = NULL; + + val = getenv ("networkInterface"); + + int i = 0; + int sockfd; + struct ifconf ifconf; + char buf[512]; + struct ifreq *ifreq; + char *ip; + + ifconf.ifc_len = 512; + ifconf.ifc_buf = buf; + + if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) + { + return -1; + } + ioctl (sockfd, SIOCGIFCONF, &ifconf); + close (sockfd); + + //first getenv + if (val != NULL) + { + ifreq = (struct ifreq *) buf; + for (i = (ifconf.ifc_len / sizeof (struct ifreq)); i > 0; i--) + { + if (strcmp (ifreq->ifr_name, val) != 0) + { + ifreq++; + continue; + } + + ip = inet_ntoa (((struct sockaddr_in *) &(ifreq->ifr_addr))->sin_addr); + + if (strcmp (ip, "127.0.0.1") == 0) + { + ifreq++; + continue; + } + + strncpy (addr, ip, uiAddrLen); + //LOGSYS(LOG_ERROR, "%s HostIp: %s,%s,len=%u" , __func__, addr,ip, uiAddrLen); + return 0; + } + } + + //bond1 + { + ifreq = (struct ifreq *) buf; + for (i = (ifconf.ifc_len / sizeof (struct ifreq)); i > 0; i--) + { + if (strcmp (ifreq->ifr_name, "bond1") != 0) + { + ifreq++; + continue; + } + + ip = inet_ntoa (((struct sockaddr_in *) &(ifreq->ifr_addr))->sin_addr); + + if (strcmp (ip, "127.0.0.1") == 0) + { + ifreq++; + continue; + } + + strncpy (addr, ip, uiAddrLen); + //LOGSYS(LOG_ERROR, "%s HostIp: %s,%s,len=%u" , __func__, addr,ip, uiAddrLen); + return 0; + } + } + + //eth1 + { + ifreq = (struct ifreq *) buf; + for (i = (ifconf.ifc_len / sizeof (struct ifreq)); i > 0; i--) + { + if (strcmp (ifreq->ifr_name, "eth1") != 0) + { + ifreq++; + continue; + } + + ip = inet_ntoa (((struct sockaddr_in *) &(ifreq->ifr_addr))->sin_addr); + + if (strcmp (ip, "127.0.0.1") == 0) + { + ifreq++; + continue; + } + + strncpy (addr, ip, uiAddrLen); + //LOGSYS(LOG_ERROR, "%s HostIp: %s,%s,len=%u" , __func__, addr,ip, uiAddrLen); + return 0; + } + } + + ifreq = (struct ifreq *) buf; + for (i = (ifconf.ifc_len / sizeof (struct ifreq)); i > 0; i--) + { + ip = inet_ntoa (((struct sockaddr_in *) &(ifreq->ifr_addr))->sin_addr); + + if (strcmp (ip, "127.0.0.1") == 0) + { + ifreq++; + continue; + } + + strncpy (addr, ip, uiAddrLen); + //LOGSYS(LOG_ERROR, "%s HostIp: %s,%s,len=%u" , __func__, addr,ip, uiAddrLen); + return 0; + } + + return -1; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/rmb_vector.c b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_vector.c new file mode 100644 index 0000000000..5e0b35b84f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/rmb_vector.c @@ -0,0 +1,84 @@ +// 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. + +#include "rmb_vector.h" +#include +#include +#include +#include +#include "rmb_msg.h" + +void Init (Array * this) +{ + this->Input = _input; + + this->get_array_size = _get_size; + this->return_index_value = _return_index_value; + + this->Constructor = _constructor; + this->Destructor = _destructor; + this->Constructor (this); +} + +void _constructor (Array * this) +{ + this->size = 0; + this->max_size = MAX_SIZE_PER_TIME; + this->Data = (DataType *) malloc (this->max_size * sizeof (DataType)); + memset (this->Data, 0x00, this->max_size * sizeof (DataType)); +} + +void _input (DataType data, Array * this) +{ + int i; + DataType *ptr; + + ptr = + (DataType *) malloc ((this->max_size + MAX_SIZE_PER_TIME) * + sizeof (DataType)); + memset (ptr, 0x00, + (this->max_size + MAX_SIZE_PER_TIME) * sizeof (DataType)); + for (i = 0; i < this->max_size; i++) + ptr[i] = this->Data[i]; + free (this->Data); + this->Data = ptr; + + snprintf (this->Data[this->max_size].unique_id, sizeof (data.unique_id), + "%s", data.unique_id); + snprintf (this->Data[this->max_size].biz_seq, sizeof (data.biz_seq), "%s", + data.biz_seq); + this->Data[this->max_size].flag = 1; + this->Data[this->max_size].timeStamp = data.timeStamp; + this->Data[this->max_size].timeout = data.timeout; + this->max_size += MAX_SIZE_PER_TIME; +} + +int _get_size (Array * this) +{ + assert (this != NULL); + return this->max_size; +} + +DataType _return_index_value (Array * this, int index) +{ + assert (this != NULL); + return (this->Data[index]); +} + +void _destructor (Array * this) +{ + assert (this != NULL); + free (this->Data); +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/wemq_fifo.c b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_fifo.c new file mode 100644 index 0000000000..e8b806129d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_fifo.c @@ -0,0 +1,350 @@ +// 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. + +/* + * A generic kernel FIFO implementation + * + * Copyright (C) 2009/2010 Stefani Seibold + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* +#include +#include +#include +#include +#include +#include +#include +*/ +//#include "wemq_fifo.h" +#include "rmb_define.h" +#define min(x,y) ({\ + typeof(x) _x = (x);\ + typeof(y) _y = (y);\ + (void)(&_x == &_y);\ + _x < _y ? _x : _y;}) +#define max(x,y) ({\ + typeof(x) _x = (x);\ + typeof(y) _y = (y);\ + (void)(&_x == &_y);\ + _x > _y ? _x : _y;}) +/* + * internal helper to calculate the unused elements in a fifo + */ +static inline unsigned int wemq_kfifo_unused (struct __wemq_kfifo *fifo) +{ + return (fifo->mask + 1) - (fifo->in - fifo->out); +} + +int __wemq_kfifo_alloc (struct __wemq_kfifo *fifo, unsigned int size, + size_t esize) +{ + /* + * round down to the next power of 2, since our 'let the indices + * wrap' technique works only in this case. + */ + size = roundup_pow_of_two (size); + + fifo->in = 0; + fifo->out = 0; + fifo->esize = esize; + + if (size < 2) + { + fifo->data = NULL; + fifo->mask = 0; + return -KFIFO_EINVAL; + } + + fifo->data = malloc (size * esize); + + if (!fifo->data) + { + fifo->mask = 0; + return -KFIFO_ENOMEM; + } + fifo->mask = size - 1; + + return 0; +} + +////EXPORT_SYMBOL(__wemq_kfifo_alloc); + +void __wemq_kfifo_free (struct __wemq_kfifo *fifo) +{ + free (fifo->data); + fifo->in = 0; + fifo->out = 0; + fifo->esize = 0; + fifo->data = NULL; + fifo->mask = 0; +} + +////EXPORT_SYMBOL(__wemq_kfifo_free); + +int __wemq_kfifo_init (struct __wemq_kfifo *fifo, void *buffer, + unsigned int size, size_t esize) +{ + size /= esize; + + size = roundup_pow_of_two (size); + + fifo->in = 0; + fifo->out = 0; + fifo->esize = esize; + fifo->data = buffer; + + if (size < 2) + { + fifo->mask = 0; + return -KFIFO_EINVAL; + } + fifo->mask = size - 1; + + return 0; +} + +//EXPORT_SYMBOL(__wemq_kfifo_init); + +static void wemq_kfifo_copy_in (struct __wemq_kfifo *fifo, const void *src, + unsigned int len, unsigned int off) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + + off &= fifo->mask; + if (esize != 1) + { + off *= esize; + size *= esize; + len *= esize; + } + l = min (len, size - off); + + memcpy (fifo->data + off, src, l); + memcpy (fifo->data, src + l, len - l); + /* + * make sure that the data in the fifo is up to date before + * incrementing the fifo->in index counter + */ + //smp_wmb(); +} + +unsigned int __wemq_kfifo_in (struct __wemq_kfifo *fifo, + const void *buf, unsigned int len) +{ + unsigned int l; + + l = wemq_kfifo_unused (fifo); + if (len > l) + len = l; + + wemq_kfifo_copy_in (fifo, buf, len, fifo->in); + fifo->in += len; + return len; +} + +//EXPORT_SYMBOL(__wemq_kfifo_in); + +static void wemq_kfifo_copy_out (struct __wemq_kfifo *fifo, void *dst, + unsigned int len, unsigned int off) +{ + unsigned int size = fifo->mask + 1; + unsigned int esize = fifo->esize; + unsigned int l; + + off &= fifo->mask; + if (esize != 1) + { + off *= esize; + size *= esize; + len *= esize; + } + l = min (len, size - off); + + memcpy (dst, fifo->data + off, l); + memcpy (dst + l, fifo->data, len - l); + /* + * make sure that the data is copied before + * incrementing the fifo->out index counter + */ + //smp_wmb(); +} + +unsigned int __wemq_kfifo_out_peek (struct __wemq_kfifo *fifo, + void *buf, unsigned int len) +{ + unsigned int l; + + l = fifo->in - fifo->out; + if (len > l) + len = l; + + wemq_kfifo_copy_out (fifo, buf, len, fifo->out); + return len; +} + +//EXPORT_SYMBOL(__wemq_kfifo_out_peek); + +unsigned int __wemq_kfifo_out (struct __wemq_kfifo *fifo, + void *buf, unsigned int len) +{ + len = __wemq_kfifo_out_peek (fifo, buf, len); + fifo->out += len; + return len; +} + +//EXPORT_SYMBOL(__wemq_kfifo_out); + +unsigned int __wemq_kfifo_max_r (unsigned int len, size_t recsize) +{ + unsigned int max = (1 << (recsize << 3)) - 1; + + if (len > max) + return max; + return len; +} + +//EXPORT_SYMBOL(__wemq_kfifo_max_r); + +#define __WEMQ_KFIFO_PEEK(data, out, mask) \ + ((data)[(out) & (mask)]) +/* + * __wemq_kfifo_peek_n internal helper function for determinate the length of + * the next record in the fifo + */ +static unsigned int __wemq_kfifo_peek_n (struct __wemq_kfifo *fifo, + size_t recsize) +{ + unsigned int l; + unsigned int mask = fifo->mask; + unsigned char *data = fifo->data; + + l = __WEMQ_KFIFO_PEEK (data, fifo->out, mask); + + if (--recsize) + l |= __WEMQ_KFIFO_PEEK (data, fifo->out + 1, mask) << 8; + + return l; +} + +#define __WEMQ_KFIFO_POKE(data, in, mask, val) \ + ( \ + (data)[(in) & (mask)] = (unsigned char)(val) \ + ) + +/* + * __wemq_kfifo_poke_n internal helper function for storeing the length of + * the record into the fifo + */ +static void __wemq_kfifo_poke_n (struct __wemq_kfifo *fifo, unsigned int n, + size_t recsize) +{ + unsigned int mask = fifo->mask; + unsigned char *data = fifo->data; + + __WEMQ_KFIFO_POKE (data, fifo->in, mask, n); + + if (recsize > 1) + __WEMQ_KFIFO_POKE (data, fifo->in + 1, mask, n >> 8); +} + +unsigned int __wemq_kfifo_len_r (struct __wemq_kfifo *fifo, size_t recsize) +{ + return __wemq_kfifo_peek_n (fifo, recsize); +} + +//EXPORT_SYMBOL(__wemq_kfifo_len_r); + +unsigned int __wemq_kfifo_in_r (struct __wemq_kfifo *fifo, const void *buf, + unsigned int len, size_t recsize) +{ + if (len + recsize > wemq_kfifo_unused (fifo)) + return 0; + + __wemq_kfifo_poke_n (fifo, len, recsize); + + wemq_kfifo_copy_in (fifo, buf, len, fifo->in + recsize); + fifo->in += len + recsize; + return len; +} + +//EXPORT_SYMBOL(__wemq_kfifo_in_r); + +static unsigned int wemq_kfifo_out_copy_r (struct __wemq_kfifo *fifo, + void *buf, unsigned int len, + size_t recsize, unsigned int *n) +{ + *n = __wemq_kfifo_peek_n (fifo, recsize); + + if (len > *n) + len = *n; + + wemq_kfifo_copy_out (fifo, buf, len, fifo->out + recsize); + return len; +} + +unsigned int __wemq_kfifo_out_peek_r (struct __wemq_kfifo *fifo, void *buf, + unsigned int len, size_t recsize) +{ + unsigned int n; + + if (fifo->in == fifo->out) + return 0; + + return wemq_kfifo_out_copy_r (fifo, buf, len, recsize, &n); +} + +//EXPORT_SYMBOL(__wemq_kfifo_out_peek_r); + +unsigned int __wemq_kfifo_out_r (struct __wemq_kfifo *fifo, void *buf, + unsigned int len, size_t recsize) +{ + unsigned int n; + + if (fifo->in == fifo->out) + return 0; + + len = wemq_kfifo_out_copy_r (fifo, buf, len, recsize, &n); + fifo->out += n + recsize; + return len; +} + +//EXPORT_SYMBOL(__wemq_kfifo_out_r); + +void __wemq_kfifo_skip_r (struct __wemq_kfifo *fifo, size_t recsize) +{ + unsigned int n; + + n = __wemq_kfifo_peek_n (fifo, recsize); + fifo->out += n + recsize; +} + +//EXPORT_SYMBOL(__wemq_kfifo_skip_r); diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/wemq_proto.c b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_proto.c new file mode 100644 index 0000000000..74c79aba74 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_proto.c @@ -0,0 +1,748 @@ +// 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. + +#include "common.h" +#include "wemq_proto.h" + +unsigned long long htonll_z (unsigned long long host) +{ + union64HN u; + u.src[0] = htonl (host >> 32); + u.src[1] = htonl (host & 0xFFFFFFFF); + return u.dest; +} + +unsigned long long ntohll_z (unsigned long long net) +{ + union64HN u; + u.src[0] = ntohl (net >> 32); + u.src[1] = ntohl (net & 0xFFFFFFFF); + return u.dest; +} + +//***************************0x01 心跳************************** +//请求 + +int GetStHeartBeatReqBaseLegth () +{ + return sizeof (int) + sizeof (unsigned int) + sizeof (char); +} + +int GetStHeartBeatReqLegth (const StHeartBeatReq * pReq) +{ + return GetStHeartBeatReqBaseLegth () + pReq->cReseveLength; +} + +//return -1.空间不足 +int EncodeStHeartBeatReq (char *buf, int *pBufLen, + const StHeartBeatReq * pReq) +{ + if (*pBufLen < GetStHeartBeatReqLegth (pReq)) + { + return -1; + } + *pBufLen = GetStHeartBeatReqLegth (pReq); + ENCODE_INT (buf, pReq->pid); + ENCODE_INT (buf, pReq->uiCount); + ENCODE_CSTR_MEMCPY (buf, pReq->strReserve, pReq->cReseveLength); + return 0; +} + +//return -1,空间不足 +//return -2,buf长度不够 +int DecodeHeartBeatReq (StHeartBeatReq * pReq, const char *buf, + const int bufLen) +{ + if (bufLen < GetStHeartBeatReqBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pReq->pid, buf, &iTmpLen); + DECODE_INT (pReq->uiCount, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strReserve, pReq->cReseveLength, buf, &iTmpLen); + return 0; +} + +//回复 + +int GetStHeartBeatRspBaseLegth () +{ + return 3 * sizeof (unsigned int) + sizeof (char); +} + +int GetStHeartBeatRspLegth (const StHeartBeatRsp * pRsp) +{ + return GetStHeartBeatRspBaseLegth () + pRsp->cReseveLength; +} + +//return -1.空间不足 +int EncodeStHeartBeatRsp (char *buf, int *pBufLen, + const StHeartBeatRsp * pRsp) +{ + if (*pBufLen < GetStHeartBeatRspLegth (pRsp)) + { + return -1; + } + *pBufLen = GetStHeartBeatRspLegth (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_INT (buf, pRsp->pid); + ENCODE_INT (buf, pRsp->uiCount); + ENCODE_CSTR_MEMCPY (buf, pRsp->strReserve, pRsp->cReseveLength); + return 0; +} + +int DecodeHeartBeatRsp (StHeartBeatRsp * pRsp, const char *buf, + const int bufLen) +{ + if (bufLen < GetStHeartBeatRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_INT (pRsp->pid, buf, &iTmpLen); + DECODE_INT (pRsp->uiCount, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strReserve, pRsp->cReseveLength, buf, &iTmpLen); + return 0; +} + +//***************************0x02 注册,建立连接************************** +//请求 + +int GetRegisterReqBaseLegth () +{ + return sizeof (int) + 10 * sizeof (char); +} + +int GetRegisterReqLegth (const StRegisterReq * pReq) +{ + return GetRegisterReqBaseLegth () + pReq->cSolaceHostLen + + pReq->cSolaceVpnLen + pReq->cSolaceUserLen + pReq->cSolacePwdLen + + pReq->cConsumerIpLen + pReq->cConsumerSysIdLen + pReq->cConsumerDcnLen + + pReq->cConsumerOrgIdLen + pReq->cConsumerVersionLen + pReq->cReseveLength; +} + +//return -1.空间不足 +int EncodeStRegisterReq (char *buf, int *pBufLen, const StRegisterReq * pReq) +{ + if (*pBufLen < GetRegisterReqLegth (pReq)) + { + return -1; + } + *pBufLen = GetRegisterReqLegth (pReq); + ENCODE_INT (buf, pReq->iPid); + ENCODE_CSTR_MEMCPY (buf, pReq->strSolaceHost, pReq->cSolaceHostLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strSolaceVpn, pReq->cSolaceVpnLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strSolaceUser, pReq->cSolaceUserLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strSolacePwd, pReq->cSolacePwdLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strConsumerIp, pReq->cConsumerIpLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strConsumerSysId, pReq->cConsumerSysIdLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strConsumerDcn, pReq->cConsumerDcnLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strConsumerOrgId, pReq->cConsumerOrgIdLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strConsumerVersion, + pReq->cConsumerVersionLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strReserve, pReq->cReseveLength); + return 0; +} + +int DecodeStRegisterReq (StRegisterReq * pReq, const char *buf, + const int bufLen) +{ + if (bufLen < GetRegisterReqBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pReq->iPid, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strSolaceHost, pReq->cSolaceHostLen, buf, + &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strSolaceVpn, pReq->cSolaceVpnLen, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strSolaceUser, pReq->cSolaceUserLen, buf, + &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strSolacePwd, pReq->cSolacePwdLen, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strConsumerIp, pReq->cConsumerIpLen, buf, + &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strConsumerSysId, pReq->cConsumerSysIdLen, buf, + &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strConsumerDcn, pReq->cConsumerDcnLen, buf, + &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strConsumerOrgId, pReq->cConsumerOrgIdLen, buf, + &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strConsumerVersion, pReq->cConsumerVersionLen, + buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strReserve, pReq->cReseveLength, buf, &iTmpLen); + return 0; +} + +int GetRegisterRspBaseLegth () +{ + return sizeof (char) + 3 * sizeof (int); +} + +int GetRegisterRsplength (const StRegisterRsp * pRsp) +{ + return GetRegisterRspBaseLegth () + pRsp->cReseveLength; +} + +int EncodeStRegisterRsp (char *buf, int *pBufLen, const StRegisterRsp * pRsp) +{ + if (*pBufLen < GetRegisterRsplength (pRsp)) + { + return -1; + } + *pBufLen = GetRegisterRsplength (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_INT (buf, pRsp->uiCcdIndex); + ENCODE_INT (buf, pRsp->uiCcdFlow); + ENCODE_CSTR_MEMCPY (buf, pRsp->strReserve, pRsp->cReseveLength); + return 0; +} + +int DecodeStRegisterRsp (StRegisterRsp * pRsp, const char *buf, + const int bufLen) +{ + if (bufLen < GetRegisterRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_INT (pRsp->uiCcdIndex, buf, &iTmpLen); + DECODE_INT (pRsp->uiCcdFlow, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strReserve, pRsp->cReseveLength, buf, &iTmpLen); + return 0; +} + +//***********************************0x06 注册接收连接*********************************** +int GetRegisterReceiveReqBaseLegth () +{ + return 2 * sizeof (int) + sizeof (char); +} + +int GetRegisterReceiveReqLegth (const StRegisterReceiveReq * pReq) +{ + return GetRegisterReceiveReqBaseLegth () + pReq->cReseveLength; +} + +//return -1.空间不足 +int EncodeStRegisterReceiveReq (char *buf, int *pBufLen, + const StRegisterReceiveReq * pReq) +{ + if (*pBufLen < GetRegisterReceiveReqLegth (pReq)) + { + return -1; + } + *pBufLen = GetRegisterReceiveReqLegth (pReq); + ENCODE_INT (buf, pReq->uiCcdIndex); + ENCODE_INT (buf, pReq->uiCcdFlow); + ENCODE_CSTR_MEMCPY (buf, pReq->strReserve, pReq->cReseveLength); + return 0; +} + +int DecodeStRegisterReceiveReq (StRegisterReceiveReq * pReq, const char *buf, + const int bufLen) +{ + if (bufLen < GetRegisterReceiveReqBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pReq->uiCcdIndex, buf, &iTmpLen); + DECODE_INT (pReq->uiCcdFlow, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strReserve, pReq->cReseveLength, buf, &iTmpLen); + return 0; +} + +int GetRegisterReceiveRspBaseLegth () +{ + return sizeof (char) + sizeof (int); +} + +int GetRegisterReceiveRsplength (const StRegisterReceiveRsp * pRsp) +{ + return GetRegisterReceiveRspBaseLegth () + pRsp->cReseveLength; +} + +int EncodeStRegisterReceiveRsp (char *buf, int *pBufLen, + const StRegisterReceiveRsp * pRsp) +{ + if (*pBufLen < GetRegisterReceiveRsplength (pRsp)) + { + return -1; + } + *pBufLen = GetRegisterReceiveRsplength (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_CSTR_MEMCPY (buf, pRsp->strReserve, pRsp->cReseveLength); + return 0; +} + +int DecodeStRegisterReceiveRsp (StRegisterRsp * pRsp, const char *buf, + const int bufLen) +{ + if (bufLen < GetRegisterReceiveRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strReserve, pRsp->cReseveLength, buf, &iTmpLen); + return 0; +} + +int GetAddListenReqLegth (const StAddListenReq * pReq) +{ + return sizeof (pReq->strSceneId) + sizeof (pReq->strServiceId); +} + +//return -1.空间不足 +int EncodeAddListenReq (char *buf, int *pBufLen, const StAddListenReq * pReq) +{ + if (*pBufLen < GetAddListenReqLegth (pReq)) + { + return -1; + } + *pBufLen = GetAddListenReqLegth (pReq); + memcpy (buf, pReq->strServiceId, sizeof (pReq->strServiceId)); + buf = buf + sizeof (pReq->strServiceId); + memcpy (buf, pReq->strSceneId, sizeof (pReq->strSceneId)); + return 0; +} + +int DecodeAddListenReq (StAddListenReq * pReq, const char *buf, + const int bufLen) +{ + if (bufLen < GetAddListenReqLegth (pReq)) + { + return -1; + } + memcpy (pReq->strServiceId, buf, sizeof (pReq->strServiceId)); + memcpy (pReq->strSceneId, buf + sizeof (pReq->strServiceId), + sizeof (pReq->strSceneId)); + return 0; +} + +int GetAddListenRspBaseLegth () +{ + return sizeof (int); +} + +int GetAddListenRspLegth (const StAddListenRsp * pRsp) +{ + return GetAddListenRspBaseLegth () + sizeof (pRsp->strSceneId) + + sizeof (pRsp->strServiceId); +} + +//return -1.空间不足 +int EncodeAddListenRsp (char *buf, int *pBufLen, const StAddListenRsp * pRsp) +{ + if (*pBufLen < GetAddListenRspLegth (pRsp)) + { + return -1; + } + *pBufLen = GetAddListenRspLegth (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + memcpy (buf, pRsp->strServiceId, sizeof (pRsp->strServiceId)); + memcpy (buf, pRsp->strSceneId, sizeof (pRsp->strSceneId)); + return 0; +} + +int DecodeAddListenRsp (StAddListenRsp * pRsp, const char *buf, + const int bufLen) +{ + if (bufLen < GetAddListenRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + memcpy (pRsp->strServiceId, buf, sizeof (pRsp->strServiceId)); + memcpy (pRsp->strSceneId, buf, sizeof (pRsp->strSceneId)); + return 0; +} + +//***************************0x06 增加监听************************** +int GetAddManageBaseLength () +{ + return sizeof (char); +} + +int GetAddManageReqLegth (const StAddManageReq * pReq) +{ + return GetAddManageBaseLength () + pReq->cManageTopicLength; +} + +//return -1.空间不足 +int EncodeAddManageReq (char *buf, int *pBufLen, const StAddManageReq * pReq) +{ + if (*pBufLen < GetAddManageReqLegth (pReq)) + { + return -1; + } + *pBufLen = GetAddManageReqLegth (pReq); + ENCODE_CSTR_MEMCPY (buf, pReq->strManageTopic, pReq->cManageTopicLength); + return 0; +} + +int DecodeAddManageReq (StAddManageReq * pReq, const char *buf, + const int bufLen) +{ + if (bufLen < GetRegisterReceiveRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_CSTR_MEMCPY (pReq->strManageTopic, pReq->cManageTopicLength, buf, + &iTmpLen); + return 0; +} + +int GetAddManageRspBaseLegth () +{ + return sizeof (int) + sizeof (char); +} + +int GetAddManageRspLegth (const StAddManageRsp * pRsp) +{ + return GetAddManageRspBaseLegth () + pRsp->cManageTopicLength; +} + +//return -1.空间不足 +int EncodeAddManageRsp (char *buf, int *pBufLen, const StAddManageRsp * pRsp) +{ + if (*pBufLen < GetAddManageRspLegth (pRsp)) + { + return -1; + } + *pBufLen = GetAddManageRspLegth (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_CSTR_MEMCPY (buf, pRsp->strManageTopic, pRsp->cManageTopicLength); + return 0; +} + +int DecodeAddManageRsp (StAddManageRsp * pRsp, const char *buf, + const int bufLen) +{ + if (bufLen < GetAddManageRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strManageTopic, pRsp->cManageTopicLength, buf, + &iTmpLen); + return 0; +} + +//***************************0x04 worker发包************************** + +int GetSendMsgReqBaseLength () +{ + return 3 * sizeof (int) + sizeof (char); +} + +int GetSendMsgReqLength (const StSendMsgReq * pReq) +{ + return GetSendMsgReqBaseLength () + pReq->uiWemqMsgLen + + pReq->cReseveLength; +} + +//return -1.空间不足 +int EncodeSendMsgReq (char *buf, int *pBufLen, const StSendMsgReq * pReq) +{ + if (*pBufLen < GetSendMsgReqLength (pReq)) + { + return -1; + } + *pBufLen = GetSendMsgReqLength (pReq); + ENCODE_INT (buf, pReq->uiMsgType); + ENCODE_INT (buf, pReq->uiSendMsgSeq); + ENCODE_DWSTR_MEMCPY (buf, pReq->strWemqMsg, pReq->uiWemqMsgLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strReserve, pReq->cReseveLength); + return 0; +} + +int DecodeSendMsgReq (StSendMsgReq * pReq, const char *buf, const int bufLen) +{ + if (bufLen < GetSendMsgReqBaseLength ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pReq->uiMsgType, buf, &iTmpLen); + DECODE_INT (pReq->uiSendMsgSeq, buf, &iTmpLen); + DECODE_DWSTR_MEMCPY (pReq->strWemqMsg, pReq->uiWemqMsgLen, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strReserve, pReq->cReseveLength, buf, &iTmpLen); + return 0; +} + +int GetSendMsgRspBaseLength () +{ + return 3 * sizeof (int) + sizeof (char); +} + +int GetSendMsgRspLength (const StSendMsgRsp * pRsp) +{ + return GetSendMsgRspBaseLength () + pRsp->cUuidLen; +} + +//return -1.空间不足 +int EncodeSendMsgRsp (char *buf, int *pBufLen, const StSendMsgRsp * pRsp) +{ + if (*pBufLen < GetSendMsgRspLength (pRsp)) + { + return -1; + } + *pBufLen = GetSendMsgRspLength (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_INT (buf, pRsp->uiMsgType); + ENCODE_INT (buf, pRsp->uiRecvMsgSeq); + ENCODE_CSTR_MEMCPY (buf, pRsp->strUuid, pRsp->cUuidLen); + return 0; +} + +int DecodeSendMsgRsp (StSendMsgRsp * pRsp, const char *buf, const int bufLen) +{ + if (bufLen < GetSendMsgRspBaseLength ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_INT (pRsp->uiMsgType, buf, &iTmpLen); + DECODE_INT (pRsp->uiRecvMsgSeq, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strUuid, pRsp->cUuidLen, buf, &iTmpLen); + return 0; +} + +//***************************0x05 worker发送消息ack************************** +//请求,为避免其他业务代码错误导致把其他人的msg ack掉, 因此这里将sessionId和sessionIndex flowIndex做核对 + +int GetAckMsgReqBaseLength () +{ + return 2 * sizeof (int) + 2 * sizeof (char) + sizeof (long); +} + +int GetAckMsgReqLength (const StAckMsgReq * pReq) +{ + return GetAckMsgReqBaseLength () + pReq->cUuidLen + pReq->cReseveLength; +} + +//return -1.空间不足 +int EncodeAckMsgReq (char *buf, int *pBufLen, const StAckMsgReq * pReq) +{ + if (*pBufLen < GetAckMsgReqLength (pReq)) + { + return -1; + } + *pBufLen = GetAckMsgReqLength (pReq); + ENCODE_INT (buf, pReq->uiSessionIndex); + ENCODE_INT (buf, pReq->uiFlowIndex); + ENCODE_LONG (buf, pReq->ulMsgId); + ENCODE_CSTR_MEMCPY (buf, pReq->strUuid, pReq->cUuidLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strReserve, pReq->cReseveLength); + return 0; +} + +int DecodeAckMsgReq (StAckMsgReq * pReq, const char *buf, const int bufLen) +{ + if (bufLen < GetAckMsgReqBaseLength ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pReq->uiSessionIndex, buf, &iTmpLen); + DECODE_INT (pReq->uiFlowIndex, buf, &iTmpLen); + DECODE_LONG (pReq->ulMsgId, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strUuid, pReq->cUuidLen, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strReserve, pReq->cReseveLength, buf, &iTmpLen); + return 0; +} + +//回包 + +int GetAckMsgRspBaseLength () +{ + return 3 * sizeof (int) + sizeof (char) + sizeof (unsigned long); +} + +int GetAckMsgRspLength (const StAckMsgRsp * pReq) +{ + return GetAckMsgRspBaseLength () + pReq->cUuidLen; +} + +//return -1.空间不足 +int EncodeAckMsgRsp (char *buf, int *pBufLen, const StAckMsgRsp * pRsp) +{ + if (*pBufLen < GetAckMsgRspLength (pRsp)) + { + return -1; + } + *pBufLen = GetAckMsgRspLength (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_INT (buf, pRsp->uiSessionIndex); + ENCODE_INT (buf, pRsp->uiFlowIndex); + ENCODE_LONG (buf, pRsp->ulMsgId); + ENCODE_CSTR_MEMCPY (buf, pRsp->strUuid, pRsp->cUuidLen); + return 0; +} + +int DecodeAckMsgRsp (StAckMsgRsp * pRsp, const char *buf, const int bufLen) +{ + if (bufLen < GetAckMsgRspBaseLength ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_INT (pRsp->uiSessionIndex, buf, &iTmpLen); + DECODE_INT (pRsp->uiFlowIndex, buf, &iTmpLen); + DECODE_LONG (pRsp->ulMsgId, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strUuid, pRsp->cUuidLen, buf, &iTmpLen); + return 0; +} + +//以下为proxy推送消息 +//***************************0x50 proxy下发消息************************** +int GetPushMsgReqBaseLegth () +{ + return (2 * sizeof (int) + 2 * sizeof (char)); +} + +int GetPushMsgReqLegth (const StPushMsgReq * pReq) +{ + return GetPushMsgReqBaseLegth () + pReq->uiWemqMsgLen + pReq->cReseveLength; +} + +//return -1.空间不足 +int EncodePushMsgReq (char *buf, int *pBufLen, const StPushMsgReq * pReq) +{ + if (*pBufLen < GetPushMsgReqLegth (pReq)) + { + return -1; + } + *pBufLen = GetPushMsgReqLegth (pReq); + ENCODE_CHAR (buf, pReq->cWemqMsgType); + ENCODE_INT (buf, pReq->uiSeq); + ENCODE_DWSTR_MEMCPY (buf, pReq->strWemqMsg, pReq->uiWemqMsgLen); + ENCODE_CSTR_MEMCPY (buf, pReq->strReserve, pReq->cReseveLength); + return 0; +} + +int DecodePushMsgReq (StPushMsgReq * pReq, const char *buf, const int bufLen) +{ + if (bufLen < GetPushMsgReqBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_CHAR (pReq->cWemqMsgType, buf, &iTmpLen); + DECODE_INT (pReq->uiSeq, buf, &iTmpLen); + DECODE_DWSTR_MEMCPY (pReq->strWemqMsg, pReq->uiWemqMsgLen, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pReq->strReserve, pReq->cReseveLength, buf, &iTmpLen); + return 0; +} + +//回包 + +int GetPushMsgRspBaseLegth () +{ + return sizeof (int) + sizeof (char); +} + +int GetPushMsgRspLegth (const StPushMsgRsp * pRsp) +{ + return GetPushMsgRspBaseLegth () + pRsp->cUuidLen; +} + +//return -1.空间不足 +int EncodePushMsgRsp (char *buf, int *pBufLen, const StPushMsgRsp * pRsp) +{ + if (*pBufLen < GetPushMsgRspLegth (pRsp)) + { + return -1; + } + *pBufLen = GetPushMsgRspLegth (pRsp); + ENCODE_INT (buf, pRsp->uiResult); + ENCODE_CSTR_MEMCPY (buf, pRsp->strUuid, pRsp->cUuidLen); + return 0; +} + +int DecodePushMsgRsp (StPushMsgRsp * pRsp, const char *buf, const int bufLen) +{ + if (bufLen < GetPushMsgRspBaseLegth ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pRsp->uiResult, buf, &iTmpLen); + DECODE_CSTR_MEMCPY (pRsp->strUuid, pRsp->cUuidLen, buf, &iTmpLen); + return 0; +} + +//*************************************************wemq worker-proxy包格式***************************** +//msg的组成都是header + msgbuf, 其中header的头4个字节为长度 +int GetWemqHeaderLen () +{ + return 5 * sizeof (int) + sizeof (unsigned short); +} + +int EncodeWemqHeader (char *buf, int *pBufLen, const StWemqHeader * pHeader) +{ + if (*pBufLen < GetWemqHeaderLen ()) + { + return -1; + } + *pBufLen = GetWemqHeaderLen (); + + ENCODE_INT (buf, pHeader->uiPkgLen); + ENCODE_INT (buf, 0xFFFFFFFF); + ENCODE_SHORT (buf, pHeader->usCmd); + ENCODE_INT (buf, pHeader->uiSessionId); + ENCODE_INT (buf, pHeader->uiSeq); + ENCODE_INT (buf, pHeader->uiReserved); + return 0; +} + +int DecodeWemqHeader (StWemqHeader * pHeader, const char *buf, + const int bufLen) +{ + if (bufLen < GetWemqHeaderLen ()) + { + return -1; + } + int iTmpLen = bufLen; + DECODE_INT (pHeader->uiPkgLen, buf, &iTmpLen); + DECODE_INT (pHeader->uiColorFlag, buf, &iTmpLen); + DECODE_SHORT (pHeader->usCmd, buf, &iTmpLen); + DECODE_INT (pHeader->uiSessionId, buf, &iTmpLen); + DECODE_INT (pHeader->uiSeq, buf, &iTmpLen); + DECODE_INT (pHeader->uiReserved, buf, &iTmpLen); + return 0; +} + +int DecodeWeMQMsg (StWeMQMSG * pMsg, const char *buf, const int bufLen) +{ + int iTmpLen = bufLen; + DECODE_INT (pMsg->uiTotalLen, buf, &iTmpLen); + DECODE_INT (pMsg->uiHeaderLen, buf, &iTmpLen); +/* + DECODE_DWSTR_MEMCPY(pMsg->cStrJsonHeader,pMsg->uiHeaderLen,buf,&iTmpLen); + pMsg->cStrJsonHeader[pMsg->uiHeaderLen] = '\0'; + DECODE_DWSTR_MEMCPY(pMsg->cStrJsonBody, pMsg->uiTotalLen - pMsg->uiHeaderLen - 8, buf, &iTmpLen); + pMsg->cStrJsonHeader[pMsg->uiTotalLen - pMsg->uiHeaderLen - 8] = '\0'; +*/ + return 0; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/wemq_tcp.c b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_tcp.c new file mode 100644 index 0000000000..971fec4c1e --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_tcp.c @@ -0,0 +1,773 @@ +// 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. + +#include "wemq_tcp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmb_define.h" + +// return=0: timeout; return<0: error; return>0: success. +static int check_recv (int fd, int iSec, int iMs) +{ + fd_set rset; + int ret; + + FD_ZERO (&rset); + FD_SET (fd, &rset); + + struct timeval tv; + tv.tv_sec = iSec; + tv.tv_usec = iMs * 1000; + + do + { + ret = select (fd + 1, &rset, NULL, NULL, &tv); + } + while (ret < 0 && errno == EINTR); + + // 如果rset只有一个socket, 不需要去判断FD_ISSET + if (ret > 0 && FD_ISSET (fd, &rset)) + { + return 1; + } + + return (ret == 0 ? 0 : -1); +} + +// return=0: timeout; return<0: error; return>0: success. +static int check_send (int fd, int iSec, int iMs) +{ + fd_set wset; + int ret; + + FD_ZERO (&wset); + FD_SET (fd, &wset); + + struct timeval tv; + tv.tv_sec = iSec; + tv.tv_usec = iMs * 1000; + + do + { + ret = select (fd + 1, NULL, &wset, NULL, &tv); + } + while (ret < 0 && errno == EINTR); + + // 如果rset只有一个socket, 不需要去判断FD_ISSET + if (ret > 0 && FD_ISSET (fd, &wset)) + { + return 1; + } + + return (ret == 0 ? 0 : -1); +} + +//************************************ +// Method: wemq_tcp_connect +// FullName: wemq_tcp_connect +// Access: public +// Returns: int if connect success return socket fd, else return -1 +// Qualifier: +// Parameter: const char * ip +// Parameter: uint16_t port +// Parameter: int timeout:单位为ms +//************************************ +int wemq_tcp_connect (const char *ip, uint16_t port, int timeout) +{ + int sockfd = -1; + struct sockaddr_in servaddr; + int flag = 0; + int ret = 0; + + if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) + { + return -1; + } + if (timeout > 0) + { + flag = fcntl (sockfd, F_GETFL) | O_NONBLOCK; + fcntl (sockfd, F_SETFL, flag); + } + + bzero (&servaddr, sizeof (servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons (port); + if (inet_pton (AF_INET, ip, &servaddr.sin_addr) <= 0) + { + close (sockfd); + return -2; + } + + do + { + ret = + connect (sockfd, (struct sockaddr *) &servaddr, + sizeof (struct sockaddr_in)); + } + while (ret < 0 && errno == EINTR); + if ((ret != 0) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) + { + close (sockfd); + return -3; + } + + // 判断是否需要超时 + if (timeout > 0) + { + fd_set write_set; + struct timeval tv; + int sock_err = 0; + int sock_err_len = sizeof (sock_err); + + FD_ZERO (&write_set); + FD_SET (sockfd, &write_set); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + do + { + ret = select (FD_SETSIZE, NULL, &write_set, NULL, &tv); + } + while (ret < 0 && errno == EINTR); + if (ret <= 0 || !FD_ISSET (sockfd, &write_set)) + { + close (sockfd); + return 0; + } + + //getscokopt: check socket connect + if (getsockopt + (sockfd, SOL_SOCKET, SO_ERROR, (char *) &sock_err, + (socklen_t *) & sock_err_len) != 0) + { + close (sockfd); + return -4; + } + if (sock_err != 0) + { + close (sockfd); + return -5; + } + + //block + flag &= ~O_NONBLOCK; + fcntl (sockfd, F_SETFL, flag); + } + return sockfd; +} + +//************************************ +// Method: wemq_tcp_send +// FullName: wemq_tcp_send +// Access: public +// Returns: int 0 for success, -1 for error +// Qualifier: +// Parameter: int fd connected socket +// Parameter: char * msg message buffer +// Parameter: uint32_t len message length +//************************************ +int wemq_tcp_send (int fd, void *msg, uint32_t totalLen, uint32_t headerLen, + int iTimeOut, SSL * ssl) +{ + //uint32_t uiHeadRemain = 4; + //uint32_t uiHeadSend = 0; + if (fd < 0 || msg == NULL) + { + return -1; + } + if (iTimeOut <= 0) + { + iTimeOut = 1000; + } + /* + while (uiHeadRemain > 0) + { + iRet = check_send(fd, iTimeOut/1000, iTimeOut%1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB(RMB_LOG_ERROR, "check_send error, errno=%d\n", errno); + return -2; + } + iRet = send(fd, "JSON", uiHeadRemain, 0); + if (iRet < 0) + { + LOGRMB(RMB_LOG_ERROR, "send error, errno=%d\n", errno); + return -2; + } + uiHeadSend += iRet; + uiHeadRemain -= iRet; + } + */ + int iRet; + uint32_t uiRemain = totalLen + 8; + uint32_t uiSend = 0; + char *msg_temp = (char *) malloc ((totalLen + 8) * sizeof (char)); + char *msg_new = msg_temp; + ENCODE_DWSTR_MEMCPY (msg_temp, "WEMQ", 4); + ENCODE_DWSTR_MEMCPY (msg_temp, "0000", 4); + ENCODE_DWSTR_MEMCPY (msg_temp, msg, totalLen); + // LOGRMB(RMB_LOG_DEBUG, "tcp data=%s\n", msg_temp); + //LOGRMB(RMB_LOG_DEBUG, "tcp data2=%s\n", (char *)msg); + while (uiRemain > 0) + { + iRet = check_send (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_send error, errno=%d\n", errno); + return -2; + } + if (NULL != ssl) + { + iRet = SSL_write (ssl, msg_new + uiSend, uiRemain); + } + else + { + iRet = send (fd, msg_new + uiSend, uiRemain, 0); + } + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "send error, errno=%d, iRet=%d\n", errno, iRet); + return -2; + } + uiSend += iRet; + uiRemain -= iRet; + } + free (msg_new); + return uiSend; +} + +int wemq_ssl_recv (int fd, void *msg, uint32_t * len, int iTimeOut, SSL * ssl) +{ + int iRet; + uint32_t uiRemain, uiRecved; + + uiRemain = 4; + uiRecved = 0; + if (fd < 0 || msg == NULL || len == NULL) + { + return -1; + } + if (iTimeOut <= 0) + { + iTimeOut = 1000; + } + while (uiRemain > 0) + { + int iRecv = 0; + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + + if (uiRecved != 4 || strcmp (msg, "WEMQ") != 0) + { + LOGRMB (RMB_LOG_ERROR, "recv msg header error,%u:%s", uiRecved, + (char *) msg); + return -3; + } + + uiRemain = 4; + uiRecved = 0; + while (uiRemain > 0) + { + int iRecv = 0; + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + if (iRecv > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + if (0 == uiRemain) + { + break; + } + + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + if (NULL != ssl) + { + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + } + else + { + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + } + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + //LOGRMB(RMB_LOG_DEBUG, "Recv version = %s\n", (char *)msg); + if (uiRecved != 4) + { + LOGRMB (RMB_LOG_ERROR, "recv msg version error,%u:%s", uiRecved, + (char *) msg); + return -3; + } + + // read msg length + uiRemain = 4; + uiRecved = 0; + while (uiRemain > 0) + { + int iRecv = 0; + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + if (iRecv > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + if (0 == uiRemain) + { + break; + } + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + + if (NULL != ssl) + { + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + } + else + { + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + } + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + + if (uiRecved != 4) + { + // can't read 4 bytes + LOGRMB (RMB_LOG_ERROR, "recv less than 4, recv %d bytes\n", uiRecved); + return -3; + } + + *len = ntohl (*(uint32_t *) msg); + + uiRemain = *len - 4; + while (uiRemain > 0) + { + int iRecv = 0; + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + if (iRecv > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + if (0 == uiRemain) + { + break; + } + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + + if (NULL != ssl) + { + iRecv = SSL_read (ssl, msg + uiRecved, uiRemain); + } + else + { + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + } + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + + if (uiRecved != *len) + { + // can't recv whole msg + return -3; + } + + return uiRecved; +} + +//************************************ +// Method: wemq_tcp_recv +// FullName: wemq_tcp_recv +// Access: public +// Returns: int 0 for success, -1 for error +// Qualifier: +// Parameter: int fd connected socket +// Parameter: void * msg receive message buffer +// Parameter: uint32_t * len receive message length +//************************************ +int wemq_tcp_recv (int fd, void *msg, uint32_t * len, int iTimeOut, SSL * ssl) +{ + int iRet; + uint32_t uiRemain, uiRecved; + + if (NULL != ssl) + { + return wemq_ssl_recv (fd, msg, len, iTimeOut, ssl); + } + + uiRemain = 4; + uiRecved = 0; + if (fd < 0 || msg == NULL || len == NULL) + { + return -1; + } + if (iTimeOut <= 0) + { + iTimeOut = 1000; + } + while (uiRemain > 0) + { + int iRecv = 0; + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + + if (uiRecved != 4 || strcmp (msg, "WEMQ") != 0) + { + LOGRMB (RMB_LOG_ERROR, "recv msg header error,%u:%s", uiRecved, + (char *) msg); + return -3; + } + + uiRemain = 4; + uiRecved = 0; + if (fd < 0 || msg == NULL || len == NULL) + { + return -1; + } + if (iTimeOut <= 0) + { + iTimeOut = 1000; + } + while (uiRemain > 0) + { + int iRecv = 0; + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + //LOGRMB(RMB_LOG_DEBUG, "Recv version = %s\n", (char *)msg); + if (uiRecved != 4) + { + LOGRMB (RMB_LOG_ERROR, "recv msg version error,%u:%s", uiRecved, + (char *) msg); + return -3; + } + + // read msg length + uiRemain = 4; + uiRecved = 0; + while (uiRemain > 0) + { + int iRecv = 0; + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + + if (uiRecved != 4) + { + // can't read 4 bytes + LOGRMB (RMB_LOG_ERROR, "recv less than 4, recv %d bytes\n", uiRecved); + return -3; + } + + *len = ntohl (*(uint32_t *) msg); + + uiRemain = *len - 4; + while (uiRemain > 0) + { + int iRecv = 0; + iRet = check_recv (fd, iTimeOut / 1000, iTimeOut % 1000); + if (iRet == 0) + { + return 0; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "check_recv error, error=%d\n", errno); + return -2; + } + + iRecv = recv (fd, msg + uiRecved, uiRemain, 0); + if (iRecv < 0 && (errno != EAGAIN)) + { + LOGRMB (RMB_LOG_ERROR, "Recv error, fd close() error=%d, iRecv=%d\n", + errno, iRecv); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, "Peer close connect, fd close() errno=%d\n", + errno); + return -2; + } + if (iRet > 0) + { + uiRecved += iRecv; + uiRemain -= iRecv; + } + } + + if (uiRecved != *len) + { + // can't recv whole msg + return -3; + } + + return uiRecved; +} + +int wemq_tcp_close (int fd, SSL * ssl) +{ + if (NULL != ssl) + { + SSL_shutdown (ssl); + SSL_free (ssl); + } + if (fd >= 0) + { + close (fd); + } + + return 0; +} + +// 获取当前socket本地的IP和端口 +void wemq_getsockename (int fd, char *ip, uint32_t len, int *port) +{ + struct sockaddr_in guest; + socklen_t guest_len = sizeof (guest); + + if (fd <= 0 || port == NULL) + { + return; + } + if (getsockname (fd, (struct sockaddr *) &guest, (socklen_t *) & guest_len) + != 0) + { + return; + } + *port = ntohs (guest.sin_port); + if (ip != NULL && len > 0) + { + inet_ntop (AF_INET, &guest.sin_addr, ip, len); + } +} + +// 获取当前socket远端的IP和端口 +void wemq_getpeername (int fd, char *ip, uint32_t len, int *port) +{ + struct sockaddr_in svr; + socklen_t svr_len = sizeof (svr); + + if (fd <= 0 || port == NULL) + { + return; + } + if (getpeername (fd, (struct sockaddr *) &svr, (socklen_t *) & svr_len) != + 0) + { + return; + } + *port = ntohs (svr.sin_port); + if (ip != NULL && len > 0) + { + inet_ntop (AF_INET, &svr.sin_addr, ip, len); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/wemq_thread.c b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_thread.c new file mode 100644 index 0000000000..7ca2c9c638 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_thread.c @@ -0,0 +1,5467 @@ +// 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. + +#include +#include +#include +#include +#include "common.h" +#include "wemq_thread.h" +#include "rmb_common.h" +#include "rmb_errno.h" +#include "wemq_tcp.h" +#include "rmb_pub.h" +#include "rmb_sub.h" +#include "rmb_access_config.h" +#define MAX_EVENTS 100 +#define HEART_BEAT_COUNT 300 +#define HEART_BEAT_PERIOD 15 +#define CHECK_RR_EMPTY_PERIOD 10 + +static enum _wemq_message_ret +{ + WEMQ_MESSAGE_RET_ERR = -1, + WEMQ_MESSAGE_RET_GOODBYE = 88, + WEMQ_MESSAGE_RET_CLIENTGOODBYE = 881, + WEMQ_MESSAGE_RET_SERVERGOODBYE = 882, + WEMQ_MESSAGE_RET_REDIRECT = 300, +}; + +extern const char *vecManageTopic[10]; +unsigned long long ullNow = 0; +char *STATE_MAP[10] = { + "THREAD_STATE_INIT", + "THREAD_STATE_CONNECT", + "THREAD_STATE_REGI", + "THREAD_STATE_OK", + "THREAD_STATE_CLOSE", + "THREAD_STATE_SERVER_BREAK", + "THREAD_STATE_BREAK", + "THREAD_STATE_RECONNECT", + "THREAD_STATE_DESTORY", + "THREAD_STATE_EXIT" +}; + +char *_wemq_cmd_map[] = { + "", + "CMD_BEAT", + "CMD_REGI", + "CMD_ADD_LISTEN", + "CMD_SEND_MSG", + "CMD_SEND_MSG_ACK", + "CMD_ADD_MANAGE", + "CMD_SEND_REQUEST", + "CMD_SEND_REQUEST_ASYNC", + "CMD_SEND_REPLY", + "CMD_SEND_PUSH", + "CMD_SEND_START" +}; + +static int32_t _wemq_thread_do_send_sync (WemqThreadCtx * pThreadCtx, + void *msg, uint32_t totalLen, + uint32_t headerLen); + +/* +unsigned long long _wemq_thread_get_cur_time() +{ + struct timeval _curTimeVal; + gettimeofday(&_curTimeVal, NULL); + ullNow = (unsigned long)_curTimeVal.tv_sec * (unsigned long)1000UL + (unsigned long)_curTimeVal.tv_usec / 1000UL; + return ullNow; +} +*/ + +static int _wemq_get_executable_path (char *processdir, size_t len) +{ + char *path_end; + if (readlink ("/proc/self/exe", processdir, len) <= 0) + return -1; + path_end = strrchr (processdir, '/'); + if (path_end == NULL) + return -1; + return (int) (path_end - processdir); +} + +static const char *_wemq_thread_get_cmd (unsigned int usCmd) +{ + const char *pRet = NULL; +// if (usCmd <= 0x50) +// { +// pRet = _wemq_cmd_map[usCmd]; +// } +// else +// { +// pRet = "CMD_PUSH"; +// } + + switch (usCmd) + { + case THREAD_MSG_CMD_BEAT: + case THREAD_MSG_CMD_REGI: + case THREAD_MSG_CMD_ADD_LISTEN: + case THREAD_MSG_CMD_SEND_MSG: + case THREAD_MSG_CMD_SEND_MSG_ACK: + case THREAD_MSG_CMD_ADD_MANAGE: + case THREAD_MSG_CMD_SEND_REQUEST: + case THREAD_MSG_CMD_SEND_REQUEST_ASYNC: + case THREAD_MSG_CMD_SEND_REPLY: + case THREAD_MSG_CMD_START: + pRet = _wemq_cmd_map[usCmd]; + break; + + case THREAD_MSG_CMD_SEND_PUSH: + pRet = "CMD_PUSH"; + break; + + default: + pRet = "CMD_ERROR"; + } + + return pRet; +} + +static int32_t _wemq_thread_check_init (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_connect (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_regi (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_ok (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_close (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_reconnect (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_break (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +static int32_t _wemq_thread_check_destory (WemqThreadCtx * pThreadCtx) +{ + return 0; +} + +/** + * 心跳包: + * cmd:HEARTBEAT_REQUEST + * headerJson={"code":0,"seq":"0160616463","command":"HEARTBEAT_REQUEST"}|bodyJson=null + * + */ +static int32_t _wemq_thread_make_heart_beat_pkg (WemqThreadCtx * pThreadCtx) +{ + StWemqThreadMsg *pThreadMsg = &pThreadCtx->m_stHeartBeat; + memset (pThreadMsg, 0, sizeof (StWemqThreadMsg)); + pThreadMsg->m_iCmd = THREAD_MSG_CMD_BEAT; + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (HEARTBEAT_REQUEST)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + pThreadMsg->m_iHeaderLen = strlen (header_str); + + pThreadMsg->m_pHeader = + (char *) malloc (pThreadMsg->m_iHeaderLen * sizeof (char) + 1); + if (pThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for heart beat header failed"); + json_object_put (jsonHeader); + return -1; + } + memcpy (pThreadMsg->m_pHeader, header_str, pThreadMsg->m_iHeaderLen); + pThreadMsg->m_pHeader[pThreadMsg->m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + pThreadMsg->m_iBodyLen = 0; + pThreadMsg->m_pBody = NULL; + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] make heart beat pkg succ %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadMsg->m_pHeader); + return 0; +} + +/** + * 发送start listen命令: + * cmd:LISTEN_REQUEST + * headerJson={"code":0,"seq":"7542688344","command":"LISTEN_REQUEST"}|bodyJson=null + * + */ +static int32_t _wemq_thread_make_start_listen_pkg (WemqThreadCtx * pThreadCtx) +{ + StWemqThreadMsg *pThreadMsg = &pThreadCtx->m_stListen; + memset (pThreadMsg, 0, sizeof (StWemqThreadMsg)); + pThreadMsg->m_iCmd = THREAD_MSG_CMD_START; + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (LISTEN_REQUEST)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + pThreadMsg->m_iHeaderLen = strlen (header_str); + + pThreadMsg->m_pHeader = + (char *) malloc (pThreadMsg->m_iHeaderLen * sizeof (char) + 1); + if (pThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for listen header failed"); + json_object_put (jsonHeader); + return -1; + } + memcpy (pThreadMsg->m_pHeader, header_str, pThreadMsg->m_iHeaderLen); + pThreadMsg->m_pHeader[pThreadMsg->m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + pThreadMsg->m_iBodyLen = 0; + pThreadMsg->m_pBody = NULL; + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] make listen pkg succ %s", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadMsg->m_pHeader); + return 0; +} + +/** + * 发送SUBSCRIBE_REQUEST: + * cmd:SUBSCRIBE_REQUEST + * headerJson={"code":0,"seq":"1333580037","command":"SUBSCRIBE_REQUEST"}| + * bodyJson={"topicList":["PRX-e-10030002-05-3","PRX-e-10020002-02-2","PRX-s-10000002-01-0","PRX-e-10020002-06-2"]} + * + */ +static int32_t _wemq_thread_make_subscribe_pkg (WemqThreadCtx * pThreadCtx) +{ + StWemqThreadMsg *pThreadMsg = &pThreadCtx->m_stListen; + memset (pThreadMsg, 0, sizeof (StWemqThreadMsg)); + pThreadMsg->m_iCmd = THREAD_MSG_CMD_ADD_LISTEN; + WEMQJSON *jsonHeader = json_object_new_object (); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (LISTEN_REQUEST)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + pThreadMsg->m_iHeaderLen = strlen (header_str); + + pThreadMsg->m_pHeader = + (char *) malloc (pThreadMsg->m_iHeaderLen * sizeof (char) + 1); + if (pThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for listen header failed"); + json_object_put (jsonHeader); + return -1; + } + memcpy (pThreadMsg->m_pHeader, header_str, pThreadMsg->m_iHeaderLen); + pThreadMsg->m_pHeader[pThreadMsg->m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + pThreadMsg->m_iBodyLen = 0; + pThreadMsg->m_pBody = NULL; + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] make listen pkg succ %s", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadMsg->m_pHeader); + return 0; +} + +/** + * register package: + * cmd:THREAD_STATE_REGI + * headerJson={"code":0,"seq":"5160263626","command":"HELLO_REQUEST"} + * bodyJson={"subsystem":"5023","dcn":"AC0","path":"/data/app/umg_proxy","pid":32893,"host":"127.0.0.1", +* "port":8362,"version":"2.0.11","username":"PU4283","password":"dsaiubd"} + */ +static int32_t _wemq_thread_make_hello_pkg (WemqThreadCtx * pThreadCtx) +{ + StWemqThreadMsg *pThreadMsg = &pThreadCtx->m_stHelloWord; + memset (pThreadMsg, 0, sizeof (StWemqThreadMsg)); + pThreadMsg->m_iCmd = THREAD_STATE_REGI; + WEMQJSON *jsonHeader = json_object_new_object (); + + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (HELLO_REQUEST)); + + WEMQJSON *jsonBody = json_object_new_object (); + + json_object_object_add (jsonBody, "subsystem", + json_object_new_string (pRmbStConfig-> + cConsumerSysId)); + json_object_object_add (jsonBody, "dcn", + json_object_new_string (pRmbStConfig-> + cConsumerDcn)); + json_object_object_add (jsonBody, "host", + json_object_new_string (pRmbStConfig->cHostIp)); + json_object_object_add (jsonBody, "port", json_object_new_string ("")); + json_object_object_add (jsonBody, "version", + json_object_new_string (RMBVERSION)); + json_object_object_add (jsonBody, "username", + json_object_new_string (pRmbStConfig->cWemqUser)); + json_object_object_add (jsonBody, "password", + json_object_new_string (pRmbStConfig->cWemqPasswd)); + json_object_object_add (jsonBody, "idc", + json_object_new_string (pRmbStConfig->cRegion)); + json_object_object_add (jsonBody, "orgid", + json_object_new_string (pRmbStConfig->strOrgId)); + + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + json_object_object_add (jsonBody, "purpose", + json_object_new_string ("pub")); + else + json_object_object_add (jsonBody, "purpose", + json_object_new_string ("sub")); + + char processPath[1024]; + memset (processPath, 0x00, sizeof (processPath)); + _wemq_get_executable_path (processPath, 1024); + json_object_object_add (jsonBody, "path", + json_object_new_string (processPath)); + char pthread_id[32]; + snprintf (pthread_id, sizeof (pthread_id), "%u", pRmbStConfig->uiPid); + json_object_object_add (jsonBody, "pid", + json_object_new_string (pthread_id)); + + const char *header_str = json_object_get_string (jsonHeader); + const char *body_str = json_object_get_string (jsonBody); + + if (header_str == NULL) + { + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + if (body_str == NULL) + { + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + + pThreadMsg->m_iHeaderLen = strlen (header_str); + + pThreadMsg->m_pHeader = + (char *) malloc (pThreadMsg->m_iHeaderLen * sizeof (char) + 1); + if (pThreadMsg->m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for hello header failed"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + memcpy (pThreadMsg->m_pHeader, header_str, pThreadMsg->m_iHeaderLen); + pThreadMsg->m_pHeader[pThreadMsg->m_iHeaderLen] = '\0'; + + pThreadMsg->m_iBodyLen = strlen (body_str); + pThreadMsg->m_pBody = + (char *) malloc (pThreadMsg->m_iBodyLen * sizeof (char) + 1); + if (pThreadMsg->m_pBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for hello body failed"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + memcpy (pThreadMsg->m_pBody, body_str, pThreadMsg->m_iBodyLen); + pThreadMsg->m_pBody[pThreadMsg->m_iBodyLen] = '\0'; + + json_object_put (jsonBody); + json_object_put (jsonHeader); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] make hello pkg succ, header = %s, body = %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadMsg->m_pHeader, pThreadMsg->m_pBody); + return 0; +} + +static inline int32_t _wemq_thread_state_trans (WemqThreadCtx * pThreadCtx, + int iState, int iNextState) +{ + ASSERT (pThreadCtx); + + LOGRMB (RMB_LOG_INFO, "[%s] [Type:%d] [TID:%lu] Thread State Trans to [%s]", + STATE_MAP[iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, STATE_MAP[iNextState]); + + pThreadCtx->m_iState = iNextState; + pThreadCtx->m_iLastState = iState; + return 0; +} + +static int32_t _wemq_thread_set_fd_nonblock (WemqThreadCtx * pThreadCtx, + int fd) +{ + int opts; + opts = fcntl (fd, F_GETFL); + if (opts < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] set non block error:%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, errno); + return -1; + } + + opts = opts | O_NONBLOCK; + + if (fcntl (fd, F_SETFL, opts) < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] set non block error:%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, errno); + return -1; + } + return 0; +} + +static int32_t _wemq_thread_add_fd (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + pThreadCtx->m_stEv.events = EPOLLIN; + pThreadCtx->m_stEv.data.fd = pThreadCtx->m_iSockFd; + + LOGRMB (RMB_LOG_INFO, "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] fd:%d\n", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, pThreadCtx->m_iSockFd); + + int iRet = -1; + iRet = + epoll_ctl (pThreadCtx->m_iEpollFd, EPOLL_CTL_ADD, pThreadCtx->m_iSockFd, + &pThreadCtx->m_stEv); + if (iRet == -1) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] epoll ctl add error:%d\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, errno); + return -1; + } + + return 0; +} + +static int32_t _wemq_thread_del_fd (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + int iRet = -1; + iRet = + epoll_ctl (pThreadCtx->m_iEpollFd, EPOLL_CTL_DEL, pThreadCtx->m_iSockFd, + &pThreadCtx->m_stEv); + if (iRet == -1) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] epoll ctl del error: %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, errno); + return -1; + } + + return 0; +} + +static int32_t _wemq_thread_del_old_fd (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + int iRet = -1; + iRet = + epoll_ctl (pThreadCtx->m_iEpollFd, EPOLL_CTL_DEL, + pThreadCtx->m_iSockFdOld, &pThreadCtx->m_stEv); + if (iRet == -1) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] epoll ctl del error: %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, errno); + return -1; + } + + return 0; +} + +static int32_t _wemq_thread_reset_sockFd (WemqThreadCtx * pThreadCtx, + bool isRecvNewConnect) +{ + if (isRecvNewConnect) + { + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + pThreadCtx->m_iSockFdNew = -1; + pThreadCtx->sslNew = NULL; + + } + else + { + _wemq_thread_del_old_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFdOld, pThreadCtx->sslOld); + pThreadCtx->m_iSockFdOld = -1; + pThreadCtx->sslOld = NULL; + pThreadCtx->m_iSockFd = pThreadCtx->m_iSockFdNew; + pThreadCtx->ssl = pThreadCtx->sslNew; + } + + return 0; +} + +static inline void _wemq_thread_clear_thread_msg (StWemqThreadMsg * + pStWemqThreadMsg) +{ + if (NULL != pStWemqThreadMsg->m_pHeader) + { + free (pStWemqThreadMsg->m_pHeader); + pStWemqThreadMsg->m_pHeader = NULL; + } + if (NULL != pStWemqThreadMsg->m_pBody) + { + free (pStWemqThreadMsg->m_pBody); + pStWemqThreadMsg->m_pBody = NULL; + } + pStWemqThreadMsg->m_iCmd = 0; + pStWemqThreadMsg->m_iHeaderLen = 0; + pStWemqThreadMsg->m_iBodyLen = 0; +} + +static int32_t _wemq_thread_get_data_from_fifo (WemqThreadCtx * pThreadCtx) +{ + int32_t iRet = -1; + + if ((iRet = wemq_kfifo_is_empty (pThreadCtx->m_ptFifo))) + { + return 0; + } + if ((iRet = + wemq_kfifo_get (pThreadCtx->m_ptFifo, + &pThreadCtx->m_stWemqThreadMsg)) < 1) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] wemq_fifo is not empty, but get 0 bytes\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + return -1; + } + + ASSERT (iRet == 1); + pThreadCtx->m_iWemqThreadMsgHandled = 0; + return iRet; +} + +static int32_t _wemq_thread_dyed_msg_ack_to_access (WemqThreadCtx * + pThreadCtx, int seq, + int status, char *msgType, + StRmbMsg * ptSendMsg) +{ + char *buf = pThreadCtx->m_pSendBuff; + int iRet = -1; + WEMQJSON *jsonHeader = json_object_new_object (); + + // 组装消息 + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (msgType)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (seq)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (status)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + return -1; + } + int wemqMsgType = 0; + if (strcmp (msgType, REQUEST_TO_CLIENT) == 0 + || strcmp (msgType, ASYNC_MESSAGE_TO_CLIENT) + || strcmp (msgType, BROADCAST_MESSAGE_TO_CLIENT)) + { + wemqMsgType = THREAD_MSG_CMD_SEND_MSG_ACK; + } + else if (strcmp (msgType, RESPONSE_TO_CLIENT)) + { + wemqMsgType = THREAD_MSG_CMD_RECV_MSG_ACK; + } + + char cTopic[128]; + char serviceOrEvent = (*(ptSendMsg->strServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + ptSendMsg->strTargetDcn, serviceOrEvent, ptSendMsg->strServiceId, + ptSendMsg->strScenarioId, *(ptSendMsg->strServiceId + 3)); + json_object_object_add (jsonBody, MSG_BODY_TOPIC_STR, + json_object_new_string (cTopic)); + + WEMQJSON *jsonBodyProperty = + rmb_pub_encode_property_for_wemq (wemqMsgType, ptSendMsg); + if (jsonBodyProperty == NULL) + { + json_object_put (jsonHeader); + json_object_put (jsonBody); + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_property_for_wemq return null"); + return -1; + } + + json_object_object_add (jsonBody, MSG_BODY_PROPERTY_JSON, jsonBodyProperty); + + WEMQJSON *jsonByteBody = + rmb_pub_encode_byte_body_for_wemq (wemqMsgType, ptSendMsg); + if (jsonByteBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_byte_body_for_wemq return null"); + return -1; + } + const char *byteBodyStr = json_object_get_string (jsonByteBody); + + json_object_object_add (jsonBody, MSG_BODY_BYTE_BODY_JSON, + json_object_new_string (byteBodyStr)); + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + + return -1; + } + + int iHeaderLen = strlen (header_str); + int iBodyLen = strlen (body_str); + int iTotalLen = iHeaderLen + iBodyLen + 8; + + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, header_str, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, body_str, iBodyLen); +// json_object_put(jsonHeader); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send:header_str:%s body_str:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, header_str, + body_str); + json_object_put (jsonHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + iHeaderLen); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_resp_ack_to_access error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +static int32_t _wemq_thread_dyed_msg_reply_to_access (WemqThreadCtx * + pThreadCtx, int seq, + int status, + char *msgType, + StRmbMsg * ptSendMsg) +{ + char *buf = pThreadCtx->m_pSendBuff; + int iRet = -1; + WEMQJSON *jsonHeader = json_object_new_object (); + + // 组装消息 + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (msgType)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (seq)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (status)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + return -1; + } + char cTopic[128]; + char serviceOrEvent = (*(ptSendMsg->strServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + ptSendMsg->strTargetDcn, serviceOrEvent, ptSendMsg->strServiceId, + ptSendMsg->strScenarioId, *(ptSendMsg->strServiceId + 3)); + json_object_object_add (jsonBody, MSG_BODY_TOPIC_STR, + json_object_new_string (cTopic)); + + WEMQJSON *jsonBodyProperty = + rmb_pub_encode_property_for_wemq (THREAD_MSG_CMD_SEND_REPLY, ptSendMsg); + if (jsonBodyProperty == NULL) + { + json_object_put (jsonHeader); + json_object_put (jsonBody); + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_property_for_wemq return null"); + return -1; + } + + json_object_object_add (jsonBody, MSG_BODY_PROPERTY_JSON, jsonBodyProperty); + + WEMQJSON *jsonByteBody = + rmb_pub_encode_byte_body_for_wemq (THREAD_MSG_CMD_SEND_REPLY, ptSendMsg); + if (jsonByteBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_byte_body_for_wemq return null"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + return -1; + } + const char *byteBodyStr = json_object_get_string (jsonByteBody); + + json_object_object_add (jsonBody, MSG_BODY_BYTE_BODY_JSON, + json_object_new_string (byteBodyStr)); + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + + return -1; + } + + int iHeaderLen = strlen (header_str); + int iBodyLen = strlen (body_str); + int iTotalLen = iHeaderLen + iBodyLen + 8; + + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, header_str, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, body_str, iBodyLen); +// json_object_put(jsonHeader); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send:header_str:%s body_str:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, header_str, + body_str); + json_object_put (jsonHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + iHeaderLen); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_resp_ack_to_access error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +static int32_t _wemq_thread_resp_ack_to_access (WemqThreadCtx * pThreadCtx, + int seq, int status, + char *msgType, + StRmbMsg * ptSendMsg) +{ + char *buf = pThreadCtx->m_pSendBuff; + int iRet = -1; + WEMQJSON *jsonHeader = json_object_new_object (); + + // 组装消息 + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (msgType)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (seq)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (status)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + return -1; + } + char cTopic[128]; + char serviceOrEvent = (*(ptSendMsg->strServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + ptSendMsg->strTargetDcn, serviceOrEvent, ptSendMsg->strServiceId, + ptSendMsg->strScenarioId, *(ptSendMsg->strServiceId + 3)); + json_object_object_add (jsonBody, MSG_BODY_TOPIC_STR, + json_object_new_string (cTopic)); + + WEMQJSON *jsonBodyProperty = + rmb_pub_encode_property_for_wemq (THREAD_MSG_CMD_RECV_MSG_ACK, ptSendMsg); + if (jsonBodyProperty == NULL) + { + json_object_put (jsonHeader); + json_object_put (jsonBody); + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_property_for_wemq return null"); + return -1; + } + + json_object_object_add (jsonBody, MSG_BODY_PROPERTY_JSON, jsonBodyProperty); + + WEMQJSON *jsonByteBody = + rmb_pub_encode_byte_body_for_wemq (THREAD_MSG_CMD_RECV_MSG_ACK, + ptSendMsg); + if (jsonByteBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_byte_body_for_wemq return null"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + return -1; + } + const char *byteBodyStr = json_object_get_string (jsonByteBody); + + json_object_object_add (jsonBody, MSG_BODY_BYTE_BODY_JSON, + json_object_new_string (byteBodyStr)); + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + + return -1; + } + + int iHeaderLen = strlen (header_str); + int iBodyLen = strlen (body_str); + int iTotalLen = iHeaderLen + iBodyLen + 8; + + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, header_str, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, body_str, iBodyLen); +// json_object_put(jsonHeader); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send:header_str:%s body_str:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, header_str, + body_str); + json_object_put (jsonHeader); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + iHeaderLen); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_resp_ack_to_access error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +static int32_t _wemq_thread_send_error_log (WemqThreadCtx * pThreadCtx, + int seq, int errCode, + char *logPoint, char *errMsg, + StRmbMsg * ptSendMsg) +{ + char *buf = pThreadCtx->m_pSendBuff; + int iRet = -1; + WEMQJSON *jsonHeader = json_object_new_object (); + + // 组装消息 + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (TRACE_LOG_TO_LOGSERVER)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (seq)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (errCode)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + json_object_put (jsonHeader); + return -1; + } + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + json_object_put (jsonHeader); + return -1; + } + WEMQJSON *jsonMessage = json_object_new_object (); + if (jsonMessage == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object return null"); + json_object_put (jsonHeader); + json_object_put (jsonBody); + return -1; + } + char cTopic[128]; + char serviceOrEvent = (*(ptSendMsg->strServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + ptSendMsg->strTargetDcn, serviceOrEvent, ptSendMsg->strServiceId, + ptSendMsg->strScenarioId, *(ptSendMsg->strServiceId + 3)); + json_object_object_add (jsonMessage, MSG_BODY_TOPIC_STR, + json_object_new_string (cTopic)); + + WEMQJSON *jsonBodyProperty = + rmb_pub_encode_property_for_wemq (THREAD_MSG_CMD_RECV_MSG_ACK, ptSendMsg); + if (jsonBodyProperty == NULL) + { + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonBody); + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_property_for_wemq return null"); + return -1; + } + + json_object_object_add (jsonMessage, MSG_BODY_PROPERTY_JSON, + jsonBodyProperty); + + WEMQJSON *jsonByteBody = + rmb_pub_encode_byte_body_for_wemq (THREAD_MSG_CMD_RECV_MSG_ACK, + ptSendMsg); + if (jsonByteBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmb_pub_encode_byte_body_for_wemq return null"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonBody); + return -1; + } + const char *byteBodyStr = json_object_get_string (jsonByteBody); + + json_object_object_add (jsonMessage, MSG_BODY_BYTE_BODY_JSON, + json_object_new_string (byteBodyStr)); + + const char *message_str = json_object_get_string (jsonMessage); + if (message_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + + return -1; + } + + json_object_object_add (jsonBody, "retCode", json_object_new_int (errCode)); + json_object_object_add (jsonBody, "retMsg", + json_object_new_string (errMsg)); + json_object_object_add (jsonBody, "level", + json_object_new_string ("error")); + json_object_object_add (jsonBody, "logPoint", + json_object_new_string (logPoint)); + json_object_object_add (jsonBody, "model", + json_object_new_string ("model")); + json_object_object_add (jsonBody, "lang", json_object_new_string ("c")); + json_object_object_add (jsonBody, "message", + json_object_new_string (message_str)); + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "Get thread msg body failed\n"); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + + return -1; + } + + int iHeaderLen = strlen (header_str); + int iBodyLen = strlen (body_str); + int iTotalLen = iHeaderLen + iBodyLen + 8; + + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, header_str, iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, body_str, iBodyLen); +// json_object_put(jsonHeader); + + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Send:%s\n", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, body_str); + json_object_put (jsonHeader); + json_object_put (jsonMessage); + json_object_put (jsonByteBody); + json_object_put (jsonBody); + + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + iHeaderLen); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_send log error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +/** + * access to api + * headerJson={"code":0,"seq":"0160616463","command":"REDIRECT_TO_CLIENT"}|bodyJson={"ip":"10.255.34.118", "port":10000} + */ +static int32_t _wemq_thread_on_message_redirect (WemqThreadCtx * pThreadCtx, + char *jsonBody) +{ + WEMQJSON *jsonRedirect = NULL; + WEMQJSON *jsonTmp = NULL; + int ret = 0; + + pThreadCtx->m_cRedirectIP[0] = '\0'; + pThreadCtx->m_iRedirectPort = 0; + //json_object_object_get_ex(jsonHeader ,MSG_HEAD_REDIRECT_OBJ, &jsonRedirect); + jsonRedirect = json_tokener_parse (jsonBody); + if (jsonRedirect == NULL) + { + LOGRMB (RMB_LOG_ERROR, "get redirect from body failed"); + return WEMQ_MESSAGE_RET_ERR; + } + + json_object_object_get_ex (jsonRedirect, "ip", &jsonTmp); + if (jsonTmp != NULL) + { + const char *ip = json_object_get_string (jsonTmp); + if (ip != NULL) + { + snprintf (pThreadCtx->m_cRedirectIP, sizeof (pThreadCtx->m_cRedirectIP), + "%s", ip); + json_object_object_get_ex (jsonRedirect, "port", &jsonTmp); + if (jsonTmp != NULL) + { + pThreadCtx->m_iRedirectPort = json_object_get_int (jsonTmp); + if (pThreadCtx->m_iRedirectPort > 0) + { +// pThreadCtx->m_lRedirect = true; + pThreadCtx->m_lRedirect = 1; + ret = WEMQ_MESSAGE_RET_REDIRECT; + } + else + { + pThreadCtx->m_cRedirectIP[0] = '\0'; + pThreadCtx->m_iRedirectPort = 0; + } + } + else + { + pThreadCtx->m_cRedirectIP[0] = '\0'; + } + } + } + + json_object_put (jsonRedirect); + return ret; +} + +static int32_t _wemq_thread_on_message (WemqThreadCtx * pThreadCtx, + bool isRecvNewConnect) +{ + ASSERT (pThreadCtx); + + stContextProxy *pContextProxy = pThreadCtx->m_ptProxyContext; + StWeMQMSG *pWemqHeader = &pThreadCtx->m_stWeMQMSG; + WEMQJSON *jsonHeader = NULL; + WEMQJSON *jsonTmp = NULL; + const char *usCmd; + int serRet = -1; + int bodyLen = 0; + int seq = -1; + long time = 0; + int ret = 0; + char cMsg[RMB_MAX_ERR_MSG_FROM_ACCESS]; + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] |access2wemq_thread|Recv header:%s body:%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pWemqHeader->cStrJsonHeader, pWemqHeader->cStrJsonBody); + + bodyLen = pWemqHeader->uiTotalLen - pWemqHeader->uiHeaderLen - 8; + jsonHeader = json_tokener_parse (pWemqHeader->cStrJsonHeader); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] json_tokener_parse header error: %s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pWemqHeader->cStrJsonHeader) return -1; + } + //get command + json_object_object_get_ex (jsonHeader, MSG_HEAD_COMMAND_STR, &jsonTmp); + if (jsonTmp != NULL) + { + usCmd = json_object_get_string (jsonTmp); + } + //get code + json_object_object_get_ex (jsonHeader, MSG_HEAD_CODE_INT, &jsonTmp); + if (jsonTmp != NULL) + { + serRet = json_object_get_int (jsonTmp); + } + //get seq + json_object_object_get_ex (jsonHeader, MSG_HEAD_SEQ_INT, &jsonTmp); + if (jsonTmp != NULL) + { + seq = json_object_get_int (jsonTmp); + } + //get time + json_object_object_get_ex (jsonHeader, MSG_HEAD_TIME_LINT, &jsonTmp); + if (jsonTmp != NULL) + { + time = (long) json_object_get_int64 (jsonTmp); + } + memset (cMsg, 0x00, sizeof (cMsg)); + json_object_object_get_ex (jsonHeader, MSG_HEAD_MSG_STR, &jsonTmp); + if (jsonTmp != NULL) + { + strncpy (cMsg, json_object_get_string (jsonTmp), sizeof (cMsg) - 1); + } + if (strcmp (cMsg, "auth exception") == 0) + { // auth failed + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] Authentication error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + return -1; + } + if (serRet != RMB_CODE_SUSS) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Time:%ld] code from access !=0, cmd=%s, seq=%d, code=%d, msg=%s!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, time, usCmd, + seq, serRet, cMsg); + } + if (strcmp (usCmd, HEARTBEAT_RESPONSE) == 0) //心跳 + { + gettimeofday (&pThreadCtx->stTimeLastRecv, NULL); + pThreadCtx->m_uiHeartBeatCurrent = 0; + + } + else if (strcmp (usCmd, HELLO_RESPONSE) == 0) + { + ret = serRet; + + } + else if (strcmp (usCmd, CLIENT_GOODBYE_RESPONSE) == 0) + { + ret = WEMQ_MESSAGE_RET_CLIENTGOODBYE; + + } + else if (strcmp (usCmd, SERVER_GOODBYE_REQUEST) == 0) + { + ret = WEMQ_MESSAGE_RET_SERVERGOODBYE; + + } + else if (strcmp (usCmd, REDIRECT_TO_CLIENT) == 0) + { + ret = + _wemq_thread_on_message_redirect (pThreadCtx, + pWemqHeader->cStrJsonBody); + + } + else if (strcmp (usCmd, ASYNC_MESSAGE_TO_SERVER_ACK) == 0) //ack 单播 from access + { + if (serRet == RMB_CODE_SUSS) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] PublishAsyncMessage request success!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + LOGRMB (RMB_LOG_DEBUG, "seq for event: %d", + pContextProxy->iSeqForEvent); + pthread_mutex_lock (&pContextProxy->eventMutex); + if (seq == pContextProxy->iSeqForEvent) + { + pContextProxy->iFlagForEvent = serRet; + pthread_cond_signal (&pContextProxy->eventCond); + } + pthread_mutex_unlock (&pContextProxy->eventMutex); + } + else if (serRet == RMB_CODE_AUT_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] PublishAsyncMessage request Authentication fail!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + pthread_mutex_lock (&pContextProxy->eventMutex); + pContextProxy->iFlagForEvent = serRet; + pthread_cond_signal (&pContextProxy->eventCond); + pthread_mutex_unlock (&pContextProxy->eventMutex); + + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] PublishAsyncMessage request fail!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + pthread_mutex_lock (&pContextProxy->eventMutex); + pContextProxy->iFlagForEvent = serRet; + pthread_cond_signal (&pContextProxy->eventCond); + pthread_mutex_unlock (&pContextProxy->eventMutex); + + } + if (pContextProxy->iFlagForEvent == -1) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] send event msg signal succ! iFlagForEvent=%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time, + serRet); + + } + + } + else if (strcmp (usCmd, ASYNC_MESSAGE_TO_CLIENT) == 0) //recv event message from proxy + { + if (serRet == 0) + { + StContext *pStContext; + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pStContext = (StContext *) (pContextProxy->pubContext); + } + else + { + pStContext = (StContext *) (pContextProxy->subContext); + } + + if (pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStContext is null"); + + } + + int iRet = 0; + if ((iRet = + trans_json_2_rmb_msg (pStContext->pReceiveWemqMsg, + pWemqHeader->cStrJsonBody, + ASYNC_MESSAGE_TO_CLIENT)) != 0) + { + LOGRMB (RMB_LOG_ERROR, "trans_json_2_rmb_msg failed,buf is:%s", + pWemqHeader->cStrJsonBody); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "trans_json_2_rmb_msg failed", + pStContext->pReceiveWemqMsg); + return -1; + } + pStContext->pReceiveWemqMsg->iMsgMode = RMB_MSG_FROM_WEMQ; + pStContext->pReceiveWemqMsg->cPkgType = QUEUE_PKG; + + pStContext->uiWemqPkgLen = MAX_LENTH_IN_A_MSG; + + set_extfields_2_rmb_msg (pStContext->pReceiveWemqMsg, + ASYNC_MESSAGE_TO_CLIENT, seq); + + iRet = + shift_msg_2_buf (pStContext->pWemqPkg, &pStContext->uiWemqPkgLen, + pStContext->pReceiveWemqMsg); + //LOGRMB(RMB_LOG_DEBUG, "appHeaderLen:%d", pStContext->pReceiveWemqMsg->iAppHeaderLen); + + //LOGRMB(RMB_LOG_DEBUG, "uiWemqPkgLen:%d", pStContext->uiWemqPkgLen); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "shift_msg_2_buf error!iRet=%d, %d, %s/%s/%s,unique_id=%s,mode=%d,receive=%s", + iRet, pStContext->pReceiveWemqMsg->iEventOrService, + pStContext->pReceiveWemqMsg->strTargetDcn, + pStContext->pReceiveWemqMsg->strServiceId, + pStContext->pReceiveWemqMsg->strScenarioId, + pStContext->pReceiveWemqMsg->sysHeader.cUniqueId, + pStContext->pReceiveWemqMsg->iMsgMode, + rmb_msg_print (pStContext->pReceiveWemqMsg)); + + } + //染色消息直接返回 + if (check_dyed_msg (pStContext->pReceiveWemqMsg) > 0) + { + _wemq_thread_dyed_msg_ack_to_access (pThreadCtx, seq, 0, + ASYNC_MESSAGE_TO_CLIENT_ACK, + pStContext->pReceiveWemqMsg); + LOGRMB (RMB_LOG_DEBUG, "get dyed msg:%s", pWemqHeader->cStrJsonBody); + return serRet; + } + int iMqIndex = req_mq_index; + LOGRMB (RMB_LOG_DEBUG, "WEMQ_CMD_ASYNCEVENT_SUB:Ready to enqueue"); + + if (pRmbStConfig->iFlagForReq == (int) MSG_IPC_MQ) + { + //if (bodyLen >= pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize - C_RMB_MQ_PKG_HEAD_SIZE) + if (pStContext->uiWemqPkgLen >= + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize - + C_RMB_MQ_PKG_HEAD_SIZE) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] receive reqSize=%u bigger than shmSize=%u,discard", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pStContext->uiWemqPkgLen, + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "receive reqSize bigger than shmSize", + pStContext->pReceiveWemqMsg); + } + else + { + while ((iRet = + rmb_context_enqueue (pStContext, + (const enum RmbMqIndex) iMqIndex, + pStContext->pWemqPkg, + pStContext->uiWemqPkgLen)) == -2) + { + // LOG + LOGRMB (RMB_LOG_DEBUG, "[Type:%d] [TID:%lu] req queue full!wait!", + pThreadCtx->m_contextType, pThreadCtx->m_threadID); + usleep (1000); + } + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] req wemq_context_enqueue error!enqueue failed=%d!receive=%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "req wemq_context_enqueue error!enqueue failed", + pStContext->pReceiveWemqMsg); + return 0; + } + else + { + LOGRMB (RMB_LOG_DEBUG, "[Type:%d] [TID:%lu] Enqueue succ, msg %s", + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pWemqHeader->cStrJsonBody); + } + } + } + else + { + iRet = + sendto (pStContext->iSocketForReq, pStContext->pWemqPkg, + pStContext->uiWemqPkgLen, 0, + (const struct sockaddr *) &pStContext->tmpReqAddr, + sizeof (pStContext->tmpReqAddr)); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] sendto failed=%d,message is:%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + } + } + } + } + + else if (strcmp (usCmd, REQUEST_TO_CLIENT) == 0) //sub端收到RR请求消息 + { + if (serRet == 0) + { + StContext *pStContext; + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pStContext = (StContext *) (pContextProxy->pubContext); + } + else + { + pStContext = (StContext *) (pContextProxy->subContext); + } + + if (pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pStContext is null"); + } + + int iRet = 0; + if ((iRet = + trans_json_2_rmb_msg (pStContext->pReceiveWemqMsg, + pWemqHeader->cStrJsonBody, + REQUEST_TO_CLIENT)) != 0) + { + LOGRMB (RMB_LOG_ERROR, "trans_json_2_rmb_msg failed,buf is:%s", + pWemqHeader->cStrJsonBody); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "trans_json_2_rmb_msg failed", + pStContext->pReceiveWemqMsg); + return -1; + } + + pStContext->pReceiveWemqMsg->iMsgMode = RMB_MSG_FROM_WEMQ; + pStContext->pReceiveWemqMsg->cPkgType = QUEUE_PKG; + + pStContext->uiWemqPkgLen = MAX_LENTH_IN_A_MSG; + + set_extfields_2_rmb_msg (pStContext->pReceiveWemqMsg, REQUEST_TO_CLIENT, + seq); + + iRet = + shift_msg_2_buf (pStContext->pWemqPkg, &pStContext->uiWemqPkgLen, + pStContext->pReceiveWemqMsg); + //LOGRMB(RMB_LOG_DEBUG, "uiWemqPkgLen:%d", pStContext->uiWemqPkgLen); + + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "shift_msg_2_buf error!iRet=%d, %d, %s/%s/%s,unique_id=%s,mode=%d,receive=%s", + iRet, pStContext->pReceiveWemqMsg->iEventOrService, + pStContext->pReceiveWemqMsg->strTargetDcn, + pStContext->pReceiveWemqMsg->strServiceId, + pStContext->pReceiveWemqMsg->strScenarioId, + pStContext->pReceiveWemqMsg->sysHeader.cUniqueId, + pStContext->pReceiveWemqMsg->iMsgMode, + rmb_msg_print (pStContext->pReceiveWemqMsg)); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "shift_msg_2_buf failed", + pStContext->pReceiveWemqMsg); + return -1; + } + + int iMqIndex = req_mq_index; + //染色消息直接返回 + if (check_dyed_msg (pStContext->pReceiveWemqMsg) > 0) + { + LOGRMB (RMB_LOG_DEBUG, "get dyed msg:%s", pWemqHeader->cStrJsonBody); + _wemq_thread_dyed_msg_ack_to_access (pThreadCtx, seq, 0, + REQUEST_TO_CLIENT_ACK, + pStContext->pReceiveWemqMsg); + _wemq_thread_dyed_msg_reply_to_access (pThreadCtx, seq, 0, + RESPONSE_TO_SERVER, + pStContext->pReceiveWemqMsg); + return serRet; + } + LOGRMB (RMB_LOG_DEBUG, "WEMQ_CMD_SYNCREQ:Ready to en queue"); + + if (pRmbStConfig->iFlagForReq == (int) MSG_IPC_MQ) + { + //if (bodyLen >= pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize - C_RMB_MQ_PKG_HEAD_SIZE) + if (pStContext->uiWemqPkgLen >= + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize - + C_RMB_MQ_PKG_HEAD_SIZE) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] receive reqSize=%u bigger than shmSize=%u,discard", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pStContext->uiWemqPkgLen, + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "receive reqSize bigger than shmSize", + pStContext->pReceiveWemqMsg); + } + else + { + while ((iRet = + rmb_context_enqueue (pStContext, + (const enum RmbMqIndex) iMqIndex, + pStContext->pWemqPkg, + pStContext->uiWemqPkgLen)) == -2) + { + // LOG + LOGRMB (RMB_LOG_DEBUG, "[Type:%d] [TID:%lu] req queue full!wait!", + pThreadCtx->m_contextType, pThreadCtx->m_threadID); + usleep (1000); + } + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] req wemq_context_enqueue error!enqueue failed=%d!receive=%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "req wemq_context_enqueue error!enqueue failed", + pStContext->pReceiveWemqMsg); + } + else + { + LOGRMB (RMB_LOG_DEBUG, + "[Type:%d] [TID:%lu] Enqueue succ, msg: header %s body %s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pWemqHeader->cStrJsonHeader, pWemqHeader->cStrJsonBody); + } + } + } + else + { + iRet = + sendto (pStContext->iSocketForReq, pStContext->pWemqPkg, + pStContext->uiWemqPkgLen, 0, + (const struct sockaddr *) &pStContext->tmpReqAddr, + sizeof (pStContext->tmpReqAddr)); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] sendto failed=%d,message is:%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + } + } + } + } + else if (strcmp (usCmd, RESPONSE_TO_CLIENT) == 0) //rr请求端收到的回包 + { + if (serRet == 0) //rsp succ + { + WEMQJSON *jsonByteBody = NULL; + WEMQJSON *systemHeader = NULL; + WEMQJSON *sysExtFields = NULL; + WEMQJSON *jsonDecoder = NULL; + int rrType = 0; + WEMQJSON *jsonBody = json_tokener_parse (pWemqHeader->cStrJsonBody); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_tokener_parse failed!,buf is:%s", + pWemqHeader->cStrJsonBody); + return -1; + } + if (!json_object_object_get_ex + (jsonBody, MSG_BODY_BYTE_BODY_JSON, &jsonByteBody)) + { + LOGRMB (RMB_LOG_ERROR, "body json no byte body!"); + json_object_put (jsonBody); + return -1; + } //byte body json + + jsonByteBody = + json_tokener_parse (json_object_get_string (jsonByteBody)); + if (NULL == jsonByteBody + || !json_object_object_get_ex (jsonByteBody, + MSG_BODY_BYTE_BODY_SYSTEM_HEADER_CONTENT_JSON, + &systemHeader)) + { + LOGRMB (RMB_LOG_ERROR, "byte body json no system header content!"); + json_object_put (jsonBody); + if (NULL != jsonByteBody) + { + json_object_put (jsonByteBody); + } + return -1; + } //system header json + + systemHeader = + json_tokener_parse (json_object_get_string (systemHeader)); + if (json_object_object_get_ex + (systemHeader, MSG_BODY_SYSTEM_EXTFIELDS_STR, &sysExtFields)) + { + sysExtFields = + json_tokener_parse (json_object_get_string (sysExtFields)); + if (json_object_object_get_ex + (sysExtFields, MSG_BODY_SYSTEM_RRTYPE_INT, &jsonDecoder)) + { + rrType = json_object_get_int (jsonDecoder); + } + } //system extFields RRtype + if (0 == rrType) + { + if (bodyLen >= (TCP_BUF_SIZE * sizeof (char))) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] get rsp too long,bodyLen=%d,buf_le=%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, + time, bodyLen, TCP_BUF_SIZE); + } + int i = 0; + int recvFlag = 0; + pthread_mutex_lock (&pContextProxy->rrMutex); + if (pContextProxy->iFlagForRR == -1) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] signal succ! iFlagForRR=0", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, + time); + memcpy (pContextProxy->mPubRRBuf, pWemqHeader->cStrJsonBody, + bodyLen); + pContextProxy->mPubRRBuf[bodyLen] = '\0'; + trans_json_2_rmb_msg (pContextProxy->pReplyMsg, + pContextProxy->mPubRRBuf, RESPONSE_TO_CLIENT); + //LOGRMB(RMB_LOG_DEBUG, "destname :%s", pContextProxy->pReplyMsg->dest.cDestName); + GetRmbNowLongTime (); + pContextProxy->pReplyMsg->sysHeader.ulReplyReceiveTime = + pRmbStConfig->ulNowTtime; + set_extfields_2_rmb_msg (pContextProxy->pReplyMsg, + RESPONSE_TO_CLIENT, seq); + if (pContextProxy->stUnique.flag == 1 + && strcmp (pContextProxy->stUnique.unique_id, + pContextProxy->pReplyMsg->sysHeader.cUniqueId) == 0) + { + if (check_dyed_msg (pContextProxy->pReplyMsg) > 0) + { + LOGRMB (RMB_LOG_DEBUG, "get dyed msg:%s", + pContextProxy->mPubRRBuf); + pContextProxy->iFlagForRR = RMB_CODE_DYED_MSG; + } + else + { + pContextProxy->iFlagForRR = serRet; + } + pContextProxy->stUnique.flag = 0; + pthread_cond_signal (&pContextProxy->rrCond); + recvFlag = 1; + + } + } + pthread_mutex_unlock (&pContextProxy->rrMutex); + if (recvFlag == 1) + { + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, 0, + RESPONSE_TO_CLIENT_ACK, + pContextProxy->pReplyMsg); + //_wemq_thread_send_error_log(pThreadCtx, seq, 0, "ok", pContextProxy->pReplyMsg); + } + } + else //case WEMQ_CMD_ASYNCRSP RR异步消息,服务请求方收到回包 + { + StContext *pStContext = (StContext *) (pContextProxy->subContext); + pContextProxy->iFlagForRRAsync = 0; + if (pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "[TID:%lu] pStContext is null", + pThreadCtx->m_threadID); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + if (NULL != systemHeader) + { + json_object_put (systemHeader); + } + if (NULL != sysExtFields) + { + json_object_put (sysExtFields); + } + return -1; + } + + int iRet = 0; + + if ((iRet = + trans_json_2_rmb_msg (pStContext->pReceiveWemqMsgForRR, + pWemqHeader->cStrJsonBody, + RESPONSE_TO_CLIENT)) != 0) + { + LOGRMB (RMB_LOG_ERROR, "trans_json_2_rmb_msg failed,buf is:%s", + pWemqHeader->cStrJsonBody); + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, -1, + RESPONSE_TO_CLIENT_ACK, + pStContext->pReceiveWemqMsgForRR); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "trans_json_2_rmb_msg failed", + pStContext->pReceiveWemqMsgForRR); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + if (NULL != systemHeader) + { + json_object_put (systemHeader); + } + if (NULL != sysExtFields) + { + json_object_put (sysExtFields); + } + return -1; + } + GetRmbNowLongTime (); + pStContext->pReceiveWemqMsgForRR->sysHeader.ulReplyReceiveTime = + pRmbStConfig->ulNowTtime; + int i; + set_extfields_2_rmb_msg (pStContext->pReceiveWemqMsgForRR, + RESPONSE_TO_CLIENT, seq); + int recvFlag = 0; + pthread_mutex_lock (&pContextProxy->rrMutex); + //因为在access goodbye的时候,消息可能在旧连接上,所以必须同时扫描新旧连接,不能只扫描新连接 + + //if(isRecvNewConnect) + //{ + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncNew. + get_array_size (&pContextProxy->pUniqueListForRRAsyncNew); i++) + { + if (pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag == 1 + && strcmp (pContextProxy->pUniqueListForRRAsyncNew.Data[i]. + unique_id, + pStContext->pReceiveWemqMsgForRR->sysHeader. + cUniqueId) == 0) + { + pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag = 0; + recvFlag = 1; + break; + } + } + // }else + // { + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncOld. + get_array_size (&pContextProxy->pUniqueListForRRAsyncOld); i++) + { + if (pContextProxy->pUniqueListForRRAsyncOld.Data[i].flag == 1 + && strcmp (pContextProxy->pUniqueListForRRAsyncOld.Data[i]. + unique_id, + pStContext->pReceiveWemqMsgForRR->sysHeader. + cUniqueId) == 0) + { + pContextProxy->pUniqueListForRRAsyncOld.Data[i].flag = 0; + recvFlag = 1; + break; + } + } + pthread_mutex_unlock (&pContextProxy->rrMutex); + //} + //已经超时,不回包给pub端 + if (recvFlag == 0) + { + LOGRMB (RMB_LOG_WARN, + "rr async response bizseq=%s, uniqueId=%s comes back, but request has timeout", + pStContext->pReceiveWemqMsgForRR->sysHeader.cBizSeqNo, + pStContext->pReceiveWemqMsgForRR->sysHeader.cUniqueId); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + if (NULL != systemHeader) + { + json_object_put (systemHeader); + } + if (NULL != sysExtFields) + { + json_object_put (sysExtFields); + } + return -1; + } + + pStContext->pReceiveWemqMsgForRR->cPkgType = RR_TOPIC_PKG; + pStContext->pReceiveWemqMsgForRR->iMsgMode = RMB_MSG_FROM_WEMQ; + pStContext->uiWemqPkgForRRAsyncLen = MAX_LENTH_IN_A_MSG; + iRet = + shift_msg_2_buf (pStContext->pWemqPkgForRRAsync, + &pStContext->uiWemqPkgForRRAsyncLen, + pStContext->pReceiveWemqMsgForRR); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "shift_msg_2_buf error!iRet=%d, %d, %s/%s/%s,unique_id=%s,mode=%d,receive=%s", + iRet, pStContext->pReceiveWemqMsgForRR->iEventOrService, + pStContext->pReceiveWemqMsgForRR->strTargetDcn, + pStContext->pReceiveWemqMsgForRR->strServiceId, + pStContext->pReceiveWemqMsgForRR->strScenarioId, + pStContext->pReceiveWemqMsgForRR->sysHeader.cUniqueId, + pStContext->pReceiveWemqMsgForRR->iMsgMode, + rmb_msg_print (pStContext->pReceiveWemqMsgForRR)); + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, -1, + RESPONSE_TO_CLIENT_ACK, + pStContext->pReceiveWemqMsgForRR); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "shift_msg_2_buf error", + pStContext->pReceiveWemqMsgForRR); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + if (NULL != systemHeader) + { + json_object_put (systemHeader); + } + if (NULL != sysExtFields) + { + json_object_put (sysExtFields); + } + return -1; + } + if (check_dyed_msg (pStContext->pReceiveWemqMsgForRR) > 0) + { + LOGRMB (RMB_LOG_DEBUG, "get dyed msg:%s", + pWemqHeader->cStrJsonBody); + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, 0, + RESPONSE_TO_CLIENT_ACK, + pStContext->pReceiveWemqMsgForRR); + json_object_put (jsonBody); + json_object_put (jsonByteBody); + if (NULL != systemHeader) + { + json_object_put (systemHeader); + } + if (NULL != sysExtFields) + { + json_object_put (sysExtFields); + } + return serRet; + } + + int iMqIndex = rr_rsp_mq_index; + LOGRMB (RMB_LOG_DEBUG, + "WEMQ_CMD_ASYNCRSP:Recv rr rsp Ready to en queue"); + if (pRmbStConfig->iFlagForRRrsp == (int) MSG_IPC_MQ) + { + if (pStContext->uiWemqPkgForRRAsyncLen >= + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize - + C_RMB_MQ_PKG_HEAD_SIZE) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] receive reqSize=%u bigger than shmSize=%u,discard", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pStContext->uiWemqPkgForRRAsyncLen, + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize); + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, -1, + RESPONSE_TO_CLIENT_ACK, + pStContext-> + pReceiveWemqMsgForRR); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "receive msg bigger than shmSize", + pStContext->pReceiveWemqMsgForRR); + } + else + { + while ((iRet = + rmb_context_enqueue (pStContext, + (const enum RmbMqIndex) iMqIndex, + pStContext->pWemqPkgForRRAsync, + pStContext-> + uiWemqPkgForRRAsyncLen)) == -2) + { + // LOG + LOGRMB (RMB_LOG_DEBUG, + "[Type:%d] [TID:%lu] req queue full!wait!", + pThreadCtx->m_contextType, pThreadCtx->m_threadID); + usleep (1000); + } + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] req wemq_context_enqueue error!enqueue failed=%d!receive=%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, -1, + RESPONSE_TO_CLIENT_ACK, + pStContext-> + pReceiveWemqMsgForRR); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, + LOG_ERROR_POINT, + "req wemq_context_enqueue error", + pStContext->pReceiveWemqMsgForRR); + } + else + { + LOGRMB (RMB_LOG_DEBUG, + "[Type:%d] [TID:%lu] Enqueue succ, msg: header %s body %s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pWemqHeader->cStrJsonHeader, pWemqHeader->cStrJsonBody); + _wemq_thread_resp_ack_to_access (pThreadCtx, seq, 0, + RESPONSE_TO_CLIENT_ACK, + pStContext-> + pReceiveWemqMsgForRR); + } + } + } + else + { + iRet = + sendto (pStContext->iSocketForRsp, pStContext->pWemqPkgForRRAsync, + pStContext->uiWemqPkgForRRAsyncLen, 0, + (const struct sockaddr *) &pStContext->tmpReplyAddr, + sizeof (pStContext->tmpReplyAddr)); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] sendto failed=%d,message is:%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + } + } + } + json_object_put (jsonByteBody); + json_object_put (jsonBody); + if (NULL != systemHeader) + { + json_object_put (systemHeader); + } + if (NULL != sysExtFields) + { + json_object_put (sysExtFields); + } + } + else if (serRet == RMB_CODE_AUT_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] rr request ret Authentication fail", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + pthread_mutex_lock (&pContextProxy->rrMutex); + pContextProxy->iFlagForRR = serRet; + pContextProxy->stUnique.flag = 0; + pthread_cond_signal (&pContextProxy->rrCond); + pthread_mutex_unlock (&pContextProxy->rrMutex); + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] rr request ret fail", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + pthread_mutex_lock (&pContextProxy->rrMutex); + pContextProxy->iFlagForRR = serRet; + pContextProxy->stUnique.flag = 0; + pthread_cond_signal (&pContextProxy->rrCond); + pthread_mutex_unlock (&pContextProxy->rrMutex); + } + } + else if (strcmp (usCmd, BROADCAST_MESSAGE_TO_SERVER_ACK) == 0) //收到广播消息的ack + { + if (serRet == RMB_CODE_SUSS) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] Publish Broadcast Message request success", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + } + else if (serRet == RMB_CODE_AUT_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] Publish Broadcast Message request Authentication fail!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] Publish Broadcast Message request failed!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + } + + pthread_mutex_lock (&pContextProxy->eventMutex); + if (pContextProxy->iFlagForEvent == -1) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] send Broadcast msg signal succ! iFlagForEvent=%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time, + serRet); + LOGRMB (RMB_LOG_DEBUG, "seq for Broadcast: %d", + pContextProxy->iSeqForEvent); + if (seq == pContextProxy->iSeqForEvent) + { + pContextProxy->iFlagForEvent = serRet; + pthread_cond_signal (&pContextProxy->eventCond); + } + } + pthread_mutex_unlock (&pContextProxy->eventMutex); + } + + else if (strcmp (usCmd, BROADCAST_MESSAGE_TO_CLIENT) == 0) //收到广播消息 + { + if (serRet == 0) + { + StContext *pStContext = NULL; + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pStContext = (StContext *) (pContextProxy->pubContext); + } + else + { + pStContext = (StContext *) (pContextProxy->subContext); + } + + if (pStContext == NULL) + { + LOGRMB (RMB_LOG_ERROR, "[TID:%lu] pStContext is null", + pThreadCtx->m_threadID); + return -1; + } + + int iRet = 0; + + if ((iRet = + trans_json_2_rmb_msg (pStContext->pReceiveWemqMsgForBroadCast, + pWemqHeader->cStrJsonBody, + BROADCAST_MESSAGE_TO_CLIENT)) != 0) + { + LOGRMB (RMB_LOG_ERROR, "trans_json_2_rmb_msg failed,buf is:%s", + pWemqHeader->cStrJsonBody); + return -1; + } + + pStContext->pReceiveWemqMsgForBroadCast->cPkgType = BROADCAST_TOPIC_PKG; + pStContext->pReceiveWemqMsgForBroadCast->iMsgMode = RMB_MSG_FROM_WEMQ; + pStContext->uiWemqPkgLen = MAX_LENTH_IN_A_MSG; + + set_extfields_2_rmb_msg (pStContext->pReceiveWemqMsgForBroadCast, + BROADCAST_MESSAGE_TO_CLIENT, seq); + + iRet = + shift_msg_2_buf (pStContext->pWemqPkg, &pStContext->uiWemqPkgLen, + pStContext->pReceiveWemqMsgForBroadCast); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "shift_msg_2_buf error!iRet=%d, %d, %s/%s/%s,unique_id=%s,mode=%d,receive=%s", + iRet, + pStContext->pReceiveWemqMsgForBroadCast->iEventOrService, + pStContext->pReceiveWemqMsgForBroadCast->strTargetDcn, + pStContext->pReceiveWemqMsgForBroadCast->strServiceId, + pStContext->pReceiveWemqMsgForBroadCast->strScenarioId, + pStContext->pReceiveWemqMsgForBroadCast->sysHeader.cUniqueId, + pStContext->pReceiveWemqMsgForBroadCast->iMsgMode, + rmb_msg_print (pStContext->pReceiveWemqMsgForBroadCast)); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "shift_msg_2_buf error", + pStContext->pReceiveWemqMsgForBroadCast); + + return -1; + } + //染色消息直接返回 + if (check_dyed_msg (pStContext->pReceiveWemqMsgForBroadCast) > 0) + { + _wemq_thread_dyed_msg_ack_to_access (pThreadCtx, seq, 0, + BROADCAST_MESSAGE_TO_CLIENT_ACK, + pStContext->pReceiveWemqMsg); + LOGRMB (RMB_LOG_DEBUG, "get dyed msg:%s", pWemqHeader->cStrJsonBody); + return serRet; + } + + int iMqIndex = broadcast_mq_index; + LOGRMB (RMB_LOG_DEBUG, + "WEMQ_CMD_BROADCAST_SUB:Recv broadcast message ready to enqueue"); + if (pRmbStConfig->iFlagForBroadCast == (int) MSG_IPC_MQ) + { + if (pStContext->uiWemqPkgLen >= + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize - + C_RMB_MQ_PKG_HEAD_SIZE) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] receive broadcast message reqSize=%u bigger than shmSize=%u,discard", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pStContext->uiWemqPkgLen, + pStContext->fifoMq.mqIndex[iMqIndex]->mq->uiBlockSize); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "receive broadcast message reqSize bigger than shmSize", + pStContext-> + pReceiveWemqMsgForBroadCast); + } + else + { + while ((iRet = + rmb_context_enqueue (pStContext, + (const enum RmbMqIndex) iMqIndex, + pStContext->pWemqPkg, + pStContext->uiWemqPkgLen)) == -2) + { + //queue full + LOGRMB (RMB_LOG_ERROR, "[Type:%d] [TID:%lu] req queue full!wait!", + pThreadCtx->m_contextType, pThreadCtx->m_threadID); + usleep (1000); + } + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] req rmb_context_enqueue error!iRet=%d!receive=%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + _wemq_thread_send_error_log (pThreadCtx, seq, -1, LOG_ERROR_POINT, + "req rmb_context_enqueue error", + pStContext-> + pReceiveWemqMsgForBroadCast); + } + else + { + LOGRMB (RMB_LOG_DEBUG, + "[Type:%d] [TID:%lu] enqueue succ, msg: header %s body %s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pWemqHeader->cStrJsonHeader, pWemqHeader->cStrJsonBody); + } + } + } + else + { + iRet = + sendto (pStContext->iSocketForBroadcast, pStContext->pWemqPkg, + pStContext->uiWemqPkgLen, 0, + (const struct sockaddr *) &pStContext->tmpBroadcastAddr, + sizeof (pStContext->tmpBroadcastAddr)); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] udp error!sendto failed=%d!receive message:%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRet, + pWemqHeader->cStrJsonBody); + } + } + } + } + else if (strcmp (usCmd, SUBSCRIBE_RESPONSE) == 0) // add subscribe response + { + if (serRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] add listen return failed, iRet=%d, errmsg=%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, serRet, cMsg); + } + + pthread_mutex_lock (&pContextProxy->regMutex); + if (pContextProxy->iFlagForReg == 0) + { + pContextProxy->iFlagForReg = 1; + pContextProxy->iResultForReg = serRet; + pthread_cond_signal (&pContextProxy->regCond); + } + pthread_mutex_unlock (&pContextProxy->regMutex); + } + else if (strcmp (usCmd, LISTEN_RESPONSE) == 0) // add listen start response + { + + if (serRet == RMB_CODE_OTHER_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] send start to access failed,iRet=%d, errmsg=%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, serRet, cMsg); + } + + if (serRet == RMB_CODE_AUT_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] send start to access authentication failed,iRet=%d, errmsg=%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, serRet, cMsg); + } + + pthread_mutex_lock (&pContextProxy->regMutex); + if (pContextProxy->iFlagForReg == 0) + { + pContextProxy->iFlagForReg = 1; + pContextProxy->iResultForReg = serRet; + pthread_cond_signal (&pContextProxy->regCond); + } + pthread_mutex_unlock (&pContextProxy->regMutex); + + } + + else + { + LOGRMB (RMB_LOG_ERROR, "[%s] [Type:%d] [TID:%lu] No Such Command:%s!", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, usCmd); + ret = -1; + } + + json_object_put (jsonHeader); + + return ret; +} + +static int32_t _wemq_thread_do_recv_sync (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + int timeout = pRmbStConfig->iWemqTcpSocketTimeout; + + unsigned int uiTimeOutTimes = 0; + unsigned int uiClosedByPeerTimes = 0; + while (1) + { + uint32_t iRecvLen; + int iRet = + wemq_tcp_recv (pThreadCtx->m_iSockFd, pThreadCtx->m_pRecvBuff, + &iRecvLen, timeout, pThreadCtx->ssl); + if (iRet == 0) + { + uiTimeOutTimes += 1; + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] TCP recv timeout!timeout_times=%u, fd=%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + uiTimeOutTimes, pThreadCtx->m_iSockFd); + if (uiTimeOutTimes >= 12) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] TCP continuity recv timeout times=%d, so close connect", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + uiTimeOutTimes); + uiTimeOutTimes = 0; + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + wemq_proxy_to_black_list (pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + return -2; + } + continue; + } + else if (iRet == -2) + { + uiClosedByPeerTimes += 1; + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] TCP conncet closed by peer(%d)", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, errno); + if (uiClosedByPeerTimes >= 3) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] TCP conncet continuity closed by peer times=%d, so close connect", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + uiClosedByPeerTimes); + uiClosedByPeerTimes = 0; + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + wemq_proxy_to_black_list (pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + return -2; + } + continue; + } + else if (iRet == -3) + { + // msg is not full + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] msg is not full", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + + return 1; + } + else if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] wemq_tcp_recv error", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return -1; + } + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] recv complete len %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, iRet); + + //memset(&pThreadCtx->m_stWeMQMSG, 0, sizeof(pThreadCtx->m_stWeMQMSG)); + memset (&pThreadCtx->m_stWeMQMSG, 0, (sizeof (int) * 2)); + DecodeWeMQMsg (&pThreadCtx->m_stWeMQMSG, pThreadCtx->m_pRecvBuff, iRet); + if (pThreadCtx->m_stWeMQMSG.uiHeaderLen == 0 + || pThreadCtx->m_stWeMQMSG.uiHeaderLen >= MAX_WEMQ_HEADER_LEN) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] recv header len %u is 0 or too long", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pThreadCtx->m_stWeMQMSG.uiHeaderLen); + return -1; + } + if (pThreadCtx->m_stWeMQMSG.uiHeaderLen > 0) + { + memcpy (pThreadCtx->m_stWeMQMSG.cStrJsonHeader, + pThreadCtx->m_pRecvBuff + 8, + pThreadCtx->m_stWeMQMSG.uiHeaderLen); + pThreadCtx->m_stWeMQMSG.cStrJsonHeader[pThreadCtx->m_stWeMQMSG. + uiHeaderLen] = '\0'; + } + unsigned int uiTmpBodyLen = + pThreadCtx->m_stWeMQMSG.uiTotalLen - + pThreadCtx->m_stWeMQMSG.uiHeaderLen - 8; + if (uiTmpBodyLen >= MAX_WEMQ_BODY_LEN) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] recv body len %d is too long", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + uiTmpBodyLen); + return -1; + } + if (uiTmpBodyLen == 0) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] recv body len is 0", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + } + //if (pThreadCtx->m_stWeMQMSG.uiTotalLen - pThreadCtx->m_stWeMQMSG.uiHeaderLen - 8 > 0) + if (uiTmpBodyLen > 0) + { + memcpy (pThreadCtx->m_stWeMQMSG.cStrJsonBody, + pThreadCtx->m_pRecvBuff + 8 + + pThreadCtx->m_stWeMQMSG.uiHeaderLen, + pThreadCtx->m_stWeMQMSG.uiTotalLen - + pThreadCtx->m_stWeMQMSG.uiHeaderLen - 8); + pThreadCtx->m_stWeMQMSG.cStrJsonBody[uiTmpBodyLen] = '\0'; + } + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq Header complete,total len %d, header len %d,header %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_stWeMQMSG.uiTotalLen, + pThreadCtx->m_stWeMQMSG.uiHeaderLen, + pThreadCtx->m_stWeMQMSG.cStrJsonHeader); + return 0; + } + return -1; +} + +static int32_t _wemq_thread_do_recv_async (WemqThreadCtx * pThreadCtx, + bool isRecvNewConnect) +{ + ASSERT (pThreadCtx); + + int nfds = + epoll_wait (pThreadCtx->m_iEpollFd, pThreadCtx->m_ptEvents, MAX_EVENTS, + 1); + if (nfds == -1) + { + LOGRMB (RMB_LOG_ERROR, "[%s] [Type:%d] [TID:%lu] epoll wait error:%d!", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, errno); + return -1; + } + if (nfds == 0) + { + return 0; + } + + unsigned long ulLastTime = 0; + unsigned long ulNowTime = 0; + struct timeval tv; + + int iTmp = 0; + int iRecvd = 0; + int iRemind = TCP_PKG_LEN_BTYES; + + for (iTmp = 0; iTmp < nfds; ++iTmp) + { + // 必须在此判断,如果新旧连接都有消息过来,后面会把当前fd改成新连接的fd,导致下次循环又会重新处理 + if (!isRecvNewConnect) + { + pThreadCtx->m_iSockFdNew = pThreadCtx->m_iSockFd; + pThreadCtx->sslNew = pThreadCtx->ssl; + pThreadCtx->m_iSockFd = pThreadCtx->m_iSockFdOld; + pThreadCtx->ssl = pThreadCtx->sslOld; + } + + if (pThreadCtx->m_ptEvents[iTmp].data.fd == pThreadCtx->m_iSockFd) + { + if (EPOLLIN == (pThreadCtx->m_ptEvents[iTmp].events & EPOLLIN)) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] EPOLLIN EVENT", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + gettimeofday (&tv, NULL); + ulLastTime = tv.tv_sec * 1000000 + tv.tv_usec; + ulNowTime = ulLastTime; + while (iRemind > 0) + { + int iRecv; + if (NULL != pThreadCtx->ssl) + { + iRecv = + SSL_read (pThreadCtx->ssl, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind); + } + else + { + iRecv = + recv (pThreadCtx->m_iSockFd, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind, 0); + } + //if (iRecv < 0 && (errno != EAGAIN)) + if (iRecv < 0) + { + if (errno == EAGAIN) + { + gettimeofday (&tv, NULL); + ulNowTime = tv.tv_sec * 1000000 + tv.tv_usec; + if ((ulNowTime - ulLastTime) > (1 * 60 * 1000000)) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + usleep (100); + continue; + } + + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Peer close connect, fd close() ret=%d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, iRecv); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv > 0) + { + iRecvd += iRecv; + iRemind -= iRecv; + } + } + + if (iRecvd != 4 || strcmp (pThreadCtx->m_pRecvBuff, "WEMQ") != 0) + { + if (!isRecvNewConnect) + { + LOGRMB (RMB_LOG_ERROR, "IP: [old proxy ip:%s|old port:%d]", + pThreadCtx->m_cProxyIPOld, pThreadCtx->m_uiProxyPortOld); + } + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%d] recv header error, buf: %s, len: %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pThreadCtx->m_pRecvBuff, iRecvd); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + gettimeofday (&tv, NULL); + ulLastTime = tv.tv_sec * 1000000 + tv.tv_usec; + ulNowTime = ulLastTime; + iRecvd = 0; + iRemind = TCP_PKG_LEN_BTYES; + while (iRemind > 0) + { + int iRecv; + if (NULL != pThreadCtx->ssl) + { + iRecv = + SSL_read (pThreadCtx->ssl, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind); + } + else + { + iRecv = + recv (pThreadCtx->m_iSockFd, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind, 0); + } + //if (iRecv < 0 && (errno != EAGAIN)) + if (iRecv < 0) + { + if (errno == EAGAIN) + { + gettimeofday (&tv, NULL); + ulNowTime = tv.tv_sec * 1000000 + tv.tv_usec; + if ((ulNowTime - ulLastTime) > (1 * 60 * 1000000)) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + usleep (100); + continue; + } + + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Peer close connect, fd close() ret=%d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, iRecv); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv > 0) + { + iRecvd += iRecv; + iRemind -= iRecv; + } + } + + if (iRecvd != 4) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%d] recv version error, version=%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pThreadCtx->m_pRecvBuff); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + gettimeofday (&tv, NULL); + ulLastTime = tv.tv_sec * 1000000 + tv.tv_usec; + ulNowTime = ulLastTime; + + iRecvd = 0; + iRemind = TCP_PKG_LEN_BTYES; + while (iRemind > 0) + { + int iRecv; + if (NULL != pThreadCtx->ssl) + { + iRecv = + SSL_read (pThreadCtx->ssl, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind); + } + else + { + iRecv = + recv (pThreadCtx->m_iSockFd, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind, 0); + } + //if (iRecv < 0 && (errno != EAGAIN)) + if (iRecv < 0) + { + if (errno == EAGAIN) + { + gettimeofday (&tv, NULL); + ulNowTime = tv.tv_sec * 1000000 + tv.tv_usec; + if ((ulNowTime - ulLastTime) > (1 * 60 * 1000000)) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + usleep (100); + continue; + } + + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Peer close connect, fd close() ret=%d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, iRecv); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv > 0) + { + iRecvd += iRecv; + iRemind -= iRecv; + } + } + //ASSERT (iRemind == 0); + if (iRemind != 0 || iRecvd != TCP_PKG_LEN_BTYES) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] get msg length failed", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + gettimeofday (&tv, NULL); + ulLastTime = tv.tv_sec * 1000000 + tv.tv_usec; + ulNowTime = ulLastTime; + + iRemind = ntohl (*(uint32_t *) pThreadCtx->m_pRecvBuff); + iRemind -= TCP_PKG_LEN_BTYES; + while (iRemind > 0) + { + int iRecv; + if (NULL != pThreadCtx->ssl) + { + iRecv = + SSL_read (pThreadCtx->ssl, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind); + } + else + { + iRecv = + recv (pThreadCtx->m_iSockFd, pThreadCtx->m_pRecvBuff + iRecvd, + iRemind, 0); + } + //if (iRecv < 0 && (errno != EAGAIN)) + if (iRecv < 0) + { + if (errno == EAGAIN) + { + gettimeofday (&tv, NULL); + ulNowTime = tv.tv_sec * 1000000 + tv.tv_usec; + if ((ulNowTime - ulLastTime) > (1 * 60 * 1000000)) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + usleep (100); + continue; + } + + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv return < 0, errno %d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, errno); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + + if (iRecv == 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Peer close connect, fd close() ret=%d", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, iRecv); + _wemq_thread_reset_sockFd (pThreadCtx, isRecvNewConnect); + return -2; + } + if (iRecv > 0) + { + iRecvd += iRecv; + iRemind -= iRecv; + } + } + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] recv complete len %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, iRecvd); + if (!isRecvNewConnect) + { + pThreadCtx->m_iSockFd = pThreadCtx->m_iSockFdNew; + pThreadCtx->ssl = pThreadCtx->sslNew; + } + //memset(&pThreadCtx->m_stWeMQMSG, 0, sizeof(pThreadCtx->m_stWeMQMSG)); + memset (&pThreadCtx->m_stWeMQMSG, 0, (sizeof (int) * 2)); + int iRet = + DecodeWeMQMsg (&pThreadCtx->m_stWeMQMSG, pThreadCtx->m_pRecvBuff, + iRecvd); + + if (pThreadCtx->m_stWeMQMSG.uiHeaderLen == 0 + || pThreadCtx->m_stWeMQMSG.uiHeaderLen >= MAX_WEMQ_HEADER_LEN) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq Header complete, header len %d is 0 or too long", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_stWeMQMSG.uiHeaderLen); + return -1; + } + if (pThreadCtx->m_stWeMQMSG.uiHeaderLen > 0) + { + memcpy (pThreadCtx->m_stWeMQMSG.cStrJsonHeader, + pThreadCtx->m_pRecvBuff + 8, + pThreadCtx->m_stWeMQMSG.uiHeaderLen); + pThreadCtx->m_stWeMQMSG.cStrJsonHeader[pThreadCtx->m_stWeMQMSG. + uiHeaderLen] = '\0'; + } + LOGRMB (RMB_LOG_DEBUG, "cStrJsonHeader: %s", + pThreadCtx->m_stWeMQMSG.cStrJsonHeader); + unsigned int uiTmpBodyLen = + pThreadCtx->m_stWeMQMSG.uiTotalLen - + pThreadCtx->m_stWeMQMSG.uiHeaderLen - 8; + if (uiTmpBodyLen >= MAX_WEMQ_BODY_LEN) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq complete,body len %d is too long", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + uiTmpBodyLen); + return -1; + } + if (uiTmpBodyLen == 0) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq complete,body len is 0", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + } + //if (pThreadCtx->m_stWeMQMSG.uiTotalLen - pThreadCtx->m_stWeMQMSG.uiHeaderLen - 8 > 0) + if (uiTmpBodyLen > 0) + { + //set message source + pThreadCtx->m_stWeMQMSG.cStrJsonBody[0] = RMB_MSG_FROM_WEMQ; + memcpy (pThreadCtx->m_stWeMQMSG.cStrJsonBody, + pThreadCtx->m_pRecvBuff + 8 + + pThreadCtx->m_stWeMQMSG.uiHeaderLen, + pThreadCtx->m_stWeMQMSG.uiTotalLen - + pThreadCtx->m_stWeMQMSG.uiHeaderLen - 8); + pThreadCtx->m_stWeMQMSG.cStrJsonBody[uiTmpBodyLen] = '\0'; + } + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq Header complete,total len %d, header len %d,header %s, body %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_stWeMQMSG.uiTotalLen, + pThreadCtx->m_stWeMQMSG.uiHeaderLen, + pThreadCtx->m_stWeMQMSG.cStrJsonHeader, + pThreadCtx->m_stWeMQMSG.cStrJsonBody); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq Header ERROR", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -1; + } + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] epoll events %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_ptEvents[iTmp].events); + } + + } + if (!isRecvNewConnect) + { + pThreadCtx->m_iSockFd = pThreadCtx->m_iSockFdNew; + pThreadCtx->ssl = pThreadCtx->sslNew; + } + } + return iRecvd; +} + +static int32_t _wemq_thread_do_send_sync (WemqThreadCtx * pThreadCtx, + void *msg, uint32_t totalLen, + uint32_t headerLen) +{ + int iRetry = 2; + int timeout = pRmbStConfig->iWemqTcpSocketTimeout; + + while (iRetry > 0) + { + int iRet = + wemq_tcp_send (pThreadCtx->m_iSockFd, msg, totalLen, headerLen, timeout, + pThreadCtx->ssl); + + if (iRet == 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Retry: %d] TCP send timeout!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, iRetry); + iRetry--; + continue; + } + else if (iRet == -2) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] TCP send error(%d)!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, errno); + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + return -1; + } + else if (iRet > 0) + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] send complete len %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, iRet); + return 0; + } + return -2; + } + + // 重试2次失败 + return -3; +} + +static int32_t _wemq_thread_do_cmd_add_listen_msg (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_ADD_LISTEN); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send header:%s, body:%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader, pStWemqThreadMsg->m_pBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] _wemq_thread_do_send_sync error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return -2; + } + + return 0; +} + +static int32_t _wemq_thread_do_cmd_start_msg (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_START); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send:%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] _wemq_thread_do_send_sync error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return -2; + } + + return 0; +} + +static int32_t _wemq_thread_do_cmd_client_goodbye_msg (WemqThreadCtx * + pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_CLIENT_GOODBYE); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send Client GoodBye:%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] _wemq_thread_do_send_sync client goodbye error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return -2; + } + + return 0; +} + +static int32_t _wemq_thread_do_cmd_send_msg (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_MSG); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + if (NULL != pStWemqThreadMsg->m_pBody) + { + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + } + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send header:%s body:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader, pStWemqThreadMsg->m_pBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + + return 0; +} + +static int32_t _wemq_thread_do_cmd_send_log (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_LOG); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + if (NULL != pStWemqThreadMsg->m_pBody) + { + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + } + + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Send:%s\n", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, pStWemqThreadMsg->m_pHeader); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + + return 0; +} + +static int32_t _wemq_thread_do_cmd_send_async_request (WemqThreadCtx * + pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_REQUEST_ASYNC); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send header:%s body:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader, pStWemqThreadMsg->m_pBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +static int32_t _wemq_thread_do_cmd_send_request (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_REQUEST); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send header:%s body:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader, pStWemqThreadMsg->m_pBody); + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + + return 0; +} + +static int32_t _wemq_thread_do_cmd_send_reply (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_REPLY); + + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss|Send header:%s body:%s\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader, pStWemqThreadMsg->m_pBody); + + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!\n", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +static int32_t _wemq_thread_do_cmd_send_msg_ack (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ + ASSERT (pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_SEND_MSG_ACK); + int iRet = 0; + StRmbMsg *pSendMsg = rmb_msg_malloc (); + if ((iRet = + trans_json_2_rmb_msg (pSendMsg, pStWemqThreadMsg->m_pBody, + REQUEST_TO_CLIENT)) != 0) + { + LOGRMB (RMB_LOG_ERROR, "trans_json_2_rmb_msg failed,buf is:%s", + pStWemqThreadMsg->m_pBody); + return -1; + } + pSendMsg->iMsgMode = RMB_MSG_FROM_WEMQ; + pSendMsg->cPkgType = QUEUE_PKG; + + WEMQJSON *jsonDecoder = NULL; + WEMQJSON *sysExtFields = NULL; + int ack_seq = 0; + sysExtFields = json_tokener_parse (pSendMsg->sysHeader.cExtFields); + + if (json_object_object_get_ex + (sysExtFields, MSG_BODY_SYSTEM_ACK_SEQ, &jsonDecoder)) + { + ack_seq = json_object_get_int (jsonDecoder); + } + else + { + LOGRMB (RMB_LOG_ERROR, "get ack_seq failed!"); + return -1; + } + + switch (*(pSendMsg->strServiceId + 3)) + { + case '0': + iRet = + _wemq_thread_resp_ack_to_access (pThreadCtx, ack_seq, 0, + REQUEST_TO_CLIENT_ACK, pSendMsg); + break; + case '1': + iRet = + _wemq_thread_resp_ack_to_access (pThreadCtx, ack_seq, 0, + ASYNC_MESSAGE_TO_CLIENT_ACK, pSendMsg); + break; + case '3': + iRet = + _wemq_thread_resp_ack_to_access (pThreadCtx, ack_seq, 0, + BROADCAST_MESSAGE_TO_CLIENT_ACK, + pSendMsg); + break; + case '4': + iRet = + _wemq_thread_resp_ack_to_access (pThreadCtx, ack_seq, 0, + BROADCAST_MESSAGE_TO_CLIENT_ACK, + pSendMsg); + break; + default: + ; + } + + json_object_put (sysExtFields); + rmb_msg_free (pSendMsg); + + return iRet; +} + +static int32_t _wemq_thread_do_cmd_send_msg_reg (WemqThreadCtx * pThreadCtx) +{ + StWemqThreadMsg *pStWemqThreadMsg = &pThreadCtx->m_stHelloWord; + int iRet = -1; + int iTotalLen = + pStWemqThreadMsg->m_iHeaderLen + pStWemqThreadMsg->m_iBodyLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pBody, + pStWemqThreadMsg->m_iBodyLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] |wemq_thread2accesss| Send header:%s, body:%s, totalLen:%d, headerLen:%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pStWemqThreadMsg->m_pHeader, pStWemqThreadMsg->m_pBody, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + //return _wemq_thread_state_trans(pThreadCtx, pThreadCtx->m_iState, THREAD_STATE_BREAK); + return -1; + } + + iRet = _wemq_thread_do_recv_sync (pThreadCtx); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_recv_sync error: %d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, iRet); + return -2; + } + + StWeMQMSG *pWemqHeader = &pThreadCtx->m_stWeMQMSG; + WEMQJSON *jsonHeader = NULL; + WEMQJSON *jsonTmp = NULL; + int usCmd = -1; + int serRet = -1; + int seq = -1; + long time = 0; + char cMessage[100]; + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] |access2wemq_thread|Recv: %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pWemqHeader->cStrJsonHeader); + jsonHeader = json_tokener_parse (pWemqHeader->cStrJsonHeader); + if (jsonHeader == NULL) + { + // 消息不完整, json解析失败 + LOGRMB (RMB_LOG_ERROR, "[Type:%d] [TID:%lu] json_tokener_parse error: %s", + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pWemqHeader->cStrJsonHeader) return 1; + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_COMMAND_STR, &jsonTmp); + if (jsonTmp != NULL) + { + usCmd = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_CODE_INT, &jsonTmp); + if (jsonTmp != NULL) + { + serRet = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_SEQ_INT, &jsonTmp); + if (jsonTmp != NULL) + { + seq = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_TIME_LINT, &jsonTmp); + if (jsonTmp != NULL) + { + time = (long) json_object_get_int64 (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_MSG_STR, &jsonTmp); + if (jsonTmp != NULL) + { + memset (cMessage, 0x00, sizeof (cMessage)); + strncpy (cMessage, json_object_get_string (jsonTmp), + sizeof (cMessage) - 1); + } + json_object_put (jsonHeader); + + if (strcmp (cMessage, "auth exception") == 0) + { // wemq user/passwd error + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] Authentication error!user:%s, passwd:%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time, + pRmbStConfig->cWemqUser, pRmbStConfig->cWemqPasswd); + return -1; + } + if (serRet == RMB_CODE_OTHER_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] register proxy error:%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time, + serRet); + return -2; + } + + if (serRet == RMB_CODE_AUT_FAIL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] register proxy Authentication error:%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time, + serRet); + return -3; + } + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [Time:%ld] register proxy success!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, time); + + //hello world之后,心跳包可以延期 + gettimeofday (&pThreadCtx->stTimeLast, NULL); + gettimeofday (&pThreadCtx->stTimeLastRecv, NULL); + + return 0; + +} + +int wemq_thread_fifo_msg_is_empty (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx is null"); + return 0; + } + + /** + * fix bug:rmb_sub_reply的消息也需要上传完毕 + */ +// if ((pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) && (pThreadCtx->m_ptFifo != NULL)) { + //check wemq thrad msg empty + if (pThreadCtx->m_ptFifo != NULL) + { + if (wemq_kfifo_is_empty (pThreadCtx->m_ptFifo)) + { + LOGRMB (RMB_LOG_INFO, "pub:pThreadCtx->m_ptFifo is empty"); + return 0; + } + else + { + return 1; + } + } + + return 0; +} + +int wemq_thread_mq_msg_is_empty (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx==NULL"); + return NULL; + } + int result = wemq_thread_check_req_mq_is_null (pThreadCtx) + && wemq_thread_check_rr_rsp_mq_is_null (pThreadCtx) + && wemq_thread_check_broadcast_mq_is_null (pThreadCtx); + if (result == 0) + { + LOGRMB (RMB_LOG_INFO, "wemq_thread_mq_msg_is_empty"); + } + return result; + +} + +StMqInfo *wemq_thread_get_mq_by_type (WemqThreadCtx * pThreadCtx, int iType) +{ + stContextProxy *pContextProxy = pThreadCtx->m_ptProxyContext; + StContext *pStContext; + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pStContext = (StContext *) (pContextProxy->pubContext); + } + else + { + pStContext = (StContext *) (pContextProxy->subContext); + } + + return pStContext->fifoMq.mqIndex[iType]; +} + +StMqInfo *wemq_thread_get_receve_req_mq (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx==NULL"); + return NULL; + } + return wemq_thread_get_mq_by_type (pThreadCtx, (int) req_mq_index); +} + +StMqInfo *wemq_thread_get_rr_rsp_mq (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx==NULL"); + return NULL; + } + return wemq_thread_get_mq_by_type (pThreadCtx, (int) rr_rsp_mq_index); +} + +StMqInfo *wemq_thread_get_broadcast_mq (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx==NULL"); + return NULL; + } + return wemq_thread_get_mq_by_type (pThreadCtx, (int) broadcast_mq_index); +} + +/* +Function: rmb_sub_check_req_mq_is_null +Description:校验是否请求队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int wemq_thread_check_req_mq_is_null (WemqThreadCtx * pThreadCtx) +{ + StMqInfo *p = wemq_thread_get_receve_req_mq (pThreadCtx); + if (p == NULL) + { + return 0; + } + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + usleep (1000); + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + return 0; +} + +/* +Function: wemq_thread_check_rr_rsp_mq_is_null +Description:校验rr_rsp队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int wemq_thread_check_rr_rsp_mq_is_null (WemqThreadCtx * pThreadCtx) +{ + StMqInfo *p = wemq_thread_get_rr_rsp_mq (pThreadCtx); + if (p == NULL) + { + return 0; + } + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + usleep (1000); + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + return 0; +} + +/* +Function: wemq_thread_check_broadcast_mq_is_null +Description:校验broadcast队列是否已经为空,如果为空,则返回0,非空,则返回1 +* Return: +* 空返回0,非空返回1 +*/ +int wemq_thread_check_broadcast_mq_is_null (WemqThreadCtx * pThreadCtx) +{ + StMqInfo *p = wemq_thread_get_broadcast_mq (pThreadCtx); + if (p == NULL) + { + return 0; + } + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + usleep (1000); + if (*(p->mq->pHead) != *(p->mq->pTail)) + { + return 1; + } + return 0; +} + +int wemq_rr_msg_is_empty (stContextProxy * pContextProxy) +{ + + if (pContextProxy == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pContextProxy is null"); + return 0; + } + + if (pContextProxy->stUnique.flag == 1) + { //有未回复的rr同步消息 + LOGRMB (RMB_LOG_DEBUG, "rr sync message is not response"); + return 1; + } + + struct timeval tv_now; + gettimeofday (&tv_now, NULL); + unsigned long ulNowTime = tv_now.tv_sec * 1000 + tv_now.tv_usec / 1000; + + int i; + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncOld. + get_array_size (&pContextProxy->pUniqueListForRRAsyncOld); i++) + { + if (pContextProxy->pUniqueListForRRAsyncOld.Data[i].flag == 1) + { //有未回复的rr异步消息 + if (ulNowTime >= pContextProxy->ulLastPrintOldListIsEmpty + 1 * 1000) + { + LOGRMB (RMB_LOG_DEBUG, "rr async is message not response"); + pContextProxy->ulLastPrintOldListIsEmpty = ulNowTime; + } + return 1; + } + } + + LOGRMB (RMB_LOG_DEBUG, "rr msg is empty"); + return 0; +} + +int wemq_rr_all_msg_is_empty (stContextProxy * pContextProxy) +{ + + if (pContextProxy == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pContextProxy is null"); + return 0; + } + + if (pContextProxy->stUnique.flag == 1) + { //有未回复的rr同步消息 + LOGRMB (RMB_LOG_DEBUG, "rr sync message is not response"); + return 1; + } + + int i; + + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncNew. + get_array_size (&pContextProxy->pUniqueListForRRAsyncNew); i++) + { + + if (pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag == 1) + { //有未回复的rr异步消息 + LOGRMB (RMB_LOG_DEBUG, + "rr async message in new session is not response"); + return 1; + } + } + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncOld. + get_array_size (&pContextProxy->pUniqueListForRRAsyncOld); i++) + { + + if (pContextProxy->pUniqueListForRRAsyncOld.Data[i].flag == 1) + { //有未回复的rr异步消息 + LOGRMB (RMB_LOG_DEBUG, + "rr async message in old session is not response"); + return 1; + } + } + + LOGRMB (RMB_LOG_DEBUG, "rr msg is empty"); + return 0; +} + +int32_t _wemq_thread_do_cmd_send_heart_beat (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * + pStWemqThreadMsg) +{ +// ASSERT(pStWemqThreadMsg->m_iCmd == THREAD_MSG_CMD_BEAT); + if (pThreadCtx == NULL || pStWemqThreadMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx or pStWemqThreadMsg is null"); + return -1; + } + + if (pStWemqThreadMsg->m_iCmd != THREAD_MSG_CMD_BEAT) + { + LOGRMB (RMB_LOG_ERROR, + "pStWemqThreadMsg->m_iCmd=%d, not THREAD_MSG_CMD_BEAT", + pStWemqThreadMsg->m_iCmd); + return -1; + } + + int iRet = -1; + int iTotalLen = pStWemqThreadMsg->m_iHeaderLen + 8; + + char *buf = pThreadCtx->m_pSendBuff; + ENCODE_INT (buf, iTotalLen); + ENCODE_INT (buf, pStWemqThreadMsg->m_iHeaderLen); + ENCODE_DWSTR_MEMCPY (buf, pStWemqThreadMsg->m_pHeader, + pStWemqThreadMsg->m_iHeaderLen); + //ENCODE_DWSTR_MEMCPY(buf, pStWemqThreadMsg->m_pBody, pStWemqThreadMsg->m_iBodyLen); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] |wemq_thread2accesss|Send:%s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pStWemqThreadMsg->m_pHeader); + + iRet = + _wemq_thread_do_send_sync (pThreadCtx, pThreadCtx->m_pSendBuff, iTotalLen, + pStWemqThreadMsg->m_iHeaderLen); + + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] _wemq_thread_do_send_sync error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return -2; + } + return 0; +} + +static int32_t _wemq_thread_send_heart_beat (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "pThreadCtx is null"); + //防止一直空转 + usleep (1000); + return -1; + } + +// if (pThreadCtx->m_iState == THREAD_STATE_INIT) +// { +// return 0; +// } + + if (pThreadCtx->m_iState != THREAD_STATE_OK) + { + return 0; + } + + if (pThreadCtx->m_iHeartBeatCount % HEART_BEAT_COUNT == 0) + { + pThreadCtx->m_iHeartBeatCount = 0; + gettimeofday (&pThreadCtx->stTimeNow, NULL); + + int time_inter = + pThreadCtx->stTimeNow.tv_sec - pThreadCtx->stTimeLast.tv_sec; + int time_inter_recv = + pThreadCtx->stTimeNow.tv_sec - pThreadCtx->stTimeLastRecv.tv_sec; + + //check heart beat time out + if (time_inter_recv >= pRmbStConfig->heartBeatTimeout) + { + //防止心跳超时日志多次打印 + pThreadCtx->stTimeLastRecv.tv_sec = pThreadCtx->stTimeNow.tv_sec; + LOGRMB (RMB_LOG_WARN, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] heart beat time out,current_times=%u!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pThreadCtx->m_uiHeartBeatCurrent); + if (pThreadCtx->m_uiHeartBeatCurrent > 2) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] send two heart beat,but no receive!", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + pThreadCtx->m_uiHeartBeatCurrent = 0; + //add to black list + wemq_proxy_to_black_list (pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + + if (time_inter >= pRmbStConfig->heartBeatPeriod) + { + pThreadCtx->m_uiHeartBeatCurrent += 1; + int iRet = + _wemq_thread_do_cmd_send_heart_beat (pThreadCtx, + &pThreadCtx->m_stHeartBeat); + if (iRet == -2) + { + //_wemq_thread_del_fd(pThreadCtx); + //pThreadCtx->m_iSockFd = -1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + pThreadCtx->stTimeLast.tv_sec = pThreadCtx->stTimeNow.tv_sec; + pThreadCtx->stTimeLast.tv_usec = pThreadCtx->stTimeNow.tv_usec; + } + } + pThreadCtx->m_iHeartBeatCount++; + + return 0; +} + +static int32_t _wemq_thread_do_req (WemqThreadCtx * pThreadCtx, + StWemqThreadMsg * pStWemqThreadMsg) +{ + int iRet = -1; + switch (pStWemqThreadMsg->m_iCmd) + { + case THREAD_MSG_CMD_ADD_LISTEN: + { + iRet = + _wemq_thread_do_cmd_add_listen_msg (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + case THREAD_MSG_CMD_START: + { + iRet = _wemq_thread_do_cmd_start_msg (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread START CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + + return iRet; + } + case THREAD_MSG_CMD_SEND_MSG: + { + iRet = _wemq_thread_do_cmd_send_msg (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + + case THREAD_MSG_CMD_SEND_LOG: + { + iRet = _wemq_thread_do_cmd_send_log (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + + case THREAD_MSG_CMD_SEND_CLIENT_GOODBYE: + { + iRet = + _wemq_thread_do_cmd_client_goodbye_msg (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + case THREAD_MSG_CMD_SEND_REQUEST: + { + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] Thread REQ CMD THREAD_MSG_CMD_SEND_REQUEST", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + iRet = _wemq_thread_do_cmd_send_request (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + case THREAD_MSG_CMD_SEND_REQUEST_ASYNC: + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] Thread REQ CMD THREAD_MSG_CMD_SEND_REQUEST", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + iRet = + _wemq_thread_do_cmd_send_async_request (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + case THREAD_MSG_CMD_SEND_REPLY: + { + + iRet = _wemq_thread_do_cmd_send_reply (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return iRet; + } + case THREAD_MSG_CMD_SEND_MSG_ACK: + { + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] Do App ACK", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID); + + /* + iRet = _wemq_thread_do_cmd_send_msg_ack(pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg(pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + */ + iRet = _wemq_thread_do_cmd_send_msg_ack (pThreadCtx, pStWemqThreadMsg); + if (iRet == 0) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Thread REQ CMD ERROR %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + _wemq_thread_get_cmd (pStWemqThreadMsg->m_iCmd)); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + else + { + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + LOGRMB (RMB_LOG_ERROR, + "data processing ERR cause _wemq_thread_do_cmd_send_msg_ack failed."); + } + } + return iRet; + } + default: + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] do req error no such type req cmd %d!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pStWemqThreadMsg->m_iCmd); + _wemq_thread_clear_thread_msg (pStWemqThreadMsg); + pThreadCtx->m_iWemqThreadMsgHandled = 1; + break; + } + return iRet; +} + +static int32_t _wemq_thread_do_last_failure_req (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx->m_iWemqThreadMsgHandled == 1) + { + return 0; + } + else + { + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] do last failure req!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + int iRet = + _wemq_thread_do_req (pThreadCtx, &pThreadCtx->m_stWemqThreadMsg); + if (iRet == -2) + { + _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + return iRet; + } + } + return 0; +} + +int do_ssl_connect (WemqThreadCtx * pThreadCtx) +{ + int err; + int sd; + struct sockaddr_in sa; + + if (NULL == pThreadCtx->sslCtx) + { + SSL_METHOD *meth; + + SSL_load_error_strings (); + SSLeay_add_ssl_algorithms (); + meth = TLSv1_2_client_method (); + pThreadCtx->sslCtx = SSL_CTX_new (meth); + } + + sd = socket (AF_INET, SOCK_STREAM, 0); + + memset (&sa, '\0', sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = inet_addr (pThreadCtx->m_cProxyIP); /* Server IP */ + sa.sin_port = htons (pThreadCtx->m_uiProxyPort); /* Server Port number */ + + err = connect (sd, (struct sockaddr *) &sa, sizeof (sa)); + if (0 != err) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [host:%s|port:%u] tls tcp Connect Error, err=%d, errno=%d!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort, err, errno); + close (sd); + return -1; + } + else + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [host:%s|port:%u] tls tcp connect suc!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + } + + pThreadCtx->ssl = SSL_new (pThreadCtx->sslCtx); + SSL_set_fd (pThreadCtx->ssl, sd); + err = SSL_connect (pThreadCtx->ssl); + if (0 > err) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [host:%s|port:%u] tls Connect Error, err=%d, errno=%d!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort, err, errno); + wemq_tcp_close (sd, pThreadCtx->ssl); + pThreadCtx->ssl = NULL; + return -1; + } + + pThreadCtx->m_iSockFd = sd; + return 0; +} + +static int32_t _wemq_thread_do_connect (WemqThreadCtx * pThreadCtx) +{ + //随机sleep配置时间+0~9ms + struct timeval tv; + gettimeofday (&tv, NULL); + long now_time = tv.tv_sec * 1000000 + tv.tv_usec; + srand ((unsigned int) now_time); + int random_time = rand () % 10; + int retry = pRmbStConfig->iWemqTcpConnectRetryNum; + int sleep_time = pRmbStConfig->iWemqTcpConnectDelayTime * 1000; + int timeout = pRmbStConfig->iWemqTcpConnectTimeout + random_time; + + //memset(pThreadCtx->m_cProxyIP, 0, sizeof(pThreadCtx->m_cProxyIP)); + pThreadCtx->m_cProxyIP[0] = '\0'; + pThreadCtx->m_uiProxyPort = 0; + pThreadCtx->m_iLocalPort = 0; + + if (pThreadCtx->m_lRedirect == 0) + { + int iRet = 0; + do + { + iRet = + wemq_proxy_get_server (pThreadCtx->m_cProxyIP, + sizeof (pThreadCtx->m_cProxyIP), + &pThreadCtx->m_uiProxyPort); + if (iRet == 2) + { + LOGRMB (RMB_LOG_ERROR, "get proxy ip/port failed"); + sleep (1); + } + } + while (iRet == 2); + } + else + { + pThreadCtx->m_lRedirect = 0; + snprintf (pThreadCtx->m_cProxyIP, sizeof (pThreadCtx->m_cProxyIP), "%s", + pThreadCtx->m_cRedirectIP); + pThreadCtx->m_uiProxyPort = pThreadCtx->m_iRedirectPort; + } + + while (retry > 0) + { + if (0 != pRmbStConfig->tlsOnoff) + { + int err = do_ssl_connect (pThreadCtx); + if (0 != err) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [retry: %d|host:%s|port:%u] tls Connect Error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, retry, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + } + else + { + wemq_getsockename (pThreadCtx->m_iSockFd, NULL, 0, + &pThreadCtx->m_iLocalPort); + if (_wemq_thread_set_fd_nonblock (pThreadCtx, pThreadCtx->m_iSockFd) + != 0) + { + LOGRMB (RMB_LOG_ERROR, + "wemq thread set pThreadCtx->m_iSockFd=%d to nonblock failed", + pThreadCtx->m_iSockFd); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + } + else + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [host:%s|port:%u|local_port:%d] tls connect to proxy, fd=%d!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort, pThreadCtx->m_iLocalPort, + pThreadCtx->m_iSockFd); + //add fd to epoll + _wemq_thread_add_fd (pThreadCtx); + return 0; + } + } + } + else + { + int iSockFd = + wemq_tcp_connect (pThreadCtx->m_cProxyIP, + (uint16_t) pThreadCtx->m_uiProxyPort, timeout); + if (iSockFd > 0) + { + pThreadCtx->m_iSockFd = iSockFd; + wemq_getsockename (iSockFd, NULL, 0, &pThreadCtx->m_iLocalPort); + if (_wemq_thread_set_fd_nonblock (pThreadCtx, pThreadCtx->m_iSockFd) + != 0) + { + //exit(1); + LOGRMB (RMB_LOG_ERROR, + "wemq thread set pThreadCtx->m_iSockFd=%d to nonblock failed", + pThreadCtx->m_iSockFd); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + //return -1; + } + else + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [host:%s|port:%u|local_port:%d] connect to proxy!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort, pThreadCtx->m_iLocalPort); + //add fd to epoll + _wemq_thread_add_fd (pThreadCtx); + return 0; + } + } + } + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] [retry: %d|host:%s|port:%u] Connect Error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, retry, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + retry--; + usleep (sleep_time); + if (retry == 0) + { + wemq_proxy_goodbye (pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [host:%s|port:%u] Connect Failed!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + return -1; + } + + } + return -2; +} + +int32_t wemq_thread_state_init (WemqThreadCtx * pThreadCtx) +{ +// ASSERT(pThreadCtx); + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "wemq_thread_state_init: pThreadCtx is null"); + return -1; + } + pThreadCtx->m_iHeartBeatCount = 0; + pThreadCtx->m_uiHeartBeatCurrent = 0; + + gettimeofday (&pThreadCtx->stTimeNow, NULL); + gettimeofday (&pThreadCtx->stTimeLast, NULL); + gettimeofday (&pThreadCtx->stTimeLastRecv, NULL); + + //pThreadCtx->m_iThreadId = pThreadCtx->m_contextType; + pThreadCtx->m_iWemqThreadMsgHandled = 1; + pThreadCtx->m_threadID = pthread_self (); + +// pThreadCtx->m_lRedirect = false; + pThreadCtx->m_lRedirect = 0; + pThreadCtx->m_cRedirectIP[0] = '\0'; + pThreadCtx->m_iRedirectPort = 0; + + pThreadCtx->m_pRecvBuff = (char *) malloc (TCP_BUF_SIZE * sizeof (char)); + if (pThreadCtx->m_pRecvBuff == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] pThreadCtx->m_pRecvBuff malloc error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + memset (pThreadCtx->m_pRecvBuff, 0x00, + sizeof (TCP_BUF_SIZE * sizeof (char))); + + pThreadCtx->m_pSendBuff = (char *) malloc (TCP_BUF_SIZE * sizeof (char)); + if (pThreadCtx->m_pSendBuff == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] pThreadCtx->m_pSendBuff malloc error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + memset (pThreadCtx->m_pSendBuff, 0x00, TCP_BUF_SIZE * sizeof (char)); + + pThreadCtx->m_iEpollFd = epoll_create (1); + if (pThreadCtx->m_iEpollFd < 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] Create Epoll fd error:%d!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, errno); + return -3; + } + + pThreadCtx->m_ptEvents = + (struct epoll_event *) malloc (MAX_EVENT * sizeof (struct epoll_event)); + if (pThreadCtx->m_ptEvents == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] Create Malloc events error!", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + rmb_errno = RMB_ERROR_MALLOC_FAIL; + return -2; + } + + pThreadCtx->sslCtx = NULL; + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + pThreadCtx->m_iSockFdNew = -1; + pThreadCtx->sslNew = NULL; + pThreadCtx->m_iSockFdOld = -1; + pThreadCtx->sslOld = NULL; + pThreadCtx->m_iSockFd = -1; + + /* + pThreadCtx->m_stReqForHeartBeat.pid = CMD_HEART_BEAT; + pThreadCtx->m_stReqForHeartBeat.uiCount = 0; + */ + _wemq_thread_make_heart_beat_pkg (pThreadCtx); + _wemq_thread_make_hello_pkg (pThreadCtx); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_CONNECT); +} + +int32_t wemq_thread_state_connect (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + ASSERT (pThreadCtx->m_iState == THREAD_STATE_CONNECT); + + int ret = _wemq_thread_do_connect (pThreadCtx); + + if (ret == 0) + { + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_REGI); + } + else if (ret < 0) + { + /** + * 1. 使用default ip/port时,如果连接失败,则通知前端连接失败 + * 2. 如果从配置中心获取ip list失败或者获取到的ip list数量小于2个,则通知前端连接失败 + */ + if (pRmbStConfig->iWemqUseHttpCfg != 1 + || ((ret = rmb_get_wemq_proxy_list_num ()) <= 1)) + { + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->pubMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForPub == 0) + { + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->pubCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->pubMutex); + } + else if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_SUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->subMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForSub == 0) + { + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->subCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->subMutex); + } + } + + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + return ret; +} + +int32_t wemq_thread_state_regi (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + ASSERT (pThreadCtx->m_iState == THREAD_STATE_REGI); + int iRet = -1; + + iRet = _wemq_thread_do_cmd_send_msg_reg (pThreadCtx); + if (iRet == 0) + { + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->pubMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForPub == 0) + { + pThreadCtx->m_ptProxyContext->iFlagForPub = 1; + pThreadCtx->m_ptProxyContext->iFlagForPublish = 1; + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->pubCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->pubMutex); + } + else if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_SUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->subMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForSub == 0) + { + pThreadCtx->m_ptProxyContext->iFlagForSub = 1; + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->subCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->subMutex); + } + + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_OK); + } + else if (iRet < 0) + { + wemq_proxy_to_black_list (pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + return -1; +} + +int32_t wemq_thread_state_ok (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + ASSERT (pThreadCtx->m_iState == THREAD_STATE_OK); + + int iRet = -1; + + if ((pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + && (pThreadCtx->m_ptProxyContext->iFlagForPublish == 0)) + { + pThreadCtx->m_ptProxyContext->iFlagForPublish = 1; + } + + iRet = _wemq_thread_do_last_failure_req (pThreadCtx); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] CALL DO LAST FAILURE REQ ERROR", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + return iRet; + } + + //旧连接还在 + if (pThreadCtx->m_iSockFdOld >= 0) + { + + wemq_thread_do_deal_with_old_connect (pThreadCtx); + } + + int iMsgNum = 0; + int iRecv = 0; + iMsgNum = _wemq_thread_get_data_from_fifo (pThreadCtx); + if (iMsgNum > 0) + { + iRet = _wemq_thread_do_req (pThreadCtx, &pThreadCtx->m_stWemqThreadMsg); + if (iRet == -2) + { + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + + } + + iRecv = _wemq_thread_do_recv_async (pThreadCtx, true); + if (iRecv > 0) + { + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] RECV %d bytes", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRecv); + iRet = _wemq_thread_on_message (pThreadCtx, true); + if (iRet == WEMQ_MESSAGE_RET_GOODBYE) + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] RECV byebye cmd", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + wemq_proxy_goodbye (pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + else if (iRet == WEMQ_MESSAGE_RET_REDIRECT) + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] --> [redirect ip:%s|port:%d] RECV redirect cmd", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, + pThreadCtx->m_cRedirectIP, pThreadCtx->m_iRedirectPort); + //_wemq_thread_del_fd(pThreadCtx); + //close(pThreadCtx->m_iSockFd); + //pThreadCtx->m_iSockFd = -1; + //return _wemq_thread_state_trans(pThreadCtx, pThreadCtx->m_iState, THREAD_STATE_BREAK); + wemq_proxy_goodbye (pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, THREAD_STATE_CLOSE); //停止发消息; + } + else if (iRet == WEMQ_MESSAGE_RET_SERVERGOODBYE) //access端主动离线 + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] RECV server goodbye cmd", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + //stContextProxy* pContextProxy = pThreadCtx->m_ptProxyContext; + + wemq_proxy_goodbye (pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + //wemq_thread_rr_msg_is_empty(pThreadCtx); + // _wemq_thread_del_fd(pThreadCtx); + // close(pThreadCtx->m_iSockFd); + // pThreadCtx->m_iSockFd = -1; + + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, THREAD_STATE_CLOSE); //停止发消息; + } + else if (iRet == WEMQ_MESSAGE_RET_CLIENTGOODBYE) //client端主动离线,收到回包 + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] RECV client goodbye cmd rsp", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + stContextProxy *pContextProxy = pThreadCtx->m_ptProxyContext; + pContextProxy->iFlagForGoodBye = 1; + pthread_cond_signal (&pContextProxy->goodByeCond); + // + //pContextProxy->iFlagForRun = 0; //停止运行状态机 + return 0; + } + } + else + { + //LOGWEMQ(WEMQ_LOG_ERROR, "[%s],[TID:%d],ERROR RECV %d bytes\n", STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_iThreadId, iRecv); + if (iRecv == -1) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu]Thread on Message ERROR", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + } + if (iRecv == -2) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] connect closed by peer", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + return 0; +} + +int32_t wemq_thread_state_close (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + ASSERT (pThreadCtx->m_iState == THREAD_STATE_CLOSE); + + stContextProxy *pContextProxy = pThreadCtx->m_ptProxyContext; + int iRet = -1; + + int iMsgNum = 0; + int iRecv = 0; + /* + if (wemq_rr_msg_is_empty(pThreadCtx->m_ptProxyContext) == 0 && pThreadCtx->m_ptProxyContext->iFlagForEvent == 0) //rr同步和异步消息和单播的ack都已全部回来 + { + LOGRMB(RMB_LOG_INFO, "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] RECV all rsp", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, + pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, + pThreadCtx->m_uiProxyPort); + //stContextProxy* pContextProxy = pThreadCtx->m_ptProxyContext; + + wemq_proxy_goodbye(pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + _wemq_thread_del_fd(pThreadCtx); + close(pThreadCtx->m_iSockFd); + pThreadCtx->m_iSockFd = -1; + return _wemq_thread_state_trans(pThreadCtx, pThreadCtx->m_iState, THREAD_STATE_BREAK); //停止 + } + */ + + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pThreadCtx->m_iSockFdOld = pThreadCtx->m_iSockFd; + pThreadCtx->sslOld = pThreadCtx->ssl; + memcpy (pThreadCtx->m_cProxyIPOld, pThreadCtx->m_cProxyIP, + strlen (pThreadCtx->m_cProxyIP)); + pThreadCtx->m_uiProxyPortOld = pThreadCtx->m_uiProxyPort; + + Array pTempList = pContextProxy->pUniqueListForRRAsyncNew; + pContextProxy->pUniqueListForRRAsyncNew = + pContextProxy->pUniqueListForRRAsyncOld; + pContextProxy->pUniqueListForRRAsyncOld = pTempList; + + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + } + else + { + struct timeval tv_now; + gettimeofday (&tv_now, NULL); + + unsigned long ulNowTime = tv_now.tv_sec * 1000 + tv_now.tv_usec / 1000; + unsigned long ulLastTime = tv_now.tv_sec * 1000 + tv_now.tv_usec / 1000; + unsigned long timeout = 4 * 1000; + + while ((ulNowTime - ulLastTime) < timeout) + { + iMsgNum = _wemq_thread_get_data_from_fifo (pThreadCtx); + if (iMsgNum > 0) + { + iRet = + _wemq_thread_do_req (pThreadCtx, &pThreadCtx->m_stWemqThreadMsg); + } + else + if (pRmbStConfig->mqIsEmpty == MQ_INIT + || pRmbStConfig->mqIsEmpty == MQ_IS_EMPTY) + break; + gettimeofday (&tv_now, NULL); + ulNowTime = tv_now.tv_sec * 1000 + tv_now.tv_usec / 1000; + } + + } + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, THREAD_STATE_BREAK); //停止 + +} + +int32_t wemq_thread_state_break (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + ASSERT (pThreadCtx->m_iState == THREAD_STATE_BREAK); + //ASSERT(pThreadCtx->m_iSockFd == -1); + if (pThreadCtx->m_iSockFd >= 0) + { + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + } + + int ret = -1; + + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pThreadCtx->m_ptProxyContext->iFlagForPublish = 0; + } + + usleep (1000); + if ((ret = _wemq_thread_do_connect (pThreadCtx)) == 0) + { + pThreadCtx->m_uiHeartBeatCurrent = 0; + pThreadCtx->m_iHeartBeatCount = 0; + gettimeofday (&pThreadCtx->stTimeNow, NULL); + gettimeofday (&pThreadCtx->stTimeLast, NULL); + gettimeofday (&pThreadCtx->stTimeLastRecv, NULL); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_RECONNECT); + } + + if (wemq_proxy_ip_is_connected () == 1) + { //所有iplist已经遍历过一次 + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->pubMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForPub == 0) + { + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->pubCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->pubMutex); + } + else if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_SUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->subMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForSub == 0) + { + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->subCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->subMutex); + } + } + + return ret; +} + +int32_t wemq_thread_state_reconnect (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + //TODO RECONNECT; + //sleep(1); + struct timeval tv; + gettimeofday (&tv, NULL); + long now_time = tv.tv_sec * 1000000 + tv.tv_usec; + srand ((unsigned int) now_time); + //随机sleep 30~50ms ,usleep 单位是纳秒 + int sleep_time = rand () % 20 + 30; + usleep (sleep_time * 1000); + // hello msg + { + int iRet = -1; + + iRet = _wemq_thread_do_cmd_send_msg_reg (pThreadCtx); + if (iRet > 0) + { + return -1; + } + else if (iRet < 0) + { + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + + /** + * 程序首次起来时,如果选择的第一个ip连接失败而第二个ip连接成功且hello world指令发送成功,则应该通知前端连接成功 + */ + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_PUB) + { + if (pThreadCtx->m_ptProxyContext->iFlagForPublish == 0) + { + pThreadCtx->m_ptProxyContext->iFlagForPublish = 1; + } + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->pubMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForPub == 0) + { + pThreadCtx->m_ptProxyContext->iFlagForPub = 1; + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->pubCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->pubMutex); + } + else if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_SUB) + { + pthread_mutex_lock (&pThreadCtx->m_ptProxyContext->subMutex); + if (pThreadCtx->m_ptProxyContext->iFlagForSub == 0) + { + pThreadCtx->m_ptProxyContext->iFlagForSub = 1; + pthread_cond_signal (&pThreadCtx->m_ptProxyContext->subCond); + } + pthread_mutex_unlock (&pThreadCtx->m_ptProxyContext->subMutex); + } + + int flag = 0; + //regist topic list + StWemqTopicProp *ptTopicProp = NULL; + if (pThreadCtx->m_ptTopicList != NULL) + { + ptTopicProp = pThreadCtx->m_ptTopicList->next; + } + WEMQJSON *jsonTopicList = json_object_new_array (); + char cBroadcastDcn[10] = "000"; + while (ptTopicProp != NULL) + { + flag = 1; + char cTopic[200]; + //char serviceOrEvent = (*(ptTopicProp->cServiceId + 3) == '0') ? 'e' : 's'; + char serviceOrEvent = (*(ptTopicProp->cServiceId + 3) == '0') ? 's' : 'e'; + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", + pRmbStConfig->cConsumerDcn, serviceOrEvent, + ptTopicProp->cServiceId, ptTopicProp->cScenario, + *(ptTopicProp->cServiceId + 3)); + json_object_array_add (jsonTopicList, json_object_new_string (cTopic)); + //自动监听广播topic + if (serviceOrEvent == 'e') + { + memset (cTopic, 0x00, sizeof (cTopic)); + snprintf (cTopic, sizeof (cTopic), "%s-%c-%s-%s-%c", cBroadcastDcn, + serviceOrEvent, ptTopicProp->cServiceId, + ptTopicProp->cScenario, *(ptTopicProp->cServiceId + 3)); + json_object_array_add (jsonTopicList, json_object_new_string (cTopic)); + } + ptTopicProp = ptTopicProp->next; + } + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_ADD_LISTEN; + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object for jsonHeader failed"); + return -1; + } + + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (SUBSCRIBE_REQUEST)); + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + + WEMQJSON *jsonBody = json_object_new_object (); + if (jsonBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object for jsonBody failed"); + json_object_put (jsonHeader); + json_object_put (jsonTopicList); + return -1; + } + + json_object_object_add (jsonBody, MSG_BODY_TOPIC_LIST_JSON, jsonTopicList); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_get_string for header is null"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -2; + } + stThreadMsg.m_iHeaderLen = strlen (header_str); + + LOGRMB (RMB_LOG_DEBUG, + "[%s] [Type:%d] [TID:%lu] Gen thread msg header succ, len %d, %s", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, stThreadMsg.m_iHeaderLen, header_str); + stThreadMsg.m_pHeader = + (char *) malloc (stThreadMsg.m_iHeaderLen * sizeof (char) + 1); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for header failed"); + json_object_put (jsonBody); + json_object_put (jsonHeader); + return -1; + } + memcpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + json_object_put (jsonHeader); + + const char *body_str = json_object_get_string (jsonBody); + if (body_str == NULL) + { + json_object_put (jsonBody); + return -1; + } + + stThreadMsg.m_iBodyLen = strlen (body_str); + stThreadMsg.m_pBody = + (char *) malloc (stThreadMsg.m_iBodyLen * sizeof (char) + 1); + if (stThreadMsg.m_pBody == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for hello body failed"); + json_object_put (jsonBody); + return -1; + } + memcpy (stThreadMsg.m_pBody, body_str, stThreadMsg.m_iBodyLen); + stThreadMsg.m_pBody[stThreadMsg.m_iBodyLen] = '\0'; + + json_object_put (jsonBody); + + int iRet = _wemq_thread_do_cmd_add_listen_msg (pThreadCtx, &stThreadMsg); + if (iRet == -2) + { + free (stThreadMsg.m_pHeader); + free (stThreadMsg.m_pBody); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + iRet = _wemq_thread_do_recv_sync (pThreadCtx); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] Decode Wemq Header ERROR", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + + StWeMQMSG *pWemqHeader = &pThreadCtx->m_stWeMQMSG; + jsonHeader = NULL; + WEMQJSON *jsonTmp = NULL; + char *usCmd; + char *msg; + int serRet = -1; + int seq = -1; + long time = 0; + + jsonHeader = json_tokener_parse (pWemqHeader->cStrJsonHeader); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] [LocalPort:%d] json_tokener_parse error: %s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, + pWemqHeader-> + cStrJsonHeader) return _wemq_thread_state_trans (pThreadCtx, + pThreadCtx-> + m_iState, + THREAD_STATE_BREAK); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_COMMAND_STR, &jsonTmp); + if (jsonTmp != NULL) + { + usCmd = json_object_get_string (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_CODE_INT, &jsonTmp); + if (jsonTmp != NULL) + { + serRet = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_SEQ_INT, &jsonTmp); + if (jsonTmp != NULL) + { + seq = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_MSG_STR, &jsonTmp); + if (jsonTmp != NULL) + { + msg = json_object_get_string (jsonTmp); + } + + json_object_put (jsonHeader); + + if ((serRet == 0) && strcmp (usCmd, SUBSCRIBE_RESPONSE) == 0) + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [msg:%s] [cmd:%s] register proxy success", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, msg, + usCmd); + + } + else + { + if (strcmp (usCmd, SUBSCRIBE_RESPONSE) == 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [msg:%s] [cmd:%s] [ret:%d] register proxy failed, iRet=%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, msg, + usCmd, serRet); + } + else + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] [Seq:%d] [msg:%s] [cmd:%s]register proxy failed, unknown cmd", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort, seq, msg, + usCmd); + } + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + + //send start command + if (flag == 1) + { + StWemqThreadMsg stThreadMsg; + memset (&stThreadMsg, 0x00, sizeof (StWemqThreadMsg)); + stThreadMsg.m_iCmd = THREAD_MSG_CMD_START; + + WEMQJSON *jsonHeader = json_object_new_object (); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "json_object_new_object failed"); + return -2; + } + //add command + json_object_object_add (jsonHeader, MSG_HEAD_COMMAND_STR, + json_object_new_string (LISTEN_REQUEST)); + //add seq + json_object_object_add (jsonHeader, MSG_HEAD_SEQ_INT, + json_object_new_int (0)); + //add code + json_object_object_add (jsonHeader, MSG_HEAD_CODE_INT, + json_object_new_int (0)); + + const char *header_str = json_object_get_string (jsonHeader); + if (header_str == NULL) + { + LOGRMB (RMB_LOG_ERROR, "header is null"); + json_object_put (jsonHeader); + return -2; + } + + stThreadMsg.m_iHeaderLen = strlen (header_str); + LOGRMB (RMB_LOG_DEBUG, "Get thread msg header succ, len=%u, %s", + stThreadMsg.m_iHeaderLen, header_str) stThreadMsg.m_pHeader = + (char *) malloc ((stThreadMsg.m_iHeaderLen + 1) * sizeof (char)); + if (stThreadMsg.m_pHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, "malloc for stThreadMsg.m_pHeader failed"); + json_object_put (jsonHeader); + return -2; + } + memcpy (stThreadMsg.m_pHeader, header_str, stThreadMsg.m_iHeaderLen); + stThreadMsg.m_pHeader[stThreadMsg.m_iHeaderLen] = '\0'; + + json_object_put (jsonHeader); + + stThreadMsg.m_iBodyLen = 0; + stThreadMsg.m_pBody = NULL; + + int iRet = _wemq_thread_do_cmd_start_msg (pThreadCtx, &stThreadMsg); + if (iRet == -2) + { + _wemq_thread_clear_thread_msg (&stThreadMsg); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + + iRet = _wemq_thread_do_recv_sync (pThreadCtx); + if (iRet != 0) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] Decode Wemq Header ERROR", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + + StWeMQMSG *pWemqHeader = &pThreadCtx->m_stWeMQMSG; + jsonHeader = NULL; + WEMQJSON *jsonTmp = NULL; + char *usCmd; + char *msg; + int serRet = -1; + int seq = -1; + long time = 0; + + jsonHeader = json_tokener_parse (pWemqHeader->cStrJsonHeader); + if (jsonHeader == NULL) + { + LOGRMB (RMB_LOG_ERROR, + "[Type:%d] [TID:%lu] [LocalPort:%d] json_tokener_parse error:%s", + pThreadCtx->m_contextType, pThreadCtx->m_threadID, + pThreadCtx->m_iLocalPort, pWemqHeader->cStrJsonHeader); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + + json_object_object_get_ex (jsonHeader, MSG_HEAD_COMMAND_STR, &jsonTmp); + if (jsonTmp != NULL) + { + usCmd = json_object_get_string (jsonTmp); + } + + json_object_object_get_ex (jsonHeader, MSG_HEAD_CODE_INT, &jsonTmp); + if (jsonTmp != NULL) + { + serRet = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_SEQ_INT, &jsonTmp); + if (jsonTmp != NULL) + { + seq = json_object_get_int (jsonTmp); + } + json_object_object_get_ex (jsonHeader, MSG_HEAD_MSG_STR, &jsonTmp); + if (jsonTmp != NULL) + { + msg = json_object_get_string (jsonTmp); + } + + json_object_put (jsonHeader); + + if (serRet != 0 || (strcmp (usCmd, LISTEN_RESPONSE) != 0)) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [Seq:%d] [msg:%s] [CMD:%d] reconnect send start listen error:%d", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, seq, msg, + usCmd, serRet); + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_BREAK); + } + } + + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_OK); +} + +int32_t wemq_thread_state_destory (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + free (pThreadCtx->m_pRecvBuff); + free (pThreadCtx->m_pSendBuff); + free (pThreadCtx->m_ptEvents); + + if (pThreadCtx->m_iSockFd != -1) + { + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->m_iSockFd = -1; + pThreadCtx->ssl = NULL; + } + if (NULL != pThreadCtx->sslCtx) + { + SSL_CTX_free (pThreadCtx->sslCtx); + pThreadCtx->sslCtx = NULL; + } + return _wemq_thread_state_trans (pThreadCtx, pThreadCtx->m_iState, + THREAD_STATE_EXIT); +} + +void wemq_thread_clear_timeout_rr_async_request (WemqThreadCtx * pThreadCtx) +{ + if (pThreadCtx->m_contextType == RMB_CONTEXT_TYPE_SUB) + return; + stContextProxy *pContextProxy = pThreadCtx->m_ptProxyContext; + struct timeval tv_now; + gettimeofday (&tv_now, NULL); + unsigned long ulNowTime = tv_now.tv_sec * 1000 + tv_now.tv_usec / 1000; + //int timeout = pRmbStConfig->rrAsyncTimeOut; + if (pThreadCtx->m_ptProxyContext->ulLastClearRRAysncMsgTime == 0) + { + pThreadCtx->m_ptProxyContext->ulLastClearRRAysncMsgTime = ulNowTime; + } + // 1s 清除一次 + if (ulNowTime >= + pThreadCtx->m_ptProxyContext->ulLastClearRRAysncMsgTime + 1 * 1000) + { + int i; + pthread_mutex_lock (&pContextProxy->rrMutex); + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncNew. + get_array_size (&pContextProxy->pUniqueListForRRAsyncNew); i++) + { + if (pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag == 1 + && ulNowTime >= + (pContextProxy->pUniqueListForRRAsyncNew.Data[i].timeStamp + + pContextProxy->pUniqueListForRRAsyncNew.Data[i].timeout)) + { //有超时的rr异步消息 + LOGRMB (RMB_LOG_WARN, + "rr async bizSeq:%s ,unique_id:%s time out, remove!", + pContextProxy->pUniqueListForRRAsyncNew.Data[i].biz_seq, + pContextProxy->pUniqueListForRRAsyncNew.Data[i].unique_id); + pContextProxy->pUniqueListForRRAsyncNew.Data[i].flag = 0; + } + } + for (i = 0; + i < + pContextProxy->pUniqueListForRRAsyncOld. + get_array_size (&pContextProxy->pUniqueListForRRAsyncOld); i++) + { + if (pContextProxy->pUniqueListForRRAsyncOld.Data[i].flag == 1 + && ulNowTime >= + (pContextProxy->pUniqueListForRRAsyncOld.Data[i].timeStamp + + pContextProxy->pUniqueListForRRAsyncOld.Data[i].timeout)) + { //有超时的rr异步消息 + LOGRMB (RMB_LOG_WARN, + "rr old async bizSeq:%s ,unique_id:%s time out, remove!", + pContextProxy->pUniqueListForRRAsyncOld.Data[i].biz_seq, + pContextProxy->pUniqueListForRRAsyncOld.Data[i].unique_id); + pContextProxy->pUniqueListForRRAsyncOld.Data[i].flag = 0; + } + } + pthread_mutex_unlock (&pContextProxy->rrMutex); + pThreadCtx->m_ptProxyContext->ulLastClearRRAysncMsgTime = ulNowTime; + } +} + +void wemq_thread_do_deal_with_old_connect (WemqThreadCtx * pThreadCtx) +{ + ASSERT (pThreadCtx); + int iRecv = 0; + int iRet = -1; + if (pThreadCtx->m_iSockFdOld >= 0) + { + if (wemq_rr_msg_is_empty (pThreadCtx->m_ptProxyContext) == 0 && pThreadCtx->m_ptProxyContext->iFlagForEvent == 0) //rr同步和异步消息和单播的ack都已全部回来 + { + LOGRMB (RMB_LOG_INFO, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] RECV all rsp", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIPOld, pThreadCtx->m_uiProxyPortOld); + //stContextProxy* pContextProxy = pThreadCtx->m_ptProxyContext; + + wemq_proxy_goodbye (pThreadCtx->m_cProxyIPOld, + pThreadCtx->m_uiProxyPortOld); + _wemq_thread_del_old_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFdOld, pThreadCtx->sslOld); + pThreadCtx->m_iSockFdOld = -1; + pThreadCtx->sslOld = NULL; + return; + } + + iRecv = _wemq_thread_do_recv_async (pThreadCtx, false); + if (iRecv > 0) + { + LOGRMB (RMB_LOG_DEBUG, "[%s] [Type:%d] [TID:%lu] RECV %d bytes", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID, iRecv); + iRet = _wemq_thread_on_message (pThreadCtx, false); + + } + else + { + //LOGWEMQ(WEMQ_LOG_ERROR, "[%s],[TID:%d],ERROR RECV %d bytes\n", STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_iThreadId, iRecv); + if (iRecv == -1) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu]Thread on Message ERROR", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID); + } + if (iRecv == -2) + { + LOGRMB (RMB_LOG_ERROR, + "[%s] [Type:%d] [TID:%lu] [LocalPort:%d] [proxy ip:%s|port:%u] connect closed by peer", + STATE_MAP[pThreadCtx->m_iState], pThreadCtx->m_contextType, + pThreadCtx->m_threadID, pThreadCtx->m_iLocalPort, + pThreadCtx->m_cProxyIP, pThreadCtx->m_uiProxyPort); + wemq_proxy_goodbye (pThreadCtx->m_cProxyIPOld, + pThreadCtx->m_uiProxyPortOld); + _wemq_thread_del_old_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFdOld, pThreadCtx->sslOld); + pThreadCtx->m_iSockFdOld = -1; + pThreadCtx->sslOld = NULL; + + } + } + } +} + +int32_t wemq_thread_run (WemqThreadCtx * pThreadCtx) +{ +// ASSERT (pThreadCtx); + if (pThreadCtx == NULL) + { + LOGRMB (RMB_LOG_ERROR, "wemq_thread_run:pThreadCtx is null"); + return -1; + } + int iRet = 0; + int iRunFlag = 1; + int countDown = 0; + while (iRunFlag) +// while (pThreadCtx->m_ptProxyContext->iFlagForRun) + { + _wemq_thread_send_heart_beat (pThreadCtx); + switch (pThreadCtx->m_iState) + { + case THREAD_STATE_INIT: + { + _wemq_thread_check_init (pThreadCtx); + iRet = wemq_thread_state_init (pThreadCtx); + if (iRet < 0) + { + LOGRMB (RMB_LOG_ERROR, "wemq_thread_state_init failed,iRet=%d", + iRet); + return -1; + } + break; + } + case THREAD_STATE_CONNECT: + { + _wemq_thread_check_connect (pThreadCtx); + wemq_thread_state_connect (pThreadCtx); + break; + } + case THREAD_STATE_REGI: + { + _wemq_thread_check_regi (pThreadCtx); + wemq_thread_state_regi (pThreadCtx); + break; + } + case THREAD_STATE_OK: + { + _wemq_thread_check_ok (pThreadCtx); + wemq_thread_state_ok (pThreadCtx); + break; + } + case THREAD_STATE_CLOSE: + { + _wemq_thread_check_close (pThreadCtx); + wemq_thread_state_close (pThreadCtx); + break; + } + + case THREAD_STATE_BREAK: + { + _wemq_thread_check_break (pThreadCtx); + wemq_thread_state_break (pThreadCtx); + break; + } + case THREAD_STATE_RECONNECT: + { + _wemq_thread_check_reconnect (pThreadCtx); + wemq_thread_state_reconnect (pThreadCtx); + break; + } + case THREAD_STATE_DESTROY: + { + _wemq_thread_check_destory (pThreadCtx); + wemq_thread_state_destory (pThreadCtx); + break; + } + default: + iRunFlag = 0; + break; + } + wemq_thread_clear_timeout_rr_async_request (pThreadCtx); + if (pThreadCtx->m_ptProxyContext->iFlagForRun == 0) + { + if (wemq_thread_fifo_msg_is_empty (pThreadCtx) == 0 + && wemq_rr_all_msg_is_empty (pThreadCtx->m_ptProxyContext) == 0) + { + iRunFlag = 0; + } + else + { + GetRmbNowLongTime (); + unsigned long timeout = pRmbStConfig->ulExitTimeOut; //default:30s + //超过timeout直接退出 + if (pRmbStConfig->ulNowTtime >= + pThreadCtx->m_ptProxyContext->ulGoodByeTime + timeout) + { + iRunFlag = 0; + } + } + } + } + LOGRMB (RMB_LOG_INFO, "[%s] [Type:%d] [TID:%lu] THREAD EXIT!!!!", + STATE_MAP[pThreadCtx->m_iState], + pThreadCtx->m_contextType, pThreadCtx->m_threadID); + + _wemq_thread_del_fd (pThreadCtx); + wemq_tcp_close (pThreadCtx->m_iSockFd, pThreadCtx->ssl); + pThreadCtx->ssl = NULL; + pThreadCtx->m_iSockFd = -1; + + return 0; +} + +int32_t check_dyed_msg (StRmbMsg * rmbMsg) +{ + if (rmbMsg == NULL) + { + LOGRMB (RMB_LOG_ERROR, "rmbMsg is null"); + return -1; + } + if (strcmp (rmbMsg->isDyedMsg, "true") == 0) + { + return 1; + } + else + { + return 0; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/src/wemq_topic_list.c b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_topic_list.c new file mode 100644 index 0000000000..7b3376e5e2 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/src/wemq_topic_list.c @@ -0,0 +1,237 @@ +// 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. + +#include +#include "wemq_topic_list.h" + +static int print_wemq_topic (StWemqTopicProp * pArg) +{ + if (pArg == NULL) + { + printf ("pArg is null\n"); + return -1; + } + + if (pArg->flag == 0) + { + printf ("Topic:\n\tflag=%d\n\tserviceid=%s\n\tscenario=%s\n", pArg->flag, + pArg->cServiceId, pArg->cScenario); + } + else if (pArg->flag == 1) + { + printf ("Topic:\n\tflag=%d\n\ttopic=%s\n", pArg->flag, pArg->cTopic); + } + else + { + printf ("unknown flag:%d\n", pArg->flag); + } + + return 0; +} + +static int wemq_topic_list_iter (StWemqTopicList * ptTopicList, + WEMQ_DEC_FUNC func) +{ + StWemqTopicProp *tmp = ptTopicList->next; + while (tmp != NULL) + { + func (tmp); + tmp = tmp->next; + } + return 1; +} + +inline int32_t wemq_topic_list_is_empty (StWemqTopicList * ptTopicList) +{ + return (ptTopicList->next == NULL) ? 1 : 0; +} + +void wemq_topic_list_init (StWemqTopicList * ptTopicList) +{ + if (!wemq_topic_list_is_empty (ptTopicList)) + { + wemq_topic_list_clear (ptTopicList); + } + ptTopicList->next = NULL; + ptTopicList->tail = NULL; +} + +int wemq_topic_list_clear (StWemqTopicList * ptTopicList) +{ + if (ptTopicList == NULL) + { + return 1; + } + + StWemqTopicProp *ptTemp1 = ptTopicList->next; + StWemqTopicProp *ptTemp2 = ptTopicList->next; + while (ptTemp1 != NULL) + { + ptTemp1 = ptTemp1->next; + ptTemp2->next = NULL; + free (ptTemp2); + ptTemp2 = ptTemp1; + } + + return 1; +} + +int32_t wemq_topic_list_add_node (StWemqTopicList * ptTopicList, + StWemqTopicProp * ptTopicProp) +{ + if (ptTopicProp == NULL) + { + return -1; + } + + if (ptTopicList == NULL) + { + return -1; + } + + if (wemq_topic_list_find_node (ptTopicList, ptTopicProp, NULL) != 1) + { + if (ptTopicList->tail == NULL) + { + StWemqTopicProp *tmp = + (StWemqTopicProp *) malloc (sizeof (StWemqTopicProp)); + if (tmp == NULL) + { + printf ("malloc for StTopicProp failed!\n"); + return -2; + } + memset (tmp, 0, sizeof (StWemqTopicProp)); + if (ptTopicProp->flag == 0) + { + strncpy (tmp->cServiceId, ptTopicProp->cServiceId, + strlen (ptTopicProp->cServiceId)); + strncpy (tmp->cScenario, ptTopicProp->cScenario, + strlen (ptTopicProp->cScenario)); + } + else + { + strncpy (tmp->cTopic, ptTopicProp->cTopic, + strlen (ptTopicProp->cTopic)); + } + tmp->flag = ptTopicProp->flag; + tmp->next = NULL; + ptTopicList->next = tmp; + ptTopicList->tail = tmp; + } + else + { + StWemqTopicProp *tmp = + (StWemqTopicProp *) malloc (sizeof (StWemqTopicProp)); + if (tmp == NULL) + { + printf ("malloc for StTopicProp failed!\n"); + return -2; + } + memset (tmp, 0, sizeof (StWemqTopicProp)); + if (ptTopicProp->flag == 0) + { + strncpy (tmp->cServiceId, ptTopicProp->cServiceId, + strlen (ptTopicProp->cServiceId)); + strncpy (tmp->cScenario, ptTopicProp->cScenario, + strlen (ptTopicProp->cScenario)); + } + else + { + strncpy (tmp->cTopic, ptTopicProp->cTopic, + strlen (ptTopicProp->cTopic)); + } + tmp->flag = ptTopicProp->flag; + tmp->next = NULL; + ptTopicList->tail->next = tmp; + ptTopicList->tail = tmp; + } + return 1; + } + else + { + return 2; + } +} + +int32_t wemq_topic_list_find_node (StWemqTopicList * ptTopicList, + StWemqTopicProp * ptTopicProp, + StWemqTopicProp ** pos) +{ + if (ptTopicList == NULL || ptTopicProp == NULL) + { + return -1; + } + + StWemqTopicProp *tmp = ptTopicList->next; + while (tmp != NULL) + { + if (tmp->flag == 0) + { + if ((strncmp + (tmp->cServiceId, ptTopicProp->cServiceId, + strlen (tmp->cServiceId)) == 0) + && + (strncmp + (tmp->cScenario, ptTopicProp->cScenario, + strlen (tmp->cScenario)) == 0)) + { + if (pos != NULL) + *pos = tmp; + return 1; + } + } + else + { + if (strncmp (tmp->cTopic, ptTopicProp->cTopic, strlen (tmp->cTopic)) == + 0) + { + if (pos != NULL) + *pos = tmp; + + return 1; + } + } + + tmp = tmp->next; + } + return -1; +} + +int32_t wemq_topic_list_del_node (StWemqTopicList * ptTopicList, + StWemqTopicProp * ptTopicProp) +{ + StWemqTopicProp *pos = NULL; + if (wemq_topic_list_find_node (ptTopicList, ptTopicProp, &pos) != 1) + { + return -1; + } + + StWemqTopicProp *tmp1 = pos; + StWemqTopicProp *tmp2 = ptTopicList->next; + if (tmp2 == tmp1) + { + ptTopicList->next = tmp1->next; + free (tmp1); + return 1; + } + + while ((tmp2->next != tmp1) && (tmp2->next != NULL)) + { + tmp2 = tmp2->next; + } + tmp2->next = tmp1->next; + free (tmp1); + return 1; +} diff --git a/eventmesh-sdks/eventmesh-sdk-c/third_party/curl b/eventmesh-sdks/eventmesh-sdk-c/third_party/curl new file mode 160000 index 0000000000..d755a5f7c0 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/third_party/curl @@ -0,0 +1 @@ +Subproject commit d755a5f7c009dd63a61b2c745180d8ba937cbfeb diff --git a/eventmesh-sdks/eventmesh-sdk-c/third_party/json-c b/eventmesh-sdks/eventmesh-sdk-c/third_party/json-c new file mode 160000 index 0000000000..b4c371fa0c --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-c/third_party/json-c @@ -0,0 +1 @@ +Subproject commit b4c371fa0cbc4dcbaccc359ce9e957a22988fb34 diff --git a/eventmesh-sdks/eventmesh-sdk-go/.golangci.yml b/eventmesh-sdks/eventmesh-sdk-go/.golangci.yml new file mode 100644 index 0000000000..9b1e3ec439 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/.golangci.yml @@ -0,0 +1,390 @@ +# +# 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. +# + +# Options for analysis running. +run: + # The default concurrency value is the number of available CPU. + #concurrency: 4 + + # Timeout for analysis, e.g. 30s, 5m. + # Default: 1m + timeout: 20m + + # Exit code when at least one issue was found. + # Default: 1 + #issues-exit-code: 2 + + # Include test files or not. + # Default: true + #tests: false + + # List of build tags, all linters use it. + # Default: []. + #build-tags: + # - mytag + + # Which dirs to skip: issues from them won't be reported. + # Can use regexp here: `generated.*`, regexp is applied on full path. + # Default value is empty list, + # but default dirs are skipped independently of this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work on Windows. + #skip-dirs: + #- src/external_libs + #- autogenerated_by_my_lib + + # Enables skipping of directories: + # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + # Default: true + #skip-dirs-use-default: false + + # Which files to skip: they will be analyzed, but issues from them won't be reported. + # Default value is empty list, + # but there is no need to include all autogenerated files, + # we confidently recognize autogenerated files. + # If it's not please let us know. + # "/" will be replaced by current OS file path separator to properly work on Windows. + #skip-files: + #- ".*\\.my\\.go$" + #- lib/bad.go + + # If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + # + # Allowed values: readonly|vendor|mod + # By default, it isn't set. + #modules-download-mode: readonly + + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + #allow-parallel-runners: false + + # Define the Go version limit. + # Mainly related to generics support since go1.18. + # Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.18 + #go: '1.19' + + +# output configuration options +output: + # Format: colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml|github-actions + # + # Multiple can be specified by separating them by comma, output can be provided + # for each of them by separating format name and path by colon symbol. + # Output path can be either `stdout`, `stderr` or path to the file to write to. + # Example: "checkstyle:report.json,colored-line-number" + # + # Default: colored-line-number + #format: json + + # Print lines of code with issue. + # Default: true + #print-issued-lines: false + + # Print linter name in the end of issue text. + # Default: true + #print-linter-name: false + + # Make issues output unique by line. + # Default: true + #uniq-by-line: false + + # Add a prefix to the output file references. + # Default is no prefix. + path-prefix: "" + + # Sort results by: filepath, line and column. + #sort-results: false + + +# This file contains only configs which differ from defaults. +# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml +linters-settings: + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 20 + # The maximal average package complexity. + # If it's higher than 0.0 (float) the check is enabled + # Default: 0.0 + #package-average: 0.5 + # Should ignore tests. + # Default: false + skip-tests: true + + errcheck: + # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. + # Such cases aren't reported by default. + # Default: false + check-type-assertions: true + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`. + # Such cases aren't reported by default. + # Default: false + check-blank: true + + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 + lines: 100 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 + statements: 50 + + gocognit: + # Minimal code complexity to report + # Default: 30 (but we recommend 10-20) + min-complexity: 20 + + gocritic: + # Settings passed to gocritic. + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be find in https://go-critic.github.io/overview. + settings: + captLocal: + # Whether to restrict checker to params only. + # Default: true + paramsOnly: false + underef: + # Whether to skip (*x).method() calls where x is a pointer receiver. + # Default: true + skipRecvDeref: false + + gomnd: + # List of function patterns to exclude from analysis. + # Values always ignored: `time.Date` + # Default: [] + ignored-functions: + - os.Chmod + - os.Mkdir + - os.MkdirAll + - os.OpenFile + - os.WriteFile + - prometheus.ExponentialBuckets + - prometheus.ExponentialBucketsRange + - prometheus.LinearBuckets + - strconv.FormatFloat + - strconv.FormatInt + - strconv.FormatUint + - strconv.ParseFloat + - strconv.ParseInt + - strconv.ParseUint + + gomodguard: + blocked: + # List of blocked modules. + # Default: [] + modules: + - github.com/golang/protobuf: + recommendations: + - google.golang.org/protobuf + reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules" + - github.com/satori/go.uuid: + recommendations: + - github.com/google/uuid + reason: "satori's package is not maintained" + - github.com/gofrs/uuid: + recommendations: + - github.com/google/uuid + reason: "see recommendation from dev-infra team: https://confluence.gtforge.com/x/gQI6Aw" + + govet: + # Enable all analyzers. + # Default: false + enable-all: true + # Disable analyzers by name. + # Run `go tool vet help` to see all analyzers. + # Default: [] + disable: + - fieldalignment # too strict + # Settings per analyzer. + settings: + shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + strict: true + + nakedret: + # Make an issue if func has more lines of code than this setting, and it has naked returns. + # Default: 30 + max-func-lines: 0 + + nolintlint: + # Exclude following linters from requiring an explanation. + # Default: [] + allow-no-explanation: [ funlen, gocognit, lll ] + # Enable to require an explanation of nonzero length after each nolint directive. + # Default: false + require-explanation: true + # Enable to require nolint directives to mention the specific linter being suppressed. + # Default: false + require-specific: true + + rowserrcheck: + # database/sql is always checked + # Default: [] + packages: + - github.com/jmoiron/sqlx + + tenv: + # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. + # Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. + # Default: false + all: true + + +linters: + disable-all: true + enable: + ## enabled by default + - errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases + - gosimple # specializes in simplifying a code + - govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string + - ineffassign # detects when assignments to existing variables are not used + - staticcheck # is a go vet on steroids, applying a ton of static analysis checks + - typecheck # like the front-end of a Go compiler, parses and type-checks Go code + - unused # checks for unused constants, variables, functions and types + ## disabled by default + - asasalint # checks for pass []any as any in variadic func(...any) + - asciicheck # checks that your code does not contain non-ASCII identifiers + - bidichk # checks for dangerous unicode character sequences + - bodyclose # checks whether HTTP response body is closed successfully + #- contextcheck # checks the function whether use a non-inherited context # TODO: enable after golangci-lint uses https://github.com/sylvia7788/contextcheck/releases/tag/v1.0.7 + - cyclop # checks function and package cyclomatic complexity + - dupl # tool for code clone detection + - durationcheck # checks for two durations multiplied together + - errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error + - errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13 + - execinquery # checks query string in Query function which reads your Go src files and warning it finds + - exhaustive # checks exhaustiveness of enum switch statements + - exportloopref # checks for pointers to enclosing loop variables + #forbidigo # forbids identifiers + - funlen # tool for detection of long functions + #gochecknoglobals # checks that no global variables exist + #gochecknoinits # checks that no init functions are present in Go code + - gocognit # computes and checks the cognitive complexity of functions + - goconst # finds repeated strings that could be replaced by a constant + - gocritic # provides diagnostics that check for bugs, performance and style issues + - gocyclo # computes and checks the cyclomatic complexity of functions + #godot # checks if comments end in a period + - goimports # in addition to fixing imports, goimports also formats your code in the same style as gofmt + - gomnd # detects magic numbers + - gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod + - gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations + - goprintffuncname # checks that printf-like functions are named with f at the end + - gosec # inspects source code for security problems + - lll # reports long lines + - makezero # finds slice declarations with non-zero initial length + - nakedret # finds naked returns in functions greater than a specified function length + - nestif # reports deeply nested if statements + - nilerr # finds the code that returns nil even if it checks that the error is not nil + - nilnil # checks that there is no simultaneous return of nil error and an invalid value + - noctx # finds sending http request without context.Context + - nolintlint # reports ill-formed or insufficient nolint directives + # nonamedreturns # reports all named returns + - nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL + - predeclared # finds code that shadows one of Go's predeclared identifiers + - promlinter # checks Prometheus metrics naming via promlint + - reassign # checks that package variables are not reassigned + - revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint + - rowserrcheck # checks whether Err of rows is checked successfully + - sqlclosecheck # checks that sql.Rows and sql.Stmt are closed + #stylecheck # is a replacement for golint + - tenv # detects using os.Setenv instead of t.Setenv since Go1.17 + - testpackage # makes you use a separate _test package + - tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes + - unconvert # removes unnecessary type conversions + - unparam # reports unused function parameters + - usestdlibvars # detects the possibility to use variables/constants from the Go standard library + - wastedassign # finds wasted assignment statements + - whitespace # detects leading and trailing whitespace + + ## you may want to enable + #- decorder # checks declaration order and count of types, constants, variables and functions + #- exhaustruct # checks if all structure fields are initialized + #- gci # controls golang package import order and makes it always deterministic + #- godox # detects FIXME, TODO and other comment keywords + #- goheader # checks is file header matches to pattern + #- interfacebloat # checks the number of methods inside an interface + #- ireturn # accept interfaces, return concrete types + #- prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated + #- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope + #- wrapcheck # checks that errors returned from external packages are wrapped + + ## disabled + #- containedctx # detects struct contained context.Context field + #- depguard # [replaced by gomodguard] checks if package imports are in a list of acceptable packages + #- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) + #- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted + #- forcetypeassert # [replaced by errcheck] finds forced type assertions + #- goerr113 # [too strict] checks the errors handling expressions + #- gofmt # [replaced by goimports] checks whether code was gofmt-ed + #- gofumpt # [replaced by goimports, gofumports is not available yet] checks whether code was gofumpt-ed + #- grouper # analyzes expression groups + #- importas # enforces consistent import aliases + #- logrlint # [owner archived repository] checks logr arguments + #- maintidx # measures the maintainability index of each function + #- misspell # [useless] finds commonly misspelled English words in comments + #- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity + #- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test + #- tagliatelle # checks the struct tags + #- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers + #- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines + + ## deprecated + #- deadcode # [deprecated, replaced by unused] finds unused code + #- exhaustivestruct # [deprecated, replaced by exhaustruct] checks if all struct's fields are initialized + #- golint # [deprecated, replaced by revive] golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes + #- ifshort # [deprecated] checks that your code uses short syntax for if-statements whenever possible + #- interfacer # [deprecated] suggests narrower interface types + #- maligned # [deprecated, replaced by govet fieldalignment] detects Go structs that would take less memory if their fields were sorted + #- nosnakecase # [deprecated, replaced by revive var-naming] detects snake case of variable naming and function name + #- scopelint # [deprecated, replaced by exportloopref] checks for unpinned variables in go programs + #- structcheck # [deprecated, replaced by unused] finds unused struct fields + #- varcheck # [deprecated, replaced by unused] finds unused global variables and constants + + +issues: + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 50 + + exclude-rules: + - source: "^//\\s*go:generate\\s" + linters: [ lll ] + - source: "(noinspection|TODO)" + linters: [ godot ] + - source: "//noinspection" + linters: [ gocritic ] + - source: "^\\s+if _, ok := err\\.\\([^.]+\\.InternalError\\); ok {" + linters: [ errorlint ] + - path: "_test\\.go" + linters: + - bodyclose + - dupl + - funlen + - goconst + - gosec + - noctx + - wrapcheck \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-go/Makefile b/eventmesh-sdks/eventmesh-sdk-go/Makefile new file mode 100644 index 0000000000..1a21d4a91f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/Makefile @@ -0,0 +1,102 @@ +# +# 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. +# + +################################################################################ +# Variables # +################################################################################ +export GO111MODULE ?= on +export GOPROXY ?= https://proxy.golang.org +export GOSUMDB ?= sum.golang.org + +# By default, disable CGO_ENABLED. See the details on https://golang.org/cmd/cgo +CGO ?= 0 + +LOCAL_ARCH := $(shell uname -m) +ifeq ($(LOCAL_ARCH),x86_64) + TARGET_ARCH_LOCAL=amd64 +else ifeq ($(shell echo $(LOCAL_ARCH) | head -c 5),armv8) + TARGET_ARCH_LOCAL=arm64 +else ifeq ($(shell echo $(LOCAL_ARCH) | head -c 4),armv) + TARGET_ARCH_LOCAL=arm +else + TARGET_ARCH_LOCAL=amd64 +endif +export GOARCH ?= $(TARGET_ARCH_LOCAL) + +LOCAL_OS := $(shell uname) +ifeq ($(LOCAL_OS),Linux) + TARGET_OS_LOCAL = linux +else ifeq ($(LOCAL_OS),Darwin) + TARGET_OS_LOCAL = darwin +else + TARGET_OS_LOCAL ?= windows +endif +export GOOS ?= $(TARGET_OS_LOCAL) + +ifeq ($(GOOS),windows) +BINARY_EXT_LOCAL:=.exe +GOLANGCI_LINT:=golangci-lint.exe +BUILDMODE:=-buildmode=exe +else +BINARY_EXT_LOCAL:= +GOLANGCI_LINT:=golangci-lint +endif + +COVERAGE_OPTS = -covermode=set -coverprofile=cover_set.out + + +################################################################################ +# Target: test # +################################################################################ +.PHONY: test +test: + go test ./... + +################################################################################ +# Target: coverage # +################################################################################ +.PHONY: coverage +coverage: + go test ./... $(COVERAGE_OPTS) + +################################################################################ +# Target: lint # +################################################################################ +.PHONY: lint +lint: + $(GOLANGCI_LINT) run --timeout=20m + +################################################################################ +# Target: go.mod # +################################################################################ +.PHONY: go.mod +go.mod: + go mod tidy + +################################################################################ +# Target: check-diff # +################################################################################ +.PHONY: check-diff +check-diff: + git diff --exit-code ./go.mod # check no changes + +################################################################################ +# Target: clean # +################################################################################ +.PHONY: clean +clean: + @-rm -rf *.out \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-go/README.md b/eventmesh-sdks/eventmesh-sdk-go/README.md new file mode 100644 index 0000000000..cdab66a7fa --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/README.md @@ -0,0 +1,30 @@ +## EventMesh Go SDK + +### Support api + +1. **gRPC** +2. **HTTP** +3. **TCP** + +### Makefile tip + +#### 1. use golangci-lint static code check + +install: + +```shell +go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest +make lint +``` + +#### 2. test code + +```shell +make test +``` + +#### 3. test coverage + +```shell +make coverage +``` diff --git a/eventmesh-sdk-go/common/constants.go b/eventmesh-sdks/eventmesh-sdk-go/common/constants.go similarity index 100% rename from eventmesh-sdk-go/common/constants.go rename to eventmesh-sdks/eventmesh-sdk-go/common/constants.go diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/id/api.go b/eventmesh-sdks/eventmesh-sdk-go/common/id/api.go new file mode 100644 index 0000000000..7a11cabaf0 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/id/api.go @@ -0,0 +1,24 @@ +/** + * 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. + */ + +package id + +// Interface api to generate uniq id +type Interface interface { + // Next create uniq ID + Next() string +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/id/id_snake.go b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_snake.go new file mode 100644 index 0000000000..9215958e7c --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_snake.go @@ -0,0 +1,97 @@ +/** + * 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. + */ + +package id + +import ( + "bytes" + "errors" + "fmt" + "net" + "strconv" + "strings" + + "github.com/sony/sonyflake" +) + +// flake generate uid by flake +type flake struct { + sf *sonyflake.Sonyflake +} + +func NewFlake() Interface { + macAddr := getMacAddr() + st := sonyflake.Settings{ + MachineID: func() (uint16, error) { + ma := strings.Split(macAddr, ":") + mid, err := strconv.ParseInt(ma[0]+ma[1], 16, 16) + return uint16(mid), err + }, + } + return &flake{ + sf: sonyflake.NewSonyflake(st), + } +} + +func NewFlakeWithSonyflake(sonyflake *sonyflake.Sonyflake) Interface { + return &flake{ + sf: sonyflake, + } +} + +// getMacAddr return the current machine mac address +func getMacAddr() (addr string) { + interfaces, err := GetNetInterfaces() + if err == nil { + for _, i := range interfaces { + if i.Flags&net.FlagUp != 0 && bytes.Compare(i.HardwareAddr, nil) != 0 { + // Don't use random as we have a real address + addr = i.HardwareAddr.String() + break + } + } + } else { + panic(errors.New("flake not created")) + } + + return +} + +func GetNetInterfaces() ([]net.Interface, error) { + return net.Interfaces() +} + +// Nextv generates next id as an uint64 +func (f *flake) Nextv() (id uint64, err error) { + var i uint64 + if f.sf != nil { + i, err = f.sf.NextID() + if err == nil { + id = i + } else { + panic(err) + } + } + return +} + +// Next generates id as a string +func (f *flake) Next() string { + var i uint64 + i, _ = f.Nextv() + return fmt.Sprintf("%d", i) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/id/id_snake_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_snake_test.go new file mode 100644 index 0000000000..54d69365fd --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_snake_test.go @@ -0,0 +1,87 @@ +/** + * 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. + */ + +package id + +import ( + "errors" + "github.com/agiledragon/gomonkey/v2" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/sony/sonyflake" + "net" + "reflect" + "strconv" + "strings" +) + +var _ = Describe("id_snake test", func() { + + Context("NewFlake() exception test ", func() { + It("should get error", func() { + mockPatches := gomonkey.ApplyFunc(GetNetInterfaces, func() ([]net.Interface, error) { + return nil, errors.New("test error") + }) + want := "flake not created" + var ret string + defer func() { + if err := recover(); err != nil { + ret = err.(error).Error() + Ω(ret).To(Equal(want)) + } + mockPatches.Reset() + }() + + _ = NewFlake() + }) + }) + + Context("NextID() exception test ", func() { + + It("should get error", func() { + macAddr := getMacAddr() + st := sonyflake.Settings{ + MachineID: func() (uint16, error) { + ma := strings.Split(macAddr, ":") + mid, err := strconv.ParseInt(ma[0]+ma[1], 16, 16) + return uint16(mid), err + }, + } + + aSonyflake := sonyflake.NewSonyflake(st) + + mockPatches := gomonkey.ApplyMethod(reflect.TypeOf(aSonyflake), "NextID", func() (uint64, error) { + return 0, errors.New("test error") + }) + + flake := NewFlakeWithSonyflake(aSonyflake) + + want := "test error" + var ret string + defer func() { + if err := recover(); err != nil { + ret = err.(error).Error() + Ω(want).To(Equal(ret)) + } + mockPatches.Reset() + }() + + _ = flake.Next() + }) + }) + +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/id/id_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_suite_test.go new file mode 100644 index 0000000000..feeacae412 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_suite_test.go @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package id + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestIdAPIs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "id module Tests") +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/id/id_uuid.go b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_uuid.go new file mode 100644 index 0000000000..84b5081b54 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_uuid.go @@ -0,0 +1,36 @@ +/** + * 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. + */ + +package id + +import ( + "github.com/google/uuid" + "strings" +) + +// UUID generate id by uuid +type UUID struct { +} + +// NewUUID uuid instance +func NewUUID() Interface { + return &UUID{} +} + +func (u *UUID) Next() string { + return strings.ReplaceAll(uuid.New().String(), "-", "") +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/id/id_uuid_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_uuid_test.go new file mode 100644 index 0000000000..fef3836acf --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/id/id_uuid_test.go @@ -0,0 +1,50 @@ +/** + * 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. + */ + +package id + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("uuid test", func() { + + var u Interface + + BeforeEach(func() { + u = NewUUID() + + }) + + Context("construct uuid ", func() { + + It("should not nil", func() { + Ω(u).To(Not(BeNil())) + }) + }) + + Context("next uuid ", func() { + + It("should not nil", func() { + n := u.Next() + Ω(n).To(Not(BeNil())) + Ω(len(n)).To(Equal(32)) + }) + }) + +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/protocol/eventmesh_message.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/eventmesh_message.go new file mode 100644 index 0000000000..f013ba40fd --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/eventmesh_message.go @@ -0,0 +1,24 @@ +// 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. + +package protocol + +type EventMeshMessage struct { + BizSeqNo string `json:"biz_seq_no"` + UniqueId string `json:"unique_id"` + Topic string `json:"topic"` + Content string `json:"content"` + Prop map[string]string `json:"prop"` +} diff --git a/eventmesh-sdk-go/common/protocol/http/body/body.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/body.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/http/body/body.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/body.go diff --git a/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go similarity index 96% rename from eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go index e7ebe973b7..f487685d59 100644 --- a/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go @@ -16,7 +16,7 @@ package client import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/body" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/body" ) var HeartbeatRequestBodyKey = struct { diff --git a/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go similarity index 87% rename from eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go index 78dc39cccc..f71d09b742 100644 --- a/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go @@ -16,8 +16,8 @@ package client import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/body" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/body" ) var SubscribeRequestBodyKey = struct { diff --git a/eventmesh-sdk-go/common/protocol/http/common/client_type.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/client_type.go similarity index 95% rename from eventmesh-sdk-go/common/protocol/http/common/client_type.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/client_type.go index 28e8d05784..39f5c9b7a1 100644 --- a/eventmesh-sdk-go/common/protocol/http/common/client_type.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/client_type.go @@ -18,6 +18,7 @@ package common type ClientType struct { Type int `json:"type"` Desc string `json:"desc"` + Name string `json:"name"` } var DefaultClientType = struct { @@ -27,9 +28,11 @@ var DefaultClientType = struct { PUB: ClientType{ Type: 1, Desc: "Client for publishing", + Name: "PUB", }, SUB: ClientType{ Type: 2, Desc: "Client for subscribing", + Name: "SUB", }, } diff --git a/eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go diff --git a/eventmesh-sdk-go/common/protocol/http/common/protocol_key.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/protocol_key.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/http/common/protocol_key.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/protocol_key.go diff --git a/eventmesh-sdk-go/common/protocol/http/common/protocol_version.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/protocol_version.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/http/common/protocol_version.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/protocol_version.go diff --git a/eventmesh-sdk-go/common/protocol/http/common/request_code.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/request_code.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/http/common/request_code.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/common/request_code.go diff --git a/eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go diff --git a/eventmesh-sdk-go/common/protocol/message_type.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/message_type.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/message_type.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/message_type.go diff --git a/eventmesh-sdk-go/common/protocol/subscription_item.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/subscription_item.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/subscription_item.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/subscription_item.go diff --git a/eventmesh-sdk-go/common/protocol/subscription_mode.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/subscription_mode.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/subscription_mode.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/subscription_mode.go diff --git a/eventmesh-sdk-go/common/protocol/subscription_type.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/subscription_type.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/subscription_type.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/subscription_type.go diff --git a/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go similarity index 93% rename from eventmesh-sdk-go/common/protocol/tcp/codec/codec.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go index a2f588715c..eb56e88665 100644 --- a/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go @@ -19,11 +19,11 @@ import ( "bytes" "encoding/binary" - gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" - gutils "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/common" + gcommon "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" + gutils "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/common" ) const ( diff --git a/eventmesh-sdk-go/common/protocol/tcp/command.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/command.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/tcp/command.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/command.go diff --git a/eventmesh-sdk-go/common/protocol/tcp/header.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/header.go similarity index 97% rename from eventmesh-sdk-go/common/protocol/tcp/header.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/header.go index ed8dcf81ee..fccc0af829 100644 --- a/eventmesh-sdk-go/common/protocol/tcp/header.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/header.go @@ -16,7 +16,7 @@ package tcp import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" ) type Header struct { diff --git a/eventmesh-sdk-go/common/protocol/tcp/package.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/package.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/tcp/package.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/package.go diff --git a/eventmesh-sdk-go/common/protocol/tcp/user_agent.go b/eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/user_agent.go similarity index 100% rename from eventmesh-sdk-go/common/protocol/tcp/user_agent.go rename to eventmesh-sdks/eventmesh-sdk-go/common/protocol/tcp/user_agent.go diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/seq/num.go b/eventmesh-sdks/eventmesh-sdk-go/common/seq/num.go new file mode 100644 index 0000000000..74692dd4c1 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/seq/num.go @@ -0,0 +1,44 @@ +/** + * 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. + */ + +package seq + +import ( + "fmt" + "go.uber.org/atomic" +) + +// Interface to generate sequence number +type Interface interface { + Next() string +} + +// AtomicSeq use atomic.Int64 to create seq number +type AtomicSeq struct { + *atomic.Uint64 +} + +// NewAtomicSeq new atomic sequence instance +func NewAtomicSeq() Interface { + return &AtomicSeq{ + Uint64: atomic.NewUint64(0), + } +} + +func (a *AtomicSeq) Next() string { + return fmt.Sprintf("%v", a.Inc()) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/seq/num_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/seq/num_suite_test.go new file mode 100644 index 0000000000..a205209193 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/seq/num_suite_test.go @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package seq + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestSeq(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "num module Tests") +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/seq/num_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/seq/num_test.go new file mode 100644 index 0000000000..cdae25ca6b --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/seq/num_test.go @@ -0,0 +1,48 @@ +/** + * 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. + */ + +package seq + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("id_snake test", func() { + + var z Interface + BeforeEach(func() { + z = NewAtomicSeq() + }) + + Context("NewAtomicSeq()() test ", func() { + It("should not be null", func() { + Ω(z).To(Not(BeNil())) + }) + }) + + Context("Next() test ", func() { + + It("should no error and increase", func() { + s := z.Next() + Ω(s).To(Equal("1")) + s = z.Next() + Ω(s).To(Equal("2")) + }) + }) + +}) diff --git a/eventmesh-sdk-go/common/utils/ip.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/ip.go similarity index 95% rename from eventmesh-sdk-go/common/utils/ip.go rename to eventmesh-sdks/eventmesh-sdk-go/common/utils/ip.go index 588cff3d32..e0802e3ec4 100644 --- a/eventmesh-sdk-go/common/utils/ip.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/ip.go @@ -16,7 +16,7 @@ package utils import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "net" "sync" diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/utils/ip_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/ip_test.go new file mode 100644 index 0000000000..a259fe8aa0 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/ip_test.go @@ -0,0 +1,35 @@ +/** + * 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. + */ + +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "net" +) + +var _ = Describe("ip test", func() { + Context("HostIPV4() test ", func() { + It("should be ipv4", func() { + ipv4 := HostIPV4() + address := net.ParseIP(ipv4) + Ω(address).To(Not(BeNil())) + }) + }) + +}) diff --git a/eventmesh-sdk-go/common/utils/json_utils.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/json_utils.go similarity index 95% rename from eventmesh-sdk-go/common/utils/json_utils.go rename to eventmesh-sdks/eventmesh-sdk-go/common/utils/json_utils.go index f871609d87..2198f500f2 100644 --- a/eventmesh-sdk-go/common/utils/json_utils.go +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/json_utils.go @@ -18,7 +18,7 @@ package utils import ( "encoding/json" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" ) func MarshalJsonBytes(obj interface{}) []byte { diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/utils/json_utils_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/json_utils_test.go new file mode 100644 index 0000000000..e83e28a8d9 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/json_utils_test.go @@ -0,0 +1,68 @@ +/** + * 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. + */ + +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("json utils test", func() { + Context("MarshalJsonBytes() test ", func() { + It("should not be nil", func() { + json_bytes := MarshalJsonBytes("test") + Ω(json_bytes).To(Not(BeNil())) + }) + + It("should not be nil", func() { + json_bytes := MarshalJsonBytes(nil) + Ω(json_bytes).To(Not(BeNil())) + }) + }) + + Context("UnMarshalJsonBytes() test ", func() { + It("should be equals source string", func() { + json_bytes := MarshalJsonBytes("test") + var test_str string + UnMarshalJsonBytes(json_bytes, &test_str) + Ω(test_str).To(Equal("test")) + }) + }) + + Context("MarshalJsonString() test ", func() { + It("should not be nil", func() { + json_bytes := MarshalJsonString("test") + Ω(json_bytes).To(Not(BeNil())) + }) + + It("should not be nil", func() { + json_bytes := MarshalJsonString(nil) + Ω(json_bytes).To(Not(BeNil())) + }) + }) + + Context("UnMarshalJsonString() test ", func() { + It("should be equals source string", func() { + json_bytes := MarshalJsonString("test") + var test_str string + UnMarshalJsonString(json_bytes, &test_str) + Ω(test_str).To(Equal("test")) + }) + }) + +}) diff --git a/eventmesh-sdk-go/common/utils/pid.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/pid.go similarity index 100% rename from eventmesh-sdk-go/common/utils/pid.go rename to eventmesh-sdks/eventmesh-sdk-go/common/utils/pid.go diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/utils/pid_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/pid_test.go new file mode 100644 index 0000000000..f129246fb4 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/pid_test.go @@ -0,0 +1,33 @@ +/** + * 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. + */ + +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("pid test", func() { + Context("CurrentPID() test ", func() { + It("should not be null", func() { + pid := CurrentPID() + Ω(pid).To(Not(BeNil())) + }) + }) + +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/utils/random_utils.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/random_utils.go new file mode 100644 index 0000000000..9669fee5f0 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/random_utils.go @@ -0,0 +1,50 @@ +// 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. + +package utils + +import ( + "math/rand" + "time" +) + +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") +var numbers = []rune("0123456789") + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func RandomStr(length uint32) string { + if length == 0 { + return "" + } + ret := make([]rune, 0, length) + for i := 0; i < int(length); i++ { + ret = append(ret, letters[rand.Intn(len(letters))]) + } + return string(ret) +} + +func RandomNumberStr(length uint32) string { + if length == 0 { + return "" + } + ret := make([]rune, 0, length) + for i := 0; i < int(length); i++ { + ret = append(ret, numbers[rand.Intn(len(numbers))]) + } + return string(ret) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/utils/random_utils_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/random_utils_test.go new file mode 100644 index 0000000000..effb05d91d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/random_utils_test.go @@ -0,0 +1,54 @@ +/** + * 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. + */ + +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("random utils test", func() { + Context("RandomStr() test ", func() { + It("should be different string", func() { + randomMap := make(map[string]struct{}) + for i := 0; i < 16; i++ { + str := RandomStr(10) + if _, ok := randomMap[str]; ok { + Ω(ok).To(Equal(false)) + } + Ω(len(str)).To(Equal(10)) + randomMap[str] = struct{}{} + } + }) + }) + + Context("RandomNumberStr() test ", func() { + It("should be different number string", func() { + randomMap := make(map[string]struct{}) + for i := 0; i < 16; i++ { + str := RandomNumberStr(10) + if _, ok := randomMap[str]; ok { + Ω(ok).To(Equal(false)) + } + Ω(len(str)).To(Equal(10)) + randomMap[str] = struct{}{} + } + }) + }) + +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/common/utils/util_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/common/utils/util_suite_test.go new file mode 100644 index 0000000000..86ff585224 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/common/utils/util_suite_test.go @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package utils + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestUtils(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "util module Tests") +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go new file mode 100644 index 0000000000..5d32840cba --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go @@ -0,0 +1,79 @@ +// 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. + +package main + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "io/ioutil" + "net/http" + "strings" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-async-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.CLUSTERING, + SubscribeType: conf.ASYNC, + Topic: "async-sub-grpc-topic", + }, "http://localhost:8080/onmessage") + if err != nil { + fmt.Println(err.Error()) + return + } + http.HandleFunc("/onmessage", func(writer http.ResponseWriter, request *http.Request) { + buf, err := ioutil.ReadAll(request.Body) + if err != nil { + return + } + defer request.Body.Close() + requestStr := strings.Replace(string(buf), "\n", "", -1) + fmt.Printf("onmessage request msg:%s\n", requestStr) + }) + http.ListenAndServe(":8080", nil) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go new file mode 100644 index 0000000000..5545a115c1 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go @@ -0,0 +1,67 @@ +// 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. + +package main + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "101.43.84.47", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-broadcast-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.BROADCASTING, + SubscribeType: conf.ASYNC, + Topic: "grpc-broadcast-topic", + }, "") + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go new file mode 100644 index 0000000000..0016d6c1e1 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go @@ -0,0 +1,67 @@ +// 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. + +package main + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-broadcast-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.BROADCASTING, + SubscribeType: conf.ASYNC, + Topic: "grpc-broadcast-topic", + }, "http://localhost:18080/onmessage") + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go new file mode 100644 index 0000000000..32166dd007 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go @@ -0,0 +1,67 @@ +// 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. + +package main + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-sync-consumer-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.CLUSTERING, + SubscribeType: conf.SYNC, + Topic: "grpc-topic", + }, "") + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go new file mode 100644 index 0000000000..8ef37e62e6 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go @@ -0,0 +1,71 @@ +// 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. + +package main + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-sync-consumer-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeStream(conf.SubscribeItem{ + SubscribeMode: conf.CLUSTERING, + SubscribeType: conf.ASYNC, + Topic: "grpc-topic", + }, func(msg *proto.SimpleMessage) interface{} { + fmt.Println("receive msg: " + msg.String()) + return nil + }) + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/bp/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/bp/main.go new file mode 100644 index 0000000000..94d2999bda --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/bp/main.go @@ -0,0 +1,88 @@ +// 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. + +package main + +import ( + "context" + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" +) + +func main() { + cfg := &conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-batch-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + } + cli, err := grpc.New(cfg) + if err != nil { + fmt.Println("create publish client err:" + err.Error()) + return + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + batchMsg := &proto.BatchMessage{ + Header: grpc.CreateHeader(cfg), + ProducerGroup: "grpc-producergroup", + Topic: "grpc-batch-topic", + MessageItem: []*proto.BatchMessage_MessageItem{ + { + Content: "test for batch publish go grpc -1", + Ttl: "1024", + UniqueId: "110", + SeqNum: "111", + Tag: "batch publish tag 1", + Properties: map[string]string{ + "from": "grpc", + "type": "batch publish", + }, + }, + { + Content: "test for batch publish go grpc", + Ttl: "1024", + UniqueId: "210", + SeqNum: "211", + Tag: "batch publish tag 2", + Properties: map[string]string{ + "from": "grpc", + "type": "batch publish", + }, + }, + }, + } + resp, err := cli.BatchPublish(context.TODO(), batchMsg) + if err != nil { + panic(err) + } + fmt.Println(resp.String()) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/publish/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/publish/main.go new file mode 100644 index 0000000000..8aff799aba --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/publish/main.go @@ -0,0 +1,74 @@ +// 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. + +package main + +import ( + "context" + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/google/uuid" + "time" +) + +func main() { + cfg := &conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + } + cli, err := grpc.New(cfg) + if err != nil { + fmt.Println("create publish client err:" + err.Error()) + return + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + for i := 0; i < 10; i++ { + builder := grpc.NewMessageBuilder() + builder.WithHeader(grpc.CreateHeader(cfg)). + WithContent("test for publish go grpc"). + WithProperties(map[string]string{ + "from": "grpc", + "for": "test"}). + WithProducerGroup("grpc-publish-producergroup"). + WithTag("grpc publish tag"). + WithTopic("grpc-topic"). + WithTTL(time.Hour). + WithSeqNO(uuid.New().String()). + WithUniqueID(uuid.New().String()) + resp, err := cli.Publish(context.TODO(), builder.SimpleMessage) + if err != nil { + panic(err) + } + fmt.Println(resp.String()) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/rr/main.go b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/rr/main.go new file mode 100644 index 0000000000..c8c6f8b9b0 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/grpc/producer/rr/main.go @@ -0,0 +1,73 @@ +// 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. + +package main + +import ( + "context" + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cfg := &conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-rr-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + } + cli, err := grpc.New(cfg) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + builder := grpc.NewMessageBuilder() + builder.WithHeader(grpc.CreateHeader(cfg)). + WithContent("test for rr go grpc"). + WithProperties(map[string]string{ + "from": "grpc", + "for": "test"}). + WithProducerGroup("grpc-rr-producergroup"). + WithTag("grpc rr tag"). + WithTopic("grpc-topic"). + WithTTL(time.Hour). + WithSeqNO("1"). + WithUniqueID("1") + + msg, err := cli.RequestReply(context.TODO(), builder.SimpleMessage) + if err != nil { + fmt.Println("send rr msg err:" + err.Error()) + return + } + fmt.Println(msg.String()) + +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go b/eventmesh-sdks/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go new file mode 100644 index 0000000000..5c5c43dafe --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go @@ -0,0 +1,69 @@ +// 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. + +package http + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/producer" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/google/uuid" + + "os" + "strconv" +) + +func AsyncPubCloudEvents() { + eventMeshIPPort := "127.0.0.1" + ":" + "10105" + producerGroup := "EventMeshTest-producerGroup" + topic := "TEST-TOPIC-HTTP-ASYNC" + env := "P" + idc := "FT" + subSys := "1234" + // FIXME Get ip dynamically + localIp := "127.0.0.1" + + // (Deep) Copy of default config + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLiteEventMeshAddr(eventMeshIPPort) + eventMeshClientConfig.SetProducerGroup(producerGroup) + eventMeshClientConfig.SetEnv(env) + eventMeshClientConfig.SetIdc(idc) + eventMeshClientConfig.SetSys(subSys) + eventMeshClientConfig.SetIp(localIp) + eventMeshClientConfig.SetPid(strconv.Itoa(os.Getpid())) + + // Make event to send + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetSubject(topic) + event.SetSource("example/uri") + event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) + event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) + event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) + data := map[string]string{"hello": "EventMesh"} + err := event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) + if err != nil { + log.Fatalf("Failed to set cloud event data, error: %v", err) + } + + // Publish event + httpProducer := producer.NewEventMeshHttpProducer(eventMeshClientConfig) + httpProducer.PublishCloudEvent(&event) +} diff --git a/eventmesh-sdk-go/examples/http/sub_cloudevents.go b/eventmesh-sdks/eventmesh-sdk-go/examples/http/sub_cloudevents.go similarity index 89% rename from eventmesh-sdk-go/examples/http/sub_cloudevents.go rename to eventmesh-sdks/eventmesh-sdk-go/examples/http/sub_cloudevents.go index 76b9866cc8..305ea2e962 100644 --- a/eventmesh-sdk-go/examples/http/sub_cloudevents.go +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/http/sub_cloudevents.go @@ -16,11 +16,11 @@ package http import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/consumer" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/consumer" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" cloudevents "github.com/cloudevents/sdk-go/v2" "net/http" @@ -68,8 +68,6 @@ func SubCloudEvents() { eventMeshHttpConsumer.Subscribe(topicList, subscribeUrl) eventMeshHttpConsumer.HeartBeat(topicList, subscribeUrl) - // FIXME Add unsubscribe - // Wait for exit <-exit } diff --git a/eventmesh-sdks/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go b/eventmesh-sdks/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go new file mode 100644 index 0000000000..052ed6c1d9 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go @@ -0,0 +1,60 @@ +// 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. + +package tcp + +import ( + "time" + + "github.com/google/uuid" + "strconv" + + "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + gtcp "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/conf" + cloudevents "github.com/cloudevents/sdk-go/v2" +) + +func AsyncPubCloudEvents() { + eventMeshIp := "127.0.0.1" + eventMeshTcpPort := 10000 + topic := "TEST-TOPIC-TCP-ASYNC" + + // Init client + userAgent := gtcp.UserAgent{Env: "test", Subsystem: "5023", Path: "/data/app/umg_proxy", Pid: 32893, + Host: "127.0.0.1", Port: 8362, Version: "2.0.11", Username: "PU4283", Password: "PUPASS", Idc: "FT", + Group: "EventmeshTestGroup", Purpose: "pub"} + config := conf.NewEventMeshTCPClientConfig(eventMeshIp, eventMeshTcpPort, userAgent) + client := tcp.CreateEventMeshTCPClient(*config, protocol.DefaultMessageType.CloudEvent) + client.Init() + + // Make event to send + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetSubject(topic) + event.SetSource("example/uri") + event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) + event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) + event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) + data := map[string]string{"hello": "EventMesh"} + event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) + + // Publish event + client.Publish(event, 10000) + time.Sleep(10 * time.Second) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/go.mod b/eventmesh-sdks/eventmesh-sdk-go/go.mod new file mode 100644 index 0000000000..b00583649d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/go.mod @@ -0,0 +1,36 @@ +// 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. + +module github.com/apache/eventmesh/eventmesh-sdk-go + +go 1.16 + +require ( + github.com/agiledragon/gomonkey/v2 v2.9.0 + github.com/cespare/xxhash v1.1.0 + github.com/cloudevents/sdk-go/v2 v2.6.0 + github.com/google/uuid v1.3.0 + github.com/json-iterator/go v1.1.10 + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.24.2 + github.com/panjf2000/ants v1.3.0 + github.com/smartystreets/goconvey v1.7.2 + github.com/sony/sonyflake v1.0.0 + github.com/stretchr/testify v1.7.0 + go.uber.org/atomic v1.4.0 + go.uber.org/zap v1.10.0 + google.golang.org/grpc v1.45.0 + google.golang.org/protobuf v1.28.0 +) diff --git a/eventmesh-sdks/eventmesh-sdk-go/go.sum b/eventmesh-sdks/eventmesh-sdk-go/go.sum new file mode 100644 index 0000000000..a856bb928f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/go.sum @@ -0,0 +1,298 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/agiledragon/gomonkey/v2 v2.9.0 h1:PDiKKybR596O6FHW+RVSG0Z7uGCBNbmbUXh3uCNQ7Hc= +github.com/agiledragon/gomonkey/v2 v2.9.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.6.0 h1:yp6zLEvhXSi6P25zzfgORgFI0quG2/NXoH9QoHzvKn8= +github.com/cloudevents/sdk-go/v2 v2.6.0/go.mod h1:nlXhgFkf0uTopxmRXalyMwS2LG70cRGPrxzmjJgSG0U= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q= +github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= +github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= +github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M= +github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= +github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/eventmesh-sdk-go/grpc/README.md b/eventmesh-sdks/eventmesh-sdk-go/grpc/README.md similarity index 100% rename from eventmesh-sdk-go/grpc/README.md rename to eventmesh-sdks/eventmesh-sdk-go/grpc/README.md diff --git a/eventmesh-sdks/eventmesh-sdk-go/grpc/api.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/api.go new file mode 100644 index 0000000000..4c6fddc7b6 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/api.go @@ -0,0 +1,51 @@ +// 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. + +package grpc + +import ( + "context" + + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "google.golang.org/grpc" +) + +// OnMessage on receive message from eventmesh, used in subscribe message +type OnMessage func(*proto.SimpleMessage) interface{} + +// Interface grpc client to producer and consumer message +type Interface interface { + // Publish send message to eventmesh, without wait the response from other client + Publish(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.Response, error) + + // RequestReply send message to eventmesh, and wait for the response + RequestReply(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.SimpleMessage, error) + + // BatchPublish send batch message to eventmesh + BatchPublish(ctx context.Context, msg *proto.BatchMessage, opts ...grpc.CallOption) (*proto.Response, error) + + // SubscribeWebhook consumer message in webhook, and OnMessage invoked when new message arrived + SubscribeWebhook(item conf.SubscribeItem, callbackURL string) error + + // SubscribeStream stream subscribe the message + SubscribeStream(item conf.SubscribeItem, handler OnMessage) error + + // UnSubscribe unsubcribe topic, and don't subscribe msg anymore + UnSubscribe() error + + // Close release all resources in the client + Close() error +} diff --git a/eventmesh-sdk-go/grpc/client.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/client.go similarity index 90% rename from eventmesh-sdk-go/grpc/client.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/client.go index d77373e070..06a41af905 100644 --- a/eventmesh-sdk-go/grpc/client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/client.go @@ -18,11 +18,11 @@ package grpc import ( "context" "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "math/rand" @@ -42,7 +42,7 @@ func New(cfg *conf.GRPCConfig, opts ...GRPCOption) (Interface, error) { // eventMeshGRPCClient define the grpc client for eventmesh api type eventMeshGRPCClient struct { grpcConn *grpc.ClientConn - // producer used to send msg to evenmesh + // producer used to send msg to eventmesh *eventMeshProducer // consumer used to subscribe msg from eventmesh *eventMeshConsumer @@ -159,6 +159,13 @@ func (e *eventMeshGRPCClient) UnSubscribe() error { // setupContext set up the context, add id if not exist func (e *eventMeshGRPCClient) setupContext(ctx context.Context) context.Context { val := ctx.Value(GRPC_ID_KEY) + + defer func() { + if err := recover(); err != nil { + log.Warnf("send as rece err:%v", err) + } + }() + if val == nil { ctx = context.WithValue(ctx, GRPC_ID_KEY, e.idg.Next()) } @@ -167,7 +174,7 @@ func (e *eventMeshGRPCClient) setupContext(ctx context.Context) context.Context // Close meshclient and free all resources func (e *eventMeshGRPCClient) Close() error { - log.Infof("close grpc client") + log.Infof("begin close grpc client") if e.cancel != nil { e.cancel() } @@ -183,8 +190,11 @@ func (e *eventMeshGRPCClient) Close() error { } e.eventMeshConsumer = nil } - if err := e.grpcConn.Close(); err != nil { - log.Warnf("err in close conn with err:%v", err) + + if e.grpcConn != nil { + if err := e.grpcConn.Close(); err != nil { + log.Warnf("err in close conn with err:%v", err) + } } log.Infof("success close grpc client") diff --git a/eventmesh-sdks/eventmesh-sdk-go/grpc/client_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/client_test.go new file mode 100644 index 0000000000..825eab7763 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/client_test.go @@ -0,0 +1,563 @@ +// 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. + +package grpc + +import ( + "context" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" + "time" +) + +type fakeidg struct { +} + +func (f *fakeidg) Next() string { + return "fake" +} + +var _ = Describe("client test", func() { + + Context("newEventMeshGRPCClient() test ", func() { + type args struct { + cfg *conf.GRPCConfig + } + + It("host is empty", func() { + tests := []struct { + name string + args args + want *eventMeshGRPCClient + wantErr bool + }{ + { + name: "host is empty", + args: args{cfg: &conf.GRPCConfig{ + Host: "", + }}, + wantErr: true, + want: nil, + }, + } + + for _, tt := range tests { + cli, err := newEventMeshGRPCClient(tt.args.cfg) + if tt.wantErr { + Ω(err).To(HaveOccurred()) + } else { + Ω(err).NotTo(HaveOccurred()) + } + + if cli != nil { + Ω(cli.Close()).NotTo(HaveOccurred()) + } + } + }) + + It("producer wrong", func() { + tests := []struct { + name string + args args + want *eventMeshGRPCClient + wantErr bool + }{ + { + name: "producer wrong", + args: args{cfg: &conf.GRPCConfig{ + Host: "1.1.1.1", + ProducerConfig: conf.ProducerConfig{}, + }}, + wantErr: false, + want: nil, + }, + } + + for _, tt := range tests { + cli, err := newEventMeshGRPCClient(tt.args.cfg) + if tt.wantErr { + Ω(err).To(HaveOccurred()) + } else { + Ω(err).NotTo(HaveOccurred()) + + } + + if cli != nil { + Ω(cli.Close()).NotTo(HaveOccurred()) + } + } + }) + + It("client with send msg", func() { + tests := []struct { + name string + args args + want *eventMeshGRPCClient + wantErr bool + }{ + { + name: "client with send msg", + args: args{cfg: &conf.GRPCConfig{ + Host: "101.43.84.47", + Port: 10205, + ENV: "sendmsgenv", + Region: "sh", + IDC: "idc01", + SYS: "test-system", + ProtocolType: "grpc", + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-producer-group", + }, + Username: "user", + Password: "passwd", + }}, + want: nil, + wantErr: false, + }, + } + + for _, tt := range tests { + cli, err := newEventMeshGRPCClient(tt.args.cfg) + if tt.wantErr { + Ω(err).To(HaveOccurred()) + } else { + Ω(err).NotTo(HaveOccurred()) + + } + + if cli != nil { + Ω(cli.Close()).NotTo(HaveOccurred()) + } + } + }) + + }) + + Context("multiple_set_context() test ", func() { + It("should done", func() { + root := context.Background() + onec, cancel := context.WithTimeout(root, time.Second*3) + defer cancel() + val := "test" + go func() { + + select { + case <-onec.Done(): + val = "test" + case <-time.After(time.Second * 1): + val = "" + } + }() + + time.Sleep(2 * time.Second) + Ω(val).To(Equal("")) + }) + + It("should timeout", func() { + root := context.Background() + onec, cancel := context.WithTimeout(root, time.Second*1) + defer cancel() + + val := "test" + go func() { + + select { + case <-onec.Done(): + val = "test" + break + case <-time.After(time.Second * 3): + val = "" + } + }() + + time.Sleep(2 * time.Second) + Ω(val).To(Equal("test")) + }) + + }) + + Context("eventMeshGRPCClient_Publish test ", func() { + + type args struct { + ctx context.Context + msg *proto.SimpleMessage + opts []grpc.CallOption + } + + It("publish msg", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + Ω(err).NotTo(HaveOccurred()) + + tests := []struct { + name string + args args + want *proto.Response + wantErr assert.ErrorAssertionFunc + }{ + { + name: "publish msg", + args: args{ + ctx: context.TODO(), + msg: &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + Topic: "test-publish-topic", + }, + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + } + + for _, tt := range tests { + _, err := cli.Publish(tt.args.ctx, tt.args.msg, tt.args.opts...) + Ω(err).NotTo(HaveOccurred()) + } + + Ω(cli.Close()).NotTo(HaveOccurred()) + + }) + + It("publish with timeout", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + Ω(err).NotTo(HaveOccurred()) + tests := []struct { + name string + args args + want *proto.Response + wantErr assert.ErrorAssertionFunc + }{ + { + name: "publish with timeout", + args: args{ + ctx: func() context.Context { + ctx, _ := context.WithTimeout(context.Background(), time.Second*10) + return ctx + }(), + msg: &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + Topic: "test-timeout-topic", + }, + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + } + + for _, tt := range tests { + _, err := cli.Publish(tt.args.ctx, tt.args.msg, tt.args.opts...) + Ω(err).NotTo(HaveOccurred()) + } + + Ω(cli.Close()).NotTo(HaveOccurred()) + + }) + + }) + + Context("eventMeshGRPCClient_RequestReply test ", func() { + type args struct { + ctx context.Context + msg *proto.SimpleMessage + opts []grpc.CallOption + } + + It("test-request-reply", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + Ω(err).NotTo(HaveOccurred()) + + tests := []struct { + name string + args args + want *proto.SimpleMessage + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test-request-reply", + args: args{ + ctx: context.TODO(), + msg: &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + Topic: "test-request-reply-topic", + }, + }, + }, + } + for _, tt := range tests { + _, err := cli.RequestReply(tt.args.ctx, tt.args.msg, tt.args.opts...) + Ω(err).NotTo(HaveOccurred()) + } + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) + + Context("eventMeshGRPCClient_RequestReply test ", func() { + type args struct { + ctx context.Context + msg *proto.BatchMessage + opts []grpc.CallOption + } + + It("test batch publish", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + Ω(err).NotTo(HaveOccurred()) + + tests := []struct { + name string + args args + want *proto.Response + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test batch publish", + args: args{ + ctx: context.TODO(), + msg: &proto.BatchMessage{ + Header: &proto.RequestHeader{}, + ProducerGroup: "fake-batch-group", + Topic: "fake-batch-topic", + MessageItem: []*proto.BatchMessage_MessageItem{ + { + Content: "batch-1", + Ttl: "1", + UniqueId: "batch-id", + SeqNum: "1", + Tag: "tag", + Properties: map[string]string{ + "from": "test", + "type": "batch-msg", + }, + }, + { + Content: "batch-2", + Ttl: "2", + UniqueId: "batch-id", + SeqNum: "2", + Tag: "tag", + Properties: map[string]string{ + "from": "test", + "type": "batch-msg", + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + _, err := cli.BatchPublish(tt.args.ctx, tt.args.msg, tt.args.opts...) + Ω(err).NotTo(HaveOccurred()) + + } + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) + + Context("eventMeshGRPCClient_webhook_subscribe test ", func() { + It("webhook_subscribe success", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + Ω(err).NotTo(HaveOccurred()) + Ω(cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: 1, + SubscribeType: 1, + Topic: "topic-1", + }, "http://localhost:8080/onmessage")).NotTo(HaveOccurred()) + time.Sleep(time.Second * 5) + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) + + Context("eventMeshGRPCClient_Subscribe test ", func() { + + type args struct { + item conf.SubscribeItem + handler OnMessage + } + + It("subcribe one success", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + Ω(err).NotTo(HaveOccurred()) + + tests := []struct { + name string + args args + wantErr assert.ErrorAssertionFunc + }{ + { + name: "subcribe one", + args: args{ + item: conf.SubscribeItem{ + SubscribeMode: 1, + SubscribeType: 1, + Topic: "topic-1", + }, + handler: func(message *proto.SimpleMessage) interface{} { + return nil + }, + }, + }, + } + for _, tt := range tests { + err := cli.SubscribeStream(tt.args.item, tt.args.handler) + Ω(err).NotTo(HaveOccurred()) + } + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) + + Context("eventMeshGRPCClient_UnSubscribe test ", func() { + It("unsubcribe success", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + Ω(err).NotTo(HaveOccurred()) + + err = cli.SubscribeStream(conf.SubscribeItem{ + SubscribeMode: 1, + SubscribeType: 1, + Topic: "topic-1", + }, func(message *proto.SimpleMessage) interface{} { + return nil + }) + Ω(err).NotTo(HaveOccurred()) + Ω(cli.UnSubscribe()).NotTo(HaveOccurred()) + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) + + Context("eventMeshGRPCClient_UnSubscribe test ", func() { + type args struct { + ctx context.Context + } + It("unsubcribe success", func() { + cli := &eventMeshGRPCClient{ + idg: &fakeidg{}, + } + + tests := []struct { + name string + args args + want string + }{ + { + name: "setup with uid", + args: args{ + ctx: context.WithValue(context.Background(), GRPC_ID_KEY, "value"), + }, + want: "value", + }, + { + name: "setup without uid", + args: args{ + ctx: context.TODO(), + }, + want: "fake", + }, + } + + for _, tt := range tests { + ctx := cli.setupContext(tt.args.ctx) + Ω(ctx.Value(GRPC_ID_KEY).(string)).To(Equal(tt.want)) + } + + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) +}) diff --git a/eventmesh-sdk-go/grpc/conf/config.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/conf/config.go similarity index 100% rename from eventmesh-sdk-go/grpc/conf/config.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/conf/config.go diff --git a/eventmesh-sdk-go/grpc/conf/config_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/conf/config_test.go similarity index 100% rename from eventmesh-sdk-go/grpc/conf/config_test.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/conf/config_test.go diff --git a/eventmesh-sdk-go/grpc/consts.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/consts.go similarity index 100% rename from eventmesh-sdk-go/grpc/consts.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/consts.go diff --git a/eventmesh-sdk-go/grpc/consumer.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/consumer.go similarity index 95% rename from eventmesh-sdk-go/grpc/consumer.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/consumer.go index 26d271a0b6..1a810abbce 100644 --- a/eventmesh-sdk-go/grpc/consumer.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/consumer.go @@ -18,11 +18,11 @@ package grpc import ( "context" "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" jsoniter "github.com/json-iterator/go" "google.golang.org/grpc" "io" @@ -162,6 +162,14 @@ func (d *eventMeshConsumer) replyMsg(msg *proto.SimpleMessage, reply interface{} return ErrUnSupportResponse } ttl := GetTTLWithDefault(msg, defaultTTL) + + var err error = nil + defer func() { + if rerr := recover(); rerr != nil { + err = rerr.(error) + } + }() + d.streamSubscribeChan <- &proto.Subscription{ Header: msg.Header, ConsumerGroup: d.cfg.ConsumerGroup, @@ -177,7 +185,7 @@ func (d *eventMeshConsumer) replyMsg(msg *proto.SimpleMessage, reply interface{} }, } - return nil + return err } // Subscribe topic for webhook diff --git a/eventmesh-sdk-go/grpc/dispatcher.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/dispatcher.go similarity index 96% rename from eventmesh-sdk-go/grpc/dispatcher.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/dispatcher.go index cb1017bb10..55b27585e3 100644 --- a/eventmesh-sdk-go/grpc/dispatcher.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/dispatcher.go @@ -17,8 +17,8 @@ package grpc import ( "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "sync" "time" diff --git a/eventmesh-sdks/eventmesh-sdk-go/grpc/dispatcher_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/dispatcher_test.go new file mode 100644 index 0000000000..15e6267238 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/dispatcher_test.go @@ -0,0 +1,73 @@ +// 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. + +package grpc + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "sync" +) + +var _ = Describe("dispatcher test", func() { + + Context("messageDispatcher_addHandler test ", func() { + type fields struct { + topicMap *sync.Map + poolsize int + } + + type args struct { + topic string + hdl OnMessage + } + It("test add handler", func() { + tests := []struct { + name string + fields fields + args args + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test add handler", + fields: fields{ + topicMap: new(sync.Map), + poolsize: 5, + }, + args: args{ + topic: "handler-1", + hdl: func(message *proto.SimpleMessage) interface{} { + return nil + }, + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + } + + for _, tt := range tests { + m := &messageDispatcher{ + topicMap: tt.fields.topicMap, + poolsize: tt.fields.poolsize, + } + Ω(m.addHandler(tt.args.topic, tt.args.hdl)).To(BeNil()) + } + }) + + }) +}) diff --git a/eventmesh-sdk-go/grpc/fake_grpcserver.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/fake_grpcserver.go similarity index 91% rename from eventmesh-sdk-go/grpc/fake_grpcserver.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/fake_grpcserver.go index 077e214af3..f28b651551 100644 --- a/eventmesh-sdk-go/grpc/fake_grpcserver.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/fake_grpcserver.go @@ -18,7 +18,8 @@ package grpc import ( "context" "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/seq" + "google.golang.org/grpc" "io" "io/ioutil" "net" @@ -27,11 +28,9 @@ import ( "sync" "time" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - - "google.golang.org/grpc" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" ) // fakeServer used to do the test @@ -62,7 +61,9 @@ func runFakeServer(ctx context.Context) error { go func() { select { case <-ctx.Done(): - srv.GracefulStop() + if srv != nil { + srv.GracefulStop() + } } }() log.Infof("serve fake server on:%v", srv.GetServiceInfo()) @@ -98,6 +99,7 @@ func (f *fakeServer) Subscribe(ctx context.Context, msg *proto.Subscription) (*p func (f *fakeServer) SubscribeStream(srv proto.ConsumerService_SubscribeStreamServer) error { wg := new(sync.WaitGroup) wg.Add(2) + go func() { defer wg.Done() for { @@ -113,8 +115,14 @@ func (f *fakeServer) SubscribeStream(srv proto.ConsumerService_SubscribeStreamSe log.Infof("rece sub:%s", sub.String()) } }() + go func() { - defer wg.Done() + defer func() { + wg.Done() + if err := recover(); err != nil { + log.Warnf("send as rece err:%v", err) + } + }() var index int = 0 for { msg := &proto.SimpleMessage{ @@ -145,6 +153,7 @@ func (f *fakeServer) SubscribeStream(srv proto.ConsumerService_SubscribeStreamSe time.Sleep(time.Second * 5) } }() + wg.Wait() log.Infof("close SubscribeStream") return nil @@ -162,7 +171,7 @@ func (f *fakeServer) Unsubscribe(ctx context.Context, msg *proto.Subscription) ( func (f *fakeServer) Heartbeat(ctx context.Context, msg *proto.Heartbeat) (*proto.Response, error) { log.Infof("fake-server, receive heartbeat request:%v", msg.String()) return &proto.Response{ - RespCode: "OK", + RespCode: "0", RespMsg: "OK", RespTime: time.Now().Format("2006-01-02 15:04:05"), }, nil @@ -181,6 +190,14 @@ func (f *fakeServer) Publish(ctx context.Context, msg *proto.SimpleMessage) (*pr // RequestReply Sync event publish func (f *fakeServer) RequestReply(ctx context.Context, rece *proto.SimpleMessage) (*proto.SimpleMessage, error) { log.Infof("receive request reply topic:%s, content:%s", rece.Topic, rece.Content) + + var err error = nil + defer func() { + if rerr := recover(); rerr != nil { + err = rerr.(error) + } + }() + return &proto.SimpleMessage{ Header: rece.Header, ProducerGroup: "fake-mock-group", @@ -194,7 +211,7 @@ func (f *fakeServer) RequestReply(ctx context.Context, rece *proto.SimpleMessage "from": "fake", "service": "RequestReply", }, - }, nil + }, err } // BatchPublish Async batch event publish diff --git a/eventmesh-sdk-go/grpc/fake_webhookserver.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/fake_webhookserver.go similarity index 93% rename from eventmesh-sdk-go/grpc/fake_webhookserver.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/fake_webhookserver.go index 46ed6a0971..18085c3337 100644 --- a/eventmesh-sdk-go/grpc/fake_webhookserver.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/fake_webhookserver.go @@ -20,6 +20,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" ) // runWebhookServer start a webhook server for fake server on @@ -35,7 +36,8 @@ func runWebhookServer(ctx context.Context) { writer.Write([]byte("read body err")) return } - fmt.Printf("got webhook msg:%s\n", string(buf)) + requestStr := strings.Replace(string(buf), "\n", "", -1) + fmt.Printf("got webhook msg:%s\n", requestStr) writer.WriteHeader(http.StatusOK) writer.Write([]byte("OK")) }) diff --git a/eventmesh-sdks/eventmesh-sdk-go/grpc/grpc_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/grpc_suite_test.go new file mode 100644 index 0000000000..4689619b45 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/grpc_suite_test.go @@ -0,0 +1,44 @@ +/** + * 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. + */ + +package grpc + +import ( + "context" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "testing" +) + +func TestGRPC(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "grpc module Tests") +} + +var gcancel context.CancelFunc + +var _ = BeforeSuite(func() { + ctx, cancel := context.WithCancel(context.Background()) + //defer cancel() + gcancel = cancel + go runFakeServer(ctx) + go runWebhookServer(ctx) +}) + +var _ = AfterSuite(func() { + gcancel() +}) diff --git a/eventmesh-sdk-go/grpc/heartbeat.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/heartbeat.go similarity index 95% rename from eventmesh-sdk-go/grpc/heartbeat.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/heartbeat.go index 105b1656e6..7bb061eeae 100644 --- a/eventmesh-sdk-go/grpc/heartbeat.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/heartbeat.go @@ -18,9 +18,9 @@ package grpc import ( "context" "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "google.golang.org/grpc" "sync" "time" diff --git a/eventmesh-sdks/eventmesh-sdk-go/grpc/heartbeat_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/heartbeat_test.go new file mode 100644 index 0000000000..21bae58fba --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/heartbeat_test.go @@ -0,0 +1,64 @@ +// 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. + +package grpc + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "time" +) + +var _ = Describe("dispatcher test", func() { + + Context("messageDispatcher_addHandler test ", func() { + It("fake-topic", func() { + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + LoadBalancerType: conf.Random, + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "fake-consumer", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 50, + Timeout: time.Second * 30, + }, + }) + Ω(err).NotTo(HaveOccurred()) + + topic := "fake-topic" + Ω(cli.SubscribeStream(conf.SubscribeItem{ + SubscribeType: 1, + SubscribeMode: 1, + Topic: topic, + }, func(message *proto.SimpleMessage) interface{} { + return nil + })).NotTo(HaveOccurred()) + + rcli := cli.(*eventMeshGRPCClient) + beat := rcli.heartbeat + Ω(beat.sendMsg(beat.client)).NotTo(HaveOccurred()) + Ω(cli.Close()).NotTo(HaveOccurred()) + }) + }) +}) diff --git a/eventmesh-sdk-go/grpc/loadbalancer/README.md b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/README.md similarity index 100% rename from eventmesh-sdk-go/grpc/loadbalancer/README.md rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/README.md diff --git a/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go similarity index 97% rename from eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go index 890162a5e1..cdf7efb01d 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go @@ -17,7 +17,7 @@ package loadbalancer import ( "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" "go.uber.org/atomic" "sync" ) diff --git a/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go similarity index 98% rename from eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go index b3eb916230..69ba973179 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go @@ -16,7 +16,7 @@ package loadbalancer import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" "github.com/stretchr/testify/assert" "sync" "testing" diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule.go similarity index 100% rename from eventmesh-sdk-go/grpc/loadbalancer/rule.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule.go diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go similarity index 96% rename from eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go index dfde0e735f..29d7129600 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go @@ -16,7 +16,7 @@ package loadbalancer import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "github.com/cespare/xxhash" "reflect" "unsafe" diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go similarity index 97% rename from eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go index 7375c78f3e..e7a5269ff7 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go @@ -17,7 +17,7 @@ package loadbalancer import ( "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" "github.com/stretchr/testify/assert" "testing" ) diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go similarity index 96% rename from eventmesh-sdk-go/grpc/loadbalancer/rule_random.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go index 03b8011986..32f9938181 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go @@ -16,7 +16,7 @@ package loadbalancer import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "math/rand" ) diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go similarity index 96% rename from eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go index 9eaec0b6dd..b0e088ee5a 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go @@ -17,7 +17,7 @@ package loadbalancer import ( "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" "github.com/stretchr/testify/assert" "testing" ) diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go similarity index 96% rename from eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go index bf12d1847c..da74b02c65 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go @@ -16,7 +16,7 @@ package loadbalancer import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" "go.uber.org/atomic" ) diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go similarity index 97% rename from eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go index 986f163268..7f8fc81967 100644 --- a/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go @@ -17,7 +17,7 @@ package loadbalancer import ( "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" "github.com/stretchr/testify/assert" "go.uber.org/atomic" "testing" diff --git a/eventmesh-sdk-go/grpc/loadbalancer/status_server.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/status_server.go similarity index 100% rename from eventmesh-sdk-go/grpc/loadbalancer/status_server.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/status_server.go diff --git a/eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go similarity index 100% rename from eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go diff --git a/eventmesh-sdk-go/grpc/msg.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/msg.go similarity index 94% rename from eventmesh-sdk-go/grpc/msg.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/msg.go index 08bc8492ab..c385b5c0df 100644 --- a/eventmesh-sdk-go/grpc/msg.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/msg.go @@ -17,9 +17,9 @@ package grpc import ( "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" "time" ) diff --git a/eventmesh-sdk-go/grpc/option.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/option.go similarity index 87% rename from eventmesh-sdk-go/grpc/option.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/option.go index c5942f1b3a..929d1e8b6f 100644 --- a/eventmesh-sdk-go/grpc/option.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/option.go @@ -16,9 +16,9 @@ package grpc import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" ) // GRPCOption option to set up the option for grpc client diff --git a/eventmesh-sdk-go/grpc/producer.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/producer.go similarity index 86% rename from eventmesh-sdk-go/grpc/producer.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/producer.go index f4d77a5616..671be54721 100644 --- a/eventmesh-sdk-go/grpc/producer.go +++ b/eventmesh-sdks/eventmesh-sdk-go/grpc/producer.go @@ -18,9 +18,9 @@ package grpc import ( "context" "fmt" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/eventmesh/eventmesh-sdk-go/grpc/proto" "google.golang.org/grpc" ) @@ -54,39 +54,30 @@ func (e *eventMeshProducer) Close() error { // Publish Async event publish func (e *eventMeshProducer) Publish(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.Response, error) { - log.Infof("publish event:%v", msg.String()) resp, err := e.client.Publish(ctx, msg, opts...) if err != nil { log.Warnf("failed to publish msg, err:%v", err) return nil, err } - - log.Infof("success publish msg:%s", msg.String()) return resp, nil } // RequestReply Sync event publish func (e *eventMeshProducer) RequestReply(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.SimpleMessage, error) { - log.Infof("request reply event:%v", msg.String()) resp, err := e.client.RequestReply(ctx, msg, opts...) if err != nil { log.Warnf("failed to request reply msg, err:%v", err) return nil, err } - - log.Infof("success request reply event") return resp, nil } // BatchPublish Async batch event publish func (e *eventMeshProducer) BatchPublish(ctx context.Context, msg *proto.BatchMessage, opts ...grpc.CallOption) (*proto.Response, error) { - log.Infof("request batch publish event:%v", msg.String()) resp, err := e.client.BatchPublish(ctx, msg, opts...) if err != nil { log.Warnf("failed to batch publish msg, err:%v", err) return nil, err } - - log.Infof("success batch publish event") return resp, nil } diff --git a/eventmesh-sdk-go/grpc/proto/README.md b/eventmesh-sdks/eventmesh-sdk-go/grpc/proto/README.md similarity index 100% rename from eventmesh-sdk-go/grpc/proto/README.md rename to eventmesh-sdks/eventmesh-sdk-go/grpc/proto/README.md diff --git a/eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go similarity index 100% rename from eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go diff --git a/eventmesh-sdk-go/grpc/proto/eventmesh-client.proto b/eventmesh-sdks/eventmesh-sdk-go/grpc/proto/eventmesh-client.proto similarity index 100% rename from eventmesh-sdk-go/grpc/proto/eventmesh-client.proto rename to eventmesh-sdks/eventmesh-sdk-go/grpc/proto/eventmesh-client.proto diff --git a/eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go similarity index 100% rename from eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go diff --git a/eventmesh-sdk-go/grpc/protocol_type.go b/eventmesh-sdks/eventmesh-sdk-go/grpc/protocol_type.go similarity index 100% rename from eventmesh-sdk-go/grpc/protocol_type.go rename to eventmesh-sdks/eventmesh-sdk-go/grpc/protocol_type.go diff --git a/eventmesh-sdk-go/http/abstract_http_client.go b/eventmesh-sdks/eventmesh-sdk-go/http/abstract_http_client.go similarity index 78% rename from eventmesh-sdk-go/http/abstract_http_client.go rename to eventmesh-sdks/eventmesh-sdk-go/http/abstract_http_client.go index 2232d31130..ff9ec3e62d 100644 --- a/eventmesh-sdk-go/http/abstract_http_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/http/abstract_http_client.go @@ -16,8 +16,9 @@ package http import ( - gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + gcommon "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/selector" nethttp "net/http" "time" ) @@ -25,11 +26,17 @@ import ( type AbstractHttpClient struct { EventMeshHttpClientConfig conf.EventMeshHttpClientConfig HttpClient *nethttp.Client + selector selector.LoadBalanceSelector } func NewAbstractHttpClient(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *AbstractHttpClient { c := &AbstractHttpClient{EventMeshHttpClientConfig: eventMeshHttpClientConfig} c.HttpClient = c.SetHttpClient() + selector, err := selector.CreateNewSelector(eventMeshHttpClientConfig.GetLoadBalanceType(), &eventMeshHttpClientConfig) + if err != nil { + panic(err) + } + c.selector = selector return c } @@ -47,8 +54,8 @@ func (c *AbstractHttpClient) SetHttpClient() *nethttp.Client { } func (c *AbstractHttpClient) SelectEventMesh() string { - // FIXME Add load balance support - uri := c.EventMeshHttpClientConfig.LiteEventMeshAddr() + meshNode := c.selector.Select() + uri := meshNode.Addr if c.EventMeshHttpClientConfig.UseTls() { return gcommon.Constants.HTTPS_PROTOCOL_PREFIX + uri diff --git a/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go b/eventmesh-sdks/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go similarity index 93% rename from eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go rename to eventmesh-sdks/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go index d0a232a103..2a22c15ee6 100644 --- a/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go +++ b/eventmesh-sdks/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go @@ -22,8 +22,7 @@ type EventMeshHttpClientConfig struct { // If you use Random strategy, the format like: 127.0.0.1:10105;127.0.0.2:10105 // If you use weighted round robin or weighted random strategy, the format like: 127.0.0.1:10105:1;127.0.0.2:10105:2 liteEventMeshAddr string - // TODO support load balance - //loadBalanceType string + loadBalanceType string consumeThreadCore int consumeThreadMax int env string @@ -142,8 +141,17 @@ func (e *EventMeshHttpClientConfig) SetUseTls(useTls bool) { e.useTls = useTls } +func (e *EventMeshHttpClientConfig) SetLoadBalanceType(loadBalanceType string) { + e.loadBalanceType = loadBalanceType +} + +func (e *EventMeshHttpClientConfig) GetLoadBalanceType() string { + return e.loadBalanceType +} + var DefaultEventMeshHttpClientConfig = EventMeshHttpClientConfig{ liteEventMeshAddr: "127.0.0.1:10105", + loadBalanceType: "random", consumeThreadCore: 2, consumeThreadMax: 5, env: "", diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/constants/protocol_type.go b/eventmesh-sdks/eventmesh-sdk-go/http/constants/protocol_type.go new file mode 100644 index 0000000000..3eec195cd5 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/constants/protocol_type.go @@ -0,0 +1,25 @@ +// 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. + +package constants + +const ( + EventMeshMessageProtocol = "eventmeshmessage" + CloudEventsProtocol = "cloudevents" + OpenMessageProtocol = "openmessage" + + ProtocolDesc = "http" + EventMeshMessageConstTTL = "ttl" +) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/consumer/consumer_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/consumer/consumer_suite_test.go new file mode 100644 index 0000000000..e7aae5b818 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/consumer/consumer_suite_test.go @@ -0,0 +1,62 @@ +/** + * 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. + */ + +package consumer + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "net/http" + "net/http/httptest" + "strings" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestConsumerAPIs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "consumer module Tests") +} + +var server *httptest.Server +var eventMeshHttpConsumer *EventMeshHttpConsumer + +var _ = BeforeSuite(func() { + f := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"retCode":0}`)) + } + server = httptest.NewServer(http.HandlerFunc(f)) + + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + sp := strings.Split(server.URL, ":") + eventMeshClientConfig.SetLiteEventMeshAddr(fmt.Sprintf("127.0.0.1:%s", sp[len(sp)-1])) + eventMeshHttpConsumer = NewEventMeshHttpConsumer(eventMeshClientConfig) + +}) + +var _ = AfterSuite(func() { + if server != nil { + server.Close() + } + + if eventMeshHttpConsumer != nil { + eventMeshHttpConsumer.Close() + } +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go b/eventmesh-sdks/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go new file mode 100644 index 0000000000..760693602f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go @@ -0,0 +1,158 @@ +// 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. + +package consumer + +import ( + gcommon "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/body/client" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/common" + gutils "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/model" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" + nethttp "net/http" + "strconv" + "sync" + "time" +) + +type EventMeshHttpConsumer struct { + *http.AbstractHttpClient + subscriptions []protocol.SubscriptionItem + mutex sync.Mutex +} + +func NewEventMeshHttpConsumer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshHttpConsumer { + c := &EventMeshHttpConsumer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} + c.subscriptions = make([]protocol.SubscriptionItem, 0, 1000) + return c +} + +func (e *EventMeshHttpConsumer) HeartBeat(topicList []protocol.SubscriptionItem, subscribeUrl string) { + if len(topicList) == 0 || len(subscribeUrl) == 0 { + return + } + + for range time.Tick(time.Duration(gcommon.Constants.HEARTBEAT) * time.Millisecond) { + var heartbeatEntities []client.HeartbeatEntity + for _, item := range topicList { + entity := client.HeartbeatEntity{Topic: item.Topic, Url: subscribeUrl} + heartbeatEntities = append(heartbeatEntities, entity) + } + + requestParam := e.buildCommonRequestParam() + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.HEARTBEAT.RequestCode)) + requestParam.AddBody(client.HeartbeatRequestBodyKey.CLIENTTYPE, common.DefaultClientType.SUB.Name) + requestParam.AddBody(client.HeartbeatRequestBodyKey.CLIENTTYPE, "SUB") + requestParam.AddBody(client.HeartbeatRequestBodyKey.HEARTBEATENTITIES, gutils.MarshalJsonString(heartbeatEntities)) + + target := e.SelectEventMesh() + resp := utils.HttpPost(e.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + log.Fatalf("Request failed, error code: %d", ret.RetCode) + } + } + +} + +func (e *EventMeshHttpConsumer) Subscribe(topicList []protocol.SubscriptionItem, subscribeUrl string) { + if len(topicList) == 0 || len(subscribeUrl) == 0 { + return + } + + requestParam := e.buildCommonRequestParam() + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.SUBSCRIBE.RequestCode)) + requestParam.AddBody(client.SubscribeRequestBodyKey.TOPIC, gutils.MarshalJsonString(topicList)) + requestParam.AddBody(client.SubscribeRequestBodyKey.URL, subscribeUrl) + requestParam.AddBody(client.SubscribeRequestBodyKey.CONSUMERGROUP, e.EventMeshHttpClientConfig.ConsumerGroup()) + + target := e.SelectEventMesh() + resp := utils.HttpPost(e.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + log.Fatalf("Request failed, error code: %d", ret.RetCode) + } + + e.mutex.Lock() + defer e.mutex.Unlock() + e.subscriptions = append(e.subscriptions, topicList...) + + result := make([]protocol.SubscriptionItem, 0, len(e.subscriptions)) + tmpMap := make(map[string]struct{}) + for _, item := range e.subscriptions { + if _, ok := tmpMap[item.Topic]; !ok { + tmpMap[item.Topic] = struct{}{} + result = append(result, item) + } + } + + e.subscriptions = result + +} + +func (e *EventMeshHttpConsumer) Unsubscribe(topicList []string, subscribeUrl string) { + if len(topicList) == 0 || len(subscribeUrl) == 0 { + return + } + requestParam := e.buildCommonRequestParam() + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.UNSUBSCRIBE.RequestCode)) + requestParam.AddBody(client.SubscribeRequestBodyKey.TOPIC, gutils.MarshalJsonString(topicList)) + requestParam.AddBody(client.SubscribeRequestBodyKey.URL, subscribeUrl) + target := e.SelectEventMesh() + resp := utils.HttpPost(e.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + log.Fatalf("Request failed, error code: %d", ret.RetCode) + } + + e.mutex.Lock() + defer e.mutex.Unlock() + topicSet := make(map[string]struct{}) + for _, topic := range topicList { + topicSet[topic] = struct{}{} + } + + subscriptions := make([]protocol.SubscriptionItem, 0, len(e.subscriptions)) + for _, sub := range e.subscriptions { + if _, ok := topicSet[sub.Topic]; !ok { + subscriptions = append(subscriptions, sub) + } + } + e.subscriptions = subscriptions +} + +func (e *EventMeshHttpConsumer) buildCommonRequestParam() *model.RequestParam { + param := model.NewRequestParam(nethttp.MethodPost) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, e.EventMeshHttpClientConfig.Env()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, e.EventMeshHttpClientConfig.Idc()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, e.EventMeshHttpClientConfig.Ip()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, e.EventMeshHttpClientConfig.Pid()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, e.EventMeshHttpClientConfig.Sys()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, e.EventMeshHttpClientConfig.UserName()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, e.EventMeshHttpClientConfig.Password()) + param.AddHeader(common.ProtocolKey.VERSION, common.DefaultProtocolVersion.V1.Version()) + param.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + param.SetTimeout(gcommon.Constants.DEFAULT_HTTP_TIME_OUT) + param.AddBody(client.HeartbeatRequestBodyKey.CONSUMERGROUP, e.EventMeshHttpClientConfig.ConsumerGroup()) + return param +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer_test.go new file mode 100644 index 0000000000..21aaebfe7d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer_test.go @@ -0,0 +1,73 @@ +/** + * 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. + */ + +package consumer + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("EventMeshHttpConsumer test", func() { + + Context("Subscribe test ", func() { + It("should success", func() { + + subscribeUrl := "http://mock-url" + topicList := []protocol.SubscriptionItem{ + { + Topic: "mock-topic", + Mode: protocol.DefaultSubscriptionMode.CLUSTERING, + Type: protocol.DefaultSubscriptionType.ASYNC, + }, + } + eventMeshHttpConsumer.Subscribe(topicList, subscribeUrl) + + Ω(1).To(Equal(len(eventMeshHttpConsumer.subscriptions))) + + topicList = []protocol.SubscriptionItem{ + { + Topic: "mock-topic2", + Mode: protocol.DefaultSubscriptionMode.CLUSTERING, + Type: protocol.DefaultSubscriptionType.ASYNC, + }, + } + eventMeshHttpConsumer.Subscribe(topicList, subscribeUrl) + Ω(2).To(Equal(len(eventMeshHttpConsumer.subscriptions))) + eventMeshHttpConsumer.Subscribe(topicList, subscribeUrl) + Ω(2).To(Equal(len(eventMeshHttpConsumer.subscriptions))) + }) + + }) + + Context("Unsubscribe test ", func() { + It("should success", func() { + subscribeUrl := "http://mock-url" + var topicList = []string{"mock-topic"} + eventMeshHttpConsumer.Unsubscribe(topicList, subscribeUrl) + Ω(1).To(Equal(len(eventMeshHttpConsumer.subscriptions))) + topicList = []string{"mock-topic2"} + eventMeshHttpConsumer.Unsubscribe(topicList, subscribeUrl) + Ω(0).To(Equal(len(eventMeshHttpConsumer.subscriptions))) + topicList = []string{"mock-topic2"} + eventMeshHttpConsumer.Unsubscribe(topicList, subscribeUrl) + Ω(0).To(Equal(len(eventMeshHttpConsumer.subscriptions))) + }) + + }) +}) diff --git a/eventmesh-sdk-go/http/eventmesh_ret_obj.go b/eventmesh-sdks/eventmesh-sdk-go/http/eventmesh_ret_obj.go similarity index 84% rename from eventmesh-sdk-go/http/eventmesh_ret_obj.go rename to eventmesh-sdks/eventmesh-sdk-go/http/eventmesh_ret_obj.go index b92113cf0d..23aa9fa078 100644 --- a/eventmesh-sdk-go/http/eventmesh_ret_obj.go +++ b/eventmesh-sdks/eventmesh-sdk-go/http/eventmesh_ret_obj.go @@ -20,3 +20,9 @@ type EventMeshRetObj struct { RetCode int `json:"retCode"` RetMsg string `json:"retMsg"` } + +type ReplyMessage struct { + Topic string `json:"topic"` + Body string `json:"body"` + Properties map[string]string `json:"properties"` +} diff --git a/eventmesh-sdk-go/http/model/request_param.go b/eventmesh-sdks/eventmesh-sdk-go/http/model/request_param.go similarity index 100% rename from eventmesh-sdk-go/http/model/request_param.go rename to eventmesh-sdks/eventmesh-sdk-go/http/model/request_param.go diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/cloudevent_producer.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/cloudevent_producer.go new file mode 100644 index 0000000000..783dcf6ede --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/cloudevent_producer.go @@ -0,0 +1,141 @@ +// 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. + +package producer + +import ( + "errors" + "fmt" + gcommon "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/common" + protocol_message "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/message" + gutils "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/constants" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/model" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" + "time" + + cloudevents "github.com/cloudevents/sdk-go/v2" + + nethttp "net/http" + "strconv" +) + +const bizSeqNoLength = 30 +const uniqueIdLen = 30 + +type CloudEventProducer struct { + *http.AbstractHttpClient +} + +func NewCloudEventProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *CloudEventProducer { + c := &CloudEventProducer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} + return c +} + +func (c *CloudEventProducer) Publish(event *cloudevents.Event) error { + enhancedEvent := c.enhanceCloudEvent(event) + requestParam := c.buildCommonPostParam(enhancedEvent) + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.MSG_SEND_ASYNC.RequestCode)) + + target := c.SelectEventMesh() + resp := utils.HttpPost(c.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + return fmt.Errorf("publish failed, http request error code: %d", ret.RetCode) + } + return nil +} + +func (c *CloudEventProducer) Request(event *cloudevents.Event, timeout time.Duration) (*cloudevents.Event, error) { + enhancedEvent := c.enhanceCloudEvent(event) + requestParam := c.buildCommonPostParam(enhancedEvent) + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.MSG_SEND_SYNC.RequestCode)) + requestParam.SetTimeout(timeout.Milliseconds()) + target := c.SelectEventMesh() + resp := utils.HttpPost(c.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + return nil, fmt.Errorf("request failed, http request code: %d", ret.RetCode) + } + retMessage, err := c.transferMessage(&ret) + if err != nil { + return nil, err + } + return retMessage, nil +} + +func (c *CloudEventProducer) transferMessage(retObj *http.EventMeshRetObj) (event *cloudevents.Event, err error) { + defer func() { + if r := recover(); r != nil { + err = errors.New("fail to transfer from EventMeshRetObj to CloudEvent") + } + }() + var message http.ReplyMessage + gutils.UnMarshalJsonString(retObj.RetMsg, &message) + retEvent := cloudevents.NewEvent() + retEvent.SetSubject(message.Topic) + retEvent.SetData("application/json", []byte(message.Body)) + for k, v := range message.Properties { + retEvent.SetExtension(k, v) + } + return &retEvent, nil +} + +func (c *CloudEventProducer) buildCommonPostParam(event *cloudevents.Event) *model.RequestParam { + eventBytes, err := event.MarshalJSON() + if err != nil { + log.Fatalf("Failed to marshal cloudevent") + } + content := string(eventBytes) + + requestParam := model.NewRequestParam(nethttp.MethodPost) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, c.EventMeshHttpClientConfig.UserName()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, c.EventMeshHttpClientConfig.Password()) + requestParam.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_TYPE, constants.CloudEventsProtocol) + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_DESC, constants.ProtocolDesc) + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_VERSION, event.SpecVersion()) + + // todo: move producerGroup tp header + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.PRODUCERGROUP, c.EventMeshHttpClientConfig.ProducerGroup()) + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.CONTENT, content) + + return requestParam +} + +func (c *CloudEventProducer) enhanceCloudEvent(event *cloudevents.Event) *cloudevents.Event { + event.SetExtension(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.BIZSEQNO, gutils.RandomNumberStr(bizSeqNoLength)) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.UNIQUEID, gutils.RandomNumberStr(uniqueIdLen)) + event.SetExtension(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + event.SetExtension(common.ProtocolKey.PROTOCOL_DESC, fmt.Sprintf("V%s", event.SpecVersion())) + event.SetExtension(common.ProtocolKey.PROTOCOL_VERSION, event.SpecVersion()) + return event +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/cloudevent_producer_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/cloudevent_producer_test.go new file mode 100644 index 0000000000..26d6bd4e5f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/cloudevent_producer_test.go @@ -0,0 +1,86 @@ +/** + * 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. + */ + +package producer + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/google/uuid" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "strconv" + "strings" + "time" +) + +var _ = Describe("EventMeshHttpProducer test", func() { + + Context("PublishCloudEvent test", func() { + It("should success", func() { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + sp := strings.Split(server.URL, ":") + eventMeshClientConfig.SetLiteEventMeshAddr(fmt.Sprintf("127.0.0.1:%s", sp[len(sp)-1])) + // Make event to send + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetSubject("test-topic") + event.SetSource("test-uri") + event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) + event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) + event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) + data := map[string]string{"hello": "EventMesh"} + err := event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) + Ω(err).NotTo(HaveOccurred()) + + // Publish event + httpProducer := NewEventMeshHttpProducer(eventMeshClientConfig) + err = httpProducer.PublishCloudEvent(&event) + Ω(err).NotTo(HaveOccurred()) + }) + }) + + Context("RequestCloudEvent test", func() { + It("should success", func() { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + sp := strings.Split(server.URL, ":") + eventMeshClientConfig.SetLiteEventMeshAddr(fmt.Sprintf("127.0.0.1:%s", sp[len(sp)-1])) + // Make event to send + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetSubject("test-topic") + event.SetSource("test-uri") + event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) + event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) + event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) + data := map[string]string{"hello": "EventMesh"} + err := event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) + Ω(err).NotTo(HaveOccurred()) + + httpProducer := NewEventMeshHttpProducer(eventMeshClientConfig) + ret, err := httpProducer.RequestCloudEvent(&event, time.Second) + Ω(err).NotTo(HaveOccurred()) + + retData := make(map[string]interface{}) + utils.UnMarshalJsonString(string(ret.DataEncoded), &retData) + Ω(float64(1)).To(Equal(retData["data"])) + }) + }) +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/eventmesh_message_producer.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/eventmesh_message_producer.go new file mode 100644 index 0000000000..e9443627cc --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/eventmesh_message_producer.go @@ -0,0 +1,137 @@ +// 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. + +package producer + +import ( + "errors" + "fmt" + gcommon "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/common" + protocol_message "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/http/message" + gutils "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/constants" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/model" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/utils" + nethttp "net/http" + "strconv" + "time" +) + +type EventMeshMessageProducer struct { + *http.AbstractHttpClient +} + +func NewEventMeshMessageProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshMessageProducer { + c := &EventMeshMessageProducer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} + return c +} + +func (c *EventMeshMessageProducer) Publish(message *protocol.EventMeshMessage) error { + err := c.validateEventMeshMessage(message) + if err != nil { + return err + } + + requestParam := c.buildCommonPostParam(message) + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.MSG_SEND_ASYNC.RequestCode)) + + target := c.SelectEventMesh() + resp := utils.HttpPost(c.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + return fmt.Errorf("publish failed, http request error code: %d", ret.RetCode) + } + return nil +} + +func (c *EventMeshMessageProducer) Request(message *protocol.EventMeshMessage, timeout time.Duration) (*protocol.EventMeshMessage, error) { + err := c.validateEventMeshMessage(message) + if err != nil { + return nil, err + } + + requestParam := c.buildCommonPostParam(message) + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.MSG_SEND_SYNC.RequestCode)) + requestParam.SetTimeout(timeout.Milliseconds()) + target := c.SelectEventMesh() + resp := utils.HttpPost(c.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + return nil, fmt.Errorf("request failed, http request code: %d", ret.RetCode) + } + retMessage, err := c.transferMessage(&ret) + if err != nil { + return nil, err + } + return retMessage, nil +} + +func (c *EventMeshMessageProducer) transferMessage(retObj *http.EventMeshRetObj) (message *protocol.EventMeshMessage, err error) { + defer func() { + if r := recover(); r != nil { + err = errors.New("fail to transfer from EventMeshRetObj to EventMeshMessage") + } + }() + var replyMessage http.ReplyMessage + gutils.UnMarshalJsonString(retObj.RetMsg, &replyMessage) + return &protocol.EventMeshMessage{ + Topic: replyMessage.Topic, + Content: replyMessage.Body, + Prop: replyMessage.Properties, + }, nil +} + +func (c *EventMeshMessageProducer) buildCommonPostParam(message *protocol.EventMeshMessage) *model.RequestParam { + requestParam := model.NewRequestParam(nethttp.MethodPost) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, c.EventMeshHttpClientConfig.UserName()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, c.EventMeshHttpClientConfig.Password()) + requestParam.AddHeader(common.ProtocolKey.VERSION, common.DefaultProtocolVersion.V1.Version()) + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_TYPE, constants.EventMeshMessageProtocol) + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_DESC, constants.ProtocolDesc) + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_VERSION, common.DefaultProtocolVersion.V1.Version()) + requestParam.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.PRODUCERGROUP, c.EventMeshHttpClientConfig.ProducerGroup()) + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.TOPIC, message.Topic) + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.CONTENT, message.Content) + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.TTL, message.Prop[constants.EventMeshMessageConstTTL]) + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.BIZSEQNO, message.BizSeqNo) + requestParam.AddBody(protocol_message.SendMessageRequestBodyKey.UNIQUEID, message.UniqueId) + return requestParam +} + +func (c *EventMeshMessageProducer) validateEventMeshMessage(message *protocol.EventMeshMessage) error { + if message == nil { + return errors.New("EventMeshMessage can not be nil") + } + if len(message.Topic) == 0 { + return errors.New("EventMeshMessage topic can not be empty") + } + if len(message.Content) == 0 { + return errors.New("EventMeshMessage content can not be empty") + } + return nil +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/eventmesh_message_producer_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/eventmesh_message_producer_test.go new file mode 100644 index 0000000000..e6891519cf --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/eventmesh_message_producer_test.go @@ -0,0 +1,75 @@ +/** + * 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. + */ + +package producer + +import ( + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "strings" + "time" +) + +var _ = Describe("EventMeshHttpProducer test", func() { + + Context("PublishEventMeshMessage test", func() { + It("should success", func() { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + sp := strings.Split(server.URL, ":") + eventMeshClientConfig.SetLiteEventMeshAddr(fmt.Sprintf("127.0.0.1:%s", sp[len(sp)-1])) + + message := &protocol.EventMeshMessage{ + BizSeqNo: "test-biz-no", + UniqueId: "test-unique-id", + Topic: "test-topic", + Content: "test-content", + Prop: map[string]string{"hello": "EventMesh"}, + } + // Publish event + httpProducer := NewEventMeshHttpProducer(eventMeshClientConfig) + err := httpProducer.PublishEventMeshMessage(message) + Ω(err).NotTo(HaveOccurred()) + }) + }) + + Context("RequestEventMeshMessage test", func() { + It("should success", func() { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + sp := strings.Split(server.URL, ":") + eventMeshClientConfig.SetLiteEventMeshAddr(fmt.Sprintf("127.0.0.1:%s", sp[len(sp)-1])) + + message := &protocol.EventMeshMessage{ + BizSeqNo: "test-biz-no", + UniqueId: "test-unique-id", + Topic: "test-topic", + Content: "test-content", + Prop: map[string]string{"hello": "EventMesh"}, + } + httpProducer := NewEventMeshHttpProducer(eventMeshClientConfig) + ret, err := httpProducer.RequestEventMeshMessage(message, time.Second) + Ω(err).NotTo(HaveOccurred()) + + retData := make(map[string]interface{}) + utils.UnMarshalJsonString(ret.Content, &retData) + Ω(float64(1)).To(Equal(retData["data"])) + }) + }) +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/http_producer.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/http_producer.go new file mode 100644 index 0000000000..744c51b3c3 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/http_producer.go @@ -0,0 +1,64 @@ +// 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. + +package producer + +import ( + "errors" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + cloudevents "github.com/cloudevents/sdk-go/v2" + "time" +) + +type EventMeshHttpProducer struct { + cloudEventProducer *CloudEventProducer + eventMeshMessageProducer *EventMeshMessageProducer +} + +func NewEventMeshHttpProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshHttpProducer { + return &EventMeshHttpProducer{ + cloudEventProducer: NewCloudEventProducer(eventMeshHttpClientConfig), + eventMeshMessageProducer: NewEventMeshMessageProducer(eventMeshHttpClientConfig), + } +} + +func (e *EventMeshHttpProducer) PublishCloudEvent(event *cloudevents.Event) error { + if event == nil { + return errors.New("publish CloudEvent message failed, message is nil") + } + return e.cloudEventProducer.Publish(event) +} + +func (e *EventMeshHttpProducer) RequestCloudEvent(event *cloudevents.Event, timeout time.Duration) (*cloudevents.Event, error) { + if event == nil { + return nil, errors.New("request CloudEvent message failed, message is nil") + } + return e.cloudEventProducer.Request(event, timeout) +} + +func (e *EventMeshHttpProducer) PublishEventMeshMessage(message *protocol.EventMeshMessage) error { + if message == nil { + return errors.New("publish EventMesh message failed, message is nil") + } + return e.eventMeshMessageProducer.Publish(message) +} + +func (e *EventMeshHttpProducer) RequestEventMeshMessage(message *protocol.EventMeshMessage, timeout time.Duration) (*protocol.EventMeshMessage, error) { + if message == nil { + return nil, errors.New("request EventMesh message failed, message is nil") + } + return e.eventMeshMessageProducer.Request(message, timeout) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/http_producer_api.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/http_producer_api.go new file mode 100644 index 0000000000..29863f95c3 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/http_producer_api.go @@ -0,0 +1,37 @@ +// 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. + +package producer + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + cloudevents "github.com/cloudevents/sdk-go/v2" + "time" +) + +type EventMeshProtocolProducer interface { + + // PublishCloudEvent publish with CloudEvent protocol + PublishCloudEvent(event *cloudevents.Event) error + // RequestCloudEvent request with CloudEvent protocol + RequestCloudEvent(event *cloudevents.Event, timeout time.Duration) (*cloudevents.Event, error) + + // PublishEventMeshMessage publish with EventMeshMessage protocol + PublishEventMeshMessage(message *protocol.EventMeshMessage) error + // RequestEventMeshMessage request with EventMeshMessage protocol + RequestEventMeshMessage(message *protocol.EventMeshMessage, timeout time.Duration) (*protocol.EventMeshMessage, error) + + // TODO: add OpenMessage support +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/producer/producer_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/producer/producer_suite_test.go new file mode 100644 index 0000000000..ac751afa20 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/producer/producer_suite_test.go @@ -0,0 +1,61 @@ +/** + * 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. + */ + +package producer + +import ( + gutils "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + ghttp "github.com/apache/eventmesh/eventmesh-sdk-go/http" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "net/http" + "net/http/httptest" + "testing" +) + +func TestProducerAPIs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "producer module Tests") +} + +var server *httptest.Server + +var _ = BeforeSuite(func() { + retData := make(map[string]interface{}) + retData["data"] = 1 + + rpy := ghttp.ReplyMessage{ + Topic: "test-topic", + Body: gutils.MarshalJsonString(retData), + } + + ret := ghttp.EventMeshRetObj{ + RetCode: 0, + RetMsg: gutils.MarshalJsonString(rpy), + } + f := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(gutils.MarshalJsonString(ret))) + } + server = httptest.NewServer(http.HandlerFunc(f)) +}) + +var _ = AfterSuite(func() { + if server != nil { + server.Close() + } +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/random_selector.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/random_selector.go new file mode 100644 index 0000000000..4525d66adc --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/random_selector.go @@ -0,0 +1,49 @@ +// 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. + +package selector + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "math/rand" + "time" +) + +const RandomSelectorType = "random" + +func init() { + rand.Seed(time.Now().UnixNano()) + registerSelectorBuilder(RandomSelectorType, buildRandomLoadSelector) +} + +func buildRandomLoadSelector(config *conf.EventMeshHttpClientConfig) (LoadBalanceSelector, error) { + meshNodes, err := parseMeshNodeFromConfig(config) + if err != nil { + return nil, err + } + return &RandomLoadSelector{clusterGroup: meshNodes}, nil +} + +type RandomLoadSelector struct { + clusterGroup []MeshNode +} + +func (s *RandomLoadSelector) Select() MeshNode { + return s.clusterGroup[rand.Intn(len(s.clusterGroup))] +} + +func (s *RandomLoadSelector) GetType() string { + return RandomSelectorType +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/random_selector_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/random_selector_test.go new file mode 100644 index 0000000000..5636deff1c --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/random_selector_test.go @@ -0,0 +1,58 @@ +// 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. + +package selector + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("RandomLoadSelector test", func() { + + Context("Select test ", func() { + It("should success", func() { + testAddr := "192.168.0.1:10105;192.168.0.2:10105;192.168.0.3:10105;" + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLoadBalanceType(RandomSelectorType) + eventMeshClientConfig.SetLiteEventMeshAddr(testAddr) + + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), + &eventMeshClientConfig) + Ω(err).Should(BeNil()) + + for i := 0; i < 100; i++ { + node := selector.Select() + Ω(node.Addr).Should(Or( + Equal("192.168.0.1:10105"), + Equal("192.168.0.2:10105"), + Equal("192.168.0.3:10105")), + ) + } + }) + }) + + Context("GetType test ", func() { + It("should success", func() { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLoadBalanceType(RandomSelectorType) + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), + &eventMeshClientConfig) + Ω(err).Should(BeNil()) + Ω(selector.GetType()).Should(Equal(RandomSelectorType)) + }) + }) +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector.go new file mode 100644 index 0000000000..d42ec0d022 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector.go @@ -0,0 +1,117 @@ +// 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. + +package selector + +import ( + "errors" + "fmt" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "regexp" + "strconv" + "strings" +) + +var ( + ipPortRegexp = regexp.MustCompile(`(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{4,5})`) + ipPortWeightRegexp = regexp.MustCompile(`(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{4,5}):(\d{1,6})`) +) + +type selectorBuilder func(*conf.EventMeshHttpClientConfig) (LoadBalanceSelector, error) + +var selectorBuilderMap = make(map[string]selectorBuilder) + +type LoadBalanceSelector interface { + Select() MeshNode + GetType() string +} + +type MeshNode struct { + Addr string + Weight int64 +} + +func GetSelectorBuilder(selectorName string) (selectorBuilder, error) { + if builder, ok := selectorBuilderMap[selectorName]; ok { + return builder, nil + } + return nil, fmt.Errorf("unknow loadbalancer type %s", selectorName) +} + +func CreateNewSelector(selectorName string, config *conf.EventMeshHttpClientConfig) (LoadBalanceSelector, error) { + builder, err := GetSelectorBuilder(selectorName) + if err != nil { + return nil, err + } + return builder(config) +} + +func registerSelectorBuilder(selectorName string, builder selectorBuilder) { + selectorBuilderMap[selectorName] = builder +} + +func parseMeshNodeFromConfig(config *conf.EventMeshHttpClientConfig) ([]MeshNode, error) { + if config == nil || len(config.LiteEventMeshAddr()) == 0 { + return nil, errors.New("fail in loading load balancer, invalid mesh address") + } + + addrList := strings.Split(strings.TrimSpace(config.LiteEventMeshAddr()), ";") + if len(addrList) == 0 { + return nil, errors.New("fail in loading load balancer, invalid mesh address") + } + + result := make([]MeshNode, 0, len(addrList)) + for _, addr := range addrList { + if len(addr) == 0 { + continue + } + isMatch := ipPortRegexp.MatchString(strings.TrimSpace(addr)) + if !isMatch { + return nil, fmt.Errorf("fail in loading load balancer, invalid mesh address : %s", addr) + } + result = append(result, MeshNode{ + Addr: addr, + }) + } + + return result, nil +} + +func parseWeightedMeshNodeFromConfig(config *conf.EventMeshHttpClientConfig) ([]MeshNode, error) { + if config == nil || len(config.LiteEventMeshAddr()) == 0 { + return nil, errors.New("fail in loading load balancer, invalid mesh address") + } + addrList := strings.Split(strings.TrimSpace(config.LiteEventMeshAddr()), ";") + if len(addrList) == 0 { + return nil, errors.New("fail in loading load balancer, invalid mesh address") + } + + result := make([]MeshNode, 0, len(addrList)) + for _, addr := range addrList { + if len(addr) == 0 { + continue + } + matches := ipPortWeightRegexp.FindStringSubmatch(strings.TrimSpace(addr)) + if len(matches) != 4 { + return nil, fmt.Errorf("fail in loading load balancer, invalid mesh address : %s", addr) + } + weight, _ := strconv.ParseInt(matches[3], 10, 64) + result = append(result, MeshNode{ + Addr: fmt.Sprintf("%s:%s", matches[1], matches[2]), + Weight: weight, + }) + } + return result, nil +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector_suite_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector_suite_test.go new file mode 100644 index 0000000000..c9ad168a7b --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector_suite_test.go @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package selector + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestSelectorAPIs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "selector module Tests") +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector_test.go new file mode 100644 index 0000000000..fb50d5d350 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/selector_test.go @@ -0,0 +1,45 @@ +// 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. + +package selector + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestCreateNewSelector(t *testing.T) { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLiteEventMeshAddr("127.0.0.1:10105;127.0.0.1:10106") + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), &eventMeshClientConfig) + if err != nil { + t.Fail() + } + assert.Equal(t, RandomSelectorType, selector.GetType()) +} + +func TestCreateNewSelectorWithWeight(t *testing.T) { + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLiteEventMeshAddr("127.0.0.1:10105:1;127.0.0.1:10106:2") + eventMeshClientConfig.SetLoadBalanceType(WeightRoundRobinSelectorType) + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), &eventMeshClientConfig) + if err != nil { + t.Fail() + } + assert.Equal(t, WeightRoundRobinSelectorType, selector.GetType()) + assert.Equal(t, int64(3), selector.(*WeightRoundRobinLoadSelector).totalWeight) + assert.Equal(t, int64(1), selector.(*WeightRoundRobinLoadSelector).clusterGroup[0].Weight) +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_random_selector.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_random_selector.go new file mode 100644 index 0000000000..5712caa7ff --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_random_selector.go @@ -0,0 +1,82 @@ +// 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. + +package selector + +import ( + "errors" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "math/rand" + "time" +) + +const WeightRandomSelectorType = "weight_random" + +func init() { + rand.Seed(time.Now().UnixNano()) + registerSelectorBuilder(WeightRandomSelectorType, buildWeightRandomLoadSelector) +} + +func buildWeightRandomLoadSelector(config *conf.EventMeshHttpClientConfig) (LoadBalanceSelector, error) { + meshNodes, err := parseWeightedMeshNodeFromConfig(config) + if err != nil { + return nil, err + } + + return NewWeightRandomLoadSelector(meshNodes) +} + +type WeightRandomLoadSelector struct { + clusterGroup []MeshNode + totalWeight int64 + sameWeightGroup bool +} + +func NewWeightRandomLoadSelector(clusterGroup []MeshNode) (*WeightRandomLoadSelector, error) { + if len(clusterGroup) == 0 { + return nil, errors.New("fail to create weight random load balancer selector, cluster group is empty") + } + var totalWeight int64 = 0 + firstWeight := clusterGroup[0].Weight + sameWeightGroup := true + for _, node := range clusterGroup { + totalWeight += node.Weight + if sameWeightGroup && firstWeight != node.Weight { + sameWeightGroup = false + } + } + return &WeightRandomLoadSelector{ + clusterGroup: clusterGroup, + totalWeight: totalWeight, + sameWeightGroup: sameWeightGroup, + }, nil +} + +func (s *WeightRandomLoadSelector) Select() MeshNode { + if !s.sameWeightGroup { + targetWeight := rand.Int63n(s.totalWeight) + for _, node := range s.clusterGroup { + targetWeight -= node.Weight + if targetWeight < 0 { + return node + } + } + } + return s.clusterGroup[rand.Intn(len(s.clusterGroup))] +} + +func (s *WeightRandomLoadSelector) GetType() string { + return WeightRandomSelectorType +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_random_selector_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_random_selector_test.go new file mode 100644 index 0000000000..9f114cc2ca --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_random_selector_test.go @@ -0,0 +1,65 @@ +// 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. + +package selector + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "math" +) + +var _ = Describe("WeightRandomLoadSelector test", func() { + + Context("Select test ", func() { + It("should success", func() { + testAddr := "192.168.0.1:10105:10;192.168.0.2:10105:20;192.168.0.3:10105:40;" + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLoadBalanceType(WeightRandomSelectorType) + eventMeshClientConfig.SetLiteEventMeshAddr(testAddr) + + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), + &eventMeshClientConfig) + Ω(err).Should(BeNil()) + + counter := make(map[string]int) + testRange := 100_000 + for i := 0; i < testRange; i++ { + node := selector.Select() + counter[node.Addr]++ + } + + diff := float64(counter["192.168.0.3:10105"] - counter["192.168.0.2:10105"]*2) + Ω(math.Abs(diff) < float64(testRange/20)).Should(BeTrue()) + + diff = float64(counter["192.168.0.3:10105"] - counter["192.168.0.1:10105"]*4) + Ω(math.Abs(diff) < float64(testRange/20)).Should(BeTrue()) + }) + }) + + Context("GetType test ", func() { + It("should success", func() { + testAddr := "192.168.0.1:10105:10;192.168.0.2:10105:20;192.168.0.3:10105:40;" + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLoadBalanceType(WeightRandomSelectorType) + eventMeshClientConfig.SetLiteEventMeshAddr(testAddr) + + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), &eventMeshClientConfig) + Ω(err).Should(BeNil()) + Ω(selector.GetType()).To(Equal(WeightRandomSelectorType)) + }) + }) +}) diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_round_robin_selector.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_round_robin_selector.go new file mode 100644 index 0000000000..ba702432e7 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_round_robin_selector.go @@ -0,0 +1,84 @@ +// 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. + +package selector + +import ( + "errors" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + "go.uber.org/atomic" +) + +const WeightRoundRobinSelectorType = "weight_round_robin" + +func init() { + registerSelectorBuilder(WeightRoundRobinSelectorType, buildWeightRoundRobinLoadSelector) +} + +func buildWeightRoundRobinLoadSelector(config *conf.EventMeshHttpClientConfig) (LoadBalanceSelector, error) { + meshNodes, err := parseWeightedMeshNodeFromConfig(config) + if err != nil { + return nil, err + } + + return NewWeightRoundRobinLoadSelector(meshNodes) +} + +type WeightRoundRobinMeshNode struct { + MeshNode + currentWeight *atomic.Int64 +} + +type WeightRoundRobinLoadSelector struct { + clusterGroup []WeightRoundRobinMeshNode + totalWeight int64 +} + +func NewWeightRoundRobinLoadSelector(clusterGroup []MeshNode) (*WeightRoundRobinLoadSelector, error) { + if len(clusterGroup) == 0 { + return nil, errors.New("fail to create weight round robin load balancer selector, cluster group is empty") + } + var totalWeight int64 = 0 + weightRoundRobinClusterGroup := make([]WeightRoundRobinMeshNode, 0, len(clusterGroup)) + for _, node := range clusterGroup { + totalWeight += node.Weight + weightRoundRobinClusterGroup = append(weightRoundRobinClusterGroup, WeightRoundRobinMeshNode{ + MeshNode: node, + currentWeight: atomic.NewInt64(0), + }) + } + + return &WeightRoundRobinLoadSelector{ + clusterGroup: weightRoundRobinClusterGroup, + totalWeight: totalWeight, + }, nil +} + +func (s *WeightRoundRobinLoadSelector) Select() MeshNode { + var targetWeight *WeightRoundRobinMeshNode = nil + for i := range s.clusterGroup { + node := &s.clusterGroup[i] + node.currentWeight.Add(node.Weight) + if targetWeight == nil || targetWeight.currentWeight.Load() < node.currentWeight.Load() { + targetWeight = node + } + } + targetWeight.currentWeight.Sub(s.totalWeight) + return targetWeight.MeshNode +} + +func (s *WeightRoundRobinLoadSelector) GetType() string { + return WeightRoundRobinSelectorType +} diff --git a/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_round_robin_selector_test.go b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_round_robin_selector_test.go new file mode 100644 index 0000000000..0a19ab2e2b --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-go/http/selector/weight_round_robin_selector_test.go @@ -0,0 +1,60 @@ +// 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. + +package selector + +import ( + "github.com/apache/eventmesh/eventmesh-sdk-go/http/conf" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("WeightRoundRobinLoadSelector test", func() { + + Context("Select test ", func() { + It("should success", func() { + testAddr := "192.168.0.1:10105:10;192.168.0.2:10105:20;192.168.0.3:10105:30;" + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLoadBalanceType(WeightRoundRobinSelectorType) + eventMeshClientConfig.SetLiteEventMeshAddr(testAddr) + + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), &eventMeshClientConfig) + Ω(err).Should(BeNil()) + + counter := make(map[string]int) + testRange := 1000 + for i := 0; i < testRange; i++ { + node := selector.Select() + counter[node.Addr]++ + } + + Ω(counter["192.168.0.2:10105"] > counter["192.168.0.1:10105"]).Should(BeTrue()) + Ω(counter["192.168.0.3:10105"] > counter["192.168.0.2:10105"]).Should(BeTrue()) + }) + }) + + Context("GetType test ", func() { + It("should success", func() { + testAddr := "192.168.0.1:10105:10;192.168.0.2:10105:20;192.168.0.3:10105:30;" + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLoadBalanceType(WeightRoundRobinSelectorType) + eventMeshClientConfig.SetLiteEventMeshAddr(testAddr) + selector, err := CreateNewSelector(eventMeshClientConfig.GetLoadBalanceType(), + &eventMeshClientConfig) + Ω(err).Should(BeNil()) + Ω(selector.GetType()).To(Equal(WeightRoundRobinSelectorType)) + }) + }) +}) diff --git a/eventmesh-sdk-go/http/utils/http_utils.go b/eventmesh-sdks/eventmesh-sdk-go/http/utils/http_utils.go similarity index 95% rename from eventmesh-sdk-go/http/utils/http_utils.go rename to eventmesh-sdks/eventmesh-sdk-go/http/utils/http_utils.go index e11913271b..cca9f78d99 100644 --- a/eventmesh-sdk-go/http/utils/http_utils.go +++ b/eventmesh-sdks/eventmesh-sdk-go/http/utils/http_utils.go @@ -16,7 +16,7 @@ package utils import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/model" + "github.com/apache/eventmesh/eventmesh-sdk-go/http/model" "io/ioutil" nethttp "net/http" "net/url" diff --git a/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go similarity index 91% rename from eventmesh-sdk-go/tcp/cloudevent_tcp_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go index b868f04ecb..1efa893d24 100644 --- a/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go @@ -16,8 +16,8 @@ package tcp import ( - gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" + gtcp "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/conf" ) type CloudEventTCPClient struct { diff --git a/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go similarity index 87% rename from eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go index b2a793a172..c4cb5843e4 100644 --- a/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go @@ -16,9 +16,9 @@ package tcp import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/utils" ) type CloudEventTCPPubClient struct { diff --git a/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go similarity index 90% rename from eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go index 813cb595db..26b9276ae7 100644 --- a/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go @@ -16,8 +16,8 @@ package tcp import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/conf" ) type CloudEventTCPSubClient struct { diff --git a/eventmesh-sdk-go/tcp/common/eventmesh_common.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/common/eventmesh_common.go similarity index 100% rename from eventmesh-sdk-go/tcp/common/eventmesh_common.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/common/eventmesh_common.go diff --git a/eventmesh-sdk-go/tcp/common/request_context.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/common/request_context.go similarity index 96% rename from eventmesh-sdk-go/tcp/common/request_context.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/common/request_context.go index 0b67ab26f6..179f3d50ba 100644 --- a/eventmesh-sdk-go/tcp/common/request_context.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/common/request_context.go @@ -16,7 +16,7 @@ package common import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" "sync" ) diff --git a/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go similarity index 94% rename from eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go index 9cf5dd5a1f..2ad990b6b8 100644 --- a/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go @@ -15,7 +15,7 @@ package conf -import "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" +import "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" type EventMeshTCPClientConfig struct { host string diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go similarity index 91% rename from eventmesh-sdk-go/tcp/eventmesh_tcp_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go index 0a7c589159..2dcd6869ad 100644 --- a/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go @@ -15,7 +15,7 @@ package tcp -import gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" +import gtcp "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" type EventMeshTCPClient interface { Init() diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go similarity index 88% rename from eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go index 7256c87f60..2eee98b30a 100644 --- a/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go @@ -16,8 +16,8 @@ package tcp import ( - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/conf" ) func CreateEventMeshTCPClient(eventMeshTcpClientConfig conf.EventMeshTCPClientConfig, messageType protocol.MessageType) EventMeshTCPClient { diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go similarity index 91% rename from eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go index 6dd0bc47a3..7ef3cb92fb 100644 --- a/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go @@ -15,7 +15,7 @@ package tcp -import gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" +import gtcp "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" type EventMeshTCPPubClient interface { init() diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go similarity index 92% rename from eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go index 98be7bba2f..7b8b8ab83c 100644 --- a/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go @@ -15,7 +15,7 @@ package tcp -import "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" +import "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol" type EventMeshTCPSubClient interface { init() diff --git a/eventmesh-sdk-go/tcp/tcp_client.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/tcp_client.go similarity index 87% rename from eventmesh-sdk-go/tcp/tcp_client.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/tcp_client.go index afd6342b2d..2ae020733b 100644 --- a/eventmesh-sdk-go/tcp/tcp_client.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/tcp_client.go @@ -23,12 +23,12 @@ import ( "net" "strconv" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp/codec" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp/codec" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/conf" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/utils" ) type BaseTCPClient struct { diff --git a/eventmesh-sdk-go/tcp/utils/message_utils.go b/eventmesh-sdks/eventmesh-sdk-go/tcp/utils/message_utils.go similarity index 75% rename from eventmesh-sdk-go/tcp/utils/message_utils.go rename to eventmesh-sdks/eventmesh-sdk-go/tcp/utils/message_utils.go index 7a8a7cd098..68e433c06a 100644 --- a/eventmesh-sdk-go/tcp/utils/message_utils.go +++ b/eventmesh-sdks/eventmesh-sdk-go/tcp/utils/message_utils.go @@ -16,16 +16,19 @@ package utils import ( - gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" - "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/common" cloudevents "github.com/cloudevents/sdk-go/v2" + + gcommon "github.com/apache/eventmesh/eventmesh-sdk-go/common" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/eventmesh/eventmesh-sdk-go/log" + "github.com/apache/eventmesh/eventmesh-sdk-go/tcp/common" ) +const seqLength = 10 + func BuildPackage(message interface{}, command tcp.Command) tcp.Package { - // FIXME Support random sequence - header := tcp.NewHeader(command, 0, "", "22222") + header := tcp.NewHeader(command, 0, "", utils.RandomNumberStr(seqLength)) pkg := tcp.NewPackage(header) if _, ok := message.(cloudevents.Event); ok { @@ -37,7 +40,7 @@ func BuildPackage(message interface{}, command tcp.Command) tcp.Package { pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_TYPE, common.EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_VERSION, event.SpecVersion()) - pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_DESC, "tcp") + pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_DESC, utils.RandomStr(seqLength)) pkg.Body = eventBytes } @@ -45,16 +48,14 @@ func BuildPackage(message interface{}, command tcp.Command) tcp.Package { } func BuildHelloPackage(agent tcp.UserAgent) tcp.Package { - // FIXME Support random sequence - header := tcp.NewHeader(tcp.DefaultCommand.HELLO_REQUEST, 0, "", "22222") + header := tcp.NewHeader(tcp.DefaultCommand.HELLO_REQUEST, 0, "", utils.RandomNumberStr(seqLength)) msg := tcp.NewPackage(header) msg.Body = agent return msg } func BuildHeartBeatPackage() tcp.Package { - // FIXME Support random sequence - header := tcp.NewHeader(tcp.DefaultCommand.HEARTBEAT_REQUEST, 0, "", "22222") + header := tcp.NewHeader(tcp.DefaultCommand.HEARTBEAT_REQUEST, 0, "", utils.RandomNumberStr(seqLength)) msg := tcp.NewPackage(header) return msg } diff --git a/eventmesh-sdks/eventmesh-sdk-java/build.gradle b/eventmesh-sdks/eventmesh-sdk-java/build.gradle new file mode 100644 index 0000000000..be55c650a3 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/build.gradle @@ -0,0 +1,68 @@ +/* + * 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. + */ + +def grpcVersion = '1.68.0' + +dependencies { + api(project(":eventmesh-common")) { + // Remove logging backend implementations to allow users to choose their own + exclude group: 'org.apache.logging.log4j', module: 'log4j-core' + exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j2-impl' + } + + implementation "com.fasterxml.jackson.core:jackson-databind" + implementation "com.fasterxml.jackson.core:jackson-core" + implementation "com.fasterxml.jackson.core:jackson-annotations" + implementation "org.apache.commons:commons-collections4" + + implementation "io.netty:netty-all" + implementation "org.apache.httpcomponents:httpclient" + + implementation "io.grpc:grpc-protobuf:${grpcVersion}" + implementation "io.grpc:grpc-stub:${grpcVersion}" + implementation "io.grpc:grpc-netty:${grpcVersion}" + implementation "io.grpc:grpc-netty-shaded:${grpcVersion}" + implementation "io.cloudevents:cloudevents-protobuf" + + // protocol + api "io.cloudevents:cloudevents-core" + api "io.cloudevents:cloudevents-json-jackson" + api "io.openmessaging:openmessaging-api" + + testImplementation project(":eventmesh-common") + + testImplementation "com.fasterxml.jackson.core:jackson-databind" + testImplementation "com.fasterxml.jackson.core:jackson-core" + testImplementation "com.fasterxml.jackson.core:jackson-annotations" + + testImplementation "io.netty:netty-all" + testImplementation "org.apache.httpcomponents:httpclient" + + implementation "io.grpc:grpc-protobuf:${grpcVersion}" + implementation "io.grpc:grpc-stub:${grpcVersion}" + implementation "com.google.protobuf:protobuf-java-util:3.25.4" + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.assertj:assertj-core" + + testImplementation "org.mockito:mockito-inline" + testImplementation "org.mockito:mockito-junit-jupiter" +} diff --git a/eventmesh-sdk-java/gradle.properties b/eventmesh-sdks/eventmesh-sdk-java/gradle.properties similarity index 100% rename from eventmesh-sdk-java/gradle.properties rename to eventmesh-sdks/eventmesh-sdk-java/gradle.properties diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/catalog/EventMeshCatalogClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/catalog/EventMeshCatalogClient.java new file mode 100644 index 0000000000..ccaee18bb6 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/catalog/EventMeshCatalogClient.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.catalog; + +import org.apache.eventmesh.client.catalog.config.EventMeshCatalogClientConfig; +import org.apache.eventmesh.client.grpc.consumer.EventMeshGrpcConsumer; +import org.apache.eventmesh.client.selector.Selector; +import org.apache.eventmesh.client.selector.SelectorFactory; +import org.apache.eventmesh.client.selector.ServiceInstance; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.catalog.protos.CatalogGrpc; +import org.apache.eventmesh.common.protocol.catalog.protos.Operation; +import org.apache.eventmesh.common.protocol.catalog.protos.QueryOperationsRequest; +import org.apache.eventmesh.common.protocol.catalog.protos.QueryOperationsResponse; +import org.apache.eventmesh.common.utils.AssertUtils; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshCatalogClient { + + private final transient EventMeshCatalogClientConfig clientConfig; + private final transient EventMeshGrpcConsumer eventMeshGrpcConsumer; + private final transient List subscriptionItems = new ArrayList<>(); + + public EventMeshCatalogClient(final EventMeshCatalogClientConfig clientConfig, + final EventMeshGrpcConsumer eventMeshGrpcConsumer) { + this.clientConfig = clientConfig; + this.eventMeshGrpcConsumer = eventMeshGrpcConsumer; + } + + public void init() { + final Selector selector = SelectorFactory.get(clientConfig.getSelectorType()); + AssertUtils.notNull(selector, String.format("selector=%s not register.please check it.", + clientConfig.getSelectorType())); + final ServiceInstance instance = selector.selectOne(clientConfig.getServerName()); + AssertUtils.notNull(instance, "catalog server is not running.please check it."); + + final ManagedChannel channel = ManagedChannelBuilder.forAddress(instance.getHost(), instance.getPort()) + .usePlaintext().build(); + final CatalogGrpc.CatalogBlockingStub catalogClient = CatalogGrpc.newBlockingStub(channel); + + final QueryOperationsRequest request = QueryOperationsRequest.newBuilder() + .setServiceName(clientConfig.getAppServerName()).build(); + final QueryOperationsResponse response = catalogClient.queryOperations(request); + log.info("received response: {}", response); + + final List operations = response.getOperationsList(); + if (CollectionUtils.isEmpty(operations)) { + return; + } + operations.forEach(operation -> { + if ("subscribe".equals(operation.getType())) { + final SubscriptionItem subscriptionItem = new SubscriptionItem(); + subscriptionItem.setTopic(operation.getChannelName()); + subscriptionItem.setMode(clientConfig.getSubscriptionMode()); + subscriptionItem.setType(clientConfig.getSubscriptionType()); + subscriptionItems.add(subscriptionItem); + } + }); + eventMeshGrpcConsumer.subscribe(subscriptionItems); + } + + public void destroy() { + if (CollectionUtils.isNotEmpty(subscriptionItems)) { + eventMeshGrpcConsumer.unsubscribe(subscriptionItems); + } + + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/catalog/config/EventMeshCatalogClientConfig.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/catalog/config/EventMeshCatalogClientConfig.java new file mode 100644 index 0000000000..0fb7b4ea93 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/catalog/config/EventMeshCatalogClientConfig.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.catalog.config; + +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class EventMeshCatalogClientConfig { + + @Builder.Default + private String serverName = "eventmesh-catalog"; + + @Builder.Default + private String selectorType = "nacos"; + + // catalog application server name + private String appServerName; + + @Builder.Default + private SubscriptionMode subscriptionMode = SubscriptionMode.CLUSTERING; + + @Builder.Default + private SubscriptionType subscriptionType = SubscriptionType.ASYNC; +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/config/EventMeshGrpcClientConfig.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/config/EventMeshGrpcClientConfig.java new file mode 100644 index 0000000000..8d37802237 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/config/EventMeshGrpcClientConfig.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.config; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class EventMeshGrpcClientConfig { + + @Builder.Default + private String serverAddr = "localhost"; + + @Builder.Default + private int serverPort = 10_205; + + @Builder.Default + private String env = "env"; + + @Builder.Default + private String consumerGroup = "DefaultConsumerGroup"; + + @Builder.Default + private String producerGroup = "DefaultProducerGroup"; + + @Builder.Default + private String idc = "default"; + + @Builder.Default + private String sys = "sys123"; + + @Builder.Default + private String userName = "username"; + + @Builder.Default + private String password = "passwd"; + + @Builder.Default + private String language = "JAVA"; + + @Builder.Default + private boolean useTls = false; + + @Builder.Default + private long timeOut = 5_000; + + @Override + public String toString() { + return "ClientConfig={ServerAddr=" + + serverAddr + + ",ServerPort=" + + serverPort + + ",env=" + + env + + ",idc=" + + idc + + ",producerGroup=" + + producerGroup + + ",consumerGroup=" + + consumerGroup + + ",sys=" + + sys + + ",userName=" + + userName + + ",password=***" + + ",useTls=" + + useTls + + ",timeOut=" + + timeOut + + "}"; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumer.java new file mode 100644 index 0000000000..623ca1c6fe --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumer.java @@ -0,0 +1,316 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.consumer; + +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toList; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.grpc.util.EventMeshCloudEventBuilder; +import org.apache.eventmesh.client.tcp.common.EventMeshCommon; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.enums.EventMeshDataContentType; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.HeartbeatItem; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc.ConsumerServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc.ConsumerServiceStub; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.HeartbeatServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.HeartbeatServiceGrpc.HeartbeatServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.ClientType; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.GrpcType; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.grpc.common.Response; +import org.apache.eventmesh.common.protocol.grpc.common.StatusCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.commons.collections4.MapUtils; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public class EventMeshGrpcConsumer implements AutoCloseable { + + private static final String SDK_STREAM_URL = "grpc_stream"; + private ManagedChannel channel; + private final EventMeshGrpcClientConfig clientConfig; + + private final Map subscriptionMap = new ConcurrentHashMap<>(); + + private final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), + new EventMeshThreadFactory("GRPCClientScheduler", true)); + + private ConsumerServiceBlockingStub consumerClient; + private ConsumerServiceStub consumerAsyncClient; + private HeartbeatServiceBlockingStub heartbeatClient; + + private ReceiveMsgHook listener; + private SubStreamHandler subStreamHandler; + + public EventMeshGrpcConsumer(final EventMeshGrpcClientConfig clientConfig) { + this.clientConfig = clientConfig; + } + + public void init() { + this.channel = ManagedChannelBuilder.forAddress(clientConfig.getServerAddr(), clientConfig.getServerPort()).usePlaintext().build(); + this.consumerClient = ConsumerServiceGrpc.newBlockingStub(channel); + this.consumerAsyncClient = ConsumerServiceGrpc.newStub(channel); + this.heartbeatClient = HeartbeatServiceGrpc.newBlockingStub(channel); + heartBeat(); + } + + /** + * Subscribes to an event at a specified URL(Webhook). + * + * @param subscriptionItems The list of subscription items. + * @param url The URL to subscribe to. + * @return A response containing information about the subscription result. + */ + public Response subscribe(final List subscriptionItems, final String url) { + log.info("Create subscription: {} , url: {}", subscriptionItems, url); + + addSubscription(subscriptionItems, url, GrpcType.WEBHOOK); + + return subscribeWebhook(subscriptionItems, url); + } + + /** + * Subscribes to a streaming. + * + * @param subscriptionItems The list of subscription items for streaming. + */ + public void subscribe(final List subscriptionItems) { + log.info("Create streaming subscription: {}", subscriptionItems); + + if (listener == null) { + log.error("Error in subscriber, no Event Listener is registered."); + return; + } + + addSubscription(subscriptionItems, SDK_STREAM_URL, GrpcType.STREAM); + + CloudEvent subscription = EventMeshCloudEventBuilder.buildEventSubscription( + clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE, null, subscriptionItems); + synchronized (this) { + if (subStreamHandler == null) { + subStreamHandler = new SubStreamHandler<>(consumerAsyncClient, clientConfig, listener); + subStreamHandler.start(); + } + } + subStreamHandler.sendSubscription(subscription); + } + + private Response subscribeWebhook(List subscriptionItems, String url) { + final CloudEvent subscription = EventMeshCloudEventBuilder.buildEventSubscription( + clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE, url, subscriptionItems); + try { + CloudEvent response = consumerClient.subscribe(subscription); + log.info("Received response:{}", response); + return Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + } catch (Exception e) { + log.error("Error in subscribe.", e); + } + return null; + } + + private void addSubscription(final List subscriptionItems, final String url, final GrpcType grpcType) { + for (SubscriptionItem item : subscriptionItems) { + subscriptionMap.putIfAbsent(item.getTopic(), new SubscriptionInfo(item, url, grpcType)); + } + } + + private void removeSubscription(final List subscriptionItems) { + Objects.requireNonNull(subscriptionItems, "subscriptionItems can not be null"); + subscriptionItems.forEach(item -> subscriptionMap.remove(item.getTopic())); + } + + public Response unsubscribe(final List subscriptionItems, final String url) { + log.info("Removing subscription: {}, url:{}", subscriptionItems, url); + + removeSubscription(subscriptionItems); + + final CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventSubscription( + clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE, url, subscriptionItems); + try { + final CloudEvent response = consumerClient.unsubscribe(cloudEvent); + log.info("Received response:{}", response); + return Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + } catch (Exception e) { + log.error("Error in unsubscribe.", e); + } + return null; + } + + public Response unsubscribe(final List subscriptionItems) { + Objects.requireNonNull(subscriptionItems, "subscriptionItems can not be null"); + log.info("Removing subscription stream: {}", subscriptionItems); + + removeSubscription(subscriptionItems); + + final CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventSubscription( + clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE, null, subscriptionItems); + + try { + final CloudEvent response = consumerClient.unsubscribe(cloudEvent); + Response parsedResponse = Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + log.info("Received response:{}", parsedResponse); + + // there is no stream subscriptions, stop the subscription stream handler + synchronized (this) { + if (MapUtils.isEmpty(subscriptionMap) && subStreamHandler != null) { + subStreamHandler.close(); + } + } + return parsedResponse; + } catch (Exception e) { + log.error("Error in unsubscribe.", e); + } + return null; + } + + public synchronized void registerListener(final ReceiveMsgHook listener) { + if (this.listener == null) { + this.listener = listener; + } + } + + private void heartBeat() { + final Map attributeValueMap = EventMeshCloudEventBuilder.buildCommonCloudEventAttributes(clientConfig, + EventMeshProtocolType.EVENT_MESH_MESSAGE); + + scheduler.scheduleAtFixedRate(() -> { + if (MapUtils.isEmpty(subscriptionMap)) { + return; + } + Map ext = new HashMap<>(attributeValueMap); + ext.put(ProtocolKey.CONSUMERGROUP, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getConsumerGroup()).build()); + ext.put(ProtocolKey.CLIENT_TYPE, CloudEventAttributeValue.newBuilder().setCeInteger(ClientType.SUB.getType()).build()); + ext.put(ProtocolKey.DATA_CONTENT_TYPE, + CloudEventAttributeValue.newBuilder().setCeString(EventMeshDataContentType.JSON.getCode()).build()); + final CloudEvent.Builder heartbeatBuilder = CloudEvent.newBuilder().putAllAttributes(ext); + List heartbeatItems = subscriptionMap.entrySet().stream() + .map(entry -> HeartbeatItem.builder().topic(entry.getKey()).url(entry.getValue().getUrl()).build()).collect(toList()); + CloudEvent heartbeat = heartbeatBuilder.setTextData(JsonUtils.toJSONString(heartbeatItems)).build(); + + try { + CloudEvent cloudEventResp = heartbeatClient.heartbeat(heartbeat); + assert cloudEventResp != null; + Response response = Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(cloudEventResp)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(cloudEventResp)) + .respTime(EventMeshCloudEventUtils.getResponseTime(cloudEventResp)) + .build(); + log.debug("Grpc Consumer Heartbeat cloudEvent: {}", response); + if (StatusCode.CLIENT_RESUBSCRIBE.getRetCode().equals(response.getRespCode())) { + resubscribe(); + } + } catch (Exception e) { + log.error("Error in sending out heartbeat.", e); + } + }, 10_000, EventMeshCommon.HEARTBEAT, TimeUnit.MILLISECONDS); + + log.info("Grpc Consumer Heartbeat started."); + } + + private void resubscribe() { + if (subscriptionMap.isEmpty()) { + return; + } + final Collection values = subscriptionMap.values(); + final AtomicBoolean isStreamSub = new AtomicBoolean(false); + for (SubscriptionInfo info : values) { + if (info.grpcType == GrpcType.STREAM) { + isStreamSub.compareAndSet(false, true); + break; + } + } + final Map> subscriptionGroup = values.stream() + .collect(Collectors.groupingBy(SubscriptionInfo::getUrl, mapping(SubscriptionInfo::getSubscriptionItem, toList()))); + + subscriptionGroup.forEach((url, items) -> { + if (isStreamSub.get()) { + CloudEvent subscription = EventMeshCloudEventBuilder.buildEventSubscription( + clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE, url, items); + subStreamHandler.sendSubscription(subscription); + } else { + subscribeWebhook(items, url); + } + }); + } + + @Override + public void close() { + if (this.subStreamHandler != null) { + this.subStreamHandler.close(); + } + + if (this.channel != null) { + channel.shutdown(); + } + + if (this.scheduler != null) { + scheduler.shutdown(); + } + } + + @Data + private static class SubscriptionInfo { + + private transient SubscriptionItem subscriptionItem; + private transient String url; + private GrpcType grpcType; + + SubscriptionInfo(final SubscriptionItem subscriptionItem, final String url, final GrpcType grpcType) { + this.subscriptionItem = subscriptionItem; + this.url = url; + this.grpcType = grpcType; + } + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java similarity index 87% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java index 905134c551..24b8ca0ae4 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/ReceiveMsgHook.java @@ -17,10 +17,11 @@ package org.apache.eventmesh.client.grpc.consumer; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; + import java.util.Optional; /** - * * @param */ public interface ReceiveMsgHook { @@ -31,8 +32,8 @@ public interface ReceiveMsgHook { * @param msg * @return */ - Optional handle(T msg) throws Throwable; + Optional handle(T msg) throws Exception; - String getProtocolType(); + EventMeshProtocolType getProtocolType(); } diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/SubStreamHandler.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/SubStreamHandler.java new file mode 100644 index 0000000000..59436be08f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/consumer/SubStreamHandler.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.consumer; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.grpc.util.EventMeshCloudEventBuilder; +import org.apache.eventmesh.common.enums.EventMeshDataContentType; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc.ConsumerServiceStub; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; + +import java.io.Serializable; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +import io.grpc.stub.StreamObserver; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SubStreamHandler extends Thread implements Serializable { + + private final transient CountDownLatch latch = new CountDownLatch(1); + + private final transient ConsumerServiceStub consumerAsyncClient; + + private final transient EventMeshGrpcClientConfig clientConfig; + + private transient StreamObserver sender; + + private final ReceiveMsgHook listener; + + public SubStreamHandler(final ConsumerServiceStub consumerAsyncClient, final EventMeshGrpcClientConfig clientConfig, + final ReceiveMsgHook listener) { + this.consumerAsyncClient = consumerAsyncClient; + this.clientConfig = clientConfig; + this.listener = listener; + } + + public void sendSubscription(final CloudEvent subscription) { + synchronized (this) { + if (this.sender == null) { + this.sender = consumerAsyncClient.subscribeStream(createReceiver()); + } + } + senderOnNext(subscription); + } + + private StreamObserver createReceiver() { + return new StreamObserver() { + + @Override + public void onNext(final CloudEvent message) { + T msg = EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(message, listener.getProtocolType()); + if (msg instanceof Set) { + log.info("Received message from Server:{}", message); + } else { + log.info("Received message from Server.|seq={}|uniqueId={}|", + EventMeshCloudEventUtils.getSeqNum(message), EventMeshCloudEventUtils.getUniqueId(message)); + CloudEvent streamReply = null; + try { + Optional reply = listener.handle(msg); + if (reply.isPresent()) { + streamReply = buildReplyMessage(message, reply.get()); + } + } catch (Exception e) { + log.error("Error in handling reply message.|seq={}|uniqueId={}|", + EventMeshCloudEventUtils.getSeqNum(message), EventMeshCloudEventUtils.getUniqueId(message), e); + } + if (streamReply != null) { + log.info("Sending reply message to Server.|seq={}|uniqueId={}|", + EventMeshCloudEventUtils.getSeqNum(streamReply), EventMeshCloudEventUtils.getUniqueId(streamReply)); + senderOnNext(streamReply); + } + } + } + + @Override + public void onError(final Throwable t) { + log.error("Received Server side error", t); + close(); + } + + @Override + public void onCompleted() { + log.info("Finished receiving messages from server."); + } + }; + } + + private CloudEvent buildReplyMessage(final CloudEvent reqMessage, final T replyMessage) { + final CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(replyMessage, + clientConfig, listener.getProtocolType()); + + return CloudEvent.newBuilder(cloudEvent).putAllAttributes(reqMessage.getAttributesMap()).putAllAttributes(cloudEvent.getAttributesMap()) + .putAttributes(ProtocolKey.DATA_CONTENT_TYPE, + CloudEventAttributeValue.newBuilder().setCeString(EventMeshDataContentType.JSON.getCode()).build()) + // Indicate that it is a subscription response + .putAttributes(ProtocolKey.SUB_MESSAGE_TYPE, CloudEventAttributeValue.newBuilder().setCeString(ProtocolKey.SUB_REPLY_MESSAGE).build()) + .build(); + } + + @Override + public void run() { + try { + latch.await(); + } catch (InterruptedException e) { + log.error("SubStreamHandler Thread interrupted", e); + Thread.currentThread().interrupt(); + } + } + + public void close() { + if (this.sender != null) { + senderOnComplete(); + } + + latch.countDown(); + log.info("SubStreamHandler closed."); + } + + private void senderOnNext(final CloudEvent subscription) { + try { + synchronized (sender) { + sender.onNext(subscription); + } + } catch (Exception e) { + log.error("StreamObserver Error onNext", e); + close(); + } + } + + private void senderOnComplete() { + try { + synchronized (sender) { + sender.onCompleted(); + } + } catch (Exception e) { + log.error("StreamObserver Error onComplete", e); + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/exception/ProtocolNotSupportException.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/exception/ProtocolNotSupportException.java new file mode 100644 index 0000000000..ef89340a84 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/exception/ProtocolNotSupportException.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.exception; + +public class ProtocolNotSupportException extends RuntimeException { + + /** + * Constructs a new runtime exception with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized + * by a call to {@link #initCause}. + */ + public ProtocolNotSupportException() { + super(); + } + + /** + * Constructs a new runtime exception with the specified detail message. The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. + */ + public ProtocolNotSupportException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and cause.

Note that the detail message associated with {@code cause} + * is not automatically incorporated in this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public ProtocolNotSupportException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which + * typically contains the class and detail message of + * cause). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + * @since 1.4 + */ + public ProtocolNotSupportException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled + * or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + * @since 1.7 + */ + protected ProtocolNotSupportException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducer.java new file mode 100644 index 0000000000..3dc1288012 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducer.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.grpc.util.EventMeshCloudEventBuilder; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc.PublisherServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.Response; +import org.apache.eventmesh.common.utils.LogUtil; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventProducer implements GrpcProducer { + + private static final EventMeshProtocolType PROTOCOL_TYPE = EventMeshProtocolType.CLOUD_EVENTS; + + private final transient EventMeshGrpcClientConfig clientConfig; + + private final transient PublisherServiceBlockingStub publisherClient; + + public CloudEventProducer(final EventMeshGrpcClientConfig clientConfig, + final PublisherServiceBlockingStub publisherClient) { + this.clientConfig = clientConfig; + this.publisherClient = publisherClient; + } + + @Override + public Response publish(final List events) { + log.info("BatchPublish message, batch size={}", events.size()); + + if (CollectionUtils.isEmpty(events)) { + return null; + } + + final CloudEventBatch cloudEventBatch = EventMeshCloudEventBuilder.buildEventMeshCloudEventBatch(events, clientConfig, PROTOCOL_TYPE); + try { + final CloudEvent response = publisherClient.batchPublish(cloudEventBatch); + Response parsedResponse = Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + + log.info("Received response:{}", parsedResponse); + return parsedResponse; + } catch (Exception e) { + log.error("Error in BatchPublish message {}", events, e); + } + return null; + } + + @Override + public Response publish(final io.cloudevents.CloudEvent cloudEvent) { + LogUtil.info(log, "Publish message: {}", cloudEvent::toString); + CloudEvent enhancedMessage = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(cloudEvent, clientConfig, PROTOCOL_TYPE); + try { + final CloudEvent response = publisherClient.publish(enhancedMessage); + Response parsedResponse = Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + log.info("Received response:{} ", parsedResponse); + return parsedResponse; + } catch (Exception e) { + log.error("Error in publishing message {}", cloudEvent, e); + } + return null; + } + + @Override + public io.cloudevents.CloudEvent requestReply(final io.cloudevents.CloudEvent cloudEvent, final long timeout) { + log.info("RequestReply message {}", cloudEvent); + final CloudEvent enhancedMessage = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(cloudEvent, clientConfig, PROTOCOL_TYPE); + try { + final CloudEvent reply = publisherClient.requestReply(enhancedMessage); + log.info("Received reply message:{}", reply); + return EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(reply, PROTOCOL_TYPE); + } catch (Exception e) { + log.error("Error in RequestReply message {}", cloudEvent, e); + } + return null; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducer.java new file mode 100644 index 0000000000..5003ed9489 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducer.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.tcp.common.EventMeshCommon; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc.PublisherServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.Response; +import org.apache.eventmesh.common.utils.LogUtil; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; + +import io.cloudevents.CloudEvent; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public class EventMeshGrpcProducer implements AutoCloseable { + + private static final String PROTOCOL_TYPE = EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME; + + private final transient EventMeshGrpcClientConfig clientConfig; + + private final transient ManagedChannel channel; + + private PublisherServiceBlockingStub publisherClient; + + private CloudEventProducer cloudEventProducer; + + private EventMeshMessageProducer eventMeshMessageProducer; + + public EventMeshGrpcProducer(EventMeshGrpcClientConfig clientConfig) { + this.clientConfig = clientConfig; + this.channel = ManagedChannelBuilder.forAddress(clientConfig.getServerAddr(), clientConfig.getServerPort()).usePlaintext().build(); + this.publisherClient = PublisherServiceGrpc.newBlockingStub(channel); + this.cloudEventProducer = new CloudEventProducer(clientConfig, publisherClient); + this.eventMeshMessageProducer = new EventMeshMessageProducer(clientConfig, publisherClient); + } + + public Response publish(T message) { + LogUtil.info(log, "Publish message: {}", message::toString); + if (message instanceof CloudEvent) { + return cloudEventProducer.publish((CloudEvent) message); + } else if (message instanceof EventMeshMessage) { + return eventMeshMessageProducer.publish((EventMeshMessage) message); + } else { + throw new IllegalArgumentException("Not support message " + message.getClass().getName()); + } + } + + @SuppressWarnings("unchecked") + public Response publish(List messageList) { + log.info("BatchPublish message: {}", messageList); + + if (CollectionUtils.isEmpty(messageList)) { + return null; + } + + T target = messageList.get(0); + if (target instanceof CloudEvent) { + return cloudEventProducer.publish((List) messageList); + } else if (target instanceof EventMeshMessage) { + return eventMeshMessageProducer.publish((List) messageList); + } else { + throw new IllegalArgumentException("Not support message " + target.getClass().getName()); + } + } + + public T requestReply(final T message, final long timeout) { + + if (message instanceof CloudEvent) { + CloudEvent cloudEvent = cloudEventProducer.requestReply((CloudEvent) message, timeout); + return (T) cloudEvent; + } else if (message instanceof EventMeshMessage) { + return (T) eventMeshMessageProducer.requestReply((EventMeshMessage) message, timeout); + } else { + throw new IllegalArgumentException("Not support message " + message.getClass().getName()); + } + } + + @Override + public void close() { + channel.shutdown(); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshMessageProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshMessageProducer.java new file mode 100644 index 0000000000..93806f8247 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/EventMeshMessageProducer.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.grpc.util.EventMeshCloudEventBuilder; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc.PublisherServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.Response; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshMessageProducer implements GrpcProducer { + + private static final EventMeshProtocolType PROTOCOL_TYPE = EventMeshProtocolType.EVENT_MESH_MESSAGE; + + private final EventMeshGrpcClientConfig clientConfig; + + private final PublisherServiceBlockingStub publisherClient; + + public EventMeshMessageProducer(EventMeshGrpcClientConfig clientConfig, PublisherServiceBlockingStub publisherClient) { + this.clientConfig = clientConfig; + this.publisherClient = publisherClient; + } + + @Override + public Response publish(EventMeshMessage message) throws EventMeshException { + + if (message == null) { + return null; + } + + log.debug("Publish message: {}", message); + CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(message, clientConfig, PROTOCOL_TYPE); + try { + CloudEvent response = publisherClient.publish(cloudEvent); + Response parsedResponse = Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + log.info("Received response:{}", parsedResponse); + return parsedResponse; + } catch (Exception e) { + log.error("Error in publishing message {}", message, e); + throw new EventMeshException("Error in publishing message {}", e); + } + } + + @Override + public Response publish(List messages) throws EventMeshException { + + if (CollectionUtils.isEmpty(messages)) { + return null; + } + CloudEventBatch cloudEventBatch = EventMeshCloudEventBuilder.buildEventMeshCloudEventBatch(messages, clientConfig, PROTOCOL_TYPE); + try { + CloudEvent response = publisherClient.batchPublish(cloudEventBatch); + Response parsedResponse = Response.builder() + .respCode(EventMeshCloudEventUtils.getResponseCode(response)) + .respMsg(EventMeshCloudEventUtils.getResponseMessage(response)) + .respTime(EventMeshCloudEventUtils.getResponseTime(response)) + .build(); + log.info("Received response:{}", parsedResponse); + return parsedResponse; + } catch (Exception e) { + log.error("Error in BatchPublish message {}", messages, e); + throw new EventMeshException("Error in BatchPublish message {}", e); + } + } + + @Override + public EventMeshMessage requestReply(EventMeshMessage message, long timeout) throws EventMeshException { + log.info("RequestReply message:{}", message); + + final CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(message, clientConfig, PROTOCOL_TYPE); + try { + final CloudEvent reply = publisherClient.withDeadlineAfter(timeout, TimeUnit.MILLISECONDS).requestReply(cloudEvent); + log.info("Received reply message:{}", reply); + return EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(reply, PROTOCOL_TYPE); + } catch (Exception e) { + log.error("Error in RequestReply message {}", message, e); + throw new EventMeshException("Error in RequestReply message {}", e); + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/GrpcProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/GrpcProducer.java new file mode 100644 index 0000000000..4c63485b44 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/producer/GrpcProducer.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import org.apache.eventmesh.common.protocol.grpc.common.Response; + +import java.util.List; + +/** + * + * @param + */ +public interface GrpcProducer { + + Response publish(T message); + + Response publish(List messages); + + T requestReply(T message, long timeout); + +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/util/EventMeshCloudEventBuilder.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/util/EventMeshCloudEventBuilder.java new file mode 100644 index 0000000000..5621b41e0f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/grpc/util/EventMeshCloudEventBuilder.java @@ -0,0 +1,286 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.util; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.client.grpc.exception.ProtocolNotSupportException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.ProtoSupport; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import io.cloudevents.SpecVersion; +import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.protobuf.ProtobufFormat; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshCloudEventBuilder { + + private static final String CLOUD_EVENT_TYPE = "org.apache.eventmesh"; + + private static final EventFormat eventProtoFormat = EventFormatProvider.getInstance().resolveFormat(ProtobufFormat.PROTO_CONTENT_TYPE); + + public static Map buildCommonCloudEventAttributes(EventMeshGrpcClientConfig clientConfig, + EventMeshProtocolType protocolType) { + final Map attributeValueMap = new HashMap<>(64); + attributeValueMap.put(ProtocolKey.ENV, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getEnv()).build()); + attributeValueMap.put(ProtocolKey.IDC, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getIdc()).build()); + attributeValueMap.put(ProtocolKey.IP, CloudEventAttributeValue.newBuilder().setCeString(IPUtils.getLocalAddress()).build()); + attributeValueMap.put(ProtocolKey.PID, CloudEventAttributeValue.newBuilder().setCeString(Long.toString(ThreadUtils.getPID())).build()); + attributeValueMap.put(ProtocolKey.SYS, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getSys()).build()); + attributeValueMap.put(ProtocolKey.LANGUAGE, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getLanguage()).build()); + attributeValueMap.put(ProtocolKey.USERNAME, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getUserName()).build()); + attributeValueMap.put(ProtocolKey.PASSWD, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getPassword()).build()); + attributeValueMap.put(ProtocolKey.PROTOCOL_TYPE, CloudEventAttributeValue.newBuilder().setCeString(protocolType.protocolTypeName()).build()); + attributeValueMap.put(ProtocolKey.PROTOCOL_VERSION, CloudEventAttributeValue.newBuilder().setCeString(SpecVersion.V1.toString()).build()); + + return attributeValueMap; + } + + public static CloudEvent buildEventSubscription(EventMeshGrpcClientConfig clientConfig, EventMeshProtocolType protocolType, String url, + List subscriptionItems) { + + if (CollectionUtils.isEmpty(subscriptionItems)) { + return null; + } + Set subscriptionItemSet = new HashSet<>(); + subscriptionItemSet.addAll(subscriptionItems); + + final Map attributeValueMap = buildCommonCloudEventAttributes(clientConfig, protocolType); + attributeValueMap.put(ProtocolKey.CONSUMERGROUP, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getConsumerGroup()).build()); + attributeValueMap.put(ProtocolKey.DATA_CONTENT_TYPE, CloudEventAttributeValue.newBuilder().setCeString("application/json").build()); + if (StringUtils.isNotBlank(url)) { + attributeValueMap.put(ProtocolKey.URL, CloudEventAttributeValue.newBuilder().setCeString(url).build()); + } + return CloudEvent.newBuilder() + .setId(RandomStringUtils.generateUUID()) + .setSource(URI.create("/").toString()) + .setSpecVersion(SpecVersion.V1.toString()) + .setType(CLOUD_EVENT_TYPE) + .setTextData(JsonUtils.toJSONString(subscriptionItemSet)) + .putAllAttributes(attributeValueMap) + .build(); + } + + /** + * @param message + * @param clientConfig + * @param protocolType + * @param + * @return CloudEvent + * @see context-attributes + */ + public static CloudEvent buildEventMeshCloudEvent(final T message, final EventMeshGrpcClientConfig clientConfig, + final EventMeshProtocolType protocolType) { + + switch (protocolType) { + case CLOUD_EVENTS: { + if (!(message instanceof io.cloudevents.CloudEvent)) { + throw new ClassCastException(message.getClass().getName() + " can not cast io.cloudevents.CloudEvent"); + } + return switchCloudEvent2EventMeshCloudEvent((io.cloudevents.CloudEvent) message, clientConfig, protocolType); + } + case EVENT_MESH_MESSAGE: { + if (!(message instanceof EventMeshMessage)) { + throw new ClassCastException(message.getClass().getName() + " can not cast" + EventMeshMessage.class.getName()); + } + return switchEventMeshMessage2EventMeshCloudEvent((EventMeshMessage) message, clientConfig, protocolType); + } + case OPEN_MESSAGE: + return null; + default: + throw new ProtocolNotSupportException("Protocol Type [" + protocolType + "] not support"); + } + } + + private static CloudEvent switchEventMeshMessage2EventMeshCloudEvent(EventMeshMessage message, EventMeshGrpcClientConfig clientConfig, + EventMeshProtocolType protocolType) { + final String ttl = message.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL) == null + ? Constants.DEFAULT_EVENTMESH_MESSAGE_TTL + : message.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL); + final Map props = message.getProp() == null ? new HashMap<>() : message.getProp(); + final String seqNum = message.getBizSeqNo() == null ? RandomStringUtils.generateNum(30) : message.getBizSeqNo(); + final String uniqueId = message.getUniqueId() == null ? RandomStringUtils.generateNum(30) : message.getUniqueId(); + final String dataContentType = props.computeIfAbsent(ProtocolKey.DATA_CONTENT_TYPE, key -> "text/plain"); + final Map attributeValueMap = buildCommonCloudEventAttributes(clientConfig, protocolType); + + attributeValueMap.put(ProtocolKey.TTL, CloudEventAttributeValue.newBuilder().setCeString(ttl).build()); + attributeValueMap.put(ProtocolKey.SEQ_NUM, CloudEventAttributeValue.newBuilder().setCeString(seqNum).build()); + attributeValueMap.put(ProtocolKey.UNIQUE_ID, CloudEventAttributeValue.newBuilder().setCeString(uniqueId).build()); + attributeValueMap.put(ProtocolKey.PROTOCOL_DESC, + CloudEventAttributeValue.newBuilder().setCeString(Constants.PROTOCOL_DESC_GRPC_CLOUD_EVENT).build()); + attributeValueMap.put(ProtocolKey.PRODUCERGROUP, + CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getProducerGroup()).build()); + if (message.getTopic() != null) { + attributeValueMap.put(ProtocolKey.SUBJECT, CloudEventAttributeValue.newBuilder().setCeString(message.getTopic()).build()); + } + attributeValueMap.put(ProtocolKey.DATA_CONTENT_TYPE, CloudEventAttributeValue.newBuilder().setCeString("text/plain").build()); + props.forEach((key, value) -> attributeValueMap.put(key, CloudEventAttributeValue.newBuilder().setCeString(value).build())); + CloudEvent.Builder builder = CloudEvent.newBuilder() + .setId(RandomStringUtils.generateUUID()) + .setSource(URI.create("/").toString()) + .setSpecVersion(SpecVersion.V1.toString()) + .setType(CLOUD_EVENT_TYPE) + .putAllAttributes(attributeValueMap); + final String content = message.getContent(); + if (StringUtils.isNotEmpty(content)) { + if (ProtoSupport.isTextContent(dataContentType)) { + builder.setTextData(content); + } else if (ProtoSupport.isProtoContent(dataContentType)) { + try { + Any dataAsAny = Any.parseFrom(content.getBytes(Constants.DEFAULT_CHARSET)); + builder.setProtoData(dataAsAny); + } catch (InvalidProtocolBufferException e) { + throw new IllegalArgumentException("parse from byte[] to com.google.protobuf.Any error", e); + } + } else { + ByteString byteString = ByteString.copyFrom(content.getBytes(Constants.DEFAULT_CHARSET)); + builder.setBinaryData(byteString); + } + } + return builder.build(); + } + + private static CloudEvent switchCloudEvent2EventMeshCloudEvent(io.cloudevents.CloudEvent message, EventMeshGrpcClientConfig clientConfig, + EventMeshProtocolType protocolType) { + + CloudEventBuilder cloudEventBuilder = CloudEventBuilder.from(message); + + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.ENV, clientConfig.getEnv()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.IDC, clientConfig.getIdc()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.IP, Objects.requireNonNull(IPUtils.getLocalAddress())); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.PID, Long.toString(ThreadUtils.getPID())); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.SYS, clientConfig.getSys()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.PROTOCOL_TYPE, protocolType.protocolTypeName()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.PROTOCOL_DESC, Constants.PROTOCOL_DESC_GRPC_CLOUD_EVENT); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.PROTOCOL_VERSION, message.getSpecVersion().toString()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.UNIQUE_ID, RandomStringUtils.generateNum(30)); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.SEQ_NUM, RandomStringUtils.generateNum(30)); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.USERNAME, clientConfig.getUserName()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.PASSWD, clientConfig.getPassword()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.PRODUCERGROUP, clientConfig.getProducerGroup()); + buildCloudEventIfAbsent(message, cloudEventBuilder, ProtocolKey.TTL, Constants.DEFAULT_EVENTMESH_MESSAGE_TTL); + + try { + return CloudEvent.parseFrom(eventProtoFormat.serialize(cloudEventBuilder.build())); + } catch (InvalidProtocolBufferException exc) { + log.error("Parse from CloudEvents CloudEvent bytes to EventMesh CloudEvent error", exc); + } + return null; + } + + private static void buildCloudEventIfAbsent(io.cloudevents.CloudEvent message, CloudEventBuilder cloudEventBuilder, + String extension, String value) { + if (Objects.isNull(message.getExtension(extension))) { + cloudEventBuilder.withExtension(extension, value); + } + } + + public static CloudEventBatch buildEventMeshCloudEventBatch(final List messageList, final EventMeshGrpcClientConfig clientConfig, + final EventMeshProtocolType protocolType) { + if (CollectionUtils.isEmpty(messageList)) { + return null; + } + List cloudEventList = messageList.stream().map(item -> buildEventMeshCloudEvent(item, clientConfig, protocolType)) + .collect(Collectors.toList()); + return CloudEventBatch.newBuilder().addAllEvents(cloudEventList).build(); + } + + @SuppressWarnings("unchecked") + public static T buildMessageFromEventMeshCloudEvent(final CloudEvent cloudEvent, final EventMeshProtocolType protocolType) { + + if (cloudEvent == null) { + return null; + } + final String seq = EventMeshCloudEventUtils.getSeqNum(cloudEvent); + final String uniqueId = EventMeshCloudEventUtils.getUniqueId(cloudEvent); + final String content = EventMeshCloudEventUtils.getDataContent(cloudEvent); + + // This is GRPC response cloudEvent + if (StringUtils.isEmpty(seq) && StringUtils.isEmpty(uniqueId)) { + // The SubscriptionItem collection contains the content for the subscription. + return (T) JsonUtils.parseTypeReferenceObject(content, + new TypeReference>>() { + + }); + } + if (protocolType == null) { + return null; + } + + switch (protocolType) { + case CLOUD_EVENTS: + return (T) switchEventMeshCloudEvent2CloudEvent(cloudEvent); + case EVENT_MESH_MESSAGE: + return (T) switchEventMeshCloudEvent2EventMeshMessage(cloudEvent); + case OPEN_MESSAGE: + default: + return null; + } + } + + private static io.cloudevents.CloudEvent switchEventMeshCloudEvent2CloudEvent(final CloudEvent cloudEvent) { + + return eventProtoFormat.deserialize(Objects.requireNonNull(cloudEvent).toByteArray()); + } + + private static EventMeshMessage switchEventMeshCloudEvent2EventMeshMessage(final CloudEvent cloudEvent) { + Map prop = new HashMap<>(); + Objects.requireNonNull(cloudEvent).getAttributesMap().forEach((key, value) -> prop.put(key, value.getCeString())); + return EventMeshMessage.builder() + .content(cloudEvent.getTextData()) + .topic(EventMeshCloudEventUtils.getSubject(cloudEvent)) + .bizSeqNo(EventMeshCloudEventUtils.getSeqNum(cloudEvent)) + .uniqueId(EventMeshCloudEventUtils.getUniqueId(cloudEvent)) + .prop(prop) + .build(); + } + +} \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractHttpClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractHttpClient.java new file mode 100644 index 0000000000..3f0bc960ec --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractHttpClient.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.ssl.MyX509TrustManager; +import org.apache.eventmesh.client.http.util.HttpLoadBalanceUtils; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.loadbalance.LoadBalanceSelector; + +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.DefaultConnectionReuseStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractHttpClient implements AutoCloseable { + + protected EventMeshHttpClientConfig eventMeshHttpClientConfig; + + protected LoadBalanceSelector eventMeshServerSelector; + + protected final CloseableHttpClient httpClient; + + public AbstractHttpClient(final EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { + Objects.requireNonNull(eventMeshHttpClientConfig, "liteClientConfig can't be null"); + Objects.requireNonNull(eventMeshHttpClientConfig.getLiteEventMeshAddr(), "liteServerAddr can't be null"); + + this.eventMeshHttpClientConfig = eventMeshHttpClientConfig; + this.eventMeshServerSelector = HttpLoadBalanceUtils.createEventMeshServerLoadBalanceSelector( + eventMeshHttpClientConfig); + this.httpClient = setHttpClient(); + } + + @Override + public void close() throws EventMeshException { + if (this.httpClient != null) { + try { + this.httpClient.close(); + } catch (IOException e) { + throw new EventMeshException(e); + } + } + + } + + private CloseableHttpClient setHttpClient() throws EventMeshException { + if (!eventMeshHttpClientConfig.isUseTls()) { + return HttpClients.createDefault(); + } + SSLContext sslContext; + try { + final String protocol = eventMeshHttpClientConfig.getSslClientProtocol(); + final TrustManager[] tm = new TrustManager[]{new MyX509TrustManager()}; + sslContext = SSLContext.getInstance(protocol); + sslContext.init(null, tm, new SecureRandom()); + + return HttpClients.custom() + .setConnectionManager(getHttpPoolManager(sslContext, eventMeshHttpClientConfig.getMaxConnectionPoolSize())) + .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) + .evictIdleConnections(eventMeshHttpClientConfig.getConnectionIdleTimeSeconds(), TimeUnit.SECONDS) + .setConnectionReuseStrategy(new DefaultConnectionReuseStrategy()) + .build(); + } catch (Exception e) { + log.error("Error in creating HttpClient.", e); + throw new EventMeshException(e); + } + } + + private HttpClientConnectionManager getHttpPoolManager(final SSLContext sslContext, final int poolSize) { + final SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier()); + final Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslFactory) + .build(); + final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + connectionManager.setMaxTotal(poolSize); + return connectionManager; + } + + protected String selectEventMesh() { + // todo: target endpoint maybe destroy, should remove the bad endpoint + if (eventMeshHttpClientConfig.isUseTls()) { + return Constants.HTTPS_PROTOCOL_PREFIX + eventMeshServerSelector.select(); + } else { + return Constants.HTTP_PROTOCOL_PREFIX + eventMeshServerSelector.select(); + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractProducerHttpClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractProducerHttpClient.java new file mode 100644 index 0000000000..55b5bc91db --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/AbstractProducerHttpClient.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.client.http.producer.EventMeshProtocolProducer; +import org.apache.eventmesh.client.http.producer.RRCallback; +import org.apache.eventmesh.client.http.producer.RRCallbackResponseHandlerAdapter; +import org.apache.eventmesh.client.http.util.HttpUtils; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.io.IOException; +import java.util.Objects; + +/** + * AbstractProducerHttpClient + * + * @param + */ +public abstract class AbstractProducerHttpClient extends AbstractHttpClient implements EventMeshProtocolProducer { + + public AbstractProducerHttpClient(final EventMeshHttpClientConfig eventMeshHttpClientConfig) + throws EventMeshException { + super(eventMeshHttpClientConfig); + } + + @Override + public void publish(final T t) throws EventMeshException { + validateMessage(t); + final String target = selectEventMesh(); + try { + final String response = HttpUtils.post(httpClient, target, builderPublishRequestParam(t)); + final EventMeshRetObj ret = JsonUtils.parseObject(response, EventMeshRetObj.class); + if (Objects.requireNonNull(ret).getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { + throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); + } + } catch (Exception exception) { + throw new EventMeshException(String.format("Publish message error, target:%s", target), exception); + } + } + + @Override + public T request(final T message, final long timeout) throws EventMeshException { + validateMessage(message); + final String target = selectEventMesh(); + try { + final String response = HttpUtils.post(httpClient, target, builderRequestParam(message, timeout)); + final EventMeshRetObj ret = JsonUtils.parseObject(response, EventMeshRetObj.class); + if (Objects.requireNonNull(ret).getRetCode() == EventMeshRetCode.SUCCESS.getRetCode()) { + return transformMessage(ret); + } + throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); + } catch (Exception e) { + throw new EventMeshException(String.format("Request message error, target:%s", target), e); + } + } + + @Override + public void request(final T message, final RRCallback rrCallback, final long timeout) throws EventMeshException { + validateMessage(message); + final String target = selectEventMesh(); + final RRCallbackResponseHandlerAdapter adapter = new RRCallbackResponseHandlerAdapter<>( + message, rrCallback, timeout); + try { + HttpUtils.post(httpClient, null, target, builderRequestParam(message, timeout), adapter); + } catch (IOException e) { + throw new EventMeshException(String.format("Request message error, target:%s", target), e); + } + + } + + public abstract RequestParam builderPublishRequestParam(T t); + + public abstract RequestParam builderRequestParam(T t, long timeout); + + public abstract void validateMessage(T t); + + public abstract T transformMessage(EventMeshRetObj retObj); +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/EventMeshRetObj.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/EventMeshRetObj.java similarity index 100% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/EventMeshRetObj.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/EventMeshRetObj.java diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ProtocolConstant.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ProtocolConstant.java similarity index 94% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ProtocolConstant.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ProtocolConstant.java index 0c1c18417f..1ea894a183 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ProtocolConstant.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ProtocolConstant.java @@ -18,7 +18,7 @@ package org.apache.eventmesh.client.http; public final class ProtocolConstant { - public static final String CE_PROTOCOL = "cloudevents"; + public static final String EM_MESSAGE_PROTOCOL = "eventmeshmessage"; public static final String OP_MESSAGE_PROTOCOL = "openmessage"; public static final String PROTOCOL_DESC = "http"; diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/EventMeshHttpClientConfig.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/EventMeshHttpClientConfig.java new file mode 100644 index 0000000000..7c427a3002 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/conf/EventMeshHttpClientConfig.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.conf; + +import org.apache.eventmesh.common.loadbalance.LoadBalanceType; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class EventMeshHttpClientConfig { + + /** + * The event server address list + *

+ * If it's a cluster, please use ; to split, and the address format is related to loadBalanceType. + *

+ * E.g. + *

If you use Random strategy, the format like: 127.0.0.1:10105;127.0.0.2:10105 + *

If you use weighted round robin or weighted random strategy, the format like: 127.0.0.1:10105:1;127.0.0.2:10105:2 + */ + @Builder.Default + private transient String liteEventMeshAddr = "localhost:10105"; + + @Builder.Default + private transient LoadBalanceType loadBalanceType = LoadBalanceType.RANDOM; + + @Builder.Default + private transient int consumeThreadCore = 2; + + @Builder.Default + private transient int consumeThreadMax = 5; + + @Builder.Default + private transient String env = ""; + + @Builder.Default + private transient String consumerGroup = "DefaultConsumerGroup"; + + @Builder.Default + private transient String producerGroup = "DefaultProducerGroup"; + + @Builder.Default + private transient String idc = ""; + + @Builder.Default + private transient String ip = "localhost"; + + @Builder.Default + private transient String pid = ""; + + @Builder.Default + private transient String sys = ""; + + @Builder.Default + private transient String userName = ""; + + @Builder.Default + private transient String password = ""; + + @Builder.Default + private transient boolean useTls = false; + + @Builder.Default + private transient String sslClientProtocol = "TLSv1.2"; + + @Builder.Default + private transient int maxConnectionPoolSize = 30; + + @Builder.Default + private transient int connectionIdleTimeSeconds = 10; + +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/EventMeshHttpConsumer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/EventMeshHttpConsumer.java new file mode 100644 index 0000000000..6e9b94bec7 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/consumer/EventMeshHttpConsumer.java @@ -0,0 +1,195 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.consumer; + +import org.apache.eventmesh.client.http.AbstractHttpClient; +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.client.http.util.HttpUtils; +import org.apache.eventmesh.client.tcp.common.EventMeshCommon; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.http.body.client.HeartbeatRequestBody; +import org.apache.eventmesh.common.protocol.http.body.client.SubscribeRequestBody; +import org.apache.eventmesh.common.protocol.http.body.client.UnSubscribeRequestBody; +import org.apache.eventmesh.common.protocol.http.common.ClientType; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import io.netty.handler.codec.http.HttpMethod; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshHttpConsumer extends AbstractHttpClient implements AutoCloseable { + + private final transient ThreadPoolExecutor consumeExecutor; + + private static final List SUBSCRIPTIONS = Collections.synchronizedList(new ArrayList<>()); + + private final transient ScheduledThreadPoolExecutor scheduler; + + public EventMeshHttpConsumer(final EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { + this(eventMeshHttpClientConfig, null); + } + + public EventMeshHttpConsumer(final EventMeshHttpClientConfig eventMeshHttpClientConfig, + final ThreadPoolExecutor customExecutor) throws EventMeshException { + super(eventMeshHttpClientConfig); + this.consumeExecutor = Optional.ofNullable(customExecutor).orElseGet( + () -> ThreadPoolFactory.createThreadPoolExecutor(eventMeshHttpClientConfig.getConsumeThreadCore(), + eventMeshHttpClientConfig.getConsumeThreadMax(), "EventMesh-client-consume")); + this.scheduler = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), + new EventMeshThreadFactory("HTTPClientScheduler", true)); + } + + /** + * When receive message will callback the url. + * + * @param topicList topic that be subscribed + * @param subscribeUrl url will be trigger + * @throws EventMeshException if subscribe failed + */ + public void subscribe(final List topicList, final String subscribeUrl) throws EventMeshException { + Objects.requireNonNull(topicList, "Subscribe item cannot be null"); + Objects.requireNonNull(subscribeUrl, "SubscribeUrl cannot be null"); + + final RequestParam subscribeParam = buildCommonRequestParam() + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.SUBSCRIBE.getRequestCode()) + .addBody(SubscribeRequestBody.TOPIC, JsonUtils.toJSONString(topicList)) + .addBody(SubscribeRequestBody.CONSUMERGROUP, eventMeshHttpClientConfig.getConsumerGroup()) + .addBody(SubscribeRequestBody.URL, subscribeUrl); + + final String target = selectEventMesh(); + try { + final String subRes = HttpUtils.post(httpClient, target, subscribeParam); + final EventMeshRetObj ret = JsonUtils.parseObject(subRes, EventMeshRetObj.class); + if (Objects.requireNonNull(ret).getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { + throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); + } + SUBSCRIPTIONS.addAll(topicList); + } catch (Exception ex) { + throw new EventMeshException(String.format("Subscribe topic error, target:%s", target), ex); + } + } + + // todo: remove http heartBeat? + public void heartBeat(final List topicList, final String subscribeUrl) { + Objects.requireNonNull(topicList, "Subscribe item cannot be null"); + Objects.requireNonNull(subscribeUrl, "SubscribeUrl cannot be null"); + + scheduler.scheduleAtFixedRate(() -> { + try { + final List heartbeatEntities = topicList.stream().map(subscriptionItem -> { + final HeartbeatRequestBody.HeartbeatEntity heartbeatEntity = new HeartbeatRequestBody.HeartbeatEntity(); + heartbeatEntity.setTopic(subscriptionItem.getTopic()); + heartbeatEntity.setUrl(subscribeUrl); + return heartbeatEntity; + }).collect(Collectors.toList()); + + final RequestParam requestParam = buildCommonRequestParam() + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.HEARTBEAT.getRequestCode()) + .addBody(HeartbeatRequestBody.CLIENTTYPE, ClientType.SUB.name()) + .addBody(HeartbeatRequestBody.HEARTBEATENTITIES, JsonUtils.toJSONString(heartbeatEntities)); + final String target = selectEventMesh(); + final String res = HttpUtils.post(httpClient, target, requestParam); + final EventMeshRetObj ret = JsonUtils.parseObject(res, EventMeshRetObj.class); + if (EventMeshRetCode.SUCCESS.getRetCode() != Objects.requireNonNull(ret).getRetCode()) { + throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); + } + } catch (Exception e) { + log.error("send heartBeat error", e); + } + }, EventMeshCommon.HEARTBEAT, EventMeshCommon.HEARTBEAT, TimeUnit.MILLISECONDS); + } + + /** + * @param topicList subscribe topic + * @param unSubscribeUrl subscribeUrl + * @throws EventMeshException if unsubscribe failed + */ + public void unsubscribe(final List topicList, final String unSubscribeUrl) throws EventMeshException { + Objects.requireNonNull(topicList, "Topics cannot be null"); + Objects.requireNonNull(unSubscribeUrl, "unSubscribeUrl cannot be null"); + + final RequestParam unSubscribeParam = buildCommonRequestParam() + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.UNSUBSCRIBE.getRequestCode()) + .addBody(UnSubscribeRequestBody.TOPIC, JsonUtils.toJSONString(topicList)) + .addBody(UnSubscribeRequestBody.URL, unSubscribeUrl); + + final String target = selectEventMesh(); + try { + final String unSubRes = HttpUtils.post(httpClient, target, unSubscribeParam); + final EventMeshRetObj ret = JsonUtils.parseObject(unSubRes, EventMeshRetObj.class); + + if (EventMeshRetCode.SUCCESS.getRetCode() != Objects.requireNonNull(ret).getRetCode()) { + throw new EventMeshException(ret.getRetCode(), ret.getRetMsg()); + } + // todo: avoid concurrentModifiedException + SUBSCRIPTIONS.removeIf(item -> topicList.contains(item.getTopic())); + } catch (Exception e) { + throw new EventMeshException(String.format("Unsubscribe topic error, target:%s", target), e); + } + } + + @Override + public void close() throws EventMeshException { + log.info("LiteConsumer shutdown begin."); + super.close(); + + if (consumeExecutor != null) { + consumeExecutor.shutdown(); + } + scheduler.shutdown(); + + log.info("LiteConsumer shutdown end."); + } + + private RequestParam buildCommonRequestParam() { + return new RequestParam(HttpMethod.POST) + .addHeader(ProtocolKey.ClientInstanceKey.ENV.getKey(), eventMeshHttpClientConfig.getEnv()) + .addHeader(ProtocolKey.ClientInstanceKey.IDC.getKey(), eventMeshHttpClientConfig.getIdc()) + .addHeader(ProtocolKey.ClientInstanceKey.IP.getKey(), eventMeshHttpClientConfig.getIp()) + .addHeader(ProtocolKey.ClientInstanceKey.PID.getKey(), eventMeshHttpClientConfig.getPid()) + .addHeader(ProtocolKey.ClientInstanceKey.SYS.getKey(), eventMeshHttpClientConfig.getSys()) + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), eventMeshHttpClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), eventMeshHttpClientConfig.getPassword()) + // add protocol version? + .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .setTimeout(Constants.DEFAULT_HTTP_TIME_OUT) + .addBody(HeartbeatRequestBody.CONSUMERGROUP, eventMeshHttpClientConfig.getConsumerGroup()); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/model/RequestParam.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/model/RequestParam.java new file mode 100644 index 0000000000..d74927bbfb --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/model/RequestParam.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.model; + +import org.apache.eventmesh.common.Constants; + +import org.apache.commons.collections4.MapUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import io.netty.handler.codec.http.HttpMethod; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public class RequestParam { + + private Map queryParams; + + private final HttpMethod httpMethod; + + private Map body; + + private Map headers; + + private long timeout = Constants.DEFAULT_HTTP_TIME_OUT; + + public RequestParam(final HttpMethod httpMethod) { + this.httpMethod = httpMethod; + } + + public HttpMethod getHttpMethod() { + return httpMethod; + } + + public Map getHeaders() { + return headers; + } + + public RequestParam setHeaders(final Map headers) { + this.headers = headers; + return this; + } + + public Map getBody() { + return body; + } + + public RequestParam setBody(final Map body) { + this.body = body; + return this; + } + + public Map getQueryParamsMap() { + return queryParams; + } + + public String getQueryParams() { + if (MapUtils.isEmpty(queryParams)) { + return ""; + } + final StringBuilder stringBuilder = new StringBuilder(); + try { + for (final Map.Entry query : queryParams.entrySet()) { + for (final String val : query.getValue()) { + stringBuilder.append(Constants.AND) + .append(URLEncoder.encode(query.getKey(), StandardCharsets.UTF_8.name())); + + if (val != null && !val.isEmpty()) { + stringBuilder.append("=") + .append(URLEncoder.encode(val, StandardCharsets.UTF_8.name())); + } + } + } + } catch (UnsupportedEncodingException e) { + log.error("get query params failed.", e); + return ""; + } + return stringBuilder.substring(1); + } + + public RequestParam setQueryParams(final Map queryParams) { + this.queryParams = queryParams; + return this; + } + + public RequestParam addQueryParam(final String key, final String value) { + if (queryParams == null) { + queryParams = new HashMap<>(); + } + if (!queryParams.containsKey(key)) { + queryParams.put(key, new String[]{value}); + } else { + queryParams.put(key, (String[]) Arrays.asList(queryParams.get(key), value).toArray()); + } + return this; + } + + public RequestParam addHeader(final String key, final Object value) { + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(key, value.toString()); + return this; + } + + public RequestParam addBody(final String key, final String value) { + if (body == null) { + body = new HashMap<>(); + } + body.put(key, value); + return this; + } + + public long getTimeout() { + return timeout; + } + + public RequestParam setTimeout(final long timeout) { + this.timeout = timeout; + return this; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/CloudEventProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/CloudEventProducer.java new file mode 100644 index 0000000000..27ab2896a8 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/CloudEventProducer.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.producer; + +import org.apache.eventmesh.client.http.AbstractProducerHttpClient; +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.client.http.ProtocolConstant; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.provider.EventFormatProvider; +import io.netty.handler.codec.http.HttpMethod; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class CloudEventProducer extends AbstractProducerHttpClient { + + public CloudEventProducer(final EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { + super(eventMeshHttpClientConfig); + } + + @Override + public RequestParam builderPublishRequestParam(final CloudEvent cloudEvent) { + final CloudEvent enhanceCloudEvent = enhanceCloudEvent(cloudEvent); + return buildCommonPostParam(enhanceCloudEvent) + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_ASYNC.getRequestCode()); + } + + @Override + public RequestParam builderRequestParam(final CloudEvent cloudEvent, long timeout) { + final CloudEvent enhanceCloudEvent = enhanceCloudEvent(cloudEvent); + return buildCommonPostParam(enhanceCloudEvent) + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) + .setTimeout(timeout); + } + + @Override + public void validateMessage(final CloudEvent cloudEvent) { + Preconditions.checkNotNull(cloudEvent, "CloudEvent cannot be null"); + } + + private void validateCloudEvent(final CloudEvent cloudEvent) { + Preconditions.checkNotNull(cloudEvent, "CloudEvent cannot be null"); + } + + private RequestParam buildCommonPostParam(final CloudEvent cloudEvent) { + validateCloudEvent(cloudEvent); + final byte[] bodyByte = Objects.requireNonNull(EventFormatProvider.getInstance().resolveFormat(cloudEvent.getDataContentType())) + .serialize(cloudEvent); + final String content = new String(bodyByte, StandardCharsets.UTF_8); + + final RequestParam requestParam = new RequestParam(HttpMethod.POST); + requestParam + .addHeader(ProtocolKey.ClientInstanceKey.ENV.getKey(), eventMeshHttpClientConfig.getEnv()) + .addHeader(ProtocolKey.ClientInstanceKey.IDC.getKey(), eventMeshHttpClientConfig.getIdc()) + .addHeader(ProtocolKey.ClientInstanceKey.IP.getKey(), eventMeshHttpClientConfig.getIp()) + .addHeader(ProtocolKey.ClientInstanceKey.PID.getKey(), eventMeshHttpClientConfig.getPid()) + .addHeader(ProtocolKey.ClientInstanceKey.SYS.getKey(), eventMeshHttpClientConfig.getSys()) + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), eventMeshHttpClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), eventMeshHttpClientConfig.getPassword()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .addHeader(ProtocolKey.PROTOCOL_TYPE, Constants.CLOUD_EVENTS_PROTOCOL_NAME) + .addHeader(ProtocolKey.PROTOCOL_DESC, ProtocolConstant.PROTOCOL_DESC) + .addHeader(ProtocolKey.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()) + + // todo: move producerGroup tp header + .addBody(SendMessageRequestBody.PRODUCERGROUP, eventMeshHttpClientConfig.getProducerGroup()) + .addBody(SendMessageRequestBody.CONTENT, content); + return requestParam; + } + + private CloudEvent enhanceCloudEvent(final CloudEvent cloudEvent) { + return CloudEventBuilder.from(cloudEvent) + .withExtension(ProtocolKey.ClientInstanceKey.ENV.getKey(), eventMeshHttpClientConfig.getEnv()) + .withExtension(ProtocolKey.ClientInstanceKey.IDC.getKey(), eventMeshHttpClientConfig.getIdc()) + .withExtension(ProtocolKey.ClientInstanceKey.IP.getKey(), eventMeshHttpClientConfig.getIp()) + .withExtension(ProtocolKey.ClientInstanceKey.PID.getKey(), eventMeshHttpClientConfig.getPid()) + .withExtension(ProtocolKey.ClientInstanceKey.SYS.getKey(), eventMeshHttpClientConfig.getSys()) + .withExtension(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .withExtension(ProtocolKey.PROTOCOL_DESC, cloudEvent.getSpecVersion().name()) + .withExtension(ProtocolKey.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()) + .withExtension(ProtocolKey.ClientInstanceKey.BIZSEQNO.getKey(), RandomStringUtils.generateNum(30)) + .withExtension(ProtocolKey.ClientInstanceKey.UNIQUEID.getKey(), RandomStringUtils.generateNum(30)) + .build(); + } + + @Override + public CloudEvent transformMessage(final EventMeshRetObj retObj) { + final SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.parseObject(retObj.getRetMsg(), + SendMessageResponseBody.ReplyMessage.class); + // todo: deserialize message + return null; + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshHttpProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshHttpProducer.java similarity index 90% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshHttpProducer.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshHttpProducer.java index a7e0a43637..7121078a25 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshHttpProducer.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshHttpProducer.java @@ -64,26 +64,25 @@ public Message request(final Message openMessage, final long timeout) throws Eve } public void request(final EventMeshMessage message, final RRCallback rrCallback, final long timeout) - throws EventMeshException { + throws EventMeshException { eventMeshMessageProducer.request(message, rrCallback, timeout); } public void request(final CloudEvent cloudEvent, final RRCallback rrCallback, final long timeout) - throws EventMeshException { + throws EventMeshException { cloudEventProducer.request(cloudEvent, rrCallback, timeout); } public void request(final Message openMessage, final RRCallback rrCallback, final long timeout) - throws EventMeshException { + throws EventMeshException { openMessageProducer.request(openMessage, rrCallback, timeout); } @Override public void close() throws EventMeshException { - try ( - final EventMeshMessageProducer ignored = eventMeshMessageProducer; - final OpenMessageProducer ignored1 = openMessageProducer; - final CloudEventProducer ignored2 = cloudEventProducer) { + try (final EventMeshMessageProducer ignored = eventMeshMessageProducer; + final OpenMessageProducer ignored1 = openMessageProducer; + final CloudEventProducer ignored2 = cloudEventProducer) { log.info("Close producer"); } } diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshMessageProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshMessageProducer.java new file mode 100644 index 0000000000..f0f471c39e --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshMessageProducer.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.producer; + +import org.apache.eventmesh.client.http.AbstractProducerHttpClient; +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.client.http.ProtocolConstant; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.ProtocolVersion; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.util.Objects; + +import io.cloudevents.SpecVersion; +import io.netty.handler.codec.http.HttpMethod; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class EventMeshMessageProducer extends AbstractProducerHttpClient { + + public EventMeshMessageProducer(final EventMeshHttpClientConfig eventMeshHttpClientConfig) throws EventMeshException { + super(eventMeshHttpClientConfig); + } + + @Override + public RequestParam builderPublishRequestParam(final EventMeshMessage message) { + return buildCommonPostParam(message) + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_ASYNC.getRequestCode()); + } + + @Override + public RequestParam builderRequestParam(final EventMeshMessage message, final long timeout) { + return buildCommonPostParam(message) + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) + .setTimeout(timeout); + } + + @Override + public void validateMessage(final EventMeshMessage message) { + Objects.requireNonNull(message, "eventMeshMessage invalid"); + Objects.requireNonNull(message.getTopic(), "eventMeshMessage[topic] invalid"); + Objects.requireNonNull(message.getContent(), "eventMeshMessage[content] invalid"); + + } + + private RequestParam buildCommonPostParam(final EventMeshMessage message) { + final RequestParam requestParam = new RequestParam(HttpMethod.POST); + requestParam + .addHeader(ProtocolKey.ClientInstanceKey.ENV.getKey(), eventMeshHttpClientConfig.getEnv()) + .addHeader(ProtocolKey.ClientInstanceKey.IDC.getKey(), eventMeshHttpClientConfig.getIdc()) + .addHeader(ProtocolKey.ClientInstanceKey.IP.getKey(), eventMeshHttpClientConfig.getIp()) + .addHeader(ProtocolKey.ClientInstanceKey.PID.getKey(), eventMeshHttpClientConfig.getPid()) + .addHeader(ProtocolKey.ClientInstanceKey.SYS.getKey(), eventMeshHttpClientConfig.getSys()) + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), eventMeshHttpClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), eventMeshHttpClientConfig.getPassword()) + .addHeader(ProtocolKey.VERSION, ProtocolVersion.V1.getVersion()) + .addHeader(ProtocolKey.PROTOCOL_TYPE, ProtocolConstant.EM_MESSAGE_PROTOCOL) + .addHeader(ProtocolKey.PROTOCOL_DESC, ProtocolConstant.PROTOCOL_DESC) + // default ce version is 1.0 + .addHeader(ProtocolKey.PROTOCOL_VERSION, SpecVersion.V1.toString()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .addBody(SendMessageRequestBody.PRODUCERGROUP, eventMeshHttpClientConfig.getProducerGroup()) + // todo: set message to content is better + .addBody(SendMessageRequestBody.TOPIC, message.getTopic()) + .addBody(SendMessageRequestBody.CONTENT, message.getContent()) + .addBody(SendMessageRequestBody.TTL, message.getProp(Constants.EVENTMESH_MESSAGE_CONST_TTL)) + .addBody(SendMessageRequestBody.BIZSEQNO, message.getBizSeqNo()) + .addBody(SendMessageRequestBody.UNIQUEID, message.getUniqueId()); + return requestParam; + } + + @Override + public EventMeshMessage transformMessage(final EventMeshRetObj retObj) { + final SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.parseObject(retObj.getRetMsg(), + SendMessageResponseBody.ReplyMessage.class); + return EventMeshMessage.builder() + .content(Objects.requireNonNull(replyMessage, "ReplyMessage must not be null").body) + .prop(replyMessage.properties) + .topic(replyMessage.topic).build(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshProtocolProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshProtocolProducer.java similarity index 97% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshProtocolProducer.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshProtocolProducer.java index b3ad6a7956..1a0001e2cd 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshProtocolProducer.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/EventMeshProtocolProducer.java @@ -34,6 +34,6 @@ public interface EventMeshProtocolProducer extends AutoCloseabl ProtocolMessage request(ProtocolMessage message, long timeout) throws EventMeshException; void request(ProtocolMessage message, RRCallback rrCallback, long timeout) - throws EventMeshException; + throws EventMeshException; } diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/OpenMessageProducer.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/OpenMessageProducer.java new file mode 100644 index 0000000000..877fb3476a --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/OpenMessageProducer.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.producer; + +import org.apache.eventmesh.client.http.AbstractProducerHttpClient; +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.client.http.ProtocolConstant; +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageRequestBody; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import org.apache.eventmesh.common.protocol.http.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.http.common.RequestCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.util.Objects; + +import io.netty.handler.codec.http.HttpMethod; +import io.openmessaging.api.Message; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class OpenMessageProducer extends AbstractProducerHttpClient { + + public OpenMessageProducer(final EventMeshHttpClientConfig eventMeshHttpClientConfig) + throws EventMeshException { + super(eventMeshHttpClientConfig); + } + + @Override + public RequestParam builderPublishRequestParam(final Message openMessage) { + return buildCommonPostParam(openMessage) + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_ASYNC.getRequestCode()); + } + + @Override + public RequestParam builderRequestParam(final Message message, final long timeout) { + return buildCommonPostParam(message) + .addHeader(ProtocolKey.REQUEST_CODE, RequestCode.MSG_SEND_SYNC.getRequestCode()) + .setTimeout(timeout); + } + + @Override + public void validateMessage(final Message message) { + Objects.requireNonNull(message, "Message cannot be null"); + } + + private RequestParam buildCommonPostParam(final Message openMessage) { + final RequestParam requestParam = new RequestParam(HttpMethod.POST); + requestParam + .addHeader(ProtocolKey.ClientInstanceKey.USERNAME.getKey(), eventMeshHttpClientConfig.getUserName()) + .addHeader(ProtocolKey.ClientInstanceKey.PASSWD.getKey(), eventMeshHttpClientConfig.getPassword()) + .addHeader(ProtocolKey.LANGUAGE, Constants.LANGUAGE_JAVA) + .addHeader(ProtocolKey.PROTOCOL_TYPE, ProtocolConstant.OP_MESSAGE_PROTOCOL) + .addHeader(ProtocolKey.PROTOCOL_DESC, ProtocolConstant.PROTOCOL_DESC) + // todo: add producerGroup to header, set protocol type, protocol version + .addBody(SendMessageRequestBody.PRODUCERGROUP, eventMeshHttpClientConfig.getProducerGroup()) + .addBody(SendMessageRequestBody.CONTENT, JsonUtils.toJSONString(openMessage)); + return requestParam; + } + + @Override + public Message transformMessage(final EventMeshRetObj retObj) { + final SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.parseObject(retObj.getRetMsg(), + SendMessageResponseBody.ReplyMessage.class); + // todo: deserialize message + return null; + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallback.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallback.java similarity index 100% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallback.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallback.java diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java new file mode 100644 index 0000000000..c07567adfe --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/producer/RRCallbackResponseHandlerAdapter.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.producer; + +import org.apache.eventmesh.client.http.EventMeshRetObj; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.http.body.message.SendMessageResponseBody; +import org.apache.eventmesh.common.protocol.http.common.EventMeshRetCode; +import org.apache.eventmesh.common.utils.JsonUtils; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.Objects; + +import io.cloudevents.CloudEvent; +import io.openmessaging.api.Message; + +/** + * RRCallbackResponseHandlerAdapter. + */ +public class RRCallbackResponseHandlerAdapter implements ResponseHandler { + + private final transient long createTime; + + private final transient ProtocolMessage protocolMessage; + + private final transient RRCallback rrCallback; + + private final transient long timeout; + + public RRCallbackResponseHandlerAdapter(final ProtocolMessage protocolMessage, final RRCallback rrCallback, + final long timeout) { + Objects.requireNonNull(rrCallback, "rrCallback invalid"); + Objects.requireNonNull(protocolMessage, "message invalid"); + + if (!(protocolMessage instanceof EventMeshMessage) + && !(protocolMessage instanceof CloudEvent) + && !(protocolMessage instanceof Message)) { + throw new IllegalArgumentException(String.format("ProtocolMessage: %s is not supported", protocolMessage)); + } + this.protocolMessage = protocolMessage; + this.rrCallback = rrCallback; + this.timeout = timeout; + this.createTime = System.currentTimeMillis(); + } + + @Override + public String handleResponse(final HttpResponse response) throws IOException { + Objects.requireNonNull(response, "HttpResponse must not be null"); + + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + rrCallback.onException(new EventMeshException(response.toString())); + return response.toString(); + } + + if (System.currentTimeMillis() - createTime > timeout) { + final String err = String.format("response too late, message: %s", protocolMessage); + rrCallback.onException(new EventMeshException(err)); + return err; + } + + final String res = EntityUtils.toString(response.getEntity(), Constants.DEFAULT_CHARSET); + final EventMeshRetObj ret = JsonUtils.parseObject(res, EventMeshRetObj.class); + Objects.requireNonNull(ret, "EventMeshRetObj must not be null"); + if (ret.getRetCode() != EventMeshRetCode.SUCCESS.getRetCode()) { + rrCallback.onException(new EventMeshException(ret.getRetCode(), ret.getRetMsg())); + return res; + } + + // todo: constructor protocol message + final ProtocolMessage protocolMessage = transformToProtocolMessage(ret); + rrCallback.onSuccess(protocolMessage); + + return protocolMessage.toString(); + } + + @SuppressWarnings("unchecked") + private ProtocolMessage transformToProtocolMessage(final EventMeshRetObj ret) { + Objects.requireNonNull(ret, "EventMeshRetObj must not be null"); + + final SendMessageResponseBody.ReplyMessage replyMessage = JsonUtils.parseObject(ret.getRetMsg(), + SendMessageResponseBody.ReplyMessage.class); + Objects.requireNonNull(replyMessage, "ReplyMessage must not be null"); + if (protocolMessage instanceof EventMeshMessage) { + final EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .content(replyMessage.body) + .prop(replyMessage.properties) + .topic(replyMessage.topic) + .build(); + + return (ProtocolMessage) eventMeshMessage; + } + // todo: constructor other protocol message + throw new RuntimeException("Unsupported callback message type"); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ssl/MyX509TrustManager.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ssl/MyX509TrustManager.java new file mode 100644 index 0000000000..0b01ae75df --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/ssl/MyX509TrustManager.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.ssl; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +public class MyX509TrustManager implements X509TrustManager { + + private transient X509TrustManager myTrustManager; + + public MyX509TrustManager() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { + final KeyStore keyStore = KeyStore.getInstance("JKS"); + final String fileName = System.getProperty("ssl.client.cer", ""); + final String pass = System.getProperty("ssl.client.pass", ""); + final char[] filePass = StringUtils.isNotBlank(pass) ? pass.toCharArray() : new char[0]; + + try (InputStream in = Files.newInputStream( + Paths.get(System.getProperty("confPath", System.getenv("confPath")) + + File.separator + fileName), + StandardOpenOption.READ)) { + keyStore.load(in, filePass); + } + + final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + for (final TrustManager trustManager : trustManagers) { + if (trustManager instanceof X509TrustManager) { + myTrustManager = (X509TrustManager) trustManager; + return; + } + } + + throw new KeyStoreException("Couldn't initialize"); + } + + @Override + public void checkClientTrusted(final X509Certificate[] x509Certificates, final String s) throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] certificates, final String authType) throws CertificateException { + if (certificates != null && certificates.length == 1) { + certificates[0].checkValidity(); + } else { + myTrustManager.checkServerTrusted(certificates, authType); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return myTrustManager.getAcceptedIssuers(); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtils.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtils.java new file mode 100644 index 0000000000..bad7183766 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtils.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.util; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.loadbalance.LoadBalanceSelector; +import org.apache.eventmesh.common.loadbalance.RandomLoadBalanceSelector; +import org.apache.eventmesh.common.loadbalance.Weight; +import org.apache.eventmesh.common.loadbalance.WeightRandomLoadBalanceSelector; +import org.apache.eventmesh.common.loadbalance.WeightRoundRobinLoadBalanceSelector; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import com.google.common.base.Splitter; + +public class HttpLoadBalanceUtils { + + private static final Pattern IP_PORT_PATTERN = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5}"); + private static final Pattern IP_PORT_WEIGHT_PATTERN = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:\\d{4,5}:\\d{1,6}"); + + public static LoadBalanceSelector createEventMeshServerLoadBalanceSelector( + final EventMeshHttpClientConfig eventMeshHttpClientConfig) + throws EventMeshException { + LoadBalanceSelector eventMeshServerSelector = null; + switch (eventMeshHttpClientConfig.getLoadBalanceType()) { + case RANDOM: + eventMeshServerSelector = new RandomLoadBalanceSelector<>(buildClusterGroupFromConfig( + eventMeshHttpClientConfig)); + break; + case WEIGHT_RANDOM: + eventMeshServerSelector = new WeightRandomLoadBalanceSelector<>(buildWeightedClusterGroupFromConfig( + eventMeshHttpClientConfig)); + break; + case WEIGHT_ROUND_ROBIN: + eventMeshServerSelector = new WeightRoundRobinLoadBalanceSelector<>(buildWeightedClusterGroupFromConfig( + eventMeshHttpClientConfig)); + break; + default: + // ignore + } + if (eventMeshServerSelector == null) { + throw new EventMeshException("liteEventMeshAddr param illegal,please check"); + } + return eventMeshServerSelector; + } + + private static List> buildWeightedClusterGroupFromConfig( + final EventMeshHttpClientConfig eventMeshHttpClientConfig) + throws EventMeshException { + final List eventMeshAddrs = Splitter.on(";") + .trimResults() + .splitToList(eventMeshHttpClientConfig.getLiteEventMeshAddr()); + + if (CollectionUtils.isEmpty(eventMeshAddrs)) { + throw new EventMeshException("liteEventMeshAddr can not be empty"); + } + + final List> eventMeshAddrWeightList = new ArrayList<>(); + for (final String eventMeshAddrWight : eventMeshAddrs) { + if (!IP_PORT_WEIGHT_PATTERN.matcher(eventMeshAddrWight).matches()) { + throw new EventMeshException( + String.format("liteEventMeshAddr:%s is not illegal", eventMeshHttpClientConfig.getLiteEventMeshAddr())); + } + final int splitIndex = eventMeshAddrWight.lastIndexOf(":"); + final Weight weight = new Weight<>( + eventMeshAddrWight.substring(0, splitIndex), + Integer.parseInt(eventMeshAddrWight.substring(splitIndex + 1))); + eventMeshAddrWeightList.add(weight); + } + return eventMeshAddrWeightList; + } + + private static List buildClusterGroupFromConfig(final EventMeshHttpClientConfig eventMeshHttpClientConfig) + throws EventMeshException { + final List eventMeshAddrs = Splitter.on(";") + .trimResults() + .splitToList(eventMeshHttpClientConfig.getLiteEventMeshAddr()); + + if (CollectionUtils.isEmpty(eventMeshAddrs)) { + throw new EventMeshException("liteEventMeshAddr can not be empty"); + } + + final List eventMeshAddrList = new ArrayList<>(); + for (final String eventMeshAddr : eventMeshAddrs) { + if (!IP_PORT_PATTERN.matcher(eventMeshAddr).matches()) { + throw new EventMeshException( + String.format("liteEventMeshAddr:%s is not illegal", eventMeshHttpClientConfig.getLiteEventMeshAddr())); + } + eventMeshAddrList.add(eventMeshAddr); + } + return eventMeshAddrList; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpUtils.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpUtils.java new file mode 100644 index 0000000000..93a9313999 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/http/util/HttpUtils.java @@ -0,0 +1,192 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.util; + +import org.apache.eventmesh.client.http.model.RequestParam; +import org.apache.eventmesh.common.Constants; + +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import io.netty.handler.codec.http.HttpMethod; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public final class HttpUtils { + + public static String post(final CloseableHttpClient client, + final String uri, + final RequestParam requestParam) throws IOException { + + return post(client, null, uri, requestParam); + } + + public static String post(final CloseableHttpClient client, + final HttpHost forwardAgent, + final String uri, + final RequestParam requestParam) throws IOException { + + return post(client, forwardAgent, uri, requestParam, new EventMeshResponseHandler()); + + } + + public static String post(final CloseableHttpClient client, + final HttpHost forwardAgent, + final String uri, + final RequestParam requestParam, + final ResponseHandler responseHandler) throws IOException { + + Preconditions.checkState(client != null, "client can't be null"); + Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); + Preconditions.checkState(requestParam != null, "requestParam can't be null"); + Preconditions.checkState(responseHandler != null, "responseHandler can't be null"); + Preconditions.checkState(requestParam.getHttpMethod().equals(HttpMethod.POST), "invalid requestParam httpMethod"); + + final HttpPost httpPost = new HttpPost(uri); + + // header + if (MapUtils.isNotEmpty(requestParam.getHeaders())) { + for (final Map.Entry entry : requestParam.getHeaders().entrySet()) { + httpPost.addHeader(entry.getKey(), entry.getValue()); + } + } + + // body + if (MapUtils.isNotEmpty(requestParam.getBody())) { + final List pairs = new ArrayList<>(); + for (final Map.Entry entry : requestParam.getBody().entrySet()) { + pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + httpPost.setEntity(new UrlEncodedFormEntity(pairs, Constants.DEFAULT_CHARSET)); + } + + // ttl + final RequestConfig.Builder configBuilder = RequestConfig.custom(); + configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) + .setConnectTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) + .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))); + + if (forwardAgent != null) { + configBuilder.setProxy(forwardAgent); + } + + httpPost.setConfig(configBuilder.build()); + + log.debug("{}", httpPost); + + return client.execute(httpPost, responseHandler); + } + + public static String get(final CloseableHttpClient client, + final String url, + final RequestParam requestParam) throws IOException { + + return get(client, null, url, requestParam, new EventMeshResponseHandler()); + } + + public static String get(final CloseableHttpClient client, + final HttpHost forwardAgent, + final String url, + final RequestParam requestParam) throws IOException { + + return get(client, forwardAgent, url, requestParam, new EventMeshResponseHandler()); + } + + public static String get(final CloseableHttpClient client, + final HttpHost forwardAgent, + final String uri, + final RequestParam requestParam, + final ResponseHandler responseHandler) throws IOException { + + Preconditions.checkState(client != null, "client can't be null"); + Preconditions.checkState(StringUtils.isNotBlank(uri), "uri can't be null"); + Preconditions.checkState(requestParam != null, "requestParam can't be null"); + Preconditions.checkState(requestParam.getHttpMethod().equals(HttpMethod.GET), "invalid requestParam httpMethod"); + + final HttpGet httpGet = new HttpGet(MapUtils.isNotEmpty(requestParam.getQueryParamsMap()) ? uri + "?" + requestParam.getQueryParams() : uri); + + // header + if (MapUtils.isNotEmpty(requestParam.getHeaders())) { + for (final Map.Entry entry : requestParam.getHeaders().entrySet()) { + httpGet.addHeader(entry.getKey(), entry.getValue()); + } + } + + // ttl + final RequestConfig.Builder configBuilder = RequestConfig.custom(); + configBuilder.setSocketTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) + .setConnectTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))) + .setConnectionRequestTimeout(Integer.parseInt(String.valueOf(requestParam.getTimeout()))); + + if (forwardAgent != null) { + configBuilder.setProxy(forwardAgent); + } + + httpGet.setConfig(configBuilder.build()); + + log.debug("{}", httpGet); + + return client.execute(httpGet, responseHandler); + } + + private static class EventMeshResponseHandler implements ResponseHandler { + + /** + * Processes an {@link HttpResponse} and returns some value corresponding to that response. + * + * @param response The response to process + * @return A value determined by the response + * @throws ClientProtocolException in case of an http protocol error + * @throws IOException in case of a problem or the connection was aborted + */ + @Override + public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + + int statusCode = response.getStatusLine().getStatusCode(); + // Successful responses (200-299) + if (statusCode >= 200 && statusCode < 300) { + HttpEntity entity = response.getEntity(); + return entity != null ? EntityUtils.toString(entity, Constants.DEFAULT_CHARSET) : null; + } else { + throw new ClientProtocolException("Unexpected response statusCode: " + statusCode); + } + } + } + +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/Selector.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/Selector.java new file mode 100644 index 0000000000..e6268667d8 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/Selector.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.selector; + +/** + * Selector is the abstract of selecting registry service instances + */ +public interface Selector { + + ServiceInstance selectOne(String serverName) throws SelectorException; +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/SelectorException.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/SelectorException.java new file mode 100644 index 0000000000..f5c61aed48 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/SelectorException.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.selector; + +public class SelectorException extends RuntimeException { + + private static final long serialVersionUID = 7126682512429265292L; + + public SelectorException(final String message) { + super(message); + } + + public SelectorException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/SelectorFactory.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/SelectorFactory.java new file mode 100644 index 0000000000..cc23ee608e --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/SelectorFactory.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.selector; + +import java.util.HashMap; +import java.util.Map; + +public class SelectorFactory { + + private static final Map SELECTOR_MAP = new HashMap<>(); + + public static Selector get(final String type) { + return SELECTOR_MAP.get(type); + } + + public static void register(final String type, final Selector selector) { + if (selector == null) { + return; + } + SELECTOR_MAP.put(type, selector); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/ServiceInstance.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/ServiceInstance.java new file mode 100644 index 0000000000..16265dd468 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/selector/ServiceInstance.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.selector; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import lombok.Data; + +@Data +public class ServiceInstance implements Serializable { + + private static final long serialVersionUID = -4622423079578878337L; + + private String host; + private int port; + private boolean isHealthy; + private Map metadata; + + public ServiceInstance() { + this.host = null; + this.port = 0; + this.isHealthy = true; + this.metadata = new HashMap<>(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClient.java similarity index 91% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClient.java index 60c27afc0e..e44fe946b1 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClient.java @@ -25,8 +25,7 @@ import org.apache.eventmesh.common.protocol.tcp.Package; /** - * EventMesh TCP client, used to sub/pub message by tcp. - * You can use {@link EventMeshTCPClientFactory} to create a target client. + * EventMesh TCP client, used to sub/pub message by tcp. You can use {@link EventMeshTCPClientFactory} to create a target client. * * @param protocol message type * @since 1.3.0 @@ -46,7 +45,7 @@ public interface EventMeshTCPClient extends AutoCloseable { void listen() throws EventMeshException; void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException; + throws EventMeshException; void unsubscribe() throws EventMeshException; @@ -54,8 +53,6 @@ void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType void registerSubBusiHandler(ReceiveMsgHook handler) throws EventMeshException; - void close() throws EventMeshException; - EventMeshTCPPubClient getPubClient(); EventMeshTCPSubClient getSubClient(); diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClientFactory.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClientFactory.java similarity index 92% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClientFactory.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClientFactory.java index 69fd2e0a61..cf411ac878 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClientFactory.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPClientFactory.java @@ -43,7 +43,7 @@ public class EventMeshTCPClientFactory { */ @SuppressWarnings("unchecked") public static EventMeshTCPClient createEventMeshTCPClient( - EventMeshTCPClientConfig eventMeshTcpClientConfig, Class protocolMessageClass) { + EventMeshTCPClientConfig eventMeshTcpClientConfig, Class protocolMessageClass) { Preconditions.checkNotNull(protocolMessageClass, "ProtocolMessage type cannot be null"); Preconditions.checkNotNull(eventMeshTcpClientConfig, "EventMeshTcpClientConfig cannot be null"); @@ -57,6 +57,6 @@ public static EventMeshTCPClient createEventM return (EventMeshTCPClient) new OpenMessageTCPClient(eventMeshTcpClientConfig); } throw new IllegalArgumentException( - String.format("ProtocolMessageClass: %s is not supported", protocolMessageClass)); + String.format("ProtocolMessageClass: %s is not supported", protocolMessageClass)); } } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPPubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPPubClient.java similarity index 97% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPPubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPPubClient.java index eafe95ec7a..5f08ae2bc9 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPPubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPPubClient.java @@ -49,5 +49,4 @@ public interface EventMeshTCPPubClient extends AutoCloseable { void registerBusiHandler(ReceiveMsgHook handler) throws EventMeshException; - void close() throws EventMeshException; } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPSubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPSubClient.java similarity index 95% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPSubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPSubClient.java index 8b1ec7b372..0097b5ba31 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPSubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/EventMeshTCPSubClient.java @@ -39,7 +39,7 @@ public interface EventMeshTCPSubClient extends AutoCloseable { void reconnect() throws EventMeshException; void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException; + throws EventMeshException; void unsubscribe() throws EventMeshException; @@ -47,5 +47,4 @@ void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType void registerBusiHandler(ReceiveMsgHook handler) throws EventMeshException; - void close() throws EventMeshException; } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java similarity index 99% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java index 949c0efa50..d435f6751e 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/AsyncRRCallback.java @@ -21,5 +21,6 @@ * AsyncRRCallback */ public interface AsyncRRCallback { + void callback(Package msg); } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java similarity index 93% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java index 606b24cfe4..902a135221 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/EventMeshCommon.java @@ -39,8 +39,6 @@ public class EventMeshCommon { */ public static final String USER_AGENT_PURPOSE_SUB = "sub"; - // protocol type - public static final String CLOUD_EVENTS_PROTOCOL_NAME = "cloudevents"; public static final String EM_MESSAGE_PROTOCOL_NAME = "eventmeshmessage"; public static final String OPEN_MESSAGE_PROTOCOL_NAME = "openmessage"; } diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java new file mode 100644 index 0000000000..a12436e330 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/MessageUtils.java @@ -0,0 +1,181 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.tcp.common; + +import static org.apache.eventmesh.common.Constants.CLOUD_EVENTS_PROTOCOL_NAME; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.Subscription; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +import org.assertj.core.util.Preconditions; + +import io.cloudevents.CloudEvent; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.provider.EventFormatProvider; +import io.openmessaging.api.Message; + +public class MessageUtils { + + private static final int SEQ_LENGTH = 10; + + public static Package hello(UserAgent user) { + final Package msg = getPackage(Command.HELLO_REQUEST); + msg.setBody(user); + return msg; + } + + public static Package heartBeat() { + return getPackage(Command.HEARTBEAT_REQUEST); + } + + public static Package goodbye() { + return getPackage(Command.CLIENT_GOODBYE_REQUEST); + } + + public static Package listen() { + return getPackage(Command.LISTEN_REQUEST); + } + + public static Package subscribe(String topic, SubscriptionMode subscriptionMode, + SubscriptionType subscriptionType) { + Package msg = getPackage(Command.SUBSCRIBE_REQUEST); + msg.setBody(generateSubscription(topic, subscriptionMode, subscriptionType)); + return msg; + } + + public static Package unsubscribe() { + return getPackage(Command.UNSUBSCRIBE_REQUEST); + } + + public static Package asyncMessageAck(Package in) { + return getPackage(Command.ASYNC_MESSAGE_TO_CLIENT_ACK, in); + } + + public static Package buildPackage(Object message, Command command) { + final Package msg = getPackage(command); + if (message instanceof CloudEvent) { + final CloudEvent cloudEvent = (CloudEvent) message; + Preconditions.checkNotNull(Objects.requireNonNull(cloudEvent.getDataContentType()), "DateContentType cannot be null"); + msg.getHeader().putProperty(Constants.PROTOCOL_TYPE, CLOUD_EVENTS_PROTOCOL_NAME); + msg.getHeader().putProperty(Constants.PROTOCOL_VERSION, cloudEvent.getSpecVersion().toString()); + msg.getHeader().putProperty(Constants.PROTOCOL_DESC, "tcp"); + + final byte[] bodyByte = Objects.requireNonNull(EventFormatProvider.getInstance().resolveFormat(cloudEvent.getDataContentType())) + .serialize((CloudEvent) message); + msg.setBody(bodyByte); + } else if (message instanceof EventMeshMessage) { + msg.getHeader().putProperty(Constants.PROTOCOL_TYPE, EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME); + msg.getHeader().putProperty(Constants.PROTOCOL_VERSION, SpecVersion.V1.toString()); + msg.getHeader().putProperty(Constants.PROTOCOL_DESC, "tcp"); + msg.setBody(message); + } else if (message instanceof Message) { + msg.getHeader().putProperty(Constants.PROTOCOL_TYPE, EventMeshCommon.OPEN_MESSAGE_PROTOCOL_NAME); + // todo: this version need to be confirmed. + msg.getHeader().putProperty(Constants.PROTOCOL_VERSION, SpecVersion.V1.toString()); + } else { + // unsupported protocol for server + throw new IllegalArgumentException("Unsupported message protocol"); + } + + return msg; + } + + public static Package broadcastMessageAck(Package in) { + return getPackage(Command.BROADCAST_MESSAGE_TO_CLIENT_ACK, in); + } + + public static Package requestToClientAck(Package in) { + return getPackage(Command.REQUEST_TO_CLIENT_ACK, in); + } + + public static Package responseToClientAck(Package in) { + return getPackage(Command.RESPONSE_TO_CLIENT_ACK, in); + } + + public static UserAgent generateSubClient(UserAgent agent) { + return getUserAgent(agent, EventMeshCommon.USER_AGENT_PURPOSE_SUB); + } + + public static UserAgent generatePubClient(UserAgent agent) { + return getUserAgent(agent, EventMeshCommon.USER_AGENT_PURPOSE_PUB); + } + + private static Subscription generateSubscription(String topic, SubscriptionMode subscriptionMode, + SubscriptionType subscriptionType) { + final Subscription subscription = new Subscription(); + final List subscriptionItems = new ArrayList<>(); + subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); + subscription.setTopicList(subscriptionItems); + return subscription; + } + + private static String generateRandomString() { + final StringBuilder builder = new StringBuilder(MessageUtils.SEQ_LENGTH); + IntStream.range(0, MessageUtils.SEQ_LENGTH).forEach(i -> builder.append((char) ThreadLocalRandom.current().nextInt(48, 57))); + + return builder.toString(); + } + + private static Package getPackage(Command command) { + final Package msg = new Package(); + msg.setHeader(new Header(command, 0, null, generateRandomString())); + return msg; + } + + private static Package getPackage(Command command, String seq, Object body) { + final Package msg = new Package(); + msg.setHeader(new Header(command, 0, null, seq)); + msg.setBody(body); + return msg; + } + + private static Package getPackage(Command command, Package in) { + return getPackage(command, in.getHeader().getSeq(), in.getBody()); + } + + private static UserAgent getUserAgent(UserAgent agent, String purpose) { + return UserAgent.builder() + .env(agent.getEnv()) + .host(agent.getHost()) + .password(agent.getPassword()) + .username(agent.getUsername()) + .path(agent.getPath()) + .port(agent.getPort()) + .subsystem(agent.getSubsystem()) + .pid(agent.getPid()) + .version(agent.getVersion()) + .idc(agent.getIdc()) + .group(agent.getGroup()) + .purpose(purpose) + .build(); + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java similarity index 100% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/ReceiveMsgHook.java diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java new file mode 100644 index 0000000000..0508d03821 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/RequestContext.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.tcp.common; + +import org.apache.eventmesh.common.protocol.tcp.Package; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RequestContext { + + private Object key; + private Package request; + private final CompletableFuture future = new CompletableFuture<>(); + + public RequestContext(final Object key, final Package request) { + this.key = key; + this.request = request; + } + + public Object getKey() { + return key; + } + + public void setKey(final Object key) { + this.key = key; + } + + public Package getRequest() { + return request; + } + + public void setRequest(final Package request) { + this.request = request; + } + + public CompletableFuture future() { + return this.future; + } + + public Package getResponse(long timeout, TimeUnit timeUnit) throws ExecutionException, InterruptedException, TimeoutException { + return this.future.get(timeout, timeUnit); + } + + public Package getResponse(long timeout) throws ExecutionException, InterruptedException, TimeoutException { + return this.future.get(timeout, TimeUnit.MILLISECONDS); + } + + public void finish(final Package msg) { + this.future.complete(msg); + } + + public static RequestContext context(final Object key, final Package request) throws Exception { + final RequestContext context = new RequestContext(key, request); + log.info("_RequestContext|create|key={}", key); + return context; + } + + public static Object key(final Package request) { + return request.getHeader().getSeq(); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java new file mode 100644 index 0000000000..0bcea69076 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/common/TcpClient.java @@ -0,0 +1,221 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.tcp.common; + +import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; +import org.apache.eventmesh.common.protocol.tcp.codec.Codec; + +import java.io.Closeable; +import java.net.InetSocketAddress; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Supplier; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.AdaptiveRecvByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class TcpClient implements Closeable { + + protected static int CLIENTNO = 0; + + static { + try { + CLIENTNO = SecureRandom.getInstanceStrong().nextInt(1000); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to generate a random number!", e); + } + } + + protected final transient ConcurrentHashMap contexts = new ConcurrentHashMap<>(); + + protected final transient String host; + protected final transient int port; + protected final transient UserAgent userAgent; + + private final transient Bootstrap bootstrap = new Bootstrap(); + + private final transient EventLoopGroup workers = new NioEventLoopGroup(); + + private transient Channel channel; + + private transient ScheduledFuture heartTask; + + protected static final ScheduledExecutorService scheduler = ThreadPoolFactory.createScheduledExecutor(Runtime.getRuntime().availableProcessors(), + new EventMeshThreadFactory("TCPClientScheduler", true)); + + public TcpClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { + Preconditions.checkNotNull(eventMeshTcpClientConfig, "EventMeshTcpClientConfig cannot be null"); + Preconditions.checkNotNull(eventMeshTcpClientConfig.getHost(), "Host cannot be null"); + Preconditions.checkState(eventMeshTcpClientConfig.getPort() > 0, "port is not validated"); + this.host = eventMeshTcpClientConfig.getHost(); + this.port = eventMeshTcpClientConfig.getPort(); + this.userAgent = eventMeshTcpClientConfig.getUserAgent(); + } + + protected synchronized void open(SimpleChannelInboundHandler handler) throws Exception { + bootstrap.group(workers); + bootstrap.channel(NioSocketChannel.class); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1_000) + .option(ChannelOption.SO_KEEPALIVE, true) + .option(ChannelOption.SO_SNDBUF, 64 * 1024) + .option(ChannelOption.SO_RCVBUF, 64 * 1024) + .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1024, 8192, 65536)) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); + bootstrap.handler(new ChannelInitializer() { + + @Override + public void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new Codec.Encoder(), new Codec.Decoder()) + .addLast(handler, newExceptionHandler()); + } + }); + + ChannelFuture f = bootstrap.connect(host, port).sync(); + InetSocketAddress localAddress = (InetSocketAddress) f.channel().localAddress(); + channel = f.channel(); + log.info("connected|local={}:{}|server={}", localAddress.getAddress().getHostAddress(), localAddress.getPort(), host + ":" + port); + } + + @Override + public void close() { + try { + + goodbye(); + + channel.disconnect().sync(); + workers.shutdownGracefully().sync(); + if (heartTask != null) { + heartTask.cancel(false); + } + + } catch (Exception e) { + Thread.currentThread().interrupt(); + log.warn("close tcp client failed.|remote address={}", channel.remoteAddress(), e); + } + } + + protected void heartbeat() { + if (heartTask == null) { + synchronized (TcpClient.class) { + heartTask = scheduler.scheduleAtFixedRate(() -> { + try { + if (!isActive()) { + reconnect(); + } + Package msg = MessageUtils.heartBeat(); + io(msg, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + log.debug("heart beat start {}", msg); + } catch (Exception e) { + // ignore + } + }, EventMeshCommon.HEARTBEAT, EventMeshCommon.HEARTBEAT, TimeUnit.MILLISECONDS); + } + } + } + + protected synchronized void reconnect() throws Exception { + ChannelFuture f = bootstrap.connect(host, port).sync(); + channel = f.channel(); + } + + protected boolean isActive() { + return (channel != null) && (channel.isActive()); + } + + protected void send(Package msg) throws Exception { + if (channel.isWritable()) { + channel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> { + if (!future.isSuccess()) { + log.warn("send msg failed", future.cause()); + } + }); + } else { + channel.writeAndFlush(msg).sync(); + } + } + + protected Package io(Package msg, long timeout) throws Exception { + Object key = RequestContext.key(msg); + RequestContext context = RequestContext.context(key, msg); + RequestContext previousContext = contexts.putIfAbsent(key, context); + if (previousContext != null) { + log.info("duplicate key : {}", key); + } + send(msg); + Supplier supplier = () -> { + try { + return context.getResponse(timeout); + } catch (ExecutionException | InterruptedException | TimeoutException exception) { + throw new RuntimeException(exception); + } + }; + return CompletableFuture.supplyAsync(supplier).get(); + } + + // todo: remove hello + protected void hello() throws Exception { + Package msg = MessageUtils.hello(userAgent); + this.io(msg, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + } + + // todo: remove goodbye + protected void goodbye() throws Exception { + Package msg = MessageUtils.goodbye(); + this.io(msg, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + } + + private ChannelDuplexHandler newExceptionHandler() { + return new ChannelDuplexHandler() { + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + log.info("exceptionCaught, close connection.|remote address={}", ctx.channel().remoteAddress(), cause); + ctx.close(); + } + }; + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java similarity index 99% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java index e47daa9245..4ef990d1dd 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/conf/EventMeshTCPClientConfig.java @@ -25,6 +25,7 @@ @Data @Builder public class EventMeshTCPClientConfig { + private String host; private int port; private UserAgent userAgent; diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPPubHandler.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPPubHandler.java similarity index 99% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPPubHandler.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPPubHandler.java index b83865991a..880dd12cd2 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPPubHandler.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPPubHandler.java @@ -52,7 +52,7 @@ protected void channelRead0(ChannelHandlerContext ctx, Package msg) { sendResponse(MessageUtils.responseToClientAck(msg)); break; case SERVER_GOODBYE_REQUEST: - //TODO + // TODO break; default: break; diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPSubHandler.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPSubHandler.java similarity index 96% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPSubHandler.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPSubHandler.java index 4669244b9f..0c9a69547a 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPSubHandler.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/AbstractEventMeshTCPSubHandler.java @@ -63,14 +63,14 @@ protected void channelRead0(ChannelHandlerContext ctx, Package msg) throws Excep // TODO break; default: - log.error("msg ignored|{}|{}", cmd, msg); + log.warn("msg ignored|{}|{}", cmd, msg); } RequestContext context = contexts.get(RequestContext.key(msg)); if (context != null) { contexts.remove(context.getKey()); context.finish(msg); } else { - log.error("msg ignored,context not found.|{}|{}", cmd, msg); + log.warn("msg ignored,context not found.|{}|{}", cmd, msg); } } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java similarity index 93% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java index d81cd84f89..dce45bf24c 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPClient.java @@ -74,7 +74,7 @@ public void listen() throws EventMeshException { @Override public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { + throws EventMeshException { cloudEventTCPSubClient.subscribe(topic, subscriptionMode, subscriptionType); } @@ -95,10 +95,8 @@ public void registerSubBusiHandler(ReceiveMsgHook handler) throws Ev @Override public void close() throws EventMeshException { - try (final EventMeshTCPPubClient pubClient = cloudEventTCPPubClient; - final EventMeshTCPSubClient subClient = cloudEventTCPSubClient) { - // close client - } + this.cloudEventTCPPubClient.close(); + this.cloudEventTCPSubClient.close(); } @Override diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java similarity index 91% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java index 9be280f563..35f2186b34 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPPubClient.java @@ -37,6 +37,7 @@ import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.jackson.JsonFormat; +import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import com.google.common.base.Preconditions; @@ -82,7 +83,7 @@ public void reconnect() throws EventMeshException { public Package rr(CloudEvent event, long timeout) throws EventMeshException { try { Package msg = MessageUtils.buildPackage(event, Command.REQUEST_TO_SERVER); - log.info("{}|rr|send|type={}|msg={}", clientNo, msg, msg); + log.info("{}|rr|send|type={}|msg={}", CLIENTNO, msg, msg); return io(msg, timeout); } catch (Exception ex) { throw new EventMeshException("rr error", ex); @@ -105,7 +106,7 @@ public Package publish(CloudEvent cloudEvent, long timeout) throws EventMeshExce try { Package msg = MessageUtils.buildPackage(cloudEvent, Command.ASYNC_MESSAGE_TO_SERVER); log.info("SimplePubClientImpl cloud event|{}|publish|send|type={}|protocol={}|msg={}", - clientNo, msg.getHeader().getCmd(), msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); + CLIENTNO, msg.getHeader().getCmd(), msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); return io(msg, timeout); } catch (Exception ex) { throw new EventMeshException("publish error", ex); @@ -116,8 +117,8 @@ public Package publish(CloudEvent cloudEvent, long timeout) throws EventMeshExce public void broadcast(CloudEvent cloudEvent, long timeout) throws EventMeshException { try { Package msg = MessageUtils.buildPackage(cloudEvent, Command.BROADCAST_MESSAGE_TO_SERVER); - log.info("{}|publish|send|type={}|protocol={}|msg={}", clientNo, msg.getHeader().getCmd(), - msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); + log.info("{}|publish|send|type={}|protocol={}|msg={}", CLIENTNO, msg.getHeader().getCmd(), + msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); super.send(msg); } catch (Exception ex) { throw new EventMeshException("Broadcast message error", ex); @@ -138,6 +139,7 @@ public void close() { } } + @Sharable private class CloudEventTCPPubHandler extends AbstractEventMeshTCPPubHandler { public CloudEventTCPPubHandler(ConcurrentHashMap contexts) { @@ -148,7 +150,7 @@ public CloudEventTCPPubHandler(ConcurrentHashMap context public void callback(CloudEvent cloudEvent, ChannelHandlerContext ctx) { if (callback != null) { callback.handle(cloudEvent) - .ifPresent(responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); + .ifPresent(responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); } } @@ -156,7 +158,7 @@ public void callback(CloudEvent cloudEvent, ChannelHandlerContext ctx) { public CloudEvent getMessage(Package tcpPackage) { EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); Preconditions.checkNotNull(eventFormat, - String.format("Cannot find the cloudevent format: %s", JsonFormat.CONTENT_TYPE)); + String.format("Cannot find the cloudevent format: %s", JsonFormat.CONTENT_TYPE)); return eventFormat.deserialize(tcpPackage.getBody().toString().getBytes(StandardCharsets.UTF_8)); } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java similarity index 86% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java index f6eee73e0f..585a58b878 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/cloudevent/CloudEventTCPSubClient.java @@ -35,8 +35,8 @@ import org.apache.commons.collections4.CollectionUtils; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -44,6 +44,7 @@ import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.jackson.JsonFormat; +import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import com.google.common.base.Preconditions; @@ -56,7 +57,7 @@ @Slf4j class CloudEventTCPSubClient extends TcpClient implements EventMeshTCPSubClient { - private final List subscriptionItems = Collections.synchronizedList(new LinkedList<>()); + private final List subscriptionItems = Collections.synchronizedList(new ArrayList<>()); private ReceiveMsgHook callback; public CloudEventTCPSubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { @@ -69,7 +70,7 @@ public void init() throws EventMeshException { open(new CloudEventTCPSubHandler(contexts)); hello(); heartbeat(); - log.info("SimpleSubClientImpl|{}|started!", clientNo); + log.info("SimpleSubClientImpl|{}|started!", CLIENTNO); } catch (Exception ex) { throw new EventMeshException("Initialize EventMeshMessageTcpSubClient error", ex); } @@ -81,9 +82,11 @@ public void reconnect() throws EventMeshException { super.reconnect(); hello(); if (!CollectionUtils.isEmpty(subscriptionItems)) { - for (SubscriptionItem item : subscriptionItems) { - Package request = MessageUtils.subscribe(item.getTopic(), item.getMode(), item.getType()); - this.io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + synchronized (subscriptionItems) { + for (SubscriptionItem item : subscriptionItems) { + Package request = MessageUtils.subscribe(item.getTopic(), item.getMode(), item.getType()); + this.io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + } } } listen(); @@ -94,7 +97,7 @@ public void reconnect() throws EventMeshException { @Override public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { + throws EventMeshException { try { subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); Package request = MessageUtils.subscribe(topic, subscriptionMode, subscriptionType); @@ -132,17 +135,17 @@ public void registerBusiHandler(ReceiveMsgHook handler) throws Event @Override public void close() { try { - goodbye(); super.close(); } catch (Exception ex) { - ex.printStackTrace(); + log.error("exception occurred when close", ex); } } + @Sharable private class CloudEventTCPSubHandler extends AbstractEventMeshTCPSubHandler { public CloudEventTCPSubHandler( - ConcurrentHashMap contexts) { + ConcurrentHashMap contexts) { super(contexts); } @@ -150,7 +153,7 @@ public CloudEventTCPSubHandler( public CloudEvent getProtocolMessage(Package tcpPackage) { EventFormat eventFormat = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); Preconditions.checkNotNull(eventFormat, - String.format("Cannot find the cloudevent format: %s", JsonFormat.CONTENT_TYPE)); + String.format("Cannot find the cloudevent format: %s", JsonFormat.CONTENT_TYPE)); return eventFormat.deserialize(tcpPackage.getBody().toString().getBytes(StandardCharsets.UTF_8)); } @@ -158,8 +161,7 @@ public CloudEvent getProtocolMessage(Package tcpPackage) { public void callback(CloudEvent cloudEvent, ChannelHandlerContext ctx) { if (callback != null) { callback.handle(cloudEvent).ifPresent( - responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER)) - ); + responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); } } diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java new file mode 100644 index 0000000000..1080926e21 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPClient.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.tcp.impl.eventmeshmessage; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import org.apache.eventmesh.client.tcp.EventMeshTCPClient; +import org.apache.eventmesh.client.tcp.EventMeshTCPPubClient; +import org.apache.eventmesh.client.tcp.EventMeshTCPSubClient; +import org.apache.eventmesh.client.tcp.common.AsyncRRCallback; +import org.apache.eventmesh.client.tcp.common.ReceiveMsgHook; +import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; +import org.apache.eventmesh.common.protocol.tcp.Package; + +import com.google.common.base.Preconditions; + +public class EventMeshMessageTCPClient implements EventMeshTCPClient { + + private final EventMeshTCPPubClient eventMeshMessageTCPPubClient; + private final EventMeshTCPSubClient eventMeshMessageTCPSubClient; + + public EventMeshMessageTCPClient(final EventMeshTCPClientConfig eventMeshTcpClientConfig) { + eventMeshMessageTCPPubClient = new EventMeshMessageTCPPubClient(eventMeshTcpClientConfig); + eventMeshMessageTCPSubClient = new EventMeshMessageTCPSubClient(eventMeshTcpClientConfig); + } + + @Override + public void init() throws EventMeshException { + eventMeshMessageTCPPubClient.init(); + eventMeshMessageTCPSubClient.init(); + } + + @Override + public Package rr(final EventMeshMessage eventMeshMessage, final long timeout) throws EventMeshException { + validateMessage(eventMeshMessage); + return eventMeshMessageTCPPubClient.rr(eventMeshMessage, timeout); + } + + @Override + public void asyncRR(final EventMeshMessage eventMeshMessage, final AsyncRRCallback callback, final long timeout) + throws EventMeshException { + validateMessage(eventMeshMessage); + eventMeshMessageTCPPubClient.asyncRR(eventMeshMessage, callback, timeout); + } + + @Override + public Package publish(final EventMeshMessage eventMeshMessage, final long timeout) throws EventMeshException { + validateMessage(eventMeshMessage); + return eventMeshMessageTCPPubClient.publish(eventMeshMessage, timeout); + } + + @Override + public void broadcast(final EventMeshMessage eventMeshMessage, final long timeout) throws EventMeshException { + validateMessage(eventMeshMessage); + eventMeshMessageTCPPubClient.broadcast(eventMeshMessage, timeout); + } + + @Override + public void listen() throws EventMeshException { + eventMeshMessageTCPSubClient.listen(); + } + + @Override + public void subscribe(final String topic, final SubscriptionMode subscriptionMode, + final SubscriptionType subscriptionType) + throws EventMeshException { + eventMeshMessageTCPSubClient.subscribe(topic, subscriptionMode, subscriptionType); + } + + @Override + public void unsubscribe() throws EventMeshException { + eventMeshMessageTCPSubClient.unsubscribe(); + } + + @Override + public void registerPubBusiHandler(final ReceiveMsgHook handler) throws EventMeshException { + eventMeshMessageTCPPubClient.registerBusiHandler(handler); + } + + @Override + public void registerSubBusiHandler(final ReceiveMsgHook handler) throws EventMeshException { + eventMeshMessageTCPSubClient.registerBusiHandler(handler); + } + + @Override + public void close() throws EventMeshException { + try { + this.eventMeshMessageTCPPubClient.close(); + } catch (Exception e) { + throw new EventMeshException(e); + } + + try { + this.eventMeshMessageTCPSubClient.close(); + } catch (Exception e) { + throw new EventMeshException(e); + } + } + + @Override + public EventMeshTCPPubClient getPubClient() { + return eventMeshMessageTCPPubClient; + } + + @Override + public EventMeshTCPSubClient getSubClient() { + return eventMeshMessageTCPSubClient; + } + + private void validateMessage(final EventMeshMessage message) { + Preconditions.checkNotNull(message, "Message cannot be null"); + Preconditions.checkArgument(isNotBlank(message.getTopic()), "Message's topic cannot be null and blank"); + Preconditions.checkArgument(isNotBlank(message.getBody()), "Message's body cannot be null and blank"); + } +} diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java similarity index 78% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java index 9d7b958a0f..3d6af79e55 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPPubClient.java @@ -44,9 +44,9 @@ @Slf4j class EventMeshMessageTCPPubClient extends TcpClient implements EventMeshTCPPubClient { - private ReceiveMsgHook callback; + private transient ReceiveMsgHook callback; - private final ConcurrentHashMap callbackConcurrentHashMap = new ConcurrentHashMap<>(); + private final transient ConcurrentHashMap callbackConcurrentHashMap = new ConcurrentHashMap<>(); public EventMeshMessageTCPPubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { super(eventMeshTcpClientConfig); @@ -58,8 +58,8 @@ public void init() throws EventMeshException { open(new EventMeshTCPPubHandler(contexts)); hello(); heartbeat(); - } catch (Exception ex) { - throw new EventMeshException("Initialize EventMeshMessageTCPPubClient error", ex); + } catch (Exception e) { + throw new EventMeshException("Initialize EventMeshMessageTCPPubClient error", e); } } @@ -69,8 +69,8 @@ public void reconnect() throws EventMeshException { try { super.reconnect(); hello(); - } catch (Exception ex) { - throw new EventMeshException("reconnect error", ex); + } catch (Exception e) { + throw new EventMeshException("reconnect error", e); } } @@ -79,23 +79,23 @@ public void reconnect() throws EventMeshException { public Package rr(EventMeshMessage eventMeshMessage, long timeout) throws EventMeshException { try { Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.REQUEST_TO_SERVER); - log.info("{}|rr|send|type={}|msg={}", clientNo, msg, msg); + log.info("{}|rr|send|type={}|msg={}", CLIENTNO, msg, msg); return io(msg, timeout); - } catch (Exception ex) { - throw new EventMeshException("rr error"); + } catch (Exception e) { + throw new EventMeshException("rr error", e); } } @Override public void asyncRR(EventMeshMessage eventMeshMessage, AsyncRRCallback callback, long timeout) - throws EventMeshException { + throws EventMeshException { try { Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.REQUEST_TO_SERVER); super.send(msg); this.callbackConcurrentHashMap.put((String) RequestContext.key(msg), callback); - } catch (Exception ex) { + } catch (Exception e) { // should trigger callback? - throw new EventMeshException("asyncRR error", ex); + throw new EventMeshException("asyncRR error", e); } } @@ -104,11 +104,11 @@ public Package publish(EventMeshMessage eventMeshMessage, long timeout) throws E try { Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.ASYNC_MESSAGE_TO_SERVER); log.info("SimplePubClientImpl em message|{}|publish|send|type={}|protocol={}|msg={}", - clientNo, msg.getHeader().getCmd(), - msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); + CLIENTNO, msg.getHeader().getCmd(), + msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); return io(msg, timeout); - } catch (Exception ex) { - throw new EventMeshException("publish error", ex); + } catch (Exception e) { + throw new EventMeshException("publish error", e); } } @@ -117,11 +117,11 @@ public void broadcast(EventMeshMessage eventMeshMessage, long timeout) throws Ev try { // todo: transform EventMeshMessage to Package Package msg = MessageUtils.buildPackage(eventMeshMessage, Command.BROADCAST_MESSAGE_TO_SERVER); - log.info("{}|publish|send|type={}|protocol={}|msg={}", clientNo, msg.getHeader().getCmd(), - msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); + log.info("{}|publish|send|type={}|protocol={}|msg={}", CLIENTNO, msg.getHeader().getCmd(), + msg.getHeader().getProperty(Constants.PROTOCOL_TYPE), msg); super.send(msg); - } catch (Exception ex) { - throw new EventMeshException("Broadcast message error", ex); + } catch (Exception e) { + throw new EventMeshException("Broadcast message error", e); } } @@ -149,22 +149,26 @@ public EventMeshTCPPubHandler(ConcurrentHashMap contexts public void callback(EventMeshMessage eventMeshMessage, ChannelHandlerContext ctx) { if (callback != null) { callback.handle(eventMeshMessage).ifPresent( - responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER)) - ); + responseMessage -> ctx.writeAndFlush( + MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); } } @Override public EventMeshMessage getMessage(Package tcpPackage) { - return JsonUtils.deserialize(tcpPackage.getBody().toString(), EventMeshMessage.class); + return JsonUtils.parseObject(tcpPackage.getBody().toString(), EventMeshMessage.class); } @Override public void sendResponse(Package tcpPackage) { try { send(tcpPackage); - } catch (Exception exception) { - throw new RuntimeException(exception); + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new RuntimeException(e); + } } } } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java similarity index 87% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java index 5ff5587b5d..7216597d7d 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/eventmeshmessage/EventMeshMessageTCPSubClient.java @@ -36,8 +36,8 @@ import org.apache.commons.collections4.CollectionUtils; +import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -48,7 +48,7 @@ @Slf4j class EventMeshMessageTCPSubClient extends TcpClient implements EventMeshTCPSubClient { - private final List subscriptionItems = Collections.synchronizedList(new LinkedList<>()); + private final List subscriptionItems = Collections.synchronizedList(new ArrayList<>()); private ReceiveMsgHook callback; public EventMeshMessageTCPSubClient(EventMeshTCPClientConfig eventMeshTcpClientConfig) { @@ -61,7 +61,7 @@ public void init() throws EventMeshException { open(new EventMeshMessageTCPSubHandler(contexts)); hello(); heartbeat(); - log.info("SimpleSubClientImpl|{}|started!", clientNo); + log.info("SimpleSubClientImpl|{}|started!", CLIENTNO); } catch (Exception ex) { throw new EventMeshException("Initialize EventMeshMessageTcpSubClient error", ex); } @@ -73,9 +73,11 @@ public void reconnect() throws EventMeshException { super.reconnect(); hello(); if (!CollectionUtils.isEmpty(subscriptionItems)) { - for (SubscriptionItem item : subscriptionItems) { - Package request = MessageUtils.subscribe(item.getTopic(), item.getMode(), item.getType()); - this.io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + synchronized (subscriptionItems) { + for (SubscriptionItem item : subscriptionItems) { + Package request = MessageUtils.subscribe(item.getTopic(), item.getMode(), item.getType()); + this.io(request, EventMeshCommon.DEFAULT_TIME_OUT_MILLS); + } } } listen(); @@ -86,7 +88,7 @@ public void reconnect() throws EventMeshException { @Override public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { + throws EventMeshException { try { subscriptionItems.add(new SubscriptionItem(topic, subscriptionMode, subscriptionType)); Package request = MessageUtils.subscribe(topic, subscriptionMode, subscriptionType); @@ -115,7 +117,6 @@ public void listen() throws EventMeshException { } } - @Override public void registerBusiHandler(ReceiveMsgHook receiveMsgHook) throws EventMeshException { this.callback = receiveMsgHook; @@ -126,26 +127,26 @@ public void close() { try { super.close(); } catch (Exception ex) { - ex.printStackTrace(); + log.error("exception occurred when close.", ex); } } private class EventMeshMessageTCPSubHandler extends AbstractEventMeshTCPSubHandler { + public EventMeshMessageTCPSubHandler(ConcurrentHashMap contexts) { super(contexts); } @Override public EventMeshMessage getProtocolMessage(Package tcpPackage) { - return JsonUtils.deserialize(tcpPackage.getBody().toString(), EventMeshMessage.class); + return JsonUtils.parseObject(tcpPackage.getBody().toString(), EventMeshMessage.class); } @Override public void callback(EventMeshMessage eventMeshMessage, ChannelHandlerContext ctx) { if (callback != null) { callback.handle(eventMeshMessage).ifPresent( - responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER)) - ); + responseMessage -> ctx.writeAndFlush(MessageUtils.buildPackage(responseMessage, Command.RESPONSE_TO_SERVER))); } } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPClient.java similarity index 92% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPClient.java index 353ce8f632..22008e1298 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPClient.java @@ -76,7 +76,7 @@ public void listen() throws EventMeshException { @Override public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { + throws EventMeshException { eventMeshTCPSubClient.subscribe(topic, subscriptionMode, subscriptionType); } @@ -97,9 +97,16 @@ public void registerSubBusiHandler(ReceiveMsgHook handler) throws Event @Override public void close() throws EventMeshException { - try (final EventMeshTCPPubClient pubClient = eventMeshTCPPubClient; - final EventMeshTCPSubClient subClient = eventMeshTCPSubClient) { - log.info("Close OpenMessageTCPClient"); + try { + this.eventMeshTCPPubClient.close(); + } catch (Exception e) { + throw new EventMeshException(e); + } + + try { + this.eventMeshTCPSubClient.close(); + } catch (Exception e) { + throw new EventMeshException(e); } } diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPPubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPPubClient.java similarity index 100% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPPubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPPubClient.java diff --git a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPSubClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPSubClient.java similarity index 98% rename from eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPSubClient.java rename to eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPSubClient.java index cf0322a0e1..cc271abf2c 100644 --- a/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPSubClient.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/tcp/impl/openmessage/OpenMessageTCPSubClient.java @@ -49,7 +49,7 @@ public void reconnect() throws EventMeshException { @Override public void subscribe(String topic, SubscriptionMode subscriptionMode, SubscriptionType subscriptionType) - throws EventMeshException { + throws EventMeshException { } diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/workflow/EventMeshWorkflowClient.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/workflow/EventMeshWorkflowClient.java new file mode 100644 index 0000000000..9a8e1fd8bc --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/workflow/EventMeshWorkflowClient.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.workflow; + +import org.apache.eventmesh.client.selector.Selector; +import org.apache.eventmesh.client.selector.SelectorFactory; +import org.apache.eventmesh.client.selector.ServiceInstance; +import org.apache.eventmesh.client.workflow.config.EventMeshWorkflowClientConfig; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteRequest; +import org.apache.eventmesh.common.protocol.workflow.protos.ExecuteResponse; +import org.apache.eventmesh.common.protocol.workflow.protos.WorkflowGrpc; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EventMeshWorkflowClient { + + private final transient EventMeshWorkflowClientConfig clientConfig; + + public EventMeshWorkflowClient(final EventMeshWorkflowClientConfig clientConfig) { + this.clientConfig = clientConfig; + } + + public WorkflowGrpc.WorkflowBlockingStub getWorkflowClient() throws Exception { + final Selector selector = SelectorFactory.get(clientConfig.getSelectorType()); + if (selector == null) { + throw new Exception(String.format("selector=%s not register.please check it.", + clientConfig.getSelectorType())); + } + final ServiceInstance instance = selector.selectOne(clientConfig.getServerName()); + if (instance == null) { + throw new Exception("workflow server is not running.please check it."); + } + final ManagedChannel channel = ManagedChannelBuilder.forAddress(instance.getHost(), + instance.getPort()).usePlaintext().build(); + return WorkflowGrpc.newBlockingStub(channel); + } + + public ExecuteResponse execute(final ExecuteRequest request) throws Exception { + final WorkflowGrpc.WorkflowBlockingStub workflowClient = getWorkflowClient(); + final ExecuteResponse response = workflowClient.execute(request); + log.info("received response:{}", response); + return response; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/workflow/config/EventMeshWorkflowClientConfig.java b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/workflow/config/EventMeshWorkflowClientConfig.java new file mode 100644 index 0000000000..0206319f65 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/main/java/org/apache/eventmesh/client/workflow/config/EventMeshWorkflowClientConfig.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.workflow.config; + +import lombok.Builder; +import lombok.Data; +import lombok.ToString; + +@Data +@Builder +@ToString +public class EventMeshWorkflowClientConfig { + + @Builder.Default + private String serverName = "eventmesh-workflow"; + + @Builder.Default + private String selectorType = "nacos"; +} diff --git a/eventmesh-sdk-java/src/main/resources/log4j2.xml b/eventmesh-sdks/eventmesh-sdk-java/src/main/resources/log4j2.xml similarity index 100% rename from eventmesh-sdk-java/src/main/resources/log4j2.xml rename to eventmesh-sdks/eventmesh-sdk-java/src/main/resources/log4j2.xml diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumerTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumerTest.java new file mode 100644 index 0000000000..508d841663 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/consumer/EventMeshGrpcConsumerTest.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.consumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.Builder; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc.ConsumerServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.ConsumerServiceGrpc.ConsumerServiceStub; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.HeartbeatServiceGrpc.HeartbeatServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.protocol.grpc.common.Response; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +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 org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +import io.cloudevents.core.v1.CloudEventV1; +import io.grpc.stub.StreamObserver; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class EventMeshGrpcConsumerTest { + + @Mock + private ConsumerServiceBlockingStub consumerClient; + @Mock + private ConsumerServiceStub consumerAsyncClient; + @Mock + private HeartbeatServiceBlockingStub heartbeatClient; + private EventMeshGrpcConsumer eventMeshGrpcConsumer; + + @BeforeEach + public void setUp() { + eventMeshGrpcConsumer = new EventMeshGrpcConsumer(EventMeshGrpcClientConfig.builder().build()); + eventMeshGrpcConsumer.init(); + eventMeshGrpcConsumer.setConsumerClient(consumerClient); + eventMeshGrpcConsumer.setConsumerAsyncClient(consumerAsyncClient); + eventMeshGrpcConsumer.setHeartbeatClient(heartbeatClient); + when(consumerClient.subscribe(any())).thenReturn(CloudEvent.getDefaultInstance()); + when(consumerClient.unsubscribe(any())).thenReturn(CloudEvent.getDefaultInstance()); + when(heartbeatClient.heartbeat(any())).thenReturn(CloudEvent.getDefaultInstance()); + when(consumerAsyncClient.subscribeStream(any())).thenAnswer(invocation -> { + StreamObserver receiver = invocation.getArgument(0); + return new StreamObserver() { + + @Override + public void onNext(CloudEvent value) { + Builder builder = CloudEvent.newBuilder(value) + .putAttributes(ProtocolKey.UNIQUE_ID, CloudEventAttributeValue.newBuilder().setCeString("1").build()) + .putAttributes(ProtocolKey.SEQ_NUM, CloudEventAttributeValue.newBuilder().setCeString("1").build()) + .setTextData("mockContent"); + receiver.onNext(builder.build()); + receiver.onCompleted(); + } + + @Override + public void onError(Throwable t) { + receiver.onError(t); + } + + @Override + public void onCompleted() { + } + }; + }); + } + + @Test + public void testSubscribeWithUrl() { + assertThat(eventMeshGrpcConsumer.subscribe(Collections.singletonList(buildMockSubscriptionItem()), "customUrl")).isEqualTo( + Response.builder().build()); + verify(consumerClient, times(1)).subscribe(any()); + verify(heartbeatClient, Mockito.after(20_000L).times(1)).heartbeat(any()); + assertThat(eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(buildMockSubscriptionItem()), "customUrl")).isEqualTo( + Response.builder().build()); + verify(consumerClient, times(1)).unsubscribe(any()); + } + + @Test + public void testSubscribeStreamWithoutListener() { + eventMeshGrpcConsumer.subscribe(Collections.singletonList(buildMockSubscriptionItem())); + verifyNoMoreInteractions(consumerAsyncClient); + } + + @Test + public void testSubscribeStream() { + List result = new ArrayList<>(); + eventMeshGrpcConsumer.registerListener(new ReceiveMsgHook() { + + @Override + public Optional handle(Object msg) { + result.add(msg); + return Optional.empty(); + } + + @Override + public EventMeshProtocolType getProtocolType() { + return EventMeshProtocolType.CLOUD_EVENTS; + } + }); + eventMeshGrpcConsumer.subscribe(Collections.singletonList(buildMockSubscriptionItem())); + assertThat(eventMeshGrpcConsumer.getSubscriptionMap()).hasSize(1); + + assertThat(result).hasSize(1).first().isInstanceOf(CloudEventV1.class); + CloudEventV1 v1 = (CloudEventV1) result.get(0); + Assertions.assertEquals(new String(v1.getData().toBytes(), Constants.DEFAULT_CHARSET), "mockContent"); + verify(consumerAsyncClient, times(1)).subscribeStream(any()); + assertThat(eventMeshGrpcConsumer.unsubscribe(Collections.singletonList(buildMockSubscriptionItem()))).isEqualTo( + Response.builder().build()); + verify(consumerClient, times(1)).unsubscribe(any()); + } + + private SubscriptionItem buildMockSubscriptionItem() { + SubscriptionItem subscriptionItem = new SubscriptionItem(); + subscriptionItem.setType(SubscriptionType.SYNC); + subscriptionItem.setMode(SubscriptionMode.CLUSTERING); + subscriptionItem.setTopic("topic"); + return subscriptionItem; + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducerTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducerTest.java new file mode 100644 index 0000000000..dcfecbff52 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/CloudEventProducerTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc.PublisherServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.Response; + +import java.util.Collections; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class CloudEventProducerTest { + + private CloudEventProducer cloudEventProducer; + @Mock + private PublisherServiceBlockingStub blockingStub; + + @Mock + private CloudEvent mockCloudEvent; + + @BeforeEach + public void setUp() throws Exception { + cloudEventProducer = new CloudEventProducer(EventMeshGrpcClientConfig.builder().build(), blockingStub); + when(blockingStub.batchPublish(Mockito.isA(CloudEventBatch.class))).thenReturn(mockCloudEvent); + when(blockingStub.publish(Mockito.isA(CloudEvent.class))).thenReturn(mockCloudEvent); + } + + @Test + public void testPublishMultiWithEmpty() { + assertThat(cloudEventProducer.publish(Collections.emptyList())).isNull(); + } + + @Test + public void testPublishMulti() { + assertThat(cloudEventProducer.publish(Collections.singletonList(new MockCloudEvent()))).isEqualTo(Response.builder().build()); + } + + @Test + public void testPublishSingle() { + assertThat(cloudEventProducer.publish(new MockCloudEvent())).isEqualTo(Response.builder().build()); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducerTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducerTest.java new file mode 100644 index 0000000000..afc4ba2103 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshGrpcProducerTest.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.EventMeshMessage.EventMeshMessageBuilder; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc.PublisherServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.Response; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class EventMeshGrpcProducerTest { + + private EventMeshGrpcProducer producer; + @Mock + private CloudEventProducer cloudEventProducer; + @Mock + private PublisherServiceBlockingStub stub; + + @Mock + private EventMeshMessageProducer eventMeshMessageProducer; + + @BeforeEach + public void setUp() throws Exception { + producer = new EventMeshGrpcProducer(EventMeshGrpcClientConfig.builder().build()); + producer.setCloudEventProducer(cloudEventProducer); + producer.setEventMeshMessageProducer(eventMeshMessageProducer); + producer.setPublisherClient(stub); + + doThrow(RuntimeException.class).when(stub).publish( + argThat(argument -> argument != null && StringUtils.equals(EventMeshCloudEventUtils.getDataContent(argument), + "mockExceptionContent"))); + doReturn(CloudEvent.getDefaultInstance()).when(stub).publish( + argThat(argument -> argument != null && StringUtils.equals(EventMeshCloudEventUtils.getDataContent(argument), "mockContent"))); + doReturn(CloudEvent.getDefaultInstance()).when(stub).batchPublish( + argThat(argument -> argument != null && StringUtils.equals(EventMeshCloudEventUtils.getSubject(argument.getEvents(0)), "mockTopic"))); + doReturn(stub).when(stub).withDeadlineAfter(1000L, TimeUnit.MILLISECONDS); + when(cloudEventProducer.publish(anyList())).thenReturn(Response.builder().build()); + when(cloudEventProducer.publish(Mockito.isA(io.cloudevents.CloudEvent.class))).thenReturn(Response.builder().build()); + when(eventMeshMessageProducer.publish(anyList())).thenReturn(Response.builder().build()); + when(eventMeshMessageProducer.publish(Mockito.isA(EventMeshMessage.class))).thenReturn(Response.builder().build()); + doAnswer(invocation -> { + EventMeshMessage eventMeshMessage = invocation.getArgument(0); + if (StringUtils.isEmpty(eventMeshMessage.getContent())) { + return null; + } + return eventMeshMessage; + }).when(eventMeshMessageProducer).requestReply(any(), Mockito.anyLong()); + + } + + @Test + public void testPublishWithException() { + assertThrows(IllegalArgumentException.class, () -> producer.publish("Not a supported message")); + } + + @Test + public void testPublishEventMeshMessage() { + assertThat(producer.publish(defaultEventMeshMessageBuilder().build())).isEqualTo(Response.builder().build()); + } + + @Test + public void testPublishEmptyList() { + assertThat(producer.publish(Collections.emptyList())).isNull(); + } + + @Test + public void testPublishGenericMessageList() { + assertThat(producer.publish(Collections.singletonList(new MockCloudEvent()))).isEqualTo( + Response.builder().build()); + EventMeshMessageBuilder eventMeshMessageBuilder = defaultEventMeshMessageBuilder(); + eventMeshMessageBuilder.prop(Collections.singletonMap(Constants.EVENTMESH_MESSAGE_CONST_TTL, "1000")); + assertThat(producer.publish(Collections.singletonList(eventMeshMessageBuilder.build()))).isEqualTo( + Response.builder().build()); + } + + @Test + public void testRequestReply() { + assertThat(producer.requestReply(defaultEventMeshMessageBuilder().content(StringUtils.EMPTY).build(), + 1000L)).isNull(); + EventMeshMessage eventMeshMessage = defaultEventMeshMessageBuilder().build(); + assertThat(producer.requestReply(eventMeshMessage, 1000L)).hasFieldOrPropertyWithValue("content", + eventMeshMessage.getContent()).hasFieldOrPropertyWithValue("topic", eventMeshMessage.getTopic()); + } + + private EventMeshMessage.EventMeshMessageBuilder defaultEventMeshMessageBuilder() { + return EventMeshMessage.builder().bizSeqNo("bizSeqNo").content("mockContent") + .createTime(System.currentTimeMillis()).uniqueId("mockUniqueId").topic("mockTopic") + .prop(Collections.emptyMap()); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshMessageProducerTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshMessageProducerTest.java new file mode 100644 index 0000000000..c31b4fcfb1 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/EventMeshMessageProducerTest.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.producer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.PublisherServiceGrpc.PublisherServiceBlockingStub; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.Response; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class EventMeshMessageProducerTest { + + private EventMeshMessageProducer eventMeshMessageProducer; + + @Mock + private PublisherServiceBlockingStub blockingStub; + + @Mock + private CloudEvent mockCloudEvent; + + @BeforeEach + public void setUp() throws Exception { + eventMeshMessageProducer = new EventMeshMessageProducer(EventMeshGrpcClientConfig.builder().build(), blockingStub); + when(blockingStub.batchPublish(Mockito.isA(CloudEventBatch.class))).thenReturn(mockCloudEvent); + when(blockingStub.publish(Mockito.isA(CloudEvent.class))).thenReturn(mockCloudEvent); + when(blockingStub.requestReply(Mockito.isA(CloudEvent.class))).thenReturn(mockCloudEvent); + doAnswer(invocation -> { + CloudEvent cloudEvent = invocation.getArgument(0); + if (StringUtils.isEmpty(EventMeshCloudEventUtils.getDataContent(cloudEvent))) { + return CloudEvent.getDefaultInstance(); + } + return CloudEvent.newBuilder(cloudEvent).build(); + }).when(blockingStub).requestReply(any()); + doReturn(blockingStub).when(blockingStub).withDeadlineAfter(1000, TimeUnit.MILLISECONDS); + } + + @Test + public void testPublishSingle() { + + EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .topic("mxsm") + .content("mxsm") + .bizSeqNo("mxsm") + .uniqueId("mxsm") + .build(); + assertThat(eventMeshMessageProducer.publish(eventMeshMessage)).isEqualTo(Response.builder().build()); + } + + @Test + public void testPublishMulti() { + + List messageArrayList = new ArrayList<>(); + for (int i = 0; i < 10; ++i) { + EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .topic("mxsm") + .content("mxsm") + .bizSeqNo("mxsm" + i) + .uniqueId("mxsm" + i) + .build(); + messageArrayList.add(eventMeshMessage); + } + assertThat(eventMeshMessageProducer.publish(messageArrayList)).isEqualTo(Response.builder().build()); + assertThat(eventMeshMessageProducer.publish(Collections.emptyList())).isNull(); + } + + @Test + public void requestReply() { + EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .topic("mxsm") + .content("mxsm") + .bizSeqNo("mxsm") + .uniqueId("mxsm") + .build(); + assertThat(eventMeshMessageProducer.requestReply(eventMeshMessage, 1000L)).isNotNull(); + } +} diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/MockCloudEvent.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/MockCloudEvent.java similarity index 100% rename from eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/MockCloudEvent.java rename to eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/producer/MockCloudEvent.java diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/util/EventMeshCloudEventBuilderTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/util/EventMeshCloudEventBuilderTest.java new file mode 100644 index 0000000000..1b1de0a191 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/grpc/util/EventMeshCloudEventBuilderTest.java @@ -0,0 +1,175 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.grpc.util; + +import org.apache.eventmesh.client.grpc.config.EventMeshGrpcClientConfig; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.enums.EventMeshProtocolType; +import org.apache.eventmesh.common.protocol.SubscriptionItem; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEvent.CloudEventAttributeValue; +import org.apache.eventmesh.common.protocol.grpc.cloudevents.CloudEventBatch; +import org.apache.eventmesh.common.protocol.grpc.common.EventMeshCloudEventUtils; +import org.apache.eventmesh.common.protocol.grpc.common.ProtocolKey; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.core.builder.CloudEventBuilder; + +public class EventMeshCloudEventBuilderTest { + + private EventMeshGrpcClientConfig clientConfig; + + @BeforeEach + public void init() { + clientConfig = EventMeshGrpcClientConfig.builder().build(); + } + + @Test + public void testBuildCommonCloudEventAttributes() { + + Map attributeValueMap = EventMeshCloudEventBuilder.buildCommonCloudEventAttributes( + clientConfig, EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNotNull(attributeValueMap); + Assertions.assertEquals(EventMeshProtocolType.CLOUD_EVENTS.protocolTypeName(), + attributeValueMap.get(ProtocolKey.PROTOCOL_TYPE).getCeString()); + Map attributeValueMap1 = EventMeshCloudEventBuilder.buildCommonCloudEventAttributes( + clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE); + Assertions.assertNotNull(attributeValueMap1); + Assertions.assertEquals(EventMeshProtocolType.EVENT_MESH_MESSAGE.protocolTypeName(), + attributeValueMap1.get(ProtocolKey.PROTOCOL_TYPE).getCeString()); + Map attributeValueMap2 = EventMeshCloudEventBuilder.buildCommonCloudEventAttributes( + clientConfig, EventMeshProtocolType.OPEN_MESSAGE); + Assertions.assertNotNull(attributeValueMap2); + Assertions.assertEquals(EventMeshProtocolType.OPEN_MESSAGE.protocolTypeName(), + attributeValueMap2.get(ProtocolKey.PROTOCOL_TYPE).getCeString()); + + } + + @Test + public void testBuildEventSubscription() { + List subscriptionItems = new ArrayList<>(); + for (int i = 0; i < 5; ++i) { + SubscriptionItem item = new SubscriptionItem(); + item.setMode(i % 2 == 0 ? SubscriptionMode.CLUSTERING : SubscriptionMode.BROADCASTING); + item.setTopic("mxsm" + i); + item.setType(i % 2 == 1 ? SubscriptionType.SYNC : SubscriptionType.ASYNC); + subscriptionItems.add(item); + } + CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventSubscription(clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE, "127.0.0.1", + subscriptionItems); + Assertions.assertNotNull(cloudEvent); + } + + @Test + public void testBuildEventMeshCloudEvent() { + String id = UUID.randomUUID().toString(); + io.cloudevents.CloudEvent event = + CloudEventBuilder.v1().withType("eventmesh").withSource(URI.create("/")).withId(id).build(); + EventMeshMessage meshMessage = EventMeshMessage.builder().build(); + Assertions.assertThrows(Exception.class, + () -> EventMeshCloudEventBuilder.buildEventMeshCloudEvent(event, clientConfig, EventMeshProtocolType.EVENT_MESH_MESSAGE)); + CloudEvent cloudEvent = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(event, clientConfig, EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNotNull(cloudEvent); + Assertions.assertEquals("eventmesh", cloudEvent.getType()); + Assertions.assertEquals(id, cloudEvent.getId()); + Assertions.assertThrows(Exception.class, + () -> EventMeshCloudEventBuilder.buildEventMeshCloudEvent(meshMessage, clientConfig, EventMeshProtocolType.CLOUD_EVENTS)); + EventMeshMessage meshMessage1 = EventMeshMessage.builder().uniqueId(id).build(); + CloudEvent cloudEvent1 = EventMeshCloudEventBuilder.buildEventMeshCloudEvent(meshMessage1, clientConfig, + EventMeshProtocolType.EVENT_MESH_MESSAGE); + Assertions.assertNotNull(cloudEvent1); + Assertions.assertEquals("org.apache.eventmesh", cloudEvent1.getType()); + Assertions.assertEquals(id, EventMeshCloudEventUtils.getUniqueId(cloudEvent1)); + + } + + @Test + public void testBuildEventMeshCloudEventBatch() { + List cloudEventList = new ArrayList<>(); + CloudEventBatch cloudEventBatch = EventMeshCloudEventBuilder.buildEventMeshCloudEventBatch(cloudEventList, clientConfig, + EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNull(cloudEventBatch); + CloudEventBatch cloudEventBatch1 = EventMeshCloudEventBuilder.buildEventMeshCloudEventBatch(null, clientConfig, + EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNull(cloudEventBatch1); + List cloudEventList2 = new ArrayList<>(); + for (int i = 0; i < 3; ++i) { + String id = UUID.randomUUID().toString(); + io.cloudevents.CloudEvent event = + CloudEventBuilder.v1().withType("eventmesh" + i).withSource(URI.create("/")).withId(id).build(); + cloudEventList2.add(event); + } + CloudEventBatch cloudEventBatch2 = EventMeshCloudEventBuilder.buildEventMeshCloudEventBatch(cloudEventList2, clientConfig, + EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNotNull(cloudEventBatch2); + + List messageList = new ArrayList<>(); + for (int i = 0; i < 3; ++i) { + EventMeshMessage meshMessage1 = EventMeshMessage.builder().uniqueId(UUID.randomUUID().toString()).build(); + messageList.add(meshMessage1); + } + CloudEventBatch cloudEventBatch3 = EventMeshCloudEventBuilder.buildEventMeshCloudEventBatch(messageList, clientConfig, + EventMeshProtocolType.EVENT_MESH_MESSAGE); + Assertions.assertNotNull(cloudEventBatch3); + Assertions.assertEquals(3, cloudEventBatch3.getEventsCount()); + } + + @Test + public void testBuildMessageFromEventMeshCloudEvent() { + + Object object = EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(null, EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNull(object); + CloudEvent eventmesh = CloudEvent.newBuilder().setSpecVersion("1.0").setType("eventmesh").setSource(URI.create("/").toString()) + .setId(UUID.randomUUID().toString()).build(); + Object event = EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(eventmesh, EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertNull(event); + CloudEvent eventmesh1 = CloudEvent.newBuilder().setSpecVersion("1.0").setType("eventmesh").setSource(URI.create("/").toString()) + .setId(UUID.randomUUID().toString()).putAttributes(ProtocolKey.SEQ_NUM, CloudEventAttributeValue.newBuilder().setCeString("1").build()) + .build(); + Object event1 = EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(eventmesh1, EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertTrue(event1 instanceof io.cloudevents.CloudEvent); + Object event2 = EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(eventmesh1, EventMeshProtocolType.EVENT_MESH_MESSAGE); + Assertions.assertTrue(event2 instanceof EventMeshMessage); + + final Map attributeValueMap = EventMeshCloudEventBuilder.buildCommonCloudEventAttributes(clientConfig, + EventMeshProtocolType.EVENT_MESH_MESSAGE); + attributeValueMap.put(ProtocolKey.CONSUMERGROUP, CloudEventAttributeValue.newBuilder().setCeString(clientConfig.getConsumerGroup()).build()); + attributeValueMap.put(ProtocolKey.DATA_CONTENT_TYPE, CloudEventAttributeValue.newBuilder().setCeString("application/json").build()); + Set set = new HashSet<>(); + SubscriptionItem subscriptionItem = new SubscriptionItem("111", SubscriptionMode.CLUSTERING, SubscriptionType.SYNC); + set.add(subscriptionItem); + CloudEvent eventmesh2 = CloudEvent.newBuilder().setSpecVersion("1.0").setType("eventmesh").setSource(URI.create("/").toString()) + .setId(UUID.randomUUID().toString()).putAllAttributes(attributeValueMap).setTextData(JsonUtils.toJSONString(set)).build(); + Object event4 = EventMeshCloudEventBuilder.buildMessageFromEventMeshCloudEvent(eventmesh2, EventMeshProtocolType.CLOUD_EVENTS); + Assertions.assertTrue(event4 instanceof Set); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncPublishInstance.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncPublishInstance.java new file mode 100644 index 0000000000..403c3d13be --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncPublishInstance.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.demo; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AsyncPublishInstance { + + public static void main(String[] args) throws Exception { + + String eventMeshIPPort = "127.0.0.1:10105"; + final String topic = "TEST-TOPIC-HTTP-ASYNC"; + + EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr(eventMeshIPPort) + .producerGroup("EventMeshTest-producerGroup") + .env("env") + .idc("idc") + .ip(IPUtils.getLocalAddress()) + .sys("1234") + .pid(String.valueOf(ThreadUtils.getPID())).build(); + + EventMeshHttpProducer eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); + for (int i = 0; i < 1; i++) { + EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content("testPublishMessage") + .topic(topic) + .uniqueId(RandomStringUtils.generateNum(30)) + .build() + .addProp(Constants.EVENTMESH_MESSAGE_CONST_TTL, String.valueOf(4 * 1000)); + + eventMeshHttpProducer.publish(eventMeshMessage); + ThreadUtils.sleep(1, TimeUnit.SECONDS); + } + ThreadUtils.sleep(30, TimeUnit.SECONDS); + try (EventMeshHttpProducer ignore = eventMeshHttpProducer) { + // ignore + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncSyncRequestInstance.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncSyncRequestInstance.java new file mode 100644 index 0000000000..5ef236acb1 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/AsyncSyncRequestInstance.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.demo; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; +import org.apache.eventmesh.client.http.producer.RRCallback; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AsyncSyncRequestInstance { + + public static void main(String[] args) throws Exception { + + EventMeshHttpProducer eventMeshHttpProducer = null; + try { + // String eventMeshIPPort = args[0]; + String eventMeshIPPort = ""; + // final String topic = args[1]; + final String topic = "TEST-TOPIC-HTTP-ASYNC"; + if (StringUtils.isBlank(eventMeshIPPort)) { + // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 + eventMeshIPPort = "127.0.0.1:10105"; + } + + EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr(eventMeshIPPort) + .producerGroup("EventMeshTest-producerGroup") + .env("env") + .idc("idc") + .ip(IPUtils.getLocalAddress()) + .sys("1234") + .pid(String.valueOf(ThreadUtils.getPID())).build(); + + eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); + + final long startTime = System.currentTimeMillis(); + final EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content("testAsyncMessage") + .topic(topic) + .uniqueId(RandomStringUtils.generateNum(30)).build(); + + eventMeshHttpProducer.request(eventMeshMessage, new RRCallback() { + + @Override + public void onSuccess(EventMeshMessage o) { + log.debug("sendmsg: {}, return: {}, cost: {}ms", + eventMeshMessage.getContent(), o.getContent(), System.currentTimeMillis() - startTime); + } + + @Override + public void onException(Throwable e) { + log.debug("sendmsg failed", e); + } + }, 3000); + + ThreadUtils.sleep(2, TimeUnit.SECONDS); + } catch (Exception e) { + log.warn("async send msg failed", e); + } + + ThreadUtils.sleep(30, TimeUnit.SECONDS); + try (final EventMeshHttpProducer ignore = eventMeshHttpProducer) { + // close producer + } catch (Exception e1) { + log.warn("producer shutdown exception", e1); + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/SyncRequestInstance.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/SyncRequestInstance.java new file mode 100644 index 0000000000..baf31566de --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/demo/SyncRequestInstance.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.demo; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.client.http.producer.EventMeshHttpProducer; +import org.apache.eventmesh.common.EventMeshMessage; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.common.utils.ThreadUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SyncRequestInstance { + + public static void main(String[] args) throws Exception { + + EventMeshHttpProducer eventMeshHttpProducer = null; + try { + String eventMeshIPPort = args[0]; + + final String topic = args[1]; + + if (StringUtils.isBlank(eventMeshIPPort)) { + // if has multi value, can config as: 127.0.0.1:10105;127.0.0.2:10105 + eventMeshIPPort = "127.0.0.1:10105"; + } + + EventMeshHttpClientConfig eventMeshClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr(eventMeshIPPort) + .producerGroup("EventMeshTest-producerGroup") + .env("env") + .idc("idc") + .ip(IPUtils.getLocalAddress()) + .sys("1234") + .pid(String.valueOf(ThreadUtils.getPID())).build(); + + eventMeshHttpProducer = new EventMeshHttpProducer(eventMeshClientConfig); + + long startTime = System.currentTimeMillis(); + EventMeshMessage eventMeshMessage = EventMeshMessage.builder() + .bizSeqNo(RandomStringUtils.generateNum(30)) + .content("contentStr with special protocal") + .topic(topic) + .uniqueId(RandomStringUtils.generateNum(30)).build(); + + EventMeshMessage rsp = eventMeshHttpProducer.request(eventMeshMessage, 10000); + log.debug("sendmsg: {}, return: {}, cost:{}ms", eventMeshMessage.getContent(), rsp.getContent(), System.currentTimeMillis() - startTime); + } catch (Exception e) { + log.warn("send msg failed", e); + } + + ThreadUtils.sleep(30, TimeUnit.SECONDS); + try (final EventMeshHttpProducer closed = eventMeshHttpProducer) { + // close producer + } catch (Exception e1) { + log.warn("producer shutdown exception", e1); + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtilsTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtilsTest.java new file mode 100644 index 0000000000..fc80ccf731 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpLoadBalanceUtilsTest.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.util; + +import org.apache.eventmesh.client.http.conf.EventMeshHttpClientConfig; +import org.apache.eventmesh.common.exception.EventMeshException; +import org.apache.eventmesh.common.loadbalance.LoadBalanceSelector; +import org.apache.eventmesh.common.loadbalance.LoadBalanceType; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class HttpLoadBalanceUtilsTest { + + @Test + public void testCreateRandomSelector() throws EventMeshException { + EventMeshHttpClientConfig eventMeshHttpClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr("127.0.0.1:1001;127.0.0.2:1002") + .build(); + LoadBalanceSelector randomSelector = HttpLoadBalanceUtils + .createEventMeshServerLoadBalanceSelector(eventMeshHttpClientConfig); + Assertions.assertEquals(LoadBalanceType.RANDOM, randomSelector.getType()); + } + + @Test + public void testCreateWeightRoundRobinSelector() throws EventMeshException { + EventMeshHttpClientConfig eventMeshHttpClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr("127.0.0.1:1001:1;127.0.0.2:1001:2") + .loadBalanceType(LoadBalanceType.WEIGHT_ROUND_ROBIN).build(); + LoadBalanceSelector weightRoundRobinSelector = HttpLoadBalanceUtils + .createEventMeshServerLoadBalanceSelector(eventMeshHttpClientConfig); + Assertions.assertEquals(LoadBalanceType.WEIGHT_ROUND_ROBIN, weightRoundRobinSelector.getType()); + } + + @Test + public void testCreateWeightRandomSelector() throws EventMeshException { + EventMeshHttpClientConfig eventMeshHttpClientConfig = EventMeshHttpClientConfig.builder() + .liteEventMeshAddr("127.0.0.1:1001:1;127.0.0.2:1001:2") + .loadBalanceType(LoadBalanceType.WEIGHT_RANDOM).build(); + LoadBalanceSelector weightRoundRobinSelector = HttpLoadBalanceUtils + .createEventMeshServerLoadBalanceSelector(eventMeshHttpClientConfig); + Assertions.assertEquals(LoadBalanceType.WEIGHT_RANDOM, weightRoundRobinSelector.getType()); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpUtilsTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpUtilsTest.java new file mode 100644 index 0000000000..ce65270297 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/http/util/HttpUtilsTest.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.http.util; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.eventmesh.client.http.model.RequestParam; + +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.netty.handler.codec.http.HttpMethod; + +public class HttpUtilsTest { + + @Test + public void testPostPositive() throws IOException { + CloseableHttpClient client = mock(CloseableHttpClient.class); + String uri = "http://example.com"; + RequestParam requestParam = new RequestParam(HttpMethod.POST); + String expectedResult = "Success"; + when(client.execute(any(HttpPost.class), any(ResponseHandler.class))).thenReturn(expectedResult); + String result = HttpUtils.post(client, uri, requestParam); + Assertions.assertEquals(expectedResult, result); + } + + @Test + public void testPostNegative() throws IOException { + CloseableHttpClient client = mock(CloseableHttpClient.class); + String uri = "http://example.com"; + RequestParam requestParam = new RequestParam(HttpMethod.GET); + String expectedResult = "Failure"; + when(client.execute(any(HttpPost.class), any(ResponseHandler.class))).thenReturn(expectedResult); + Assertions.assertThrows(Exception.class, () -> HttpUtils.post(client, uri, requestParam)); + } + + @Test + public void testGetPositive() throws IOException { + CloseableHttpClient client = mock(CloseableHttpClient.class); + String uri = "http://example.com"; + RequestParam requestParam = new RequestParam(HttpMethod.GET); + String expectedResult = "Success"; + when(client.execute(any(HttpGet.class), any(ResponseHandler.class))).thenReturn(expectedResult); + String result = HttpUtils.get(client, uri, requestParam); + Assertions.assertEquals(expectedResult, result); + } + + @Test + public void testGetNegative() throws IOException { + CloseableHttpClient client = mock(CloseableHttpClient.class); + String uri = "http://example.com"; + RequestParam requestParam = new RequestParam(HttpMethod.POST); + String expectedResult = "Failure"; + when(client.execute(any(HttpGet.class), any(ResponseHandler.class))).thenReturn(expectedResult); + Assertions.assertThrows(Exception.class, () -> HttpUtils.get(client, uri, requestParam)); + } +} diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestCaseTopicSet.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestCaseTopicSet.java similarity index 81% rename from eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestCaseTopicSet.java rename to eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestCaseTopicSet.java index 669e598a8c..f340e93bd5 100644 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestCaseTopicSet.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestCaseTopicSet.java @@ -22,13 +22,13 @@ */ public class EventMeshTestCaseTopicSet { - // public static final String TOPIC_PRX_WQ2ClientBroadCast = "topic-broadcast-test"; + // public static final String TOPIC_PRX_WQ2ClientBroadCast = "topic-broadcast-test"; public static final String TOPIC_PRX_WQ2ClientBroadCast = "TEST-TOPIC-TCP-BROADCAST"; - // public static final String TOPIC_PRX_SyncSubscribeTest = "topic-sync-test"; + // public static final String TOPIC_PRX_SyncSubscribeTest = "topic-sync-test"; public static final String TOPIC_PRX_SyncSubscribeTest = "TEST-TOPIC-TCP-SYNC"; - // public static final String TOPIC_PRX_WQ2ClientUniCast = "topic-async-test"; + // public static final String TOPIC_PRX_WQ2ClientUniCast = "topic-async-test"; public static final String TOPIC_PRX_WQ2ClientUniCast = "TEST-TOPIC-TCP-ASYNC"; } diff --git a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java similarity index 87% rename from eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java rename to eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java index 6b12419801..dd59233467 100644 --- a/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/EventMeshTestUtils.java @@ -31,35 +31,36 @@ import java.util.concurrent.ThreadLocalRandom; public class EventMeshTestUtils { + private static final int seqLength = 10; public static UserAgent generateClient1() { return UserAgent.builder() - .host("127.0.0.1") - .password(generateRandomString(8)) - .username("PU4283") - .group("EventmeshTestGroup") - .path("/data/app/umg_proxy") - .port(8362) - .subsystem("5023") - .pid(32893) - .version("2.0.11") - .idc("FT") - .build(); + .host("127.0.0.1") + .password(generateRandomString(8)) + .username("PU4283") + .group("EventmeshTestGroup") + .path("/data/app/umg_proxy") + .port(8362) + .subsystem("5023") + .pid(32893) + .version("2.0.11") + .idc("FT") + .build(); } public static UserAgent generateClient2() { return UserAgent.builder() - .host("127.0.0.1") - .password(generateRandomString(8)) - .username("PU4283") - .group("EventmeshTestGroup") - .path("/data/app/umg_proxy") - .port(9362) - .subsystem("5017") - .pid(42893) - .version("2.0.11") - .idc("FT").build(); + .host("127.0.0.1") + .password(generateRandomString(8)) + .username("PU4283") + .group("EventmeshTestGroup") + .path("/data/app/umg_proxy") + .port(9362) + .subsystem("5017") + .pid(42893) + .version("2.0.11") + .idc("FT").build(); } public static Package syncRR() { @@ -107,7 +108,6 @@ public static EventMeshMessage generateSyncRRMqMsg() { return mqMsg; } - private static EventMeshMessage generateAsyncRRMqMsg() { EventMeshMessage mqMsg = new EventMeshMessage(); mqMsg.setTopic(TOPIC_PRX_SyncSubscribeTest); diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/MessageUtilsTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/MessageUtilsTest.java new file mode 100644 index 0000000000..4916cf5612 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/common/MessageUtilsTest.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.tcp.common; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.protocol.SubscriptionMode; +import org.apache.eventmesh.common.protocol.SubscriptionType; +import org.apache.eventmesh.common.protocol.tcp.Command; +import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; +import org.apache.eventmesh.common.protocol.tcp.Header; +import org.apache.eventmesh.common.protocol.tcp.Package; +import org.apache.eventmesh.common.protocol.tcp.Subscription; +import org.apache.eventmesh.common.protocol.tcp.UserAgent; + +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class MessageUtilsTest { + + @Test + public void testHello() { + // Positive Test Case + UserAgent user = new UserAgent(); + Package msg = MessageUtils.hello(user); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.HELLO_REQUEST, msg.getHeader().getCommand()); + Assertions.assertNotNull(msg.getBody()); + Assertions.assertTrue(msg.getBody() instanceof UserAgent); + // Negative Test Case + Assertions.assertDoesNotThrow(() -> MessageUtils.hello(null)); + } + + @Test + public void testHeartBeat() { + // Positive Test Case + Package msg = MessageUtils.heartBeat(); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.HEARTBEAT_REQUEST, msg.getHeader().getCommand()); + Assertions.assertNull(msg.getBody()); + // Negative Test Case + msg = null; + Assertions.assertNull(msg); + } + + @Test + public void testGoodbye() { + // Positive Test Case + Package msg = MessageUtils.goodbye(); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.CLIENT_GOODBYE_REQUEST, msg.getHeader().getCommand()); + Assertions.assertNull(msg.getBody()); + // Negative Test Case + msg = null; + Assertions.assertNull(msg); + } + + @Test + public void testListen() { + // Positive Test Case + Package msg = MessageUtils.listen(); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.LISTEN_REQUEST, msg.getHeader().getCommand()); + Assertions.assertNull(msg.getBody()); + // Negative Test Case + msg = null; + Assertions.assertNull(msg); + } + + @Test + public void testSubscribe() { + // Positive Test Case + String topic = "testTopic"; + SubscriptionMode subscriptionMode = SubscriptionMode.CLUSTERING; + SubscriptionType subscriptionType = SubscriptionType.SYNC; + Package msg = MessageUtils.subscribe(topic, subscriptionMode, subscriptionType); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.SUBSCRIBE_REQUEST, msg.getHeader().getCommand()); + Assertions.assertNotNull(msg.getBody()); + Assertions.assertTrue(msg.getBody() instanceof Subscription); + // Negative Test Case + Assertions.assertDoesNotThrow(() -> MessageUtils.subscribe(null, null, null)); + } + + @Test + public void testUnsubscribe() { + // Positive Test Case + Package msg = MessageUtils.unsubscribe(); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.UNSUBSCRIBE_REQUEST, msg.getHeader().getCommand()); + Assertions.assertNull(msg.getBody()); + // Negative Test Case + msg = null; + Assertions.assertNull(msg); + } + + @Test + public void testAsyncMessageAck() { + // Positive Test Case + Package in = new Package(); + Header header = new Header(Command.ASYNC_MESSAGE_TO_CLIENT_ACK, 0, null, UUID.randomUUID().toString()); + in.setHeader(header); + in.setBody("testBody"); + Package msg = MessageUtils.asyncMessageAck(in); + Assertions.assertNotNull(msg); + Assertions.assertEquals(Command.ASYNC_MESSAGE_TO_CLIENT_ACK, msg.getHeader().getCommand()); + Assertions.assertEquals(msg.getHeader().getSeq(), in.getHeader().getSeq()); + Assertions.assertNotNull(msg.getBody()); + Assertions.assertEquals(msg.getBody(), in.getBody()); + // Negative Test Case + Assertions.assertThrows(Exception.class, () -> MessageUtils.asyncMessageAck(null)); + } + + @Test + public void testBuildPackage() { + // Positive Test Case + EventMeshMessage eventMeshMessage = new EventMeshMessage(); + eventMeshMessage.setBody("111"); + Command command = Command.ASYNC_MESSAGE_TO_SERVER; + Package msg = MessageUtils.buildPackage(eventMeshMessage, command); + Assertions.assertNotNull(msg); + Assertions.assertEquals(msg.getHeader().getCommand(), command); + Assertions.assertEquals(EventMeshCommon.EM_MESSAGE_PROTOCOL_NAME, msg.getHeader().getProperty(Constants.PROTOCOL_TYPE)); + Assertions.assertEquals("tcp", msg.getHeader().getProperty(Constants.PROTOCOL_DESC)); + Assertions.assertNotNull(msg.getBody()); + Assertions.assertTrue(msg.getBody() instanceof EventMeshMessage); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/impl/EventMeshTCPClientFactoryTest.java b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/impl/EventMeshTCPClientFactoryTest.java new file mode 100644 index 0000000000..c9510078f4 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-java/src/test/java/org/apache/eventmesh/client/tcp/impl/EventMeshTCPClientFactoryTest.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.eventmesh.client.tcp.impl; + +import org.apache.eventmesh.client.tcp.EventMeshTCPClient; +import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory; +import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig; +import org.apache.eventmesh.client.tcp.impl.cloudevent.CloudEventTCPClient; +import org.apache.eventmesh.client.tcp.impl.eventmeshmessage.EventMeshMessageTCPClient; +import org.apache.eventmesh.client.tcp.impl.openmessage.OpenMessageTCPClient; +import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.openmessaging.api.Message; + +public class EventMeshTCPClientFactoryTest { + + @Test + public void createEventMeshTCPClient() { + EventMeshTCPClientConfig meshTCPClientConfig = EventMeshTCPClientConfig.builder() + .host("localhost") + .port(1234) + .build(); + + EventMeshTCPClient eventMeshMessageTCPClient = + EventMeshTCPClientFactory.createEventMeshTCPClient(meshTCPClientConfig, EventMeshMessage.class); + Assertions.assertEquals(EventMeshMessageTCPClient.class, eventMeshMessageTCPClient.getClass()); + + EventMeshTCPClient cloudEventTCPClient = + EventMeshTCPClientFactory.createEventMeshTCPClient(meshTCPClientConfig, CloudEvent.class); + Assertions.assertEquals(CloudEventTCPClient.class, cloudEventTCPClient.getClass()); + + EventMeshTCPClient openMessageTCPClient = + EventMeshTCPClientFactory.createEventMeshTCPClient(meshTCPClientConfig, Message.class); + Assertions.assertEquals(OpenMessageTCPClient.class, openMessageTCPClient.getClass()); + } +} diff --git a/eventmesh-sdk-java/src/test/resources/application.properties b/eventmesh-sdks/eventmesh-sdk-java/src/test/resources/application.properties similarity index 100% rename from eventmesh-sdk-java/src/test/resources/application.properties rename to eventmesh-sdks/eventmesh-sdk-java/src/test/resources/application.properties diff --git a/eventmesh-sdk-java/src/test/resources/log4j2.xml b/eventmesh-sdks/eventmesh-sdk-java/src/test/resources/log4j2.xml similarity index 100% rename from eventmesh-sdk-java/src/test/resources/log4j2.xml rename to eventmesh-sdks/eventmesh-sdk-java/src/test/resources/log4j2.xml diff --git a/eventmesh-sdks/eventmesh-sdk-rust/.gitignore b/eventmesh-sdks/eventmesh-sdk-rust/.gitignore new file mode 100644 index 0000000000..593b689a59 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/.gitignore @@ -0,0 +1,6 @@ +target +Cargo.lock +.git +target/ +.vscode +.idea \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-rust/Cargo.toml b/eventmesh-sdks/eventmesh-sdk-rust/Cargo.toml new file mode 100644 index 0000000000..42bf18682c --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/Cargo.toml @@ -0,0 +1,86 @@ +# +# 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. +# + +[package] +name = "eventmesh" +version = "1.9.0" +edition = "2021" +authors = [ + "mxsm " +] +msrv = "1.75.0" +description = "Rust client for Apache EventMesh" +license = "Apache-2.0" +keywords = ["EventMesh", "SDK", "rust-client", "rust", "eventmesh-rust-sdk"] +readme = "./README.md" +homepage = "https://github.com/apache/eventmesh" +repository = "https://github.com/apache/eventmesh" + +[features] +default = ["grpc", "eventmesh_message"] +full = ["grpc", "eventmesh_message","cloud_events"] +eventmesh_message = [] +cloud_events = [] +tls = [] +grpc = [] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +# common +anyhow = "1.0" + +#Rust grpc +tonic = "0.10" +prost = "0.12" +prost-types = "0.12" + +#tokio +tokio = { version = "1.32.0", features = ["full"] } + +#serde +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +#log +tracing = "0.1" +tracing-subscriber = "0.3" + +#cloudEvents +cloudevents-sdk = "0.7.0" + +# tools crate +thiserror = "1.0" +bytes = "1" +rand = "0.8" +uuid = { version = "1.4.1", features = ["v4"] } +local-ip-address = "0.5.6" +futures = "0.3" +log = "0.4.20" +chrono = "0.4" + +[build-dependencies] +tonic-build = "0.10" + +[[example]] +name = "producer_example" +path = "examples/grpc/producer_example.rs" +required-features = ["grpc", "eventmesh_message","cloud_events"] + +[[example]] +name = "consumer_example" +path = "examples/grpc/consumer_example.rs" +required-features = ["grpc", "eventmesh_message"] \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-rust/README.md b/eventmesh-sdks/eventmesh-sdk-rust/README.md new file mode 100644 index 0000000000..04dc48088a --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/README.md @@ -0,0 +1,156 @@ +## Eventmesh-rust-sdk + +Eventmesh rust sdk + +## Quickstart + +### Requirements + +1. rust toolchain, eventmesh's MSRV is 1.75. +2. protoc 3.15.0+ +3. setup eventmesh runtime + +### Add Dependency + +```toml +[dependencies] +eventmesh = { version = "1.9", features = ["default"] } +``` + +### Send message + +```rust +use std::time::{SystemTime, UNIX_EPOCH}; +use tracing::info; + +use eventmesh::config::EventMeshGrpcClientConfig; +use eventmesh::grpc::grpc_producer::EventMeshGrpcProducer; +use eventmesh::grpc::GrpcEventMeshMessageProducer; +use eventmesh::log; +use eventmesh::model::message::EventMeshMessage; + +#[eventmesh::main] +async fn main() -> Result<(), Box> { + log::init_logger(); + + let grpc_client_config = EventMeshGrpcClientConfig::new(); + let mut producer = GrpcEventMeshMessageProducer::new(grpc_client_config); + + //Publish Message + info!("Publish Message to EventMesh........"); + let message = EventMeshMessage::default() + .with_biz_seq_no("1") + .with_content("123") + .with_create_time(SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as u64) + .with_topic("123") + .with_unique_id("1111"); + let response = producer.publish(message.clone()).await?; + info!("Publish Message to EventMesh return result: {}", response); + + //Publish batch message + info!("Publish batch message to EventMesh........"); + let messages = vec![message.clone(), message.clone(), message.clone()]; + let response = producer.publish_batch(messages).await?; + info!( + "Publish batch message to EventMesh return result: {}", + response + ); + + //Publish batch message + info!("Publish request reply message to EventMesh........"); + let response = producer.request_reply(message.clone(), 1000).await?; + info!( + "Publish request reply message to EventMesh return result: {}", + response + ); + Ok(()) +} +``` + +### Subscribe message + +```rust +use std::time::Duration; + +use tracing::info; + +use eventmesh::common::ReceiveMessageListener; +use eventmesh::config::EventMeshGrpcClientConfig; +use eventmesh::grpc::grpc_consumer::EventMeshGrpcConsumer; +use eventmesh::log; +use eventmesh::model::message::EventMeshMessage; +use eventmesh::model::subscription::{SubscriptionItem, SubscriptionMode, SubscriptionType}; + +struct EventMeshListener; + +impl ReceiveMessageListener for EventMeshListener { + type Message = EventMeshMessage; + + fn handle(&self, msg: Self::Message) -> eventmesh::Result> { + info!("Receive message from eventmesh================{:?}", msg); + Ok(None) + } +} + +#[eventmesh::main] +async fn main() -> Result<(), Box> { + log::init_logger(); + let grpc_client_config = EventMeshGrpcClientConfig::new(); + let listener = Box::new(EventMeshListener); + let mut consumer = EventMeshGrpcConsumer::new(grpc_client_config, listener); + //send + let item = SubscriptionItem::new( + "TEST-TOPIC-GRPC-ASYNC", + SubscriptionMode::CLUSTERING, + SubscriptionType::ASYNC, + ); + info!("==========Start consumer======================\n{}", item); + let _response = consumer.subscribe(vec![item.clone()]).await?; + tokio::time::sleep(Duration::from_secs(1000)).await; + info!("=========Unsubscribe start================"); + let response = consumer.unsubscribe(vec![item.clone()]).await?; + println!("unsubscribe result:{}", response); + Ok(()) +} + +``` + +## Development Guide + +### Dependencies + +In order to build `tonic` >= 0.8.0, you need the `protoc` Protocol Buffers compiler, along with Protocol Buffers resource files. + +#### Ubuntu + +```bash +sudo apt update && sudo apt upgrade -y +sudo apt install -y protobuf-compiler libprotobuf-dev +``` + +#### Alpine Linux + +```sh +sudo apk add protoc protobuf-dev +``` + +#### macOS + +Assuming [Homebrew](https://brew.sh/) is already installed. (If not, see instructions for installing Homebrew on [the Homebrew website](https://brew.sh/).) + +```zsh +brew install protobuf +``` + +#### Windows + +- Download the latest version of `protoc-xx.y-win64.zip` from [HERE](https://github.com/protocolbuffers/protobuf/releases/latest) +- Extract the file `bin\protoc.exe` and put it somewhere in the `PATH` +- Verify installation by opening a command prompt and enter `protoc --version` + +### Build + +```shell +cargo build +``` + diff --git a/eventmesh-sdks/eventmesh-sdk-rust/build.rs b/eventmesh-sdks/eventmesh-sdk-rust/build.rs new file mode 100644 index 0000000000..55a010d4f7 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/build.rs @@ -0,0 +1,30 @@ +/* + * 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. + */ + +fn main() -> Result<(), Box> { + tonic_build::configure() + .build_client(true) + .build_server(false) + .compile( + &[ + "proto/eventmesh-service.proto", + "proto/eventmesh-cloudevents.proto", + ], + &["proto"], + )?; + Ok(()) +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/examples/grpc/consumer_example.rs b/eventmesh-sdks/eventmesh-sdk-rust/examples/grpc/consumer_example.rs new file mode 100644 index 0000000000..8f84875d69 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/examples/grpc/consumer_example.rs @@ -0,0 +1,58 @@ +/* + * 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. + */ +use std::time::Duration; + +use tracing::info; + +use eventmesh::common::ReceiveMessageListener; +use eventmesh::config::EventMeshGrpcClientConfig; +use eventmesh::grpc::grpc_consumer::EventMeshGrpcConsumer; +use eventmesh::log; +use eventmesh::model::message::EventMeshMessage; +use eventmesh::model::subscription::{SubscriptionItem, SubscriptionMode, SubscriptionType}; + +struct EventMeshListener; + +impl ReceiveMessageListener for EventMeshListener { + type Message = EventMeshMessage; + + fn handle(&self, msg: Self::Message) -> eventmesh::Result> { + info!("Receive message from eventmesh================{:?}", msg); + Ok(None) + } +} + +#[eventmesh::main] +async fn main() -> Result<(), Box> { + log::init_logger(); + let grpc_client_config = EventMeshGrpcClientConfig::new(); + let listener = Box::new(EventMeshListener); + let mut consumer = EventMeshGrpcConsumer::new(grpc_client_config, listener); + //send + let item = SubscriptionItem::new( + "TEST-TOPIC-GRPC-ASYNC", + SubscriptionMode::CLUSTERING, + SubscriptionType::ASYNC, + ); + info!("==========Start consumer======================\n{}", item); + let _response = consumer.subscribe(vec![item.clone()]).await?; + tokio::time::sleep(Duration::from_secs(1000)).await; + info!("=========Unsubscribe start================"); + let response = consumer.unsubscribe(vec![item.clone()]).await?; + println!("unsubscribe result:{}", response); + Ok(()) +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/examples/grpc/producer_example.rs b/eventmesh-sdks/eventmesh-sdk-rust/examples/grpc/producer_example.rs new file mode 100644 index 0000000000..959c1a6a02 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/examples/grpc/producer_example.rs @@ -0,0 +1,102 @@ +/* + * 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. + */ +use std::time::{SystemTime, UNIX_EPOCH}; + +use chrono::Utc; +use cloudevents::{EventBuilder, EventBuilderV10}; +use tracing::info; + +use eventmesh::common::ProtocolKey; +use eventmesh::config::EventMeshGrpcClientConfig; +use eventmesh::grpc::grpc_producer::EventMeshGrpcProducer; +use eventmesh::grpc::GrpcEventMeshProducer; +use eventmesh::log; +use eventmesh::model::message::EventMeshMessage; + +#[eventmesh::main] +async fn main() -> Result<(), Box> { + log::init_logger(); + + //Publish Message + #[cfg(feature = "eventmesh_message")] + { + let grpc_client_config = EventMeshGrpcClientConfig::new(); + let mut producer = GrpcEventMeshProducer::new(grpc_client_config); + info!("Publish Message to EventMesh........"); + let message = EventMeshMessage::default() + .with_biz_seq_no("1") + .with_content("123") + .with_create_time(SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as u64) + .with_topic("123") + .with_unique_id("1111"); + let response = producer.publish(message.clone()).await?; + info!("Publish Message to EventMesh return result: {}", response); + + //Publish batch message + info!("Publish batch message to EventMesh........"); + let messages = vec![message.clone(), message.clone(), message.clone()]; + let response = producer.publish_batch(messages).await?; + info!( + "Publish batch message to EventMesh return result: {}", + response + ); + + //Publish batch message + info!("Publish request reply message to EventMesh........"); + let response = producer.request_reply(message.clone(), 1000).await?; + info!( + "Publish request reply message to EventMesh return result: {}", + response + ); + } + + #[cfg(feature = "cloud_events")] + { + let grpc_client_config = EventMeshGrpcClientConfig::new(); + let mut producer = GrpcEventMeshProducer::new(grpc_client_config); + info!("Publish Message to EventMesh........"); + let message = EventBuilderV10::new() + .id("my_event.my_application") + .source("http://localhost:8080") + .subject("mxsm") + .ty("example.demo") + .time(Utc::now()) + .data(ProtocolKey::CLOUDEVENT_CONTENT_TYPE, "{\"aaa\":\"1111\"}") + .build()?; + let response = producer.publish(message.clone()).await?; + info!("Publish Message to EventMesh return result: {}", response); + + //Publish batch message + info!("Publish batch message to EventMesh........"); + let messages = vec![message.clone(), message.clone(), message.clone()]; + let response = producer.publish_batch(messages).await?; + info!( + "Publish batch message to EventMesh return result: {}", + response + ); + + //Publish batch message + info!("Publish request reply message to EventMesh........"); + let response = producer.request_reply(message.clone(), 1000).await?; + info!( + "Publish request reply message to EventMesh return result: {}", + response + ); + } + + Ok(()) +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/proto/eventmesh-cloudevents.proto b/eventmesh-sdks/eventmesh-sdk-rust/proto/eventmesh-cloudevents.proto new file mode 100644 index 0000000000..37e07a0b40 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/proto/eventmesh-cloudevents.proto @@ -0,0 +1,86 @@ +/* + * 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. + */ + + + +/** + * CloudEvent Protobuf Format + * + * - Required context attributes are explicitly represented. + * - Optional and Extension context attributes are carried in a map structure. + * - Data may be represented as binary, text, or protobuf messages. + */ + +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option java_package = "org.apache.eventmesh.common.protocol.grpc.cloudevents"; +option java_multiple_files = true; +option java_outer_classname = "EventMeshCloudEvents"; + + +message CloudEvent { + + // -- CloudEvent Context Attributes + + // Required Attributes + string id = 1; + string source = 2; // URI-reference + string spec_version = 3; + string type = 4; + + // Optional & Extension Attributes + map attributes = 5; + + // -- CloudEvent Data (Bytes, Text, or Proto) + oneof data { + bytes binary_data = 6; + string text_data = 7; + google.protobuf.Any proto_data = 8; + } + + /** + * The CloudEvent specification defines + * seven attribute value types... + */ + + message CloudEventAttributeValue { + + oneof attr { + bool ce_boolean = 1; + int32 ce_integer = 2; + string ce_string = 3; + bytes ce_bytes = 4; + string ce_uri = 5; + string ce_uri_ref = 6; + google.protobuf.Timestamp ce_timestamp = 7; + } + } +} + +/** + * CloudEvent Protobuf Batch Format + * + */ + +message CloudEventBatch { + repeated CloudEvent events = 1; +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/proto/eventmesh-service.proto b/eventmesh-sdks/eventmesh-sdk-rust/proto/eventmesh-service.proto new file mode 100644 index 0000000000..99d57bc514 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/proto/eventmesh-service.proto @@ -0,0 +1,58 @@ +/* + * 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. + */ +syntax = "proto3"; + +package org.apache.eventmesh.cloudevents.v1; + +import "google/protobuf/empty.proto"; +import "eventmesh-cloudevents.proto"; + +option java_package = "org.apache.eventmesh.common.protocol.grpc.cloudevents"; +option java_multiple_files = true; +option java_outer_classname = "EventMeshGrpcService"; + + +service PublisherService { + //publish event + rpc publish(CloudEvent) returns (CloudEvent); + + //publish event with reply + rpc requestReply(CloudEvent) returns (CloudEvent); + + //publish event one way + rpc publishOneWay(CloudEvent) returns (google.protobuf.Empty); + + // publish batch event + rpc batchPublish(CloudEventBatch) returns (CloudEvent); + + //publish batch event one way + rpc batchPublishOneWay(CloudEventBatch) returns (google.protobuf.Empty); +} + +service ConsumerService { + // The subscribed event will be delivered by invoking the webhook url in the Subscription + rpc subscribe(CloudEvent) returns (CloudEvent); + + // The subscribed event will be delivered through stream of Message + rpc subscribeStream(stream CloudEvent) returns (stream CloudEvent); + + rpc unsubscribe(CloudEvent) returns (CloudEvent); +} + +service HeartbeatService { + rpc heartbeat(CloudEvent) returns (CloudEvent); +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/common.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/common.rs new file mode 100644 index 0000000000..7b3ea0d018 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/common.rs @@ -0,0 +1,55 @@ +/* + * 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. + */ +//! Common utilities for eventmesh. + +/// Constants. +pub mod constants; + +/// Eventmesh message utilities. +pub mod grpc_eventmesh_message_utils; + +/// Local IP helper. +pub(crate) mod local_ip; + +/// Protocol keys. +mod protocol_key; + +/// Random string generator. +mod random_string_util; + +/// Re-export protocol keys. +pub use crate::common::protocol_key::ProtocolKey; + +/// Re-export random string generator. +pub use crate::common::random_string_util::RandomStringUtils; + +/// Trait for message listener. +pub trait ReceiveMessageListener: Sync + Send { + /// Message type. + type Message; + + /// Handle received message. + /// + /// # Arguments + /// + /// * `msg` - The received message. + /// + /// # Returns + /// + /// The processed message or error. + fn handle(&self, msg: Self::Message) -> crate::Result>; +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/common/constants.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/common/constants.rs new file mode 100644 index 0000000000..5c0ef06907 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/common/constants.rs @@ -0,0 +1,56 @@ +/* + * 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. + */ +pub const DEFAULT_EVENTMESH_MESSAGE_TTL: i32 = 4000; +pub const SDK_STREAM_URL: &str = "grpc_stream"; + +pub struct DataContentType; + +impl DataContentType { + pub const TEXT_PLAIN: &'static str = "text/plain"; + pub const JSON: &'static str = "application/json"; +} + +pub(crate) struct SpecVersion; + +#[allow(dead_code)] +impl SpecVersion { + pub(crate) const V1: &'static str = "1.0"; + pub(crate) const V03: &'static str = "0.3"; +} + +#[derive(Debug, PartialEq, Eq)] +pub enum ClientType { + PUB, + SUB, +} + +impl ClientType { + pub fn get(type_: i32) -> Option { + match type_ { + 1 => Some(ClientType::PUB), + 2 => Some(ClientType::SUB), + _ => None, + } + } + + pub fn contains(client_type: i32) -> bool { + match client_type { + 1 | 2 => true, + _ => false, + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/common/grpc_eventmesh_message_utils.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/common/grpc_eventmesh_message_utils.rs new file mode 100644 index 0000000000..c1ff9a3221 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/common/grpc_eventmesh_message_utils.rs @@ -0,0 +1,671 @@ +/* + * 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. + */ + +use std::any::Any; +use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; +use std::time::{SystemTime, UNIX_EPOCH}; + +use cloudevents::Data::String as EventString; +use cloudevents::{AttributesReader, Data, Event, EventBuilder, EventBuilderV10}; +use tonic::transport::Uri; + +use crate::common::constants::{DataContentType, SpecVersion, DEFAULT_EVENTMESH_MESSAGE_TTL}; +use crate::common::{ProtocolKey, RandomStringUtils}; +use crate::config::EventMeshGrpcClientConfig; +use crate::model::message::EventMeshMessage; +use crate::model::response::EventMeshResponse; +use crate::model::subscription::SubscriptionItem; +use crate::model::EventMeshProtocolType; +use crate::proto_cloud_event::{PbAttr, PbCloudEvent, PbCloudEventAttributeValue, PbData}; + +pub struct ProtoSupport; + +impl ProtoSupport { + pub fn is_text_content(content_type: &str) -> bool { + if content_type.is_empty() { + return false; + } + + content_type.starts_with("text/") + || content_type == "application/json" + || content_type == "application/xml" + || content_type.ends_with("+json") + || content_type.ends_with("+xml") + } + + pub fn is_proto_content(content_type: &str) -> bool { + content_type == "application/protobuf" + } +} + +pub struct EventMeshCloudEventUtils; + +impl EventMeshCloudEventUtils { + const CLOUD_EVENT_TYPE: &'static str = "org.apache.eventmesh"; + + pub fn build_common_cloud_event_attributes( + client_config: &EventMeshGrpcClientConfig, + protocol_type: EventMeshProtocolType, + ) -> HashMap { + let mut attribute_value_map = HashMap::with_capacity(64); + attribute_value_map.insert( + ProtocolKey::ENV.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.env.clone())), + }, + ); + attribute_value_map.insert( + ProtocolKey::IDC.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.idc.clone())), + }, + ); + attribute_value_map.insert( + ProtocolKey::IP.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(crate::common::local_ip::get_local_ip_v4())), + }, + ); + attribute_value_map.insert( + ProtocolKey::PID.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(std::process::id().to_string())), + }, + ); + attribute_value_map.insert( + ProtocolKey::SYS.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.sys.clone())), + }, + ); + attribute_value_map.insert( + ProtocolKey::LANGUAGE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.language.clone())), + }, + ); + attribute_value_map.insert( + ProtocolKey::USERNAME.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.user_name.clone())), + }, + ); + attribute_value_map.insert( + ProtocolKey::PASSWD.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.password.clone())), + }, + ); + attribute_value_map.insert( + ProtocolKey::PROTOCOL_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + protocol_type.protocol_type_name().to_string(), + )), + }, + ); + attribute_value_map.insert( + ProtocolKey::PROTOCOL_VERSION.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(SpecVersion::V1.to_string())), + }, + ); + attribute_value_map + } + + pub fn build_event_subscription( + client_config: &EventMeshGrpcClientConfig, + protocol_type: EventMeshProtocolType, + url: &str, + subscription_items: &[SubscriptionItem], + ) -> Option { + if subscription_items.is_empty() { + return None; + } + let subscription_item_set: HashSet = + subscription_items.iter().cloned().collect(); + let mut attribute_value_map = + Self::build_common_cloud_event_attributes(client_config, protocol_type); + attribute_value_map.insert( + ProtocolKey::CONSUMERGROUP.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(client_config.consumer_group.clone()?)), + }, + ); + attribute_value_map.insert( + ProtocolKey::DATA_CONTENT_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::JSON.to_string())), + }, + ); + if !url.trim().is_empty() { + attribute_value_map.insert( + ProtocolKey::URL.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(url.to_string())), + }, + ); + } + let subscription_item_json = serde_json::to_string(&subscription_item_set); + if subscription_item_json.is_err() { + return None; + } + Some(PbCloudEvent { + id: RandomStringUtils::generate_uuid(), + source: Uri::builder() + .path_and_query("/") + .build() + .unwrap() + .to_string(), + spec_version: SpecVersion::V1.to_string(), + r#type: Self::CLOUD_EVENT_TYPE.to_string(), + attributes: attribute_value_map, + data: Some(PbData::TextData(subscription_item_json.unwrap())), + }) + } + + pub fn build_event_mesh_cloud_event( + message: T, + client_config: &EventMeshGrpcClientConfig, + ) -> Option + where + T: Any, + { + let message_any = &message as &dyn Any; + + if let Some(em_message) = message_any.downcast_ref::() { + return Some(Self::switch_event_mesh_message_2_event_mesh_cloud_event( + em_message, + client_config, + EventMeshProtocolType::EventMeshMessage, + )); + } + if let Some(cloud_event) = message_any.downcast_ref::() { + return Some(Self::switch_cloud_event_2_event_mesh_cloud_event( + cloud_event, + client_config, + EventMeshProtocolType::CloudEvents, + )); + } + + None + } + + pub fn switch_event_mesh_message_2_event_mesh_cloud_event( + message: &EventMeshMessage, + client_config: &EventMeshGrpcClientConfig, + protocol_type: EventMeshProtocolType, + ) -> PbCloudEvent { + let mut attribute_value_map = + Self::build_common_cloud_event_attributes(client_config, protocol_type); + let ttl = message + .get_prop(ProtocolKey::TTL) + .cloned() + .unwrap_or_else(|| DEFAULT_EVENTMESH_MESSAGE_TTL.to_string()); + let seq_num = message + .biz_seq_no + .clone() + .unwrap_or_else(|| RandomStringUtils::generate_num(30)); + let unique_id = message + .unique_id + .clone() + .unwrap_or_else(|| RandomStringUtils::generate_num(30)); + attribute_value_map + .entry(ProtocolKey::DATA_CONTENT_TYPE.to_string()) + .or_insert_with(|| PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::TEXT_PLAIN.to_string())), + }); + + attribute_value_map.insert( + ProtocolKey::TTL.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(ttl.to_string())), + }, + ); + attribute_value_map.insert( + ProtocolKey::SEQ_NUM.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(seq_num.to_string())), + }, + ); + + attribute_value_map.insert( + ProtocolKey::SEQ_NUM.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(seq_num.to_string())), + }, + ); + + attribute_value_map.insert( + ProtocolKey::PROTOCOL_DESC.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + ProtocolKey::PROTOCOL_DESC_GRPC_CLOUD_EVENT.to_string(), + )), + }, + ); + + attribute_value_map.insert( + ProtocolKey::UNIQUE_ID.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(unique_id.to_string())), + }, + ); + attribute_value_map.insert( + ProtocolKey::PRODUCERGROUP.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + client_config.producer_group.clone().unwrap(), + )), + }, + ); + if let Some(topic) = &message.topic { + attribute_value_map.insert( + ProtocolKey::SUBJECT.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(topic.to_string())), + }, + ); + } + attribute_value_map.insert( + ProtocolKey::DATA_CONTENT_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::TEXT_PLAIN.to_string())), + }, + ); + let props = &message.prop; + let text_plain = DataContentType::TEXT_PLAIN.to_string(); + let data_content_type = props + .get(ProtocolKey::DATA_CONTENT_TYPE) + .unwrap_or(&text_plain); + props.iter().for_each(|(key, value)| { + attribute_value_map.insert( + key.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(value.to_string())), + }, + ); + }); + + let data = { + if let Some(content) = &message.content { + if ProtoSupport::is_text_content(data_content_type) { + Some(PbData::TextData(content.to_string())) + } else if ProtoSupport::is_proto_content(data_content_type) { + Some(PbData::ProtoData(prost_types::Any { + type_url: String::from(""), + value: content.clone().into_bytes(), + })) + } else { + Some(PbData::BinaryData(content.clone().into_bytes())) + } + } else { + None + } + }; + PbCloudEvent { + id: RandomStringUtils::generate_uuid(), + source: Uri::builder() + .path_and_query("/") + .build() + .unwrap() + .to_string(), + spec_version: SpecVersion::V1.to_string(), + r#type: Self::CLOUD_EVENT_TYPE.to_string(), + attributes: attribute_value_map, + data, + } + } + + pub fn switch_cloud_event_2_event_mesh_cloud_event( + message: &Event, + client_config: &EventMeshGrpcClientConfig, + protocol_type: EventMeshProtocolType, + ) -> PbCloudEvent { + let mut attribute_value_map = + Self::build_common_cloud_event_attributes(client_config, protocol_type); + let ttl = message + .extension(ProtocolKey::TTL) + .map_or(DEFAULT_EVENTMESH_MESSAGE_TTL.to_string(), |value| { + value.to_string() + }); + let seq_num = message + .extension(ProtocolKey::SEQ_NUM) + .map_or(RandomStringUtils::generate_num(30), |value| { + value.to_string() + }); + let unique_id = message.id().to_string(); + attribute_value_map + .entry(ProtocolKey::DATA_CONTENT_TYPE.to_string()) + .or_insert_with(|| PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::TEXT_PLAIN.to_string())), + }); + + attribute_value_map.insert( + ProtocolKey::TTL.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(ttl.to_string())), + }, + ); + attribute_value_map.insert( + ProtocolKey::SEQ_NUM.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(seq_num.to_string())), + }, + ); + + attribute_value_map.insert( + ProtocolKey::SEQ_NUM.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(seq_num.to_string())), + }, + ); + + attribute_value_map.insert( + ProtocolKey::PROTOCOL_DESC.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + ProtocolKey::PROTOCOL_DESC_GRPC_CLOUD_EVENT.to_string(), + )), + }, + ); + + attribute_value_map.insert( + ProtocolKey::UNIQUE_ID.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(unique_id.to_string())), + }, + ); + attribute_value_map.insert( + ProtocolKey::PRODUCERGROUP.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + client_config.producer_group.clone().unwrap(), + )), + }, + ); + + attribute_value_map.insert( + ProtocolKey::SUBJECT.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(message.subject().unwrap().to_string())), + }, + ); + + attribute_value_map.insert( + ProtocolKey::DATA_CONTENT_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::TEXT_PLAIN.to_string())), + }, + ); + message.iter_extensions().for_each(|(key, value)| { + attribute_value_map.insert( + key.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(value.to_string())), + }, + ); + }); + + let data = { + if let Some(content) = message.data() { + match content { + Data::Binary(bytes) => Some(PbData::ProtoData(prost_types::Any { + type_url: String::from(""), + value: bytes.clone(), + })), + EventString(string) => Some(PbData::TextData(string.clone())), + Data::Json(_json) => None, + } + } else { + None + } + }; + PbCloudEvent { + id: RandomStringUtils::generate_uuid(), + source: Uri::builder() + .path_and_query("/") + .build() + .unwrap() + .to_string(), + spec_version: SpecVersion::V1.to_string(), + r#type: Self::CLOUD_EVENT_TYPE.to_string(), + attributes: attribute_value_map, + data, + } + } + + pub fn build_message_from_event_mesh_cloud_event(cloud_event: &PbCloudEvent) -> Option + where + T: Any + Debug + From, + { + let seq = EventMeshCloudEventUtils::get_seq_num(cloud_event); + let unique_id = EventMeshCloudEventUtils::get_unique_id(cloud_event); + + if seq.is_empty() || unique_id.is_empty() { + return None; + } + Some(T::from(cloud_event.clone())) + } + + pub(crate) fn switch_event_mesh_cloud_event_2_event_mesh_message( + cloud_event: &PbCloudEvent, + ) -> EventMeshMessage { + let mut prop = HashMap::new(); + cloud_event.attributes.iter().for_each(|(key, value)| { + prop.insert( + key.to_string(), + (&(value.attr)).clone().unwrap().to_string(), + ); + }); + let topic = EventMeshCloudEventUtils::get_subject(cloud_event); + let biz_seq_no = EventMeshCloudEventUtils::get_seq_num(cloud_event); + let unique_id = EventMeshCloudEventUtils::get_unique_id(cloud_event); + let content = EventMeshCloudEventUtils::get_text_data(cloud_event); + EventMeshMessage { + biz_seq_no: Some(biz_seq_no), + unique_id: Some(unique_id), + topic: Some(topic), + content: Some(content), + prop, + create_time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_or_else(|_err| 0u64, |time| time.as_millis() as u64), + } + } + + pub(crate) fn switch_event_mesh_cloud_event_2_cloud_event(cloud_event: PbCloudEvent) -> Event { + let topic = EventMeshCloudEventUtils::get_subject(&cloud_event); + let unique_id = EventMeshCloudEventUtils::get_unique_id(&cloud_event); + let content = EventMeshCloudEventUtils::get_text_data(&cloud_event); + let source = EventMeshCloudEventUtils::get_source(&cloud_event); + + let mut builder = EventBuilderV10::new() + .id(unique_id) + .subject(topic) + .source(source) + .ty(ProtocolKey::CLOUD_EVENTS_PROTOCOL_NAME) + .data(DataContentType::JSON, content); + + for (key, value) in cloud_event.attributes { + builder = builder.extension(key.as_str(), value.attr.clone().unwrap().to_string()); + } + + builder.build().unwrap() + } + + #[allow(dead_code)] + pub(crate) fn switch_cloud_event_2_event_mesh_message(cloud_event: Event) -> EventMeshMessage { + let mut prop = HashMap::new(); + cloud_event.iter_attributes().for_each(|(key, value)| { + prop.insert(key.to_string(), value.to_string()); + }); + let topic = cloud_event.subject().unwrap().to_string(); + let biz_seq_no = cloud_event + .extension(ProtocolKey::SEQ_NUM) + .unwrap() + .to_string(); + let unique_id = cloud_event.id().to_string(); + let content = cloud_event.data().unwrap().to_string(); + EventMeshMessage { + biz_seq_no: Some(biz_seq_no), + unique_id: Some(unique_id), + topic: Some(topic), + content: Some(content), + prop, + create_time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_or_else(|_err| 0u64, |time| time.as_millis() as u64), + } + } + + pub fn get_seq_num(cloud_event: &PbCloudEvent) -> String { + cloud_event + .attributes + .get(ProtocolKey::SEQ_NUM) + .map_or_else( + || String::new(), + |ce| { + ce.attr + .clone() + .unwrap_or(PbAttr::CeString(String::new())) + .to_string() + }, + ) + } + + pub fn get_unique_id(cloud_event: &PbCloudEvent) -> String { + cloud_event + .attributes + .get(ProtocolKey::UNIQUE_ID) + .map_or_else( + || String::new(), + |ce| { + ce.attr + .clone() + .unwrap_or(PbAttr::CeString(String::new())) + .to_string() + }, + ) + } + + pub fn get_data_content(cloud_event: &PbCloudEvent) -> String { + cloud_event + .attributes + .get(ProtocolKey::DATA_CONTENT_TYPE) + .map_or_else( + || String::new(), + |ce| { + ce.attr + .clone() + .unwrap_or(PbAttr::CeString(String::new())) + .to_string() + }, + ) + } + + pub fn get_subject(cloud_event: &PbCloudEvent) -> String { + cloud_event + .attributes + .get(ProtocolKey::SUBJECT) + .map_or_else( + || String::new(), + |ce| { + ce.attr + .clone() + .unwrap_or(PbAttr::CeString(String::new())) + .to_string() + }, + ) + } + + pub fn get_text_data(cloud_event: &PbCloudEvent) -> String { + cloud_event + .data + .clone() + .unwrap_or(PbData::TextData(String::new())) + .to_string() + } + + pub fn get_source(cloud_event: &PbCloudEvent) -> String { + cloud_event.attributes.get(ProtocolKey::SOURCE).map_or_else( + || String::new(), + |ce| { + ce.attr + .clone() + .unwrap_or(PbAttr::CeString(String::new())) + .to_string() + }, + ) + } + + pub fn get_response(cloud_event: &PbCloudEvent) -> EventMeshResponse { + let code = cloud_event + .attributes + .get(ProtocolKey::GRPC_RESPONSE_CODE) + .map_or_else( + || None, + |val| { + if let Some(ref value) = val.attr { + Some(value.to_string()) + } else { + None + } + }, + ); + let msg = cloud_event + .attributes + .get(ProtocolKey::GRPC_RESPONSE_MESSAGE) + .map_or_else( + || None, + |val| { + if let Some(ref value) = val.attr { + Some(value.to_string()) + } else { + None + } + }, + ); + let time = cloud_event + .attributes + .get(ProtocolKey::GRPC_RESPONSE_TIME) + .map_or_else( + || None, + |val| { + if let Some(ref value) = val.attr { + Some(value.to_string().parse::().unwrap_or(0)) + } else { + None + } + }, + ); + EventMeshResponse::new(code, msg, time) + } + + pub fn get_ttl(cloud_event: &PbCloudEvent) -> String { + cloud_event.attributes.get(ProtocolKey::TTL).map_or_else( + || String::new(), + |ce| { + ce.attr + .clone() + .unwrap_or(PbAttr::CeString(String::new())) + .to_string() + }, + ) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/common/local_ip.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/common/local_ip.rs new file mode 100644 index 0000000000..4c46a2931d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/common/local_ip.rs @@ -0,0 +1,30 @@ +/* + * 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. + */ +use local_ip_address::local_ip; +use std::net::{IpAddr, Ipv4Addr}; + +/// Get local IPv4 address. +/// +/// Get local IPv4 address, fallback to 127.0.0.1 if failed. +/// +/// # Returns +/// +/// The local IPv4 address as string. +pub(crate) fn get_local_ip_v4() -> String { + let ip_addr = local_ip().unwrap_or(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + ip_addr.to_string() +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/common/protocol_key.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/common/protocol_key.rs new file mode 100644 index 0000000000..c4f4b27778 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/common/protocol_key.rs @@ -0,0 +1,66 @@ +/* + * 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. + */ +pub struct ProtocolKey; + +#[allow(dead_code)] +impl ProtocolKey { + // EventMesh extensions + pub const ENV: &'static str = "env"; + pub const IDC: &'static str = "idc"; + pub const SYS: &'static str = "sys"; + pub const PID: &'static str = "pid"; + pub const IP: &'static str = "ip"; + pub const USERNAME: &'static str = "username"; + pub const PASSWD: &'static str = "passwd"; + pub const LANGUAGE: &'static str = "language"; + pub const PROTOCOL_TYPE: &'static str = "protocoltype"; + pub const PROTOCOL_VERSION: &'static str = "protocolversion"; + pub const PROTOCOL_DESC: &'static str = "protocoldesc"; + pub const SEQ_NUM: &'static str = "seqnum"; + pub const UNIQUE_ID: &'static str = "uniqueid"; + pub const TTL: &'static str = "ttl"; + pub const PRODUCERGROUP: &'static str = "producergroup"; + pub const CONSUMERGROUP: &'static str = "consumergroup"; + pub const TAG: &'static str = "tag"; + pub const CONTENT_TYPE: &'static str = "contenttype"; + pub const PROPERTY_MESSAGE_CLUSTER: &'static str = "cluster"; + pub const URL: &'static str = "url"; + pub const CLIENT_TYPE: &'static str = "clienttype"; + pub const GRPC_RESPONSE_CODE: &'static str = "status_code"; + pub const GRPC_RESPONSE_MESSAGE: &'static str = "response_message"; + pub const GRPC_RESPONSE_TIME: &'static str = "time"; + + pub const SUB_MESSAGE_TYPE: &'static str = "submessagetype"; + + // CloudEvents spec + pub const ID: &'static str = "id"; + pub const SOURCE: &'static str = "source"; + pub const SPECVERSION: &'static str = "specversion"; + pub const TYPE: &'static str = "type"; + pub const DATA_CONTENT_TYPE: &'static str = "datacontenttype"; + pub const DATA_SCHEMA: &'static str = "dataschema"; + pub const SUBJECT: &'static str = "subject"; + pub const TIME: &'static str = "time"; + pub const EVENT_DATA: &'static str = "eventdata"; + + //protocol desc + pub const PROTOCOL_DESC_GRPC_CLOUD_EVENT: &'static str = "grpc-cloud-event"; + + pub const CLOUD_EVENTS_PROTOCOL_NAME: &'static str = "cloudevents"; + + pub const CLOUDEVENT_CONTENT_TYPE: &'static str = "application/cloudevents+json"; +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/common/random_string_util.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/common/random_string_util.rs new file mode 100644 index 0000000000..71c48a7248 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/common/random_string_util.rs @@ -0,0 +1,53 @@ +/* + * 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. + */ +use rand::distributions::Alphanumeric; +use rand::Rng; +use std::iter; +use uuid; + +pub struct RandomStringUtils; + +impl RandomStringUtils { + /// Generate a random alphanumeric string. + /// + /// Generate a random string with given length, containing alphanumeric characters. + /// + /// # Arguments + /// + /// * `length` - The length of generated string. + /// + /// # Returns + /// + /// The randomly generated string. + pub fn generate_num(length: usize) -> String { + let random_string = iter::repeat(()) + .map(|()| rand::thread_rng().sample(Alphanumeric) as char) + .take(length) + .collect(); + random_string + } + + /// Generate a random UUID string. + /// + /// # Returns + /// + /// The randomly generated UUID string. + pub fn generate_uuid() -> String { + let uuid = uuid::Uuid::new_v4(); + uuid.to_string() + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/config.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/config.rs new file mode 100644 index 0000000000..3deb30beb7 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/config.rs @@ -0,0 +1,26 @@ +/* + * 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. + */ + +//! Configurations. + +/// gRPC client configuration. +mod grpc_config; + +#[cfg(feature = "grpc")] + +/// Re-export gRPC client configuration when "grpc" feature is enabled. +pub use crate::config::grpc_config::EventMeshGrpcClientConfig; diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/config/grpc_config.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/config/grpc_config.rs new file mode 100644 index 0000000000..25855a0d7f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/config/grpc_config.rs @@ -0,0 +1,127 @@ +/* + * 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. + */ +#[derive(Debug, Clone)] +pub struct EventMeshGrpcClientConfig { + pub(crate) server_addr: String, + pub(crate) server_port: u32, + pub(crate) env: String, + pub(crate) consumer_group: Option, + pub(crate) producer_group: Option, + pub(crate) idc: String, + pub(crate) sys: String, + pub(crate) user_name: String, + pub(crate) password: String, + pub(crate) language: String, + pub(crate) use_tls: Option, + pub(crate) time_out: Option, +} + +impl Default for EventMeshGrpcClientConfig { + fn default() -> Self { + Self { + server_addr: "localhost".to_string(), + server_port: 10205, + env: "dev".to_string(), + consumer_group: Some("DefaultConsumerGroup".to_string()), + producer_group: Some("DefaultProducerGroup".to_string()), + idc: "default".to_string(), + sys: "evetmesh".to_string(), + user_name: "username".to_string(), + password: "password".to_string(), + language: "Rust".to_string(), + use_tls: Some(false), + time_out: Some(5000), + } + } +} + +impl ToString for EventMeshGrpcClientConfig { + fn to_string(&self) -> String { + format!( + "ClientConfig={{ServerAddr={},ServerPort={},env={:?},\ + idc={:?},producerGroup={:?},consumerGroup={:?},\ + sys={:?},userName={:?},password=***,\ + useTls={:?},timeOut={:?}}}", + self.server_addr, + self.server_port, + self.env, + self.idc, + self.producer_group, + self.consumer_group, + self.sys, + self.user_name, + self.use_tls, + self.time_out + ) + } +} + +#[allow(dead_code)] +impl EventMeshGrpcClientConfig { + pub fn new() -> Self { + Default::default() + } + + pub fn set_server_addr(mut self, server_addr: String) -> Self { + self.server_addr = server_addr; + self + } + pub fn set_server_port(mut self, server_port: u32) -> Self { + self.server_port = server_port; + self + } + pub fn set_env(mut self, env: String) -> Self { + self.env = env; + self + } + pub fn set_consumer_group(mut self, consumer_group: String) -> Self { + self.consumer_group = Some(consumer_group); + self + } + pub fn set_producer_group(mut self, producer_group: String) -> Self { + self.producer_group = Some(producer_group); + self + } + pub fn set_idc(mut self, idc: String) -> Self { + self.idc = idc; + self + } + pub fn set_sys(mut self, sys: String) -> Self { + self.sys = sys; + self + } + pub fn set_user_name(mut self, user_name: String) -> Self { + self.user_name = user_name; + self + } + pub fn set_password(mut self, password: String) -> Self { + self.password = password; + self + } + pub fn set_language(mut self, language: String) -> Self { + self.language = language; + self + } + pub fn set_use_tls(mut self, use_tls: bool) -> Self { + self.use_tls = Some(use_tls); + self + } + pub fn set_time_out(mut self, time_out: u64) -> Self { + self.time_out = Some(time_out); + self + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/error.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/error.rs new file mode 100644 index 0000000000..3315a0ae4f --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/error.rs @@ -0,0 +1,58 @@ +/* + * 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. + */ + +use std::fmt::{Display, Formatter}; +use thiserror::Error; + +#[allow(dead_code)] +#[derive(Debug, Error)] +pub enum EventMeshError { + /// Invalid arguments + InvalidArgs(String), + + /// gRpc status + #[cfg(feature = "grpc")] + GRpcStatus(#[from] tonic::Status), + + EventMeshLocal(String), + + EventMeshRemote(String), + + EventMeshFromStrError(String), +} + +impl Display for EventMeshError { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(feature = "grpc")] + EventMeshError::GRpcStatus(e) => write!(f, "grpc request error: {}", e), + EventMeshError::EventMeshLocal(ref err_msg) => { + write!(f, "EventMesh client error: {}", err_msg) + } + EventMeshError::EventMeshRemote(ref err_msg) => { + write!(f, "EventMesh remote error: {}", err_msg) + } + EventMeshError::EventMeshFromStrError(ref err_msg) => { + write!(f, "EventMesh Parse from String error: {}", err_msg) + } + EventMeshError::InvalidArgs(ref err_msg) => { + write!(f, "Invalid args: {}", err_msg) + } + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/grpc.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc.rs new file mode 100644 index 0000000000..30046f8c5a --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc.rs @@ -0,0 +1,34 @@ +/* + * 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. + */ + +//! gRPC client implementations. + +/// EventMesh message types. +pub(crate) mod r#impl; + +/// gRPC consumer client. +pub mod grpc_consumer; + +/// gRPC producer client. +pub mod grpc_producer; + +/// Protobuf generated definitions. +pub(crate) mod pb; + +#[cfg(feature = "grpc")] +/// Re-export gRPC eventmesh message producer when features enabled. +pub use crate::grpc::r#impl::grpc_producer_impl::GrpcEventMeshProducer; diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/grpc_consumer.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/grpc_consumer.rs new file mode 100644 index 0000000000..e31c97a530 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/grpc_consumer.rs @@ -0,0 +1,248 @@ +/* + * 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. + */ +use std::collections::HashMap; +use std::sync::Arc; +use std::time::Duration; + +use futures::lock::Mutex; +use tonic::codegen::tokio_stream::StreamExt; +use tracing::error; + +use crate::common::constants::{DataContentType, SDK_STREAM_URL}; +use crate::common::grpc_eventmesh_message_utils::EventMeshCloudEventUtils; +use crate::common::{ProtocolKey, ReceiveMessageListener}; +use crate::config::EventMeshGrpcClientConfig; +use crate::error::EventMeshError::{EventMeshLocal, InvalidArgs}; +use crate::model::message::EventMeshMessage; +use crate::model::response::EventMeshResponse; +use crate::model::subscription::{ + HeartbeatItem, SubscriptionItem, SubscriptionItemWrapper, SubscriptionReply, +}; +use crate::model::EventMeshProtocolType; +use crate::net::GrpcClient; +use crate::proto_cloud_event::{PbAttr, PbCloudEvent, PbCloudEventAttributeValue, PbData}; + +pub struct EventMeshGrpcConsumer { + inner: GrpcClient, + grpc_config: EventMeshGrpcClientConfig, + subscription_map: Arc>>, + listener: Arc>>, +} + +impl EventMeshGrpcConsumer { + pub fn new( + grpc_config: EventMeshGrpcClientConfig, + listener: Box>, + ) -> Self { + let client = GrpcClient::new(&grpc_config).unwrap(); + let subscription_map = Arc::new(Mutex::new(HashMap::with_capacity(16))); + let listener = Arc::new(listener); + let _ = EventMeshGrpcConsumer::heartbeat( + client.clone(), + grpc_config.clone(), + Arc::clone(&subscription_map), + ); + Self { + inner: client, + grpc_config, + subscription_map: Arc::clone(&subscription_map), + listener: Arc::clone(&listener), + } + } + + pub async fn subscribe_webhook( + &mut self, + subscription_items: Vec, + url: impl Into, + ) -> crate::Result { + if subscription_items.is_empty() { + return Err(InvalidArgs("subscription_items is empty".to_string()).into()); + } + let cloud_event = EventMeshCloudEventUtils::build_event_subscription( + &self.grpc_config, + EventMeshProtocolType::EventMeshMessage, + url.into().as_str(), + &subscription_items, + ); + if cloud_event.is_none() { + return Err( + EventMeshLocal("SubscriptionItem switch to CloudEvent error".to_string()).into(), + ); + } + let result = self + .inner + .subscribe_webhook_inner(cloud_event.unwrap()) + .await?; + Ok(EventMeshCloudEventUtils::get_response(&result)) + } + + pub async fn subscribe( + &mut self, + subscription_items: Vec, + ) -> crate::Result<()> { + if subscription_items.is_empty() { + return Err(InvalidArgs("subscription_items is empty".to_string()).into()); + } + + let map = self.subscription_map.clone(); + let mut guard = map.lock().await; + subscription_items.iter().for_each(|item| { + guard.insert( + item.topic.clone(), + SubscriptionItemWrapper { + subscription_item: item.clone(), + url: SDK_STREAM_URL.to_string(), + }, + ); + }); + let cloud_event = EventMeshCloudEventUtils::build_event_subscription( + &self.grpc_config, + EventMeshProtocolType::EventMeshMessage, + String::new().as_str(), + &subscription_items, + ); + if cloud_event.is_none() { + return Err( + EventMeshLocal("SubscriptionItem switch to CloudEvent error".to_string()).into(), + ); + } + let (keeper, mut resp_stream) = self.inner.subscribe_bi_inner(cloud_event.unwrap()).await?; + let listener_inner = Arc::clone(&self.listener); + tokio::spawn(async move { + while let Some(received) = resp_stream.next().await { + if let Err(status) = received { + error!("Subscribe receive error, status {}", status); + continue; + } + let mut received = received.unwrap(); + let eventmesh_message = + EventMeshCloudEventUtils::build_message_from_event_mesh_cloud_event::< + EventMeshMessage, + >(&received); + if eventmesh_message.is_none() { + continue; + } + received.attributes.insert( + ProtocolKey::DATA_CONTENT_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::JSON.to_string())), + }, + ); + + let handled_msg = listener_inner.handle(eventmesh_message.unwrap()); + if let Ok(msg_option) = handled_msg { + if let Some(_msg) = msg_option { + received.attributes.insert( + ProtocolKey::SUB_MESSAGE_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + SubscriptionReply::SUB_TYPE.to_string(), + )), + }, + ); + received.data = None; + let _ = keeper.sender.send(received).await; + } + } else { + error!("Handle Receive error:{}", handled_msg.unwrap_err()) + } + } + }); + Ok(()) + } + + pub async fn unsubscribe( + &mut self, + unsubscription_items: Vec, + ) -> crate::Result { + if unsubscription_items.is_empty() { + return Err(InvalidArgs("unsubscription_items is empty".to_string()).into()); + } + let map = self.subscription_map.clone(); + let mut guard = map.lock().await; + unsubscription_items.iter().for_each(|item| { + guard.remove(item.topic.as_str()); + }); + let cloud_event = EventMeshCloudEventUtils::build_event_subscription( + &self.grpc_config, + EventMeshProtocolType::EventMeshMessage, + String::new().as_str(), + &unsubscription_items, + ); + if cloud_event.is_none() { + return Err( + EventMeshLocal("SubscriptionItem switch to CloudEvent error".to_string()).into(), + ); + } + let result = self.inner.unsubscribe_inner(cloud_event.unwrap()).await?; + Ok(EventMeshCloudEventUtils::get_response(&result)) + } + + fn heartbeat( + mut client: GrpcClient, + grpc_config: EventMeshGrpcClientConfig, + subscription_map: Arc>>, + ) -> crate::Result<()> { + tokio::spawn(async move { + loop { + tokio::time::sleep(Duration::from_secs(20)).await; + let mut attributes = EventMeshCloudEventUtils::build_common_cloud_event_attributes( + &grpc_config, + EventMeshProtocolType::EventMeshMessage, + ); + attributes.insert( + ProtocolKey::CONSUMERGROUP.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString( + grpc_config.consumer_group.clone().unwrap(), + )), + }, + ); + attributes.insert( + ProtocolKey::CLIENT_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeInteger(2)), + }, + ); + attributes.insert( + ProtocolKey::DATA_CONTENT_TYPE.to_string(), + PbCloudEventAttributeValue { + attr: Some(PbAttr::CeString(DataContentType::JSON.to_string())), + }, + ); + + let map = subscription_map.lock().await; + let heartbeat_items = map + .iter() + .filter_map(|(key, value)| { + Some(HeartbeatItem { + topic: key.to_string(), + url: value.url.clone(), + }) + }) + .collect::>(); + let mut cloud_event = PbCloudEvent::default(); + cloud_event.attributes = attributes; + cloud_event.data = Some(PbData::TextData( + serde_json::to_string(&heartbeat_items).unwrap(), + )); + let _result = client.heartbeat_inner(cloud_event).await; + } + }); + Ok(()) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/grpc_producer.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/grpc_producer.rs new file mode 100644 index 0000000000..867588fb88 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/grpc_producer.rs @@ -0,0 +1,39 @@ +/* + * 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. + */ +//! Trait for gRPC eventmesh producer. + +use crate::model::response::EventMeshResponse; +use std::future::Future; + +/// Trait for gRPC eventmesh producer. +pub trait EventMeshGrpcProducer { + /// Publish a message. + fn publish(&mut self, message: M) -> impl Future>; + + /// Publish a batch of messages. + fn publish_batch( + &mut self, + messages: Vec, + ) -> impl Future>; + + /// Request reply for a message. + fn request_reply( + &mut self, + message: M, + time_out: u64, + ) -> impl Future>; +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/impl.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/impl.rs new file mode 100644 index 0000000000..edb47941c5 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/impl.rs @@ -0,0 +1,19 @@ +/* + * 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. + */ + +#[cfg(feature = "grpc")] +pub mod grpc_producer_impl; diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/impl/grpc_producer_impl.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/impl/grpc_producer_impl.rs new file mode 100644 index 0000000000..f81c3f65e7 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/impl/grpc_producer_impl.rs @@ -0,0 +1,159 @@ +/* + * 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. + */ +use std::any::Any; +use std::fmt::Debug; +use std::marker::PhantomData; + +use tonic::transport::Uri; + +use crate::common::constants::{DataContentType, DEFAULT_EVENTMESH_MESSAGE_TTL}; +use crate::common::grpc_eventmesh_message_utils::EventMeshCloudEventUtils; +use crate::config::EventMeshGrpcClientConfig; +use crate::error::EventMeshError; +use crate::grpc::grpc_producer::EventMeshGrpcProducer; +use crate::model::message::EventMeshMessage; +use crate::model::response::EventMeshResponse; +use crate::model::EventMeshProtocolType; +use crate::net::GrpcClient; +use crate::proto_cloud_event::{ + EventMeshCloudEventBuilder, PbCloudEvent, PbCloudEventBatch, PbData, +}; + +/// gRPC EventMesh message producer. +pub struct GrpcEventMeshProducer { + /// gRPC client. + inner: GrpcClient, + + /// gRPC configuration. + grpc_config: EventMeshGrpcClientConfig, + + _mark: PhantomData, +} + +impl GrpcEventMeshProducer +where + M: Any, +{ + pub fn new(grpc_config: EventMeshGrpcClientConfig) -> Self { + let client = GrpcClient::new(&grpc_config).unwrap(); + Self { + inner: client, + grpc_config, + _mark: PhantomData::, + } + } + + #[allow(dead_code)] + fn build_event_mesh_cloud_event(&mut self, message: EventMeshMessage) -> PbCloudEvent { + let mut event = EventMeshCloudEventBuilder::default() + .with_env(self.grpc_config.env.clone()) + .with_idc(self.grpc_config.idc.clone()) + .with_ip(crate::common::local_ip::get_local_ip_v4()) + .with_pid(std::process::id().to_string()) + .with_sys(self.grpc_config.sys.clone()) + .with_user_name(self.grpc_config.user_name.clone()) + .with_password(self.grpc_config.password.clone()) + .with_language("Rust") + .with_protocol_type(EventMeshProtocolType::CloudEvents.protocol_type_name()) + .with_ttl(DEFAULT_EVENTMESH_MESSAGE_TTL.to_string()) + .with_subject(message.biz_seq_no.clone().unwrap()) + .with_producergroup( + self.grpc_config + .producer_group + .clone() + .map_or_else(|| String::from("Default_Producer_Group"), |val| val) + .clone(), + ) + .with_uniqueid(message.unique_id.unwrap()) + .with_data_content_type(DataContentType::TEXT_PLAIN) + .build(); + event.id = message.biz_seq_no.clone().unwrap(); + event.source = Uri::builder() + .path_and_query("/") + .build() + .unwrap() + .to_string(); + event.spec_version = "1.0".to_string(); + event.r#type = "Rust".to_string(); + event.data = Some(PbData::TextData(message.content.unwrap().into())); + event + } + + fn build_event_mesh_cloud_event_batch( + &mut self, + messages: Vec, + ) -> Option { + if messages.is_empty() { + return None; + } + + let events = messages + .into_iter() + .map(|msg| { + EventMeshCloudEventUtils::build_event_mesh_cloud_event(msg, &self.grpc_config) + .unwrap() + }) + .collect(); + + let mut cloud_event_batch = PbCloudEventBatch::default(); + cloud_event_batch.events = events; + + Some(cloud_event_batch) + } +} + +/// gRPC EventMesh message producer implementation. +#[allow(unused_variables)] +impl EventMeshGrpcProducer for GrpcEventMeshProducer +where + M: Any + Debug + From, +{ + /// Publish a message. + async fn publish(&mut self, message: M) -> crate::Result { + let event = + EventMeshCloudEventUtils::build_event_mesh_cloud_event(message, &self.grpc_config); + if event.is_none() { + return Err(EventMeshError::EventMeshLocal( + "Create Event Mesh cloud event Error".to_string(), + ) + .into()); + } + let result = self.inner.publish_inner(event.unwrap()).await?; + Ok(EventMeshCloudEventUtils::get_response(&result)) + } + + /// Publish a batch of messages. + async fn publish_batch(&mut self, messages: Vec) -> crate::Result { + let events = self.build_event_mesh_cloud_event_batch(messages); + if events.is_none() { + return Err(EventMeshError::EventMeshLocal("Vec is empty".to_string()).into()); + } + let result = self.inner.batch_publish_inner(events.unwrap()).await?; + Ok(EventMeshCloudEventUtils::get_response(&result)) + } + + /// Request reply for a message. + async fn request_reply(&mut self, message: M, time_out: u64) -> crate::Result { + let event = + EventMeshCloudEventUtils::build_event_mesh_cloud_event(message, &self.grpc_config); + let result = self + .inner + .request_reply_inner(event.unwrap(), time_out) + .await?; + Ok(EventMeshCloudEventUtils::build_message_from_event_mesh_cloud_event(&result).unwrap()) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/pb.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/pb.rs new file mode 100644 index 0000000000..26e69e91a9 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/grpc/pb.rs @@ -0,0 +1,19 @@ +/* + * 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. + */ +pub mod cloud_events { + tonic::include_proto!("org.apache.eventmesh.cloudevents.v1"); +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/lib.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/lib.rs new file mode 100644 index 0000000000..a03f8cfa2d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/lib.rs @@ -0,0 +1,323 @@ +/* + * 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. + */ +//! +//! + +/// Re-export eventmesh main. +pub use eventmesh::main; +/// Re-export eventmesh as tokio. +pub use tokio as eventmesh; + +/// Shorthand for `anyhow::Result`. +pub type Result = anyhow::Result; + +// Modules + +/// Configurations. +pub mod config; + +/// Errors. +pub(crate) mod error; + +/// Network utils. +mod net; + +/// Common utilities. +pub mod common; + +/// gRPC client implementations. +pub mod grpc; + +/// Logging. +pub mod log; + +/// Data models. +pub mod model; + +/// Module contains Protobuf CloudEvent related types and builder. +pub mod proto_cloud_event { + use cloudevents::Event; + + use crate::common::ProtocolKey; + /// Protobuf CloudEvent attribute value enum. + pub use crate::grpc::pb::cloud_events::cloud_event::cloud_event_attribute_value::Attr as PbAttr; + use crate::grpc::pb::cloud_events::cloud_event::cloud_event_attribute_value::Attr; + pub use crate::grpc::pb::cloud_events::cloud_event::CloudEventAttributeValue as PbCloudEventAttributeValue; + pub use crate::grpc::pb::cloud_events::cloud_event::Data as PbData; + use crate::grpc::pb::cloud_events::cloud_event::{CloudEventAttributeValue, Data}; + /// Protobuf CloudEvent message. + pub use crate::grpc::pb::cloud_events::{ + CloudEvent as PbCloudEvent, CloudEventBatch as PbCloudEventBatch, + }; + use crate::model::message::EventMeshMessage; + + impl ToString for PbAttr { + /// Convert Protobuf attribute to String. + fn to_string(&self) -> String { + match self { + Attr::CeBoolean(value) => value.to_string(), + Attr::CeInteger(value) => value.to_string(), + Attr::CeString(value) => value.clone(), + Attr::CeBytes(value) => unsafe { String::from_utf8_unchecked(value.clone()) }, + Attr::CeUri(value) => value.clone(), + Attr::CeUriRef(value) => value.clone(), + Attr::CeTimestamp(value) => value.to_string(), + } + } + } + + impl From for PbCloudEvent { + fn from(_value: EventMeshMessage) -> Self { + todo!() + } + } + + impl From for PbCloudEvent { + fn from(_value: Event) -> Self { + todo!() + } + } + + impl ToString for PbData { + /// Convert Protobuf data to String. + fn to_string(&self) -> String { + match self { + Data::BinaryData(value) => unsafe { String::from_utf8_unchecked(value.clone()) }, + Data::TextData(value) => value.clone(), + Data::ProtoData(value) => unsafe { + String::from_utf8_unchecked(value.value.clone()) + }, + } + } + } + + /// Builder for constructing Protobuf CloudEvent. + #[derive(Debug, Default)] + pub struct EventMeshCloudEventBuilder { + /// Environment attribute. + pub(crate) env: String, + + /// IDC attribute. + pub(crate) idc: String, + + /// IP address attribute. + pub(crate) ip: String, + + /// Optional process ID attribute. + pub(crate) pid: Option, + + /// System attribute. + pub(crate) sys: String, + + /// Username attribute. + pub(crate) user_name: String, + + /// Password attribute. + pub(crate) password: String, + + /// Language attribute. + pub(crate) language: String, + + /// Protocol type attribute. + pub(crate) protocol_type: String, + + /// Protocol version attribute. + pub(crate) protocol_version: String, + + /// TTL attribute. + pub(crate) ttl: String, + + /// Subject attribute. + pub(crate) subject: String, + + /// Producer group attribute. + pub(crate) producergroup: String, + + /// Unique ID attribute. + pub(crate) uniqueid: String, + + /// Data content type attribute. + pub(crate) data_content_type: String, + } + + impl EventMeshCloudEventBuilder { + /// Set process ID attribute. + pub fn with_pid(mut self, pid: impl Into) -> Self { + self.pid = Some(pid.into()); + self + } + + /// Set environment attribute. + pub fn with_env(mut self, env: impl Into) -> Self { + self.env = env.into(); + self + } + + /// Set IDC attribute. + pub fn with_idc(mut self, idc: impl Into) -> Self { + self.idc = idc.into(); + self + } + + /// Set IP address attribute. + pub fn with_ip(mut self, ip: impl Into) -> Self { + self.ip = ip.into(); + self + } + + /// Set system attribute. + pub fn with_sys(mut self, sys: impl Into) -> Self { + self.sys = sys.into(); + self + } + + /// Set username attribute. + pub fn with_user_name(mut self, user_name: impl Into) -> Self { + self.user_name = user_name.into(); + self + } + + /// Set password attribute. + pub fn with_password(mut self, password: impl Into) -> Self { + self.password = password.into(); + self + } + + /// Set language attribute. + pub fn with_language(mut self, language: impl Into) -> Self { + self.language = language.into(); + self + } + + /// Set protocol type attribute. + pub fn with_protocol_type(mut self, protocol_type: impl Into) -> Self { + self.protocol_type = protocol_type.into(); + self + } + + /// Set protocol version attribute. + pub fn with_protocol_version(mut self, protocol_version: impl Into) -> Self { + self.protocol_version = protocol_version.into(); + self + } + + /// Set TTL attribute. + pub fn with_ttl(mut self, ttl: impl Into) -> Self { + self.ttl = ttl.into(); + self + } + + /// Set subject attribute. + pub fn with_subject(mut self, subject: impl Into) -> Self { + self.subject = subject.into(); + self + } + + /// Set producer group attribute. + pub fn with_producergroup(mut self, producergroup: impl Into) -> Self { + self.producergroup = producergroup.into(); + self + } + + /// Set unique ID attribute. + pub fn with_uniqueid(mut self, uniqueid: impl Into) -> Self { + self.uniqueid = uniqueid.into(); + self + } + + /// Set data content type attribute. + pub fn with_data_content_type(mut self, data_content_type: impl Into) -> Self { + self.data_content_type = data_content_type.into(); + self + } + + /// Build the Protobuf CloudEvent + pub fn build(&self) -> PbCloudEvent { + let mut cloud_event = PbCloudEvent::default(); + cloud_event.attributes.insert( + ProtocolKey::ENV.to_string(), + Self::build_cloud_event_attr(&self.env), + ); + cloud_event.attributes.insert( + ProtocolKey::IDC.to_string(), + Self::build_cloud_event_attr(&self.idc), + ); + cloud_event.attributes.insert( + ProtocolKey::IP.to_string(), + Self::build_cloud_event_attr(&self.ip), + ); + if let Some(ref pid) = self.pid { + cloud_event.attributes.insert( + ProtocolKey::PID.to_string(), + Self::build_cloud_event_attr(pid), + ); + } + cloud_event.attributes.insert( + ProtocolKey::SYS.to_string(), + Self::build_cloud_event_attr(&self.sys), + ); + cloud_event.attributes.insert( + ProtocolKey::LANGUAGE.to_string(), + Self::build_cloud_event_attr(&self.language), + ); + cloud_event.attributes.insert( + ProtocolKey::USERNAME.to_string(), + Self::build_cloud_event_attr(&self.user_name), + ); + cloud_event.attributes.insert( + ProtocolKey::PASSWD.to_string(), + Self::build_cloud_event_attr(&self.password), + ); + cloud_event.attributes.insert( + ProtocolKey::PROTOCOL_TYPE.to_string(), + Self::build_cloud_event_attr(&self.protocol_type), + ); + cloud_event.attributes.insert( + ProtocolKey::PROTOCOL_VERSION.to_string(), + Self::build_cloud_event_attr(&self.protocol_version), + ); + cloud_event.attributes.insert( + ProtocolKey::TTL.to_string(), + Self::build_cloud_event_attr(&self.ttl), + ); + cloud_event.attributes.insert( + ProtocolKey::SUBJECT.to_string(), + Self::build_cloud_event_attr(&self.subject), + ); + cloud_event.attributes.insert( + ProtocolKey::PRODUCERGROUP.to_string(), + Self::build_cloud_event_attr(&self.producergroup), + ); + cloud_event.attributes.insert( + ProtocolKey::UNIQUE_ID.to_string(), + Self::build_cloud_event_attr(&self.uniqueid), + ); + cloud_event.attributes.insert( + ProtocolKey::DATA_CONTENT_TYPE.to_string(), + Self::build_cloud_event_attr(&self.data_content_type), + ); + cloud_event + } + + /// Helper method to build a Protobuf CloudEvent attribute value. + fn build_cloud_event_attr(value: impl Into) -> CloudEventAttributeValue { + let mut attr_value = PbCloudEventAttributeValue::default(); + attr_value.attr = Some(PbAttr::CeString(value.into())); + attr_value + } + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/log.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/log.rs new file mode 100644 index 0000000000..87f39217bc --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/log.rs @@ -0,0 +1,26 @@ +/* + * 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. + */ + +pub fn init_logger() { + tracing_subscriber::fmt() + .with_thread_names(true) + .with_level(true) + .with_line_number(true) + .with_thread_ids(true) + .with_max_level(tracing::Level::INFO) + .init(); +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/model.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/model.rs new file mode 100644 index 0000000000..299c11147a --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/model.rs @@ -0,0 +1,58 @@ +/* + * 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. + */ + +use std::fmt::{Display, Formatter}; + +#[derive(Debug)] +pub enum EventMeshProtocolType { + CloudEvents, + EventMeshMessage, + OpenMessage, +} + +impl Display for EventMeshProtocolType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + EventMeshProtocolType::CloudEvents => { + writeln!(f, "cloudevents") + } + EventMeshProtocolType::EventMeshMessage => { + writeln!(f, "eventmeshmessage") + } + EventMeshProtocolType::OpenMessage => { + writeln!(f, "openmessage") + } + } + } +} + +impl EventMeshProtocolType { + pub fn protocol_type_name(&self) -> &'static str { + match self { + EventMeshProtocolType::CloudEvents => "cloudevents", + EventMeshProtocolType::EventMeshMessage => "eventmeshmessage", + EventMeshProtocolType::OpenMessage => "openmessage", + } + } +} + +pub mod message; + +pub(crate) mod convert; +pub mod event_clouds; +pub(crate) mod response; +pub mod subscription; diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/model/convert.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/model/convert.rs new file mode 100644 index 0000000000..8a4901f6a4 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/model/convert.rs @@ -0,0 +1,32 @@ +/* + * 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. + */ + +use crate::proto_cloud_event::PbCloudEvent; + +/// Trait for converting from Protobuf CloudEvent to a type `T`. +pub trait FromPbCloudEvent { + /// Convert Protobuf CloudEvent to type `T`. + /// + /// # Arguments + /// + /// * `event` - The Protobuf CloudEvent to convert from. + /// + /// # Returns + /// + /// Optional converted value of type `T`. + fn from_pb_cloud_event(event: &PbCloudEvent) -> Option; +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/model/event_clouds.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/model/event_clouds.rs new file mode 100644 index 0000000000..324ea00a94 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/model/event_clouds.rs @@ -0,0 +1,28 @@ +/* + * 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. + */ + + use crate::common::grpc_eventmesh_message_utils::EventMeshCloudEventUtils; + use cloudevents::Event; + + use crate::proto_cloud_event::PbCloudEvent; + + impl From for Event { + fn from(value: PbCloudEvent) -> Self { + EventMeshCloudEventUtils::switch_event_mesh_cloud_event_2_cloud_event(value) + } + } + \ No newline at end of file diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/model/message.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/model/message.rs new file mode 100644 index 0000000000..a3c42e6f06 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/model/message.rs @@ -0,0 +1,206 @@ +/* + * 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. + */ + +#![cfg(feature = "eventmesh_message")] + +#[allow(unused_imports)] +use cloudevents::Event; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt; +use std::time::{SystemTime, UNIX_EPOCH}; + +use crate::common::grpc_eventmesh_message_utils::EventMeshCloudEventUtils; +use crate::model::convert::FromPbCloudEvent; +use crate::proto_cloud_event::PbCloudEvent; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct EventMeshMessage { + #[serde(rename = "bizSeqNo")] + pub(crate) biz_seq_no: Option, + #[serde(rename = "uniqueId")] + pub(crate) unique_id: Option, + pub(crate) topic: Option, + pub(crate) content: Option, + pub(crate) prop: HashMap, + #[serde(rename = "createTime")] + pub(crate) create_time: u64, +} + +impl fmt::Display for EventMeshMessage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "EventMeshMessage {{")?; + if let Some(biz_seq_no) = &self.biz_seq_no { + write!(f, " biz_seq_no: {},", biz_seq_no)?; + } + if let Some(unique_id) = &self.unique_id { + write!(f, " unique_id: {},", unique_id)?; + } + if let Some(topic) = &self.topic { + write!(f, " topic: {},", topic)?; + } + if let Some(content) = &self.content { + write!(f, " content: {},", content)?; + } + write!(f, " prop: {{")?; + for (key, value) in &self.prop { + write!(f, " {}: {},", key, value)?; + } + write!(f, " }},")?; + write!(f, " create_time: {},", self.create_time)?; + write!(f, " }}") + } +} +impl Default for EventMeshMessage { + fn default() -> Self { + Self { + biz_seq_no: None, + unique_id: None, + topic: None, + content: None, + prop: HashMap::with_capacity(0), + create_time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_or_else(|_err| 0u64, |time| time.as_millis() as u64), + } + } +} + +#[allow(dead_code)] +impl EventMeshMessage { + pub fn new( + biz_seq_no: impl Into, + unique_id: impl Into, + topic: impl Into, + content: impl Into, + prop: HashMap, + create_time: u64, + ) -> Self { + Self { + biz_seq_no: Some(biz_seq_no.into()), + unique_id: Some(unique_id.into()), + topic: Some(topic.into()), + content: Some(content.into()), + prop, + create_time, + } + } + + pub fn add_prop(mut self, key: String, val: String) -> Self { + self.prop.insert(key, val); + self + } + + pub fn get_prop(&self, key: &str) -> Option<&String> { + self.prop.get(key) + } + + pub fn remove_prop_if_present(mut self, key: &str) -> Self { + self.prop.remove(key); + self + } + + pub fn with_biz_seq_no(mut self, biz_seq_no: impl Into) -> Self { + self.biz_seq_no = Some(biz_seq_no.into()); + self + } + + pub fn with_unique_id(mut self, unique_id: impl Into) -> Self { + self.unique_id = Some(unique_id.into()); + self + } + + pub fn with_topic(mut self, topic: impl Into) -> Self { + self.topic = Some(topic.into()); + self + } + + pub fn with_content(mut self, content: impl Into) -> Self { + self.content = Some(content.into()); + self + } + + pub fn with_create_time(mut self, create_time: u64) -> Self { + self.create_time = create_time; + self + } +} + +impl FromPbCloudEvent for EventMeshMessage { + fn from_pb_cloud_event(event: &PbCloudEvent) -> Option { + Some(EventMeshCloudEventUtils::switch_event_mesh_cloud_event_2_event_mesh_message(event)) + } +} + +impl From for EventMeshMessage { + fn from(value: PbCloudEvent) -> Self { + EventMeshCloudEventUtils::switch_event_mesh_cloud_event_2_event_mesh_message(&value) + } +} + +#[cfg(feature = "cloud_events")] +impl From for EventMeshMessage { + fn from(value: Event) -> Self { + EventMeshCloudEventUtils::switch_cloud_event_2_event_mesh_message(value) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default() { + let default_msg = EventMeshMessage::default(); + + assert_eq!(default_msg.biz_seq_no, None); + assert_eq!(default_msg.unique_id, None); + assert_eq!(default_msg.topic, None); + assert_eq!(default_msg.content, None); + assert!(default_msg.prop.is_empty()); + } + + #[test] + fn test_new() { + let msg = EventMeshMessage::new( + "biz_seq_123", + "unique_456", + "test_topic", + "message_content", + HashMap::new(), + 1234567890, + ); + + assert_eq!(msg.biz_seq_no, Some("biz_seq_123".to_string())); + assert_eq!(msg.unique_id, Some("unique_456".to_string())); + assert_eq!(msg.topic, Some("test_topic".to_string())); + assert_eq!(msg.content, Some("message_content".to_string())); + assert!(msg.prop.is_empty()); + assert_eq!(msg.create_time, 1234567890); + } + + #[test] + fn test_add_prop() { + let mut msg = EventMeshMessage::default(); + + msg = msg.add_prop("key1".to_string(), "value1".to_string()); + msg = msg.add_prop("key2".to_string(), "value2".to_string()); + + assert_eq!(msg.get_prop("key1"), Some(&"value1".to_string())); + assert_eq!(msg.get_prop("key2"), Some(&"value2".to_string())); + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/model/response.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/model/response.rs new file mode 100644 index 0000000000..6e269623cb --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/model/response.rs @@ -0,0 +1,63 @@ +/* + * 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. + */ + +use std::fmt::{Display, Formatter}; + +use serde::Deserialize; + +#[derive(Debug, Deserialize, Default)] +pub struct EventMeshResponse { + #[serde(rename = "respCode")] + resp_code: Option, + + #[serde(rename = "respMsg")] + resp_msg: Option, + + #[serde(rename = "respTime")] + resp_time: Option, +} + +impl EventMeshResponse { + pub fn new( + resp_code: Option, + resp_msg: Option, + resp_time: Option, + ) -> Self { + Self { + resp_code, + resp_msg, + resp_time, + } + } +} + +impl Display for EventMeshResponse { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "EventMeshResponse[")?; + if let Some(ref code) = self.resp_code { + write!(f, "code={code},")?; + } + if let Some(ref msg) = self.resp_msg { + write!(f, "message={msg},")?; + } + if let Some(time) = self.resp_time { + write!(f, "response time={time},")?; + } + write!(f, "]")?; + Ok(()) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/model/subscription.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/model/subscription.rs new file mode 100644 index 0000000000..a31cd3b90d --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/model/subscription.rs @@ -0,0 +1,277 @@ +/* + * 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. + */ +use std::collections::HashMap; +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; + +use serde::{Deserialize, Serialize}; + +use crate::error::EventMeshError; + +#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Hash, Clone)] +pub struct SubscriptionItem { + pub topic: String, + pub mode: SubscriptionMode, + #[serde(rename = "type")] + pub type_: SubscriptionType, +} + +impl SubscriptionItem { + pub fn new(topic: impl Into, mode: SubscriptionMode, type_: SubscriptionType) -> Self { + SubscriptionItem { + topic: topic.into(), + mode, + type_, + } + } +} + +impl fmt::Display for SubscriptionItem { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "SubscriptionItem {{ topic: {}, mode: {}, type: {} }}", + self.topic, self.mode, self.type_ + ) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Hash)] +pub enum SubscriptionMode { + BROADCASTING, + CLUSTERING, + UNRECOGNIZED, +} + +impl Display for SubscriptionMode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!(f, "{}", self.to_string()) + } +} + +impl SubscriptionMode { + pub fn to_string(&self) -> &'static str { + match self { + SubscriptionMode::BROADCASTING => "BROADCASTING", + SubscriptionMode::CLUSTERING => "CLUSTERING", + SubscriptionMode::UNRECOGNIZED => "UNRECOGNIZED", + } + } + + fn from_str_inner(input: &str) -> Result { + match input { + "BROADCASTING" => Ok(SubscriptionMode::BROADCASTING), + "CLUSTERING" => Ok(SubscriptionMode::CLUSTERING), + "UNRECOGNIZED" => Ok(SubscriptionMode::UNRECOGNIZED), + _ => Err(EventMeshError::EventMeshFromStrError(format!( + "{} can not parse to SubscriptionMode", + input + ))), + } + } +} + +impl FromStr for SubscriptionMode { + type Err = EventMeshError; + + fn from_str(s: &str) -> Result { + Self::from_str_inner(s) + } +} + +impl TryFrom for SubscriptionMode { + type Error = EventMeshError; + + fn try_from(value: String) -> Result { + Self::from_str_inner(value.as_str()) + } +} + +impl TryFrom<&'static str> for SubscriptionMode { + type Error = EventMeshError; + + fn try_from(value: &'static str) -> Result { + Self::from_str_inner(value) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Hash)] +pub enum SubscriptionType { + SYNC, + ASYNC, + UNRECOGNIZED, +} + +impl Display for SubscriptionType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!(f, "{}", self.to_string()) + } +} + +impl SubscriptionType { + pub fn to_string(&self) -> &'static str { + match self { + SubscriptionType::SYNC => "SYNC", + SubscriptionType::ASYNC => "ASYNC", + SubscriptionType::UNRECOGNIZED => "UNRECOGNIZED", + } + } + + fn from_str_inner(s: &str) -> Result { + match s { + "SYNC" => Ok(SubscriptionType::SYNC), + "ASYNC" => Ok(SubscriptionType::ASYNC), + "UNRECOGNIZED" => Ok(SubscriptionType::UNRECOGNIZED), + _ => Err(EventMeshError::EventMeshFromStrError(format!( + "{} can not parse to SubscriptionMode", + s + ))), + } + } +} + +impl FromStr for SubscriptionType { + type Err = EventMeshError; + + fn from_str(s: &str) -> Result { + Self::from_str_inner(s) + } +} + +impl TryFrom for SubscriptionType { + type Error = EventMeshError; + + fn try_from(value: String) -> Result { + Self::from_str_inner(value.as_str()) + } +} + +impl TryFrom<&'static str> for SubscriptionType { + type Error = EventMeshError; + + fn try_from(value: &'static str) -> Result { + Self::from_str_inner(value) + } +} + +#[derive(Debug)] +pub(crate) struct SubscriptionItemWrapper { + pub(crate) subscription_item: SubscriptionItem, + pub(crate) url: String, +} + +impl Display for SubscriptionItemWrapper { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!( + f, + "SubscriptionItem={},url={}", + self.subscription_item, self.url + ) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SubscriptionReply { + #[serde(rename = "producerGroup")] + pub(crate) producer_group: String, + pub(crate) topic: String, + pub(crate) content: String, + pub(crate) ttl: String, + #[serde(rename = "uniqueId")] + pub(crate) unique_id: String, + #[serde(rename = "seqNum")] + pub(crate) seq_num: String, + pub(crate) tag: Option, + pub(crate) properties: HashMap, +} + +impl SubscriptionReply { + pub const SUB_TYPE: &'static str = "subscription_reply"; + + pub fn new( + producer_group: String, + topic: String, + content: String, + ttl: String, + unique_id: String, + seq_num: String, + tag: Option, + properties: HashMap, + ) -> Self { + Self { + producer_group, + topic, + content, + ttl, + unique_id, + seq_num, + tag, + properties, + } + } +} + +impl ToString for SubscriptionReply { + fn to_string(&self) -> String { + format!( + "SubscriptionReply {{ + producer_group: {:?}, + topic: {:?}, + content: {:?}, + ttl: {:?}, + unique_id: {:?}, + seq_num: {:?}, + tag: {:?}, + properties: {:?} + }}", + self.producer_group, + self.topic, + self.content, + self.ttl, + self.unique_id, + self.seq_num, + self.tag, + self.properties + ) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct HeartbeatItem { + pub(crate) topic: String, + pub(crate) url: String, +} + +impl HeartbeatItem { + pub fn new(topic: String, url: String) -> Self { + Self { topic, url } + } +} + +impl Display for HeartbeatItem { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!( + f, + "HeartbeatItem {{ + topic: {}, + url: {} + }}", + self.url, self.topic + ) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/net.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/net.rs new file mode 100644 index 0000000000..1a1b09f320 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/net.rs @@ -0,0 +1,20 @@ +/* + * 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. + */ +#![allow(unused_imports)] +pub use crate::net::grpc::grpc_client::GrpcClient; +pub use crate::net::grpc::grpc_client::SubscribeStreamKeeper; +mod grpc; diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/net/grpc.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/net/grpc.rs new file mode 100644 index 0000000000..54ddb9a238 --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/net/grpc.rs @@ -0,0 +1,17 @@ +/* + * 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. + */ +pub(crate) mod grpc_client; diff --git a/eventmesh-sdks/eventmesh-sdk-rust/src/net/grpc/grpc_client.rs b/eventmesh-sdks/eventmesh-sdk-rust/src/net/grpc/grpc_client.rs new file mode 100644 index 0000000000..8d4a376f0b --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/src/net/grpc/grpc_client.rs @@ -0,0 +1,212 @@ +/* + * 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. + */ +use std::time::Duration; + +use tokio::sync::mpsc; +use tokio::sync::mpsc::Sender; +use tonic::codegen::tokio_stream::wrappers::ReceiverStream; +use tonic::transport::{Channel, Endpoint, Uri}; +use tonic::{Request, Streaming}; + +use crate::common::ProtocolKey; +use crate::config::EventMeshGrpcClientConfig; +use crate::error::EventMeshError; +use crate::error::EventMeshError::EventMeshRemote; +use crate::grpc::pb::cloud_events::cloud_event::cloud_event_attribute_value::Attr; +use crate::grpc::pb::cloud_events::consumer_service_client::ConsumerServiceClient; +use crate::grpc::pb::cloud_events::heartbeat_service_client::HeartbeatServiceClient; +use crate::grpc::pb::cloud_events::publisher_service_client::PublisherServiceClient; +use crate::proto_cloud_event::{PbCloudEvent, PbCloudEventBatch}; + +pub struct SubscribeStreamKeeper { + pub(crate) sender: Sender, +} + +impl SubscribeStreamKeeper { + pub(crate) fn new(sender: Sender) -> Self { + Self { sender } + } +} + +#[derive(Clone)] +pub struct GrpcClient { + publisher_inner: PublisherServiceClient, + consumer_inner: ConsumerServiceClient, + heartbeat_inner: HeartbeatServiceClient, +} + +impl GrpcClient { + pub fn new(grpc_config: &EventMeshGrpcClientConfig) -> crate::Result { + #[cfg(feature = "tls")] + let scheme = { "https" }; + + #[cfg(not(feature = "tls"))] + let scheme = { + if let Some(tls) = grpc_config.use_tls { + if tls { + "https" + } else { + "http" + } + } else { + "http" + } + }; + let url = format!("{}:{}", grpc_config.server_addr, grpc_config.server_port); + let endpoint_uri = Uri::builder() + .scheme(scheme) + .authority(url) + .path_and_query("/") + .build()?; + let endpoint = Endpoint::from(endpoint_uri) + .connect_timeout(Duration::from_millis(10000)) + .keep_alive_while_idle(true) + .tcp_nodelay(true) + .tcp_keepalive(Some(Duration::from_secs(100))); + + let channel = endpoint.connect_lazy(); + let publisher_service_client = PublisherServiceClient::new(channel.clone()); + let consumer_service_client = ConsumerServiceClient::new(channel.clone()); + let heartbeat_inner_client = HeartbeatServiceClient::new(channel); + Ok(Self { + publisher_inner: publisher_service_client, + consumer_inner: consumer_service_client, + heartbeat_inner: heartbeat_inner_client, + }) + } + + pub(crate) async fn publish_inner( + &mut self, + cloud_event: PbCloudEvent, + ) -> crate::Result { + let result = self + .publisher_inner + .publish(cloud_event) + .await + .map_err(|e| EventMeshError::GRpcStatus(e))? + .into_inner(); + Ok(result) + } + + pub(crate) async fn batch_publish_inner( + &mut self, + cloud_events: PbCloudEventBatch, + ) -> crate::Result { + let result = self + .publisher_inner + .batch_publish(cloud_events) + .await + .map_err(|e| EventMeshError::GRpcStatus(e))? + .into_inner(); + Ok(result) + } + + pub(crate) async fn request_reply_inner( + &mut self, + cloud_event: PbCloudEvent, + time_out: u64, + ) -> crate::Result { + let future_task = self.publisher_inner.request_reply(cloud_event); + let result = tokio::time::timeout(Duration::from_millis(time_out), future_task).await; + match result { + Ok(Ok(value)) => { + let event = value.into_inner(); + if let Some(code) = event.attributes.get(ProtocolKey::GRPC_RESPONSE_CODE) { + if let Some(code_num) = &code.attr { + match code_num { + Attr::CeString(cd) if cd != "0" => { + if let Some(msg) = + event.attributes.get(ProtocolKey::GRPC_RESPONSE_MESSAGE) + { + if let Some(msg_inner) = &msg.attr { + match msg_inner { + Attr::CeString(msg) => { + return Err(EventMeshRemote(msg.to_string()).into()); + } + _ => {} + } + } + } + return Err( + EventMeshRemote("EventMesh remote error".to_string()).into() + ); + } + _ => {} + } + } + } + Ok(event) + } + Ok(Err(err)) => Err(EventMeshError::GRpcStatus(err).into()), + Err(_) => Err(EventMeshError::EventMeshLocal("Request reply error".to_string()).into()), + } + } + + pub(crate) async fn subscribe_webhook_inner( + &mut self, + cloud_event: PbCloudEvent, + ) -> crate::Result { + let result = self + .consumer_inner + .subscribe(cloud_event) + .await + .map_err(|e| EventMeshError::GRpcStatus(e))? + .into_inner(); + Ok(result) + } + + pub(crate) async fn subscribe_bi_inner( + &mut self, + cloud_event: PbCloudEvent, + ) -> crate::Result<(SubscribeStreamKeeper, Streaming)> { + let (sender, receiver) = mpsc::channel::(16); + sender.send(cloud_event).await?; + let streaming = self + .consumer_inner + .subscribe_stream(Request::new(ReceiverStream::new(receiver))) + .await + .map_err(|e| EventMeshError::GRpcStatus(e))? + .into_inner(); + Ok((SubscribeStreamKeeper::new(sender), streaming)) + } + + pub(crate) async fn unsubscribe_inner( + &mut self, + cloud_event: PbCloudEvent, + ) -> crate::Result { + let result = self + .consumer_inner + .unsubscribe(cloud_event) + .await + .map_err(|e| EventMeshError::GRpcStatus(e))? + .into_inner(); + Ok(result) + } + + pub(crate) async fn heartbeat_inner( + &mut self, + cloud_event: PbCloudEvent, + ) -> crate::Result { + let result = self + .heartbeat_inner + .heartbeat(Request::new(cloud_event)) + .await + .map_err(|e| EventMeshError::GRpcStatus(e))? + .into_inner(); + Ok(result) + } +} diff --git a/eventmesh-sdks/eventmesh-sdk-rust/tests/eventmesh_message_utils_test.rs b/eventmesh-sdks/eventmesh-sdk-rust/tests/eventmesh_message_utils_test.rs new file mode 100644 index 0000000000..fc523880ca --- /dev/null +++ b/eventmesh-sdks/eventmesh-sdk-rust/tests/eventmesh_message_utils_test.rs @@ -0,0 +1,62 @@ +/* + * 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. + */ + +use eventmesh::common::grpc_eventmesh_message_utils::{EventMeshCloudEventUtils, ProtoSupport}; +use eventmesh::config::EventMeshGrpcClientConfig; +use eventmesh::model::EventMeshProtocolType; +use eventmesh::proto_cloud_event::PbAttr; + +#[test] +fn test_proto_support_is_text_content() { + assert!(ProtoSupport::is_text_content("text/plain")); + assert!(ProtoSupport::is_text_content("text/html")); + assert!(ProtoSupport::is_text_content("application/json")); + assert!(ProtoSupport::is_text_content("application/xml")); + assert!(!ProtoSupport::is_text_content("application/json+foo")); + assert!(!ProtoSupport::is_text_content("application/xml+bar")); + assert!(!ProtoSupport::is_text_content("")); + assert!(!ProtoSupport::is_text_content("application/octet-stream")); +} + +#[test] +fn test_proto_support_is_proto_content() { + assert!(ProtoSupport::is_proto_content("application/protobuf")); + assert!(!ProtoSupport::is_proto_content("")); + assert!(!ProtoSupport::is_proto_content("application/json")); + assert!(!ProtoSupport::is_proto_content("text/plain")); +} + +#[test] +fn test_event_mesh_cloud_event_utils_build_common_cloud_event_attributes() { + let client_config = EventMeshGrpcClientConfig::default() + .set_env("test_env".to_string()) + .set_idc("test_idc".to_string()); + let protocol_type = EventMeshProtocolType::CloudEvents; + let attribute_map = EventMeshCloudEventUtils::build_common_cloud_event_attributes( + &client_config, + protocol_type, + ); + + assert_eq!( + *attribute_map.get("env").map(|attr| &attr.attr).unwrap(), + Some(PbAttr::CeString("test_env".to_string())) + ); + assert_eq!( + *attribute_map.get("idc").map(|attr| &attr.attr).unwrap(), + Some(PbAttr::CeString("test_idc".to_string())) + ); +} diff --git a/eventmesh-sdks/gradle.properties b/eventmesh-sdks/gradle.properties new file mode 100644 index 0000000000..a9fd83fea0 --- /dev/null +++ b/eventmesh-sdks/gradle.properties @@ -0,0 +1,16 @@ +# +# 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. +# \ No newline at end of file diff --git a/eventmesh-security-plugin/eventmesh-security-acl/src/main/java/org/apache/eventmesh/acl/impl/AclServiceImpl.java b/eventmesh-security-plugin/eventmesh-security-acl/src/main/java/org/apache/eventmesh/acl/impl/AclServiceImpl.java index 8d73bc7c9d..96e2b84845 100644 --- a/eventmesh-security-plugin/eventmesh-security-acl/src/main/java/org/apache/eventmesh/acl/impl/AclServiceImpl.java +++ b/eventmesh-security-plugin/eventmesh-security-acl/src/main/java/org/apache/eventmesh/acl/impl/AclServiceImpl.java @@ -17,44 +17,44 @@ package org.apache.eventmesh.acl.impl; +import org.apache.eventmesh.api.acl.AclProperties; import org.apache.eventmesh.api.acl.AclService; import org.apache.eventmesh.api.exception.AclException; -import java.util.Properties; - public class AclServiceImpl implements AclService { + @Override public void init() throws AclException { - //TODO + // TODO } @Override public void start() throws AclException { - //TODO + // TODO } @Override public void shutdown() throws AclException { - //TODO + // TODO } @Override - public void doAclCheckInConnect(Properties aclProperties) throws AclException { - //TODO + public void doAclCheckInConnect(AclProperties aclProperties) throws AclException { + // TODO } @Override - public void doAclCheckInHeartbeat(Properties aclProperties) throws AclException { - //TODO + public void doAclCheckInHeartbeat(AclProperties aclProperties) throws AclException { + // TODO } @Override - public void doAclCheckInSend(Properties aclProperties) throws AclException { - //TODO + public void doAclCheckInSend(AclProperties aclProperties) throws AclException { + // TODO } @Override - public void doAclCheckInReceive(Properties aclProperties) throws AclException { - //TODO + public void doAclCheckInReceive(AclProperties aclProperties) throws AclException { + // TODO } } diff --git a/eventmesh-security-plugin/eventmesh-security-acl/src/test/java/org/apache/eventmesh/acl/impl/AclServiceImplTest.java b/eventmesh-security-plugin/eventmesh-security-acl/src/test/java/org/apache/eventmesh/acl/impl/AclServiceImplTest.java new file mode 100644 index 0000000000..2108331c24 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-acl/src/test/java/org/apache/eventmesh/acl/impl/AclServiceImplTest.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.acl.impl; + +import org.apache.eventmesh.api.acl.AclProperties; +import org.apache.eventmesh.api.acl.AclService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class AclServiceImplTest { + + private static AclService service; + + @BeforeAll + public static void beforeClass() { + service = new AclServiceImpl(); + } + + @Test + public void testInit() { + Assertions.assertDoesNotThrow(service::init); + } + + @Test + public void testStart() { + Assertions.assertDoesNotThrow(service::start); + } + + @Test + public void testShutdown() { + Assertions.assertDoesNotThrow(service::shutdown); + } + + @Test + public void testDoAclCheckInConnect() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInConnect(new AclProperties())); + } + + @Test + public void testDoAclCheckInHeartbeat() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInHeartbeat(new AclProperties())); + } + + @Test + public void testDoAclCheckInSend() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInSend(new AclProperties())); + } + + @Test + public void testDoAclCheckInReceive() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInReceive(new AclProperties())); + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclProperties.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclProperties.java new file mode 100644 index 0000000000..d340f12888 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclProperties.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.acl; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class AclProperties { + + private String clientIp; + private String user; + private String pwd; + private String subsystem; + private String topic; + private Integer requestCode; + private String requestURI; + private String token; + private String version; + private Map extendedFields = new ConcurrentHashMap<>(); + + public String getClientIp() { + return clientIp; + } + + public void setClientIp(String clientIp) { + this.clientIp = clientIp; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getPwd() { + return pwd; + } + + public void setPwd(String pwd) { + this.pwd = pwd; + } + + public String getSubsystem() { + return subsystem; + } + + public void setSubsystem(String subsystem) { + this.subsystem = subsystem; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public Integer getRequestCode() { + return requestCode; + } + + public void setRequestCode(Integer requestCode) { + this.requestCode = requestCode; + } + + public String getRequestURI() { + return requestURI; + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public void setExtendedField(String key, Object object) { + extendedFields.put(key, object); + } + + public Object getExtendedField(String key) { + return extendedFields.get(key); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclPropertyKeys.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclPropertyKeys.java index 074516fc17..606a91b949 100644 --- a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclPropertyKeys.java +++ b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclPropertyKeys.java @@ -18,6 +18,7 @@ package org.apache.eventmesh.api.acl; public class AclPropertyKeys { + public static final String CLIENT_IP = "clientIp"; public static final String USER = "user"; public static final String PASSWORD = "pwd"; @@ -25,4 +26,5 @@ public class AclPropertyKeys { public static final String TOPIC = "topic"; public static final String REQUEST_CODE = "requestCode"; public static final String REQUEST_URI = "requestURI"; + public static final String CLIENT_VERSION = "clientVersion"; } diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclService.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclService.java index 8387de2900..3217aaccb8 100644 --- a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclService.java +++ b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/acl/AclService.java @@ -21,25 +21,24 @@ import org.apache.eventmesh.spi.EventMeshExtensionType; import org.apache.eventmesh.spi.EventMeshSPI; -import java.util.Properties; - /** * AclService */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.SECURITY) +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.SECURITY) public interface AclService { + void init() throws AclException; void start() throws AclException; void shutdown() throws AclException; - void doAclCheckInConnect(Properties aclProperties) throws AclException; + void doAclCheckInConnect(AclProperties aclProperties) throws AclException; - void doAclCheckInHeartbeat(Properties aclProperties) throws AclException; + void doAclCheckInHeartbeat(AclProperties aclProperties) throws AclException; - void doAclCheckInSend(Properties aclProperties) throws AclException; + void doAclCheckInSend(AclProperties aclProperties) throws AclException; - void doAclCheckInReceive(Properties aclProperties) throws AclException; + void doAclCheckInReceive(AclProperties aclProperties) throws AclException; } diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/auth/AuthService.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/auth/AuthService.java index d957b50bb4..8e3ec8fed9 100644 --- a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/auth/AuthService.java +++ b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/auth/AuthService.java @@ -26,7 +26,7 @@ /** * AuthService */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.SECURITY) +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.SECURITY) public interface AuthService { void init() throws AuthException; @@ -35,5 +35,5 @@ public interface AuthService { void shutdown() throws AuthException; - Map getAuthParams() throws AuthException; + Map getAuthParams() throws AuthException; } diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/common/ConfigurationWrapper.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/common/ConfigurationWrapper.java deleted file mode 100644 index dc359c1219..0000000000 --- a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/common/ConfigurationWrapper.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.api.common; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.URL; -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConfigurationWrapper { - - private static Logger logger = LoggerFactory.getLogger("ConfigurationWrapper"); - - private static final String EVENTMESH_CONFIG_HOME = System.getProperty("confPath", System.getenv("confPath")); - - public static Properties getConfig(String configFile) { - String configFilePath; - - // get from classpath - URL resource = ConfigurationWrapper.class.getClassLoader().getResource(configFile); - if (resource != null && new File(resource.getPath()).exists()) { - configFilePath = resource.getPath(); - } else { - // get from config home - configFilePath = EVENTMESH_CONFIG_HOME + File.separator + configFile; - } - - logger.info("loading auth config: {}", configFilePath); - Properties properties = new Properties(); - try { - properties.load(new BufferedReader(new FileReader(configFilePath))); - } catch (IOException e) { - throw new IllegalArgumentException( - String.format("Cannot load RocketMQ configuration file from :%s", configFilePath)); - } - return properties; - } -} diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AclException.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AclException.java index 115be40bec..15fa47564a 100644 --- a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AclException.java +++ b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AclException.java @@ -22,6 +22,8 @@ */ public class AclException extends RuntimeException { + private static final long serialVersionUID = -8030697611105117189L; + public AclException(String message) { super(message); } diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AuthException.java b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AuthException.java index 67bef31d7b..7241fb502a 100644 --- a/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AuthException.java +++ b/eventmesh-security-plugin/eventmesh-security-api/src/main/java/org/apache/eventmesh/api/exception/AuthException.java @@ -19,6 +19,8 @@ public class AuthException extends RuntimeException { + private static final long serialVersionUID = 7040545308620024091L; + public AuthException(String message) { super(message); } diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/acl/AclServiceTest.java b/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/acl/AclServiceTest.java new file mode 100644 index 0000000000..36f1188c77 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/acl/AclServiceTest.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.acl; + +import org.apache.eventmesh.api.exception.AclException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class AclServiceTest { + + private static class DemoAclService implements AclService { + + @Override + public void init() throws AclException { + + } + + @Override + public void start() throws AclException { + + } + + @Override + public void shutdown() throws AclException { + + } + + @Override + public void doAclCheckInConnect(AclProperties aclProperties) throws AclException { + + } + + @Override + public void doAclCheckInHeartbeat(AclProperties aclProperties) throws AclException { + + } + + @Override + public void doAclCheckInSend(AclProperties aclProperties) throws AclException { + + } + + @Override + public void doAclCheckInReceive(AclProperties aclProperties) throws AclException { + + } + } + + private static AclService service; + + @BeforeAll + public static void beforeClass() { + service = new DemoAclService(); + } + + @Test + public void testInit() { + Assertions.assertDoesNotThrow(service::init); + } + + @Test + public void testStart() { + Assertions.assertDoesNotThrow(service::start); + } + + @Test + public void testShutdown() { + Assertions.assertDoesNotThrow(service::shutdown); + } + + @Test + public void testDoAclCheckInConnect() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInConnect(new AclProperties())); + } + + @Test + public void testDoAclCheckInHeartbeat() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInHeartbeat(new AclProperties())); + } + + @Test + public void testDoAclCheckInSend() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInSend(new AclProperties())); + } + + @Test + public void testDoAclCheckInReceive() { + Assertions.assertDoesNotThrow(() -> service.doAclCheckInReceive(new AclProperties())); + } + +} diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/auth/AuthServiceTest.java b/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/auth/AuthServiceTest.java new file mode 100644 index 0000000000..4dcf88ead3 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/auth/AuthServiceTest.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.auth; + +import org.apache.eventmesh.api.exception.AuthException; + +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class AuthServiceTest { + + private static class DemoAuthService implements AuthService { + + @Override + public void init() throws AuthException { + + } + + @Override + public void start() throws AuthException { + + } + + @Override + public void shutdown() throws AuthException { + + } + + @Override + public Map getAuthParams() throws AuthException { + return null; + } + } + + private static AuthService service; + + @BeforeAll + public static void beforeClass() { + service = new DemoAuthService(); + } + + @Test + public void testInit() { + Assertions.assertDoesNotThrow(service::init); + } + + @Test + public void testStart() { + Assertions.assertDoesNotThrow(service::start); + } + + @Test + public void testShutdown() { + Assertions.assertDoesNotThrow(service::shutdown); + } + + @Test + public void testGetAuthParams() { + Map authParams = service.getAuthParams(); + Assertions.assertNull(authParams); + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/exception/AclExceptionTest.java b/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/exception/AclExceptionTest.java new file mode 100644 index 0000000000..94ca153480 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-api/src/test/java/org/apache/eventmesh/api/exception/AclExceptionTest.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.exception; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class AclExceptionTest { + + @Test + public void testConstructWithMsg() { + Assertions.assertDoesNotThrow(() -> new AclException("test")); + Assertions.assertDoesNotThrow(() -> new AclException(null)); + } + + @Test + public void testConstructWithMsgAndExption() { + Assertions.assertDoesNotThrow(() -> new AclException("test", new Exception("test1"))); + Assertions.assertDoesNotThrow(() -> new AclException(null, null)); + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/build.gradle b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/build.gradle index bb0f4d6314..d28a30d69f 100644 --- a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/build.gradle +++ b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/build.gradle @@ -17,6 +17,11 @@ dependencies { implementation project(":eventmesh-security-plugin:eventmesh-security-api") + implementation "org.apache.commons:commons-lang3" + implementation project(":eventmesh-common") + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' testImplementation project(":eventmesh-security-plugin:eventmesh-security-api") -} \ No newline at end of file + testImplementation "org.apache.commons:commons-lang3" +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigs.java b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigs.java index c077bf4844..f1d56d4e7f 100644 --- a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigs.java +++ b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigs.java @@ -17,25 +17,18 @@ package org.apache.eventmesh.auth.http.basic.config; -import org.apache.eventmesh.api.common.ConfigurationWrapper; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; -import java.util.Properties; +import lombok.Data; +@Data +@Config(prefix = "auth", path = "classPath://auth-http-basic.properties") public class AuthConfigs { - public String username; + @ConfigField(field = "username") + private String username; + @ConfigField(field = "password") public String password; - - private static AuthConfigs instance; - - public static synchronized AuthConfigs getConfigs() { - if (instance == null) { - Properties props = ConfigurationWrapper.getConfig("auth-http-basic.properties"); - instance = new AuthConfigs(); - instance.username = props.getProperty("auth.username"); - instance.password = props.getProperty("auth.password"); - } - return instance; - } } diff --git a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicService.java b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicService.java index c32c98807c..7950fca6c2 100644 --- a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicService.java +++ b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/main/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicService.java @@ -20,19 +20,24 @@ import org.apache.eventmesh.api.auth.AuthService; import org.apache.eventmesh.api.exception.AuthException; import org.apache.eventmesh.auth.http.basic.config.AuthConfigs; +import org.apache.eventmesh.common.config.Config; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; import java.util.Map; +@Config(field = "authConfigs") public class AuthHttpBasicService implements AuthService { + /** + * Unified configuration class corresponding to auth-http-basic.properties + */ private AuthConfigs authConfigs; @Override public void init() throws AuthException { - authConfigs = AuthConfigs.getConfigs(); + } @Override @@ -46,16 +51,18 @@ public void shutdown() throws AuthException { } @Override - public Map getAuthParams() throws AuthException { - if (authConfigs == null) { - init(); - } - - String token = Base64.getEncoder().encodeToString((authConfigs.username + authConfigs.password) - .getBytes(StandardCharsets.UTF_8)); + public Map getAuthParams() throws AuthException { + String password = authConfigs.getPassword(); + String username = authConfigs.getUsername(); + String token = Base64.getEncoder() + .encodeToString((username + password).getBytes(StandardCharsets.UTF_8)); - Map authParams = new HashMap(); + Map authParams = new HashMap<>(2); authParams.put("Authorization", "Basic " + token); return authParams; } + + public AuthConfigs getClientConfiguration() { + return this.authConfigs; + } } diff --git a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigsTest.java b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigsTest.java new file mode 100644 index 0000000000..2cfad09e46 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/java/org/apache/eventmesh/auth/http/basic/config/AuthConfigsTest.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.auth.http.basic.config; + +import org.apache.eventmesh.api.auth.AuthService; +import org.apache.eventmesh.auth.http.basic.impl.AuthHttpBasicService; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class AuthConfigsTest { + + @Test + public void getConfigWhenAuthHttpBasicServiceInit() { + AuthHttpBasicService authService = (AuthHttpBasicService) EventMeshExtensionFactory.getExtension( + AuthService.class, "auth-http-basic"); + + AuthConfigs config = authService.getClientConfiguration(); + assertConfig(config); + } + + private void assertConfig(AuthConfigs config) { + Assertions.assertEquals(config.getUsername(), "username-success!!!"); + Assertions.assertEquals(config.getPassword(), "password-success!!!"); + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicServiceTest.java b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicServiceTest.java new file mode 100644 index 0000000000..cb5f5d81bb --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/java/org/apache/eventmesh/auth/http/basic/impl/AuthHttpBasicServiceTest.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.auth.http.basic.impl; + +import org.apache.eventmesh.api.auth.AuthService; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class AuthHttpBasicServiceTest { + + private static AuthHttpBasicService service; + + @BeforeAll + public static void beforeClass() { + service = (AuthHttpBasicService) EventMeshExtensionFactory.getExtension( + AuthService.class, "auth-http-basic"); + } + + @Test + public void testInitAndGetAuthParams() { + service.init(); + Map authParams = service.getAuthParams(); + String authorization = authParams.get("Authorization"); + Assertions.assertNotNull(authorization); + Assertions.assertTrue(authorization.length() > 5); + } + + @Test + public void testStart() { + Assertions.assertDoesNotThrow(service::start); + } + + @Test + public void testShutdown() { + Assertions.assertDoesNotThrow(service::shutdown); + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/resources/auth-http-basic.properties b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/resources/auth-http-basic.properties new file mode 100644 index 0000000000..0e46ee68cb --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-http-basic/src/test/resources/auth-http-basic.properties @@ -0,0 +1,18 @@ +# +# 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. +# +auth.username = username-success!!! +auth.password = password-success!!! \ No newline at end of file diff --git a/eventmesh-security-plugin/eventmesh-security-auth-token/build.gradle b/eventmesh-security-plugin/eventmesh-security-auth-token/build.gradle new file mode 100644 index 0000000000..2c4e7ed516 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-token/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + + +def jwtVersion = '0.11.1' + +dependencies { + + implementation project(":eventmesh-common") + implementation "io.jsonwebtoken:jjwt-api:${jwtVersion}" + implementation "io.jsonwebtoken:jjwt-impl:${jwtVersion}" + implementation "io.jsonwebtoken:jjwt-jackson:${jwtVersion}" + + implementation project(":eventmesh-security-plugin:eventmesh-security-api") + + testImplementation project(":eventmesh-security-plugin:eventmesh-security-api") + + +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-token/gradle.properties b/eventmesh-security-plugin/eventmesh-security-auth-token/gradle.properties new file mode 100644 index 0000000000..a8a200562d --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-token/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# + +pluginType=security +pluginName=auth-token \ No newline at end of file diff --git a/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/java/org/apache/eventmesh/auth/token/impl/AuthTokenServiceImpl.java b/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/java/org/apache/eventmesh/auth/token/impl/AuthTokenServiceImpl.java new file mode 100644 index 0000000000..47e3e57895 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/java/org/apache/eventmesh/auth/token/impl/AuthTokenServiceImpl.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.eventmesh.auth.token.impl; + +import org.apache.eventmesh.api.acl.AclProperties; +import org.apache.eventmesh.api.acl.AclService; +import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.auth.token.impl.auth.AuthTokenUtils; + +public class AuthTokenServiceImpl implements AclService { + + @Override + public void init() throws AclException { + } + + @Override + public void start() throws AclException { + + } + + @Override + public void shutdown() throws AclException { + + } + + @Override + public void doAclCheckInConnect(AclProperties aclProperties) throws AclException { + AuthTokenUtils.helloTaskAuthTokenByPublicKey(aclProperties); + } + + @Override + public void doAclCheckInHeartbeat(AclProperties aclProperties) throws AclException { + + } + + @Override + public void doAclCheckInSend(AclProperties aclProperties) throws AclException { + AuthTokenUtils.authTokenByPublicKey(aclProperties); + } + + @Override + public void doAclCheckInReceive(AclProperties aclProperties) throws AclException { + AuthTokenUtils.authTokenByPublicKey(aclProperties); + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/java/org/apache/eventmesh/auth/token/impl/auth/AuthTokenUtils.java b/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/java/org/apache/eventmesh/auth/token/impl/auth/AuthTokenUtils.java new file mode 100644 index 0000000000..16005649f4 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/java/org/apache/eventmesh/auth/token/impl/auth/AuthTokenUtils.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package org.apache.eventmesh.auth.token.impl.auth; + +import org.apache.eventmesh.api.acl.AclProperties; +import org.apache.eventmesh.api.exception.AclException; +import org.apache.eventmesh.common.config.CommonConfiguration; +import org.apache.eventmesh.common.utils.ConfigurationContextUtil; +import org.apache.eventmesh.common.utils.TypeUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Objects; +import java.util.Set; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwt; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.JwtParser; +import io.jsonwebtoken.Jwts; + +public class AuthTokenUtils { + + public static void authTokenByPublicKey(AclProperties aclProperties) { + + String token = aclProperties.getToken(); + if (StringUtils.isNotBlank(token)) { + if (!authAccess(aclProperties)) { + throw new AclException("group:" + aclProperties.getExtendedField("group ") + " has no auth to access the topic:" + + aclProperties.getTopic()); + } + String publicKeyUrl = getPublicKeyUrl(); + validateToken(token, publicKeyUrl, aclProperties); + } else { + throw new AclException("invalid token!"); + } + } + + public static void helloTaskAuthTokenByPublicKey(AclProperties aclProperties) { + String token = aclProperties.getToken(); + if (StringUtils.isNotBlank(token)) { + validateToken(token, getPublicKeyUrl(), aclProperties); + } else { + throw new AclException("invalid token!"); + } + } + + public static boolean authAccess(AclProperties aclProperties) { + + String topic = aclProperties.getTopic(); + + Object topics = aclProperties.getExtendedField("topics"); + + if (!(topics instanceof Set)) { + return false; + } + + Set groupTopics = TypeUtils.castSet(topics, String.class); + + return groupTopics.contains(topic); + } + + private static String getPublicKeyUrl() { + String publicKeyUrl = null; + for (String key : ConfigurationContextUtil.KEYS) { + CommonConfiguration commonConfiguration = ConfigurationContextUtil.get(key); + if (null == commonConfiguration) { + continue; + } + if (StringUtils.isBlank(commonConfiguration.getEventMeshSecurityPublickey())) { + throw new AclException("publicKeyUrl cannot be null"); + } + publicKeyUrl = commonConfiguration.getEventMeshSecurityPublickey(); + } + return publicKeyUrl; + } + + private static void validateToken(String token, String publicKeyUrl, AclProperties aclProperties) { + String sub; + token = token.replace("Bearer ", ""); + byte[] validationKeyBytes; + try { + validationKeyBytes = Files.readAllBytes(Paths.get(Objects.requireNonNull(publicKeyUrl))); + X509EncodedKeySpec spec = new X509EncodedKeySpec(validationKeyBytes); + KeyFactory kf = KeyFactory.getInstance("RSA"); + Key validationKey = kf.generatePublic(spec); + JwtParser signedParser = Jwts.parserBuilder().setSigningKey(validationKey).build(); + Jwt signJwt = signedParser.parseClaimsJws(token); + sub = signJwt.getBody().get("sub", String.class); + if (!sub.contains(aclProperties.getExtendedField("group").toString()) && !sub.contains("pulsar-admin")) { + throw new AclException("group:" + aclProperties.getExtendedField("group ") + " has no auth to access eventMesh:" + + aclProperties.getTopic()); + } + } catch (IOException e) { + throw new AclException("public key read error!", e); + } catch (NoSuchAlgorithmException e) { + throw new AclException("no such RSA algorithm!", e); + } catch (InvalidKeySpecException e) { + throw new AclException("invalid public key spec!", e); + } catch (JwtException e) { + throw new AclException("invalid token!", e); + } + } +} diff --git a/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.acl.AclService b/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.acl.AclService new file mode 100644 index 0000000000..45abac89d6 --- /dev/null +++ b/eventmesh-security-plugin/eventmesh-security-auth-token/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.acl.AclService @@ -0,0 +1,16 @@ +# 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. + +auth-token=org.apache.eventmesh.auth.token.impl.AuthTokenServiceImpl \ No newline at end of file diff --git a/eventmesh-spi/build.gradle b/eventmesh-spi/build.gradle index 4980522b47..e4e682109e 100644 --- a/eventmesh-spi/build.gradle +++ b/eventmesh-spi/build.gradle @@ -18,4 +18,10 @@ dependencies { implementation project(":eventmesh-common") implementation "org.apache.commons:commons-collections4" testImplementation project(":eventmesh-common") -} \ No newline at end of file + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java index eb4de8aa80..cc47f5ef9f 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java @@ -17,101 +17,142 @@ package org.apache.eventmesh.spi; +import org.apache.eventmesh.common.config.ConfigService; import org.apache.eventmesh.spi.loader.ExtensionClassLoader; import org.apache.eventmesh.spi.loader.JarExtensionClassLoader; import org.apache.eventmesh.spi.loader.MetaInfExtensionClassLoader; import org.apache.commons.lang3.StringUtils; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** - * The extension fetching factory, all extension plugins should be fetched by this factory. - * And all the extension plugins defined in eventmesh should have {@link EventMeshSPI} annotation. + * The extension fetching factory, all extension plugins should be fetched by this factory. And all the extension plugins defined in eventmesh should + * have {@link EventMeshSPI} annotation. */ +@Slf4j public class EventMeshExtensionFactory { - private EventMeshExtensionFactory() { - - } + private static final List EXTENSION_CLASS_LOADERS = new ArrayList<>(); - private static final Logger logger = LoggerFactory.getLogger(EventMeshExtensionFactory.class); - - private static final List extensionClassLoaders = new ArrayList<>(); + private static final ConcurrentHashMap EXTENSION_INSTANCE_CACHE = new ConcurrentHashMap<>(16); static { - extensionClassLoaders.add(new MetaInfExtensionClassLoader()); - extensionClassLoaders.add(new JarExtensionClassLoader()); + EXTENSION_CLASS_LOADERS.add(MetaInfExtensionClassLoader.getInstance()); + EXTENSION_CLASS_LOADERS.add(JarExtensionClassLoader.getInstance()); } - private static final ConcurrentHashMap EXTENSION_INSTANCE_CACHE = - new ConcurrentHashMap<>(16); + private EventMeshExtensionFactory() { + + } /** - * @param extensionType extension plugin class type - * @param extensionName extension instance name - * @param the type of the plugin + * Get an instance of an extension plugin. + * + * @param extensionClass extension plugin class type + * @param extensionName extension instance name + * @param the type of the plugin * @return plugin instance */ - public static T getExtension(Class extensionType, String extensionName) { - if (extensionType == null) { - throw new ExtensionException("extensionType is null"); + public static T getExtension(Class extensionClass, String extensionName) { + if (extensionClass == null) { + throw new ExtensionException("extensionClass is null"); } if (StringUtils.isEmpty(extensionName)) { throw new ExtensionException("extensionName is null"); } - if (!extensionType.isInterface() || !extensionType.isAnnotationPresent(EventMeshSPI.class)) { - throw new ExtensionException(String.format("extensionType:%s is invalided", extensionType)); + if (!extensionClass.isInterface() || !extensionClass.isAnnotationPresent(EventMeshSPI.class)) { + throw new ExtensionException(String.format("extensionClass:%s is invalided", extensionClass)); } - EventMeshSPI eventMeshSPIAnnotation = extensionType.getAnnotation(EventMeshSPI.class); + EventMeshSPI eventMeshSPIAnnotation = extensionClass.getAnnotation(EventMeshSPI.class); if (eventMeshSPIAnnotation.isSingleton()) { - return getSingletonExtension(extensionType, extensionName); + return getSingletonExtension(extensionClass, eventMeshSPIAnnotation, extensionName); } - return getPrototypeExtension(extensionType, extensionName); + return getPrototypeExtension(extensionClass, extensionName); } + /** + * Get a singleton instance of an extension plugin. + * + * @param extensionClass the type of the extension plugin + * @param spi the type of the spi + * @param extensionInstanceName the name of the extension instance + * @param the type of the extension plugin + * @return a singleton instance of the extension plugin + */ @SuppressWarnings("unchecked") - private static T getSingletonExtension(Class extensionType, String extensionInstanceName) { - return (T) EXTENSION_INSTANCE_CACHE.computeIfAbsent(extensionInstanceName, name -> { - Class extensionInstanceClass = getExtensionInstanceClass(extensionType, extensionInstanceName); + private static T getSingletonExtension(Class extensionClass, EventMeshSPI spi, String extensionInstanceName) { + return (T) EXTENSION_INSTANCE_CACHE.computeIfAbsent(new Extension(spi, extensionInstanceName), name -> { + Class extensionInstanceClass = getExtensionInstanceClass(extensionClass, extensionInstanceName); + if (extensionInstanceClass == null) { + log.warn("Get extension instance class {} is null", extensionClass.getName()); + return null; + } try { - if (extensionInstanceClass == null) { - return null; - } - T extensionInstance = extensionInstanceClass.newInstance(); - logger.info("initialize extension instance success, extensionType: {}, extensionInstanceName: {}", - extensionType, extensionInstanceName); + T extensionInstance = extensionInstanceClass.getDeclaredConstructor().newInstance(); + ConfigService.getInstance().populateConfigForObject(extensionInstance); + + log.info("initialize extension instance success, extensionClass: {}, extensionInstanceName: {}", + extensionClass, extensionInstanceName); return extensionInstance; - } catch (InstantiationException | IllegalAccessException e) { + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new ExtensionException("Extension initialize error", e); + } catch (NoSuchFieldException | IOException e) { + log.error("initialize extension instance config failed, extensionClass: {}, extensionInstanceName: {}", + extensionClass, extensionInstanceName, e); throw new ExtensionException("Extension initialize error", e); } }); } + /** + * Get a new instance of an extension plugin. + * + * @param extensionType the type of the extension plugin + * @param extensionInstanceName the name of the extension instance + * @param the type of the extension plugin + * @return a new instance of the extension plugin + */ private static T getPrototypeExtension(Class extensionType, String extensionInstanceName) { Class extensionInstanceClass = getExtensionInstanceClass(extensionType, extensionInstanceName); + if (extensionInstanceClass == null) { + return null; + } try { - if (extensionInstanceClass == null) { - return null; - } - T extensionInstance = extensionInstanceClass.newInstance(); - logger.info("initialize extension instance success, extensionType: {}, extensionName: {}", + T extensionInstance = extensionInstanceClass.getDeclaredConstructor().newInstance(); + ConfigService.getInstance().populateConfigForObject(extensionInstance); + + log.info("initialize extension instance success, extensionType: {}, extensionName: {}", extensionType, extensionInstanceName); return extensionInstance; - } catch (InstantiationException | IllegalAccessException e) { + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new ExtensionException("Extension initialize error", e); + } catch (NoSuchFieldException | IOException e) { + log.error("initialize extension instance config failed, extensionType: {}, extensionInstanceName: {}", + extensionType, extensionInstanceName, e); throw new ExtensionException("Extension initialize error", e); } } + /** + * Get the class of an extension instance. + * + * @param extensionType the type of the extension instance + * @param extensionInstanceName the name of the extension instance + * @param the type of the extension instance + * @return the class of the extension instance + */ @SuppressWarnings("unchecked") private static Class getExtensionInstanceClass(Class extensionType, String extensionInstanceName) { - for (ExtensionClassLoader extensionClassLoader : extensionClassLoaders) { + for (ExtensionClassLoader extensionClassLoader : EXTENSION_CLASS_LOADERS) { Map> extensionInstanceClassMap = extensionClassLoader.loadExtensionClass(extensionType, extensionInstanceName); Class instanceClass = extensionInstanceClassMap.get(extensionInstanceName); if (instanceClass != null) { @@ -121,4 +162,32 @@ private static Class getExtensionInstanceClass(Class extensionType, St return null; } + private static class Extension { + + private EventMeshSPI spi; + + private String extensionInstanceName; + + public Extension(EventMeshSPI spi, String extensionInstanceName) { + this.spi = spi; + this.extensionInstanceName = extensionInstanceName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Extension)) { + return false; + } + Extension extension = (Extension) o; + return Objects.equals(spi, extension.spi) && Objects.equals(extensionInstanceName, extension.extensionInstanceName); + } + + @Override + public int hashCode() { + return Objects.hash(spi, extensionInstanceName); + } + } } diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java index 5aab9d1df7..8de4e1ecfd 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java @@ -21,13 +21,21 @@ * An Extension can be defined by extensionTypeName and extensionInstanceName */ public enum EventMeshExtensionType { + UNKNOWN("unknown"), CONNECTOR("connector"), - REGISTRY("registry"), + STORAGE("storage"), + META("metaStorage"), + REGISTRY("registryCenter"), SECURITY("security"), PROTOCOL("protocol"), METRICS("metrics"), TRACE("trace"), + JDBC_CDC_ENGINE("jdbc_cdc_engine"), + JDBC_SNAPSHOT_ENGINE("jdbc_snapshot_engine"), + JDBC_DATABASE_DIALECT("jdbc_database_dialect"), + OFFSETMGMT("offsetMgmt"), + RETRY("retry"), ; private final String extensionTypeName; diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java index a0ae5ecd3e..7722d59613 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java @@ -34,7 +34,7 @@ /** * If true, the spi instance is singleton */ - boolean isSingleton() default false; + boolean isSingleton() default true; /** * {@link EventMeshExtensionType} @@ -44,4 +44,3 @@ EventMeshExtensionType eventMeshExtensionType(); } - diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshExtensionConstant.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshExtensionConstant.java index d550c35c6c..9995c2f288 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshExtensionConstant.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshExtensionConstant.java @@ -18,6 +18,7 @@ package org.apache.eventmesh.spi.loader; public class EventMeshExtensionConstant { + /** * eventmesh plugin base path */ diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshUrlClassLoader.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshUrlClassLoader.java index 9a27d495e1..713e5ac12f 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshUrlClassLoader.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/EventMeshUrlClassLoader.java @@ -26,15 +26,13 @@ public class EventMeshUrlClassLoader extends URLClassLoader { public static EventMeshUrlClassLoader getInstance() { - return EventMeshUrlClassLoaderHolder.instance; + return EventMeshUrlClassLoaderHolder.INSTANCE; } /** * Appends the specified URL to the list of URLs to search for classes and resources. *

- * If the URL specified is {@code null} or is already in the - * list of URLs, or if this loader is closed, then invoking this - * method has no effect. + * If the URL specified is {@code null} or is already in the list of URLs, or if this loader is closed, then invoking this method has no effect. *

* More detail see {@link URLClassLoader#addURL(URL)} * @@ -52,6 +50,8 @@ private EventMeshUrlClassLoader(URL[] urls, ClassLoader parent) { } private static class EventMeshUrlClassLoaderHolder { - private static EventMeshUrlClassLoader instance = new EventMeshUrlClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()); + + private static final EventMeshUrlClassLoader INSTANCE = new EventMeshUrlClassLoader(new URL[0], + Thread.currentThread().getContextClassLoader()); } } diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/JarExtensionClassLoader.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/JarExtensionClassLoader.java index 8c7d883f14..0680831f5a 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/JarExtensionClassLoader.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/JarExtensionClassLoader.java @@ -35,48 +35,47 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.common.base.Joiner; import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; + /** * Load extension from '${eventMeshPluginDir}', the default loading directory is './plugin' */ +@Slf4j public class JarExtensionClassLoader implements ExtensionClassLoader { - private static final Logger logger = LoggerFactory.getLogger(JarExtensionClassLoader.class); - private static final String EVENT_MESH_PLUGIN_DIR = "eventMeshPluginDir"; - private static final ConcurrentHashMap, Map>> EXTENSION_CLASS_CACHE = - new ConcurrentHashMap<>(16); + private static final String EVENTMESH_EXTENSION_PLUGIN_DIR = System.getProperty(EVENT_MESH_PLUGIN_DIR, + Joiner.on(File.separator).join(Lists.newArrayList(".", "plugin"))); + + private static final JarExtensionClassLoader INSTANCE = new JarExtensionClassLoader(); + + private final ConcurrentHashMap, Map>> extensionClassCache = new ConcurrentHashMap<>(16); - private static final String EVENTMESH_EXTENSION_PLUGIN_DIR = - System.getProperty(EVENT_MESH_PLUGIN_DIR, - Joiner.on(File.separator).join(Lists.newArrayList(".", "plugin"))); + private JarExtensionClassLoader() { + + } + + public static JarExtensionClassLoader getInstance() { + return INSTANCE; + } @Override - public Map> loadExtensionClass(Class extensionType, - String extensionInstanceName) { - return EXTENSION_CLASS_CACHE - .computeIfAbsent(extensionType, t -> doLoadExtensionClass(t, extensionInstanceName)); + public Map> loadExtensionClass(Class extensionType, String extensionInstanceName) { + return extensionClassCache.computeIfAbsent(extensionType, this::doLoadExtensionClass); } - private Map> doLoadExtensionClass(Class extensionType, - String extensionInstanceName) { + private Map> doLoadExtensionClass(Class extensionType) { Map> extensionMap = new HashMap<>(16); EventMeshSPI eventMeshSpiAnnotation = extensionType.getAnnotation(EventMeshSPI.class); - String pluginDir = Paths.get( - EVENTMESH_EXTENSION_PLUGIN_DIR, - eventMeshSpiAnnotation.eventMeshExtensionType().getExtensionTypeName(), - extensionInstanceName - ).toString(); + String pluginDir = Paths.get(EVENTMESH_EXTENSION_PLUGIN_DIR, eventMeshSpiAnnotation.eventMeshExtensionType().getExtensionTypeName()) + .toString(); - String extensionFileName = - EventMeshExtensionConstant.EVENTMESH_EXTENSION_META_DIR + extensionType.getName(); + String extensionFileName = EventMeshExtensionConstant.EVENTMESH_EXTENSION_META_DIR + extensionType.getName(); EventMeshUrlClassLoader urlClassLoader = EventMeshUrlClassLoader.getInstance(); urlClassLoader.addUrls(loadJarPathFromResource(pluginDir)); try { @@ -96,7 +95,7 @@ private Map> doLoadExtensionClass(Class extensionType, private List loadJarPathFromResource(String pluginPath) { File plugin = new File(pluginPath); if (!plugin.exists()) { - logger.warn("plugin dir:{} is not exist", pluginPath); + log.warn("plugin dir:{} is not exist", pluginPath); return Lists.newArrayList(); } if (plugin.isFile() && plugin.getName().endsWith(".jar")) { @@ -113,15 +112,13 @@ private List loadJarPathFromResource(String pluginPath) { pluginUrls.addAll(loadJarPathFromResource(file.getPath())); } } - // TODO: Sort the path here just to guarantee load the ConsumeMessageConcurrentlyService - // defined in EventMesh rather than defined in rocketmq + // Sort the path here just to guarantee load the ConsumeMessageConcurrentlyService + // defined in EventMesh rather than defined in rocketmq pluginUrls.sort(Comparator.comparing(URL::getPath)); return pluginUrls; } - private static Map> loadResources(URLClassLoader urlClassLoader, URL url, - Class extensionType) - throws IOException { + private Map> loadResources(URLClassLoader urlClassLoader, URL url, Class extensionType) throws IOException { Map> extensionMap = new HashMap<>(); try (InputStream inputStream = url.openStream()) { Properties properties = new Properties(); @@ -131,13 +128,10 @@ private static Map> loadResources(URLClassLoader urlClassLo String extensionClassStr = (String) extensionClass; try { Class targetClass = urlClassLoader.loadClass(extensionClassStr); - logger - .info("load extension class success, extensionType: {}, extensionClass: {}", - extensionType, targetClass); + log.info("load extension class success, extensionType: {}, extensionClass: {}", extensionType, targetClass); if (!extensionType.isAssignableFrom(targetClass)) { throw new ExtensionException( - String.format("class: %s is not subClass of %s", targetClass, - extensionType)); + String.format("class: %s is not subClass of %s", targetClass, extensionType)); } extensionMap.put(extensionNameStr, targetClass); } catch (ClassNotFoundException e) { diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/MetaInfExtensionClassLoader.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/MetaInfExtensionClassLoader.java index 8e6cc8a56f..0884df230f 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/MetaInfExtensionClassLoader.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/loader/MetaInfExtensionClassLoader.java @@ -28,22 +28,30 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** * Load extension from classpath */ + +@Slf4j public class MetaInfExtensionClassLoader implements ExtensionClassLoader { - private static final Logger logger = LoggerFactory.getLogger(MetaInfExtensionClassLoader.class); + private static final MetaInfExtensionClassLoader INSTANCE = new MetaInfExtensionClassLoader(); + + private final ConcurrentHashMap, Map>> extensionClassCache = new ConcurrentHashMap<>(16); + + private MetaInfExtensionClassLoader() { - private static final ConcurrentHashMap, Map>> EXTENSION_CLASS_CACHE = - new ConcurrentHashMap<>(16); + } @Override public Map> loadExtensionClass(Class extensionType, String extensionInstanceName) { - return EXTENSION_CLASS_CACHE.computeIfAbsent(extensionType, this::doLoadExtensionClass); + return extensionClassCache.computeIfAbsent(extensionType, this::doLoadExtensionClass); + } + + public static MetaInfExtensionClassLoader getInstance() { + return INSTANCE; } private Map> doLoadExtensionClass(Class extensionType) { @@ -64,7 +72,7 @@ private Map> doLoadExtensionClass(Class extensionType) { return extensionMap; } - private static Map> loadResources(URL url, Class extensionType) throws IOException { + private Map> loadResources(URL url, Class extensionType) throws IOException { Map> extensionMap = new HashMap<>(); try (InputStream inputStream = url.openStream()) { Properties properties = new Properties(); @@ -74,11 +82,9 @@ private static Map> loadResources(URL url, Class extensi String extensionClassStr = (String) extensionClass; try { Class targetClass = Class.forName(extensionClassStr); - logger.info("load extension class success, extensionType: {}, extensionClass: {}", - extensionType, targetClass); + log.info("load extension class success, extensionType: {}, extensionClass: {}", extensionType, targetClass); if (!extensionType.isAssignableFrom(targetClass)) { - throw new ExtensionException( - String.format("class: %s is not subClass of %s", targetClass, extensionType)); + throw new ExtensionException(String.format("class: %s is not subClass of %s", targetClass, extensionType)); } extensionMap.put(extensionNameStr, targetClass); } catch (ClassNotFoundException e) { diff --git a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java index 5dc24c592a..5837bdcff2 100644 --- a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java +++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java @@ -17,11 +17,12 @@ package org.apache.eventmesh.spi; +import org.apache.eventmesh.spi.example.TestAnotherSingletonExtension; import org.apache.eventmesh.spi.example.TestPrototypeExtension; import org.apache.eventmesh.spi.example.TestSingletonExtension; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class EventMeshExtensionFactoryTest { @@ -29,13 +30,26 @@ public class EventMeshExtensionFactoryTest { public void testGetSingletonExtension() { TestSingletonExtension extensionA = EventMeshExtensionFactory.getExtension(TestSingletonExtension.class, "singletonExtension"); TestSingletonExtension extensionB = EventMeshExtensionFactory.getExtension(TestSingletonExtension.class, "singletonExtension"); - Assert.assertSame(extensionA, extensionB); + Assertions.assertSame(extensionA, extensionB); + + TestAnotherSingletonExtension singletonExtension = EventMeshExtensionFactory.getExtension(TestAnotherSingletonExtension.class, + "singletonExtension"); + Assertions.assertNotNull(singletonExtension); + TestSingletonExtension singletonExtension1 = EventMeshExtensionFactory.getExtension(TestSingletonExtension.class, "singletonExtension"); + Assertions.assertNotNull(singletonExtension1); + } @Test public void testGetPrototypeExtension() { TestPrototypeExtension prototypeExtensionA = EventMeshExtensionFactory.getExtension(TestPrototypeExtension.class, "prototypeExtension"); TestPrototypeExtension prototypeExtensionB = EventMeshExtensionFactory.getExtension(TestPrototypeExtension.class, "prototypeExtension"); - Assert.assertNotSame(prototypeExtensionA, prototypeExtensionB); + Assertions.assertNotSame(prototypeExtensionA, prototypeExtensionB); + } + + @Test + public void testGetExtension() { + Assertions.assertThrows(ExtensionException.class, () -> EventMeshExtensionFactory.getExtension(null, "eventmesh")); + Assertions.assertThrows(ExtensionException.class, () -> EventMeshExtensionFactory.getExtension(TestPrototypeExtension.class, null)); } -} \ No newline at end of file +} diff --git a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/AnotherSingletonExtension.java b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/AnotherSingletonExtension.java new file mode 100644 index 0000000000..d7de5985b6 --- /dev/null +++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/AnotherSingletonExtension.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.spi.example; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AnotherSingletonExtension implements TestAnotherSingletonExtension { + + @Override + public void hello() { + log.info("I am SingletonExtension"); + } +} diff --git a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/PrototypeExtension.java b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/PrototypeExtension.java index 27a50ac59c..6684c72510 100644 --- a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/PrototypeExtension.java +++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/PrototypeExtension.java @@ -17,15 +17,13 @@ package org.apache.eventmesh.spi.example; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class PrototypeExtension implements TestPrototypeExtension { - private static final Logger logger = LoggerFactory.getLogger(PrototypeExtension.class); - @Override public void hello() { - logger.info("I am PrototypeExtension"); + log.info("I am PrototypeExtension"); } } diff --git a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/SingletonExtension.java b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/SingletonExtension.java index 285867c2dd..3c398f4dc8 100644 --- a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/SingletonExtension.java +++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/SingletonExtension.java @@ -17,15 +17,13 @@ package org.apache.eventmesh.spi.example; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class SingletonExtension implements TestSingletonExtension { - private static final Logger logger = LoggerFactory.getLogger(SingletonExtension.class); - @Override public void hello() { - logger.info("I am SingletonExtension"); + log.info("I am SingletonExtension"); } } diff --git a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestAnotherSingletonExtension.java b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestAnotherSingletonExtension.java new file mode 100644 index 0000000000..92d7b1fd33 --- /dev/null +++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestAnotherSingletonExtension.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.eventmesh.spi.example; + +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * TestAnotherSingletonExtension + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.SECURITY) +public interface TestAnotherSingletonExtension { + + void hello(); +} diff --git a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestSingletonExtension.java b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestSingletonExtension.java index 9b67793e12..e05fe9592c 100644 --- a/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestSingletonExtension.java +++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/example/TestSingletonExtension.java @@ -23,7 +23,7 @@ /** * TestSingletonExtension */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.UNKNOWN) +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.UNKNOWN) public interface TestSingletonExtension { void hello(); diff --git a/eventmesh-spi/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.spi.example.TestAnotherSingletonExtension b/eventmesh-spi/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.spi.example.TestAnotherSingletonExtension new file mode 100644 index 0000000000..c8db961c38 --- /dev/null +++ b/eventmesh-spi/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.spi.example.TestAnotherSingletonExtension @@ -0,0 +1,17 @@ +# +# 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. + +singletonExtension=org.apache.eventmesh.spi.example.AnotherSingletonExtension diff --git a/eventmesh-starter/src/main/java/org/apache/eventmesh/starter/StartUp.java b/eventmesh-starter/src/main/java/org/apache/eventmesh/starter/StartUp.java index 4a2ab9d5ac..1b8ff85894 100644 --- a/eventmesh-starter/src/main/java/org/apache/eventmesh/starter/StartUp.java +++ b/eventmesh-starter/src/main/java/org/apache/eventmesh/starter/StartUp.java @@ -20,6 +20,7 @@ import org.apache.eventmesh.runtime.boot.EventMeshStartup; public class StartUp { + public static void main(String[] args) throws Exception { EventMeshStartup.main(args); } diff --git a/eventmesh-storage-plugin/build.gradle b/eventmesh-storage-plugin/build.gradle new file mode 100644 index 0000000000..d973dcedae --- /dev/null +++ b/eventmesh-storage-plugin/build.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-api/build.gradle new file mode 100644 index 0000000000..25c68d12e6 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/build.gradle @@ -0,0 +1,33 @@ +/* + * 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. + */ + +dependencies { + api project(":eventmesh-spi") + implementation project(":eventmesh-common") + api 'io.cloudevents:cloudevents-core' + api 'io.dropwizard.metrics:metrics-core' + api "io.dropwizard.metrics:metrics-healthchecks" + api "io.dropwizard.metrics:metrics-annotation" + api "io.dropwizard.metrics:metrics-json" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-api/gradle.properties new file mode 100644 index 0000000000..a9fd83fea0 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/gradle.properties @@ -0,0 +1,16 @@ +# +# 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. +# \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/AbstractContext.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/AbstractContext.java similarity index 99% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/AbstractContext.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/AbstractContext.java index 4fa7bd2ecf..42b7eb314e 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/AbstractContext.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/AbstractContext.java @@ -21,4 +21,5 @@ * AbstractContext */ public interface AbstractContext { + } diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/AsyncConsumeContext.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/AsyncConsumeContext.java similarity index 99% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/AsyncConsumeContext.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/AsyncConsumeContext.java index 7c1c739cd5..d56ef58fba 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/AsyncConsumeContext.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/AsyncConsumeContext.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.api; - public abstract class AsyncConsumeContext { public abstract void commit(EventMeshAction action); diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventListener.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventListener.java similarity index 93% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventListener.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventListener.java index eede41ca09..4416b1ea58 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventListener.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventListener.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.api; - import io.cloudevents.CloudEvent; /** @@ -25,8 +24,7 @@ * *

* - * Thread safe requirements: this interface will be invoked by multi threads, - * so users should keep thread safe during the consume process. + * Thread safe requirements: this interface will be invoked by multi threads, so users should keep thread safe during the consume process. * *

*/ diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventMeshAction.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventMeshAction.java similarity index 100% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventMeshAction.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventMeshAction.java diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventMeshAsyncConsumeContext.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventMeshAsyncConsumeContext.java similarity index 78% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventMeshAsyncConsumeContext.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventMeshAsyncConsumeContext.java index 633a5b712b..54a9c3f175 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/EventMeshAsyncConsumeContext.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/EventMeshAsyncConsumeContext.java @@ -17,19 +17,13 @@ package org.apache.eventmesh.api; +import lombok.Getter; +import lombok.Setter; +@Getter +@Setter public abstract class EventMeshAsyncConsumeContext extends AsyncConsumeContext { private AbstractContext abstractContext; - public AbstractContext getAbstractContext() { - return abstractContext; - } - - public void setAbstractContext(AbstractContext abstractContext) { - this.abstractContext = abstractContext; - } - - public abstract void commit(EventMeshAction action); - } \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/LifeCycle.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/LifeCycle.java similarity index 93% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/LifeCycle.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/LifeCycle.java index f5d61de333..4150b9ea53 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/LifeCycle.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/LifeCycle.java @@ -21,8 +21,7 @@ import org.apache.eventmesh.api.producer.Producer; /** - * The {@code LifeCycle} defines a lifecycle interface for a OMS related service endpoint, - * like {@link Producer}, {@link Consumer}, and so on. + * The {@code LifeCycle} defines a lifecycle interface for a OMS related service endpoint, like {@link Producer}, {@link Consumer}, and so on. */ public interface LifeCycle { diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/RequestReplyCallback.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/RequestReplyCallback.java similarity index 100% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/RequestReplyCallback.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/RequestReplyCallback.java diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/SendCallback.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/SendCallback.java similarity index 100% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/SendCallback.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/SendCallback.java diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/SendResult.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/SendResult.java new file mode 100644 index 0000000000..2dd4a9b6aa --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/SendResult.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api; + +public class SendResult { + + private String messageId; + + private String topic; + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + @Override + public String toString() { + return "SendResult[topic=" + topic + ", messageId=" + messageId + ']'; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/TopicNameHelper.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/TopicNameHelper.java new file mode 100644 index 0000000000..8a7d34f320 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/TopicNameHelper.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api; + +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +import lombok.SneakyThrows; + +/** + * Topic name generator. + */ +@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.STORAGE) +public interface TopicNameHelper { + + @SneakyThrows + default boolean isRetryTopic(String retryTopic) { + throw new IllegalAccessException("Method not supported."); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/AbstractAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/AbstractAdmin.java new file mode 100644 index 0000000000..5668dbb178 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/AbstractAdmin.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.admin; + +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +public abstract class AbstractAdmin implements Admin { + + private final AtomicBoolean started; + + public AbstractAdmin(AtomicBoolean started) { + this.started = started; + } + + @Override + public boolean isStarted() { + return started.get(); + } + + @Override + public boolean isClosed() { + return !started.get(); + } + + @Override + public void start() { + started.set(true); + } + + @Override + public void shutdown() { + started.set(false); + } + + @Override + public void init(Properties properties) throws Exception { + + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return null; + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/Admin.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/Admin.java new file mode 100644 index 0000000000..a268adde3b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/Admin.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.admin; + +import org.apache.eventmesh.api.LifeCycle; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +/** + * Admin API. + */ +@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.STORAGE) +public interface Admin extends LifeCycle { + + /** + * Initializes admin api service. + */ + void init(Properties properties) throws Exception; + + /** + * Get the list of topics. + * + * @return List of topics. + */ + List getTopic() throws Exception; + + /** + * Create one topic. + */ + void createTopic(String topicName) throws Exception; + + /** + * Delete one topic. + */ + void deleteTopic(String topicName) throws Exception; + + /** + * Get the list of all events. + * + * @return List of events. + */ + List getEvent(String topicName, int offset, int length) throws Exception; + + /** + * Publish an event. + */ + void publish(CloudEvent cloudEvent) throws Exception; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/TopicProperties.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/TopicProperties.java new file mode 100644 index 0000000000..775e998ba2 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/admin/TopicProperties.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.admin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TopicProperties { + + public String name; + public long messageCount; + + @JsonCreator + public TopicProperties( + @JsonProperty("name") String name, + @JsonProperty("messageCount") long messageCount) { + super(); + this.name = name; + this.messageCount = messageCount; + } +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/consumer/Consumer.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/consumer/Consumer.java similarity index 93% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/consumer/Consumer.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/consumer/Consumer.java index 52b1a93d64..266aef1e18 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/consumer/Consumer.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/consumer/Consumer.java @@ -31,18 +31,16 @@ /** * Consumer Interface. */ -@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.CONNECTOR) +@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.STORAGE) public interface Consumer extends LifeCycle { void init(Properties keyValue) throws Exception; void updateOffset(List cloudEvents, AbstractContext context); - //void subscribe(String topic, final EventListener listener) throws Exception; - void subscribe(String topic) throws Exception; void unsubscribe(String topic); void registerEventListener(EventListener listener); -} +} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/exception/OnExceptionContext.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/exception/OnExceptionContext.java similarity index 95% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/exception/OnExceptionContext.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/exception/OnExceptionContext.java index d51da7a0d1..f4d9488306 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/exception/OnExceptionContext.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/exception/OnExceptionContext.java @@ -35,5 +35,5 @@ public class OnExceptionContext { /** * Detailed exception stack information. */ - private ConnectorRuntimeException exception; + private StorageRuntimeException exception; } diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/exception/StorageRuntimeException.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/exception/StorageRuntimeException.java new file mode 100644 index 0000000000..db2728897e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/exception/StorageRuntimeException.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.exception; + +public class StorageRuntimeException extends RuntimeException { + + public StorageRuntimeException() { + + } + + public StorageRuntimeException(String message) { + super(message); + } + + public StorageRuntimeException(Throwable throwable) { + super(throwable); + } + + public StorageRuntimeException(String message, Throwable throwable) { + super(message, throwable); + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/factory/StoragePluginFactory.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/factory/StoragePluginFactory.java new file mode 100644 index 0000000000..237491c2ff --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/factory/StoragePluginFactory.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.factory; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; + +/** + * The factory to get connector {@link Admin}, {@link Producer} and {@link Consumer} + */ +public class StoragePluginFactory { + + /** + * Get MeshMQAdmin instance by plugin name + * + * @param connectorPluginName plugin name + * @return MeshMQAdmin instance + */ + public static Admin getMeshMQAdmin(String connectorPluginName) { + return EventMeshExtensionFactory.getExtension(Admin.class, connectorPluginName); + } + + /** + * Get MeshMQProducer instance by plugin name + * + * @param connectorPluginName plugin name + * @return MeshMQProducer instance + */ + public static Producer getMeshMQProducer(String connectorPluginName) { + return EventMeshExtensionFactory.getExtension(Producer.class, connectorPluginName); + } + + /** + * Get MeshMQPushConsumer instance by plugin name + * + * @param connectorPluginName plugin name + * @return MeshMQPushConsumer instance + */ + public static Consumer getMeshMQPushConsumer(String connectorPluginName) { + return EventMeshExtensionFactory.getExtension(Consumer.class, connectorPluginName); + } + + private static T getPlugin(Class pluginType, String pluginName) { + return EventMeshExtensionFactory.getExtension(pluginType, pluginName); + } +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/producer/Producer.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/producer/Producer.java similarity index 96% rename from eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/producer/Producer.java rename to eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/producer/Producer.java index d8fd2b6a7f..d023004dc0 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/api/producer/Producer.java +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/producer/Producer.java @@ -20,7 +20,6 @@ import org.apache.eventmesh.api.LifeCycle; import org.apache.eventmesh.api.RequestReplyCallback; import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; import org.apache.eventmesh.spi.EventMeshExtensionType; import org.apache.eventmesh.spi.EventMeshSPI; @@ -31,7 +30,7 @@ /** * Producer Interface. */ -@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.CONNECTOR) +@EventMeshSPI(isSingleton = false, eventMeshExtensionType = EventMeshExtensionType.STORAGE) public interface Producer extends LifeCycle { void init(Properties properties) throws Exception; diff --git a/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/storage/StorageResourceService.java b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/storage/StorageResourceService.java new file mode 100644 index 0000000000..c92b93d6ba --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-api/src/main/java/org/apache/eventmesh/api/storage/StorageResourceService.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.api.storage; + +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + +/** + * ConnectorResourceService + */ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.STORAGE) +public interface StorageResourceService { + + /** + * Resource initialization in connector,such as,some public thread pool if exist + * + * @throws Exception + */ + void init() throws Exception; + + /** + * Resource release in connector,such as,some public thread pool if exist + * + * @throws Exception + */ + void release() throws Exception; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-kafka/build.gradle new file mode 100644 index 0000000000..dbae8d398d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/build.gradle @@ -0,0 +1,40 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-common") + // https://mavenlibs.com/maven/dependency/io.cloudevents/cloudevents-kafka + implementation group: 'io.cloudevents', name: 'cloudevents-kafka', version: '2.5.0' + + // https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients + implementation 'org.apache.kafka:kafka-clients:3.9.0' + + testImplementation 'org.junit.jupiter:junit-jupiter' + + testImplementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + testImplementation project(":eventmesh-common") + + testImplementation "org.mockito:mockito-core" + + compileOnly 'org.projectlombok:lombok' + compileOnly 'com.google.code.findbugs:jsr305:3.0.2' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties new file mode 100644 index 0000000000..84cc1ec8d2 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/gradle.properties @@ -0,0 +1,20 @@ +# 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. +# + +kafka_version=3.2.0 + +pluginType=storage +pluginName=kafka \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/admin/KafkaAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/admin/KafkaAdmin.java new file mode 100644 index 0000000000..f86bfee87d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/admin/KafkaAdmin.java @@ -0,0 +1,150 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.admin; + +import static org.apache.eventmesh.storage.kafka.common.EventMeshConstants.DEFAULT_TIMEOUT_IN_SECONDS; + +import org.apache.eventmesh.api.admin.AbstractAdmin; +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.storage.kafka.config.ClientConfiguration; + +import org.apache.kafka.clients.admin.Admin; +import org.apache.kafka.clients.admin.ListOffsetsResult.ListOffsetsResultInfo; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.clients.admin.OffsetSpec; +import org.apache.kafka.clients.admin.TopicDescription; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.KafkaFuture; +import org.apache.kafka.common.TopicPartition; +import org.apache.kafka.common.TopicPartitionInfo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KafkaAdmin extends AbstractAdmin { + + // properties for kafka admin client + private static final Properties kafkaProps = new Properties(); + + // properties for topic management + private static final Map topicProps = new HashMap<>(); + + public KafkaAdmin() { + super(new AtomicBoolean(false)); + + ConfigService configService = ConfigService.getInstance(); + ClientConfiguration clientConfiguration = configService.buildConfigInstance(ClientConfiguration.class); + + kafkaProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, clientConfiguration.getNamesrvAddr()); + topicProps.put("partitionNum", clientConfiguration.getPartitions()); + topicProps.put("replicationFactorNum", (int) clientConfiguration.getReplicationFactors()); + } + + @Override + public List getTopic() { + try (Admin client = Admin.create(kafkaProps)) { + Set topicList = client.listTopics().names().get(DEFAULT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + Map> topicDescriptionFutures = client.describeTopics(topicList).values(); + List result = new ArrayList<>(); + for (Entry> entry : topicDescriptionFutures.entrySet()) { + String topicName = entry.getKey(); + TopicDescription topicDescription = entry.getValue().get(DEFAULT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + + long messageCount = topicDescription.partitions().stream() + .mapToInt(TopicPartitionInfo::partition) + .mapToLong(partition -> { + try { + return getMsgCount(topicName, partition, client); + } catch (TimeoutException e) { + log.error("Failed to get msg offset when listing topics. Kafka response timed out in {} seconds.", + DEFAULT_TIMEOUT_IN_SECONDS); + throw new RuntimeException(e); + } catch (ExecutionException | InterruptedException e) { + log.error("Failed to get msg offset when listing topics.", e); + throw new RuntimeException(e); + } + }) + .sum(); + + result.add(new TopicProperties(topicName, messageCount)); + } + result.sort(Comparator.comparing(t -> t.name)); + return result; + } catch (TimeoutException e) { + log.error("Failed to list topics. Kafka response timed out in {} seconds.", DEFAULT_TIMEOUT_IN_SECONDS); + throw new RuntimeException(e); + } catch (Exception e) { + log.error("Failed to list topics.", e); + throw new RuntimeException(e); + } + } + + private long getMsgCount(String topicName, int partition, Admin client) throws ExecutionException, InterruptedException, TimeoutException { + TopicPartition topicPartition = new TopicPartition(topicName, partition); + long earliestOffset = getOffset(topicPartition, OffsetSpec.earliest(), client); + long latestOffset = getOffset(topicPartition, OffsetSpec.latest(), client); + return latestOffset - earliestOffset; + } + + private long getOffset(TopicPartition topicPartition, OffsetSpec offsetSpec, Admin client) + throws ExecutionException, InterruptedException, TimeoutException { + Map offsetSpecMap = Collections.singletonMap(topicPartition, offsetSpec); + Map offsetResultMap = + client.listOffsets(offsetSpecMap).all().get(DEFAULT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + return offsetResultMap.get(topicPartition).offset(); + } + + @Override + public void createTopic(String topicName) { + try (Admin client = Admin.create(kafkaProps)) { + NewTopic newTopic = new NewTopic(topicName, topicProps.get("partitionNum"), topicProps.get("replicationFactorNum").shortValue()); + client.createTopics(Collections.singletonList(newTopic)).all().get(DEFAULT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + } catch (TimeoutException e) { + log.error("Failed to create topic. Kafka response timed out in {} seconds.", DEFAULT_TIMEOUT_IN_SECONDS); + } catch (Exception e) { + log.error("Failed to create topic.", e); + } + } + + @Override + public void deleteTopic(String topicName) { + try (Admin client = Admin.create(kafkaProps)) { + client.deleteTopics(Collections.singletonList(topicName)).all().get(DEFAULT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + } catch (TimeoutException e) { + log.error("Failed to delete topic. Kafka response timed out in {} seconds.", DEFAULT_TIMEOUT_IN_SECONDS); + } catch (Exception e) { + log.error("Failed to delete topic.", e); + } + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/admin/KafkaAdminAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/admin/KafkaAdminAdaptor.java new file mode 100644 index 0000000000..042756d457 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/admin/KafkaAdminAdaptor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.admin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +public class KafkaAdminAdaptor implements Admin { + + private final KafkaAdmin admin; + + public KafkaAdminAdaptor() { + admin = new KafkaAdmin(); + } + + @Override + public boolean isStarted() { + return admin.isStarted(); + } + + @Override + public boolean isClosed() { + return admin.isClosed(); + } + + @Override + public void start() { + admin.start(); + } + + @Override + public void shutdown() { + admin.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + admin.init(properties); + } + + @Override + public List getTopic() throws Exception { + return admin.getTopic(); + } + + @Override + public void createTopic(String topicName) throws Exception { + admin.createTopic(topicName); + } + + @Override + public void deleteTopic(String topicName) throws Exception { + admin.deleteTopic(topicName); + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return admin.getEvent(topicName, offset, length); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + admin.publish(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/common/Constants.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/common/Constants.java new file mode 100644 index 0000000000..3e6e4c8003 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/common/Constants.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.common; + +public class Constants { + + public static final String BROADCAST_PREFIX = "broadcast-"; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/common/EventMeshConstants.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/common/EventMeshConstants.java new file mode 100644 index 0000000000..4b54846ce4 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/common/EventMeshConstants.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.common; + +public class EventMeshConstants { + + public static final String EVENTMESH_CONF_FILE = "kafka-client.properties"; + + public static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; + + public static final int DEFAULT_TIMEOUT_IN_SECONDS = 10; + + public static final String STORE_TIMESTAMP = "storetime"; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/config/ClientConfiguration.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/config/ClientConfiguration.java new file mode 100644 index 0000000000..0eff16ec7c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/config/ClientConfiguration.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Config(prefix = "eventMesh.server.kafka", path = "classPath://kafka-client.properties") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ClientConfiguration { + + @ConfigField(field = "namesrvAddr", notEmpty = true) + @Builder.Default + private String namesrvAddr = ""; + + @ConfigField(field = "username") + @Builder.Default + private String clientUserName = "username"; + + @ConfigField(field = "password") + @Builder.Default + private String clientPass = "password"; + + @ConfigField(field = "num.partitions") + @Builder.Default + private int partitions = 1; + + @ConfigField(field = "num.replicationFactors") + @Builder.Default + private short replicationFactors = 1; + + @ConfigField(field = "client.consumeThreadMin") + @Builder.Default + private Integer consumeThreadMin = 2; + + @ConfigField(field = "client.consumeThreadMax") + @Builder.Default + private Integer consumeThreadMax = 2; + + @ConfigField(field = "client.consumeThreadPoolQueueSize") + @Builder.Default + private Integer consumeQueueSize = 10000; + + @ConfigField(field = "client.pullBatchSize") + @Builder.Default + private Integer pullBatchSize = 32; + + @ConfigField(field = "client.ackwindow") + @Builder.Default + private Integer ackWindow = 1000; + + @ConfigField(field = "client.pubwindow") + @Builder.Default + private Integer pubWindow = 100; + + @ConfigField(field = "client.comsumeTimeoutInMin") + @Builder.Default + private long consumeTimeout = 0L; + + @ConfigField(field = "client.pollNameServerInterval") + @Builder.Default + private Integer pollNameServerInterval = 10 * 1000; + + @ConfigField(field = "client.heartbeatBrokerInterval") + @Builder.Default + private Integer heartbeatBrokerInterval = 30 * 1000; + + @ConfigField(field = "client.rebalanceInterval") + @Builder.Default + private Integer rebalanceInterval = 20 * 1000; + + @ConfigField(field = "cluster") + @Builder.Default + private String clusterName = ""; + + @ConfigField(field = "accessKey") + @Builder.Default + private String accessKey = ""; + + @ConfigField(field = "secretKey") + @Builder.Default + private String secretKey = ""; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/ConsumerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/ConsumerImpl.java new file mode 100644 index 0000000000..467ffb7d0f --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/ConsumerImpl.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.exception.StorageRuntimeException; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.TopicPartition; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; +import io.cloudevents.kafka.CloudEventDeserializer; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ConsumerImpl { + + private final KafkaConsumer kafkaConsumer; + private final Properties properties; + private AtomicBoolean started = new AtomicBoolean(false); + private EventListener eventListener; + private KafkaConsumerRunner kafkaConsumerRunner; + private ExecutorService executorService; + private Set topicsSet; + + public ConsumerImpl(final Properties properties) { + // Setting the ClassLoader to null is necessary for Kafka consumer configuration + final ClassLoader original = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(null); + + Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, properties.getProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, CloudEventDeserializer.class); + props.put(ConsumerConfig.GROUP_ID_CONFIG, properties.getProperty(ConsumerConfig.GROUP_ID_CONFIG)); + props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false"); + + this.properties = props; + this.kafkaConsumer = new KafkaConsumer(props); + kafkaConsumerRunner = new KafkaConsumerRunner(this.kafkaConsumer); + executorService = Executors.newFixedThreadPool(10); + topicsSet = new HashSet<>(); + + Thread.currentThread().setContextClassLoader(original); + } + + public Properties attributes() { + return properties; + } + + public void start() { + if (this.started.compareAndSet(false, true)) { + executorService.submit(kafkaConsumerRunner); + } + } + + public synchronized void shutdown() { + if (this.started.compareAndSet(true, false)) { + // Shutdown the executor and interrupt any running tasks + kafkaConsumerRunner.shutdown(); + executorService.shutdown(); + } + } + + public boolean isStarted() { + return this.started.get(); + } + + public boolean isClosed() { + return !this.isStarted(); + } + + public KafkaConsumer getKafkaConsumer() { + return kafkaConsumer; + } + + public synchronized void subscribe(String topic) { + try { + // Get the current subscription + topicsSet.add(topic); + List topics = new ArrayList<>(topicsSet); + this.kafkaConsumer.subscribe(topics); + } catch (Exception e) { + log.error("Error while subscribing the Kafka consumer to topic: ", e); + throw new StorageRuntimeException( + String.format("Kafka consumer can't attach to %s.", topic)); + } + } + + public synchronized void unsubscribe(String topic) { + try { + // Kafka will unsubscribe *all* topic if calling unsubscribe, so we + this.kafkaConsumer.unsubscribe(); + topicsSet.remove(topic); + List topics = new ArrayList<>(topicsSet); + this.kafkaConsumer.subscribe(topics); + } catch (Exception e) { + log.error("Error while unsubscribing the Kafka consumer: ", e); + throw new StorageRuntimeException(String.format("kafka push consumer fails to unsubscribe topic: %s", topic)); + } + } + + public void updateOffset(List cloudEvents, AbstractContext context) { + Long maxOffset = cloudEvents.stream().map(cloudEvent -> this.kafkaConsumerRunner.getOffset(cloudEvent)).max(Long::compare).get(); + cloudEvents.forEach(cloudEvent -> this.updateOffset(cloudEvent.getSubject(), maxOffset)); + } + + public void updateOffset(String topicName, long offset) { + this.kafkaConsumer.seek(new TopicPartition(topicName, 1), offset); + } + + public void registerEventListener(EventListener listener) { + this.eventListener = listener; + this.kafkaConsumerRunner.setListener(this.eventListener); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/KafkaConsumerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/KafkaConsumerImpl.java new file mode 100644 index 0000000000..0fa75d3843 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/KafkaConsumerImpl.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.kafka.config.ClientConfiguration; + +import org.apache.kafka.clients.consumer.ConsumerConfig; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +@Config(field = "clientConfiguration") +public class KafkaConsumerImpl implements Consumer { + + private ConsumerImpl consumer; + + /** + * Unified configuration class corresponding to kafka-client.properties + */ + private ClientConfiguration clientConfiguration; + + @Override + public synchronized void init(Properties props) { + String namesrvAddr = clientConfiguration.getNamesrvAddr(); + String consumerGroup = props.getProperty("consumerGroup"); + + // Other config props + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, namesrvAddr); + props.put(ConsumerConfig.GROUP_ID_CONFIG, consumerGroup); + consumer = new ConsumerImpl(props); + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + consumer.updateOffset(cloudEvents, context); + } + + @Override + public void subscribe(String topic) { + consumer.subscribe(topic); + } + + @Override + public boolean isStarted() { + return consumer.isStarted(); + } + + @Override + public boolean isClosed() { + return consumer.isClosed(); + } + + @Override + public synchronized void start() { + consumer.start(); + } + + @Override + public void unsubscribe(String topic) { + consumer.unsubscribe(topic); + } + + @Override + public void registerEventListener(EventListener listener) { + consumer.registerEventListener(listener); + } + + @Override + public synchronized void shutdown() { + consumer.shutdown(); + } + + public ClientConfiguration getClientConfiguration() { + return this.clientConfiguration; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/KafkaConsumerRunner.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/KafkaConsumerRunner.java new file mode 100644 index 0000000000..93d86181a5 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/consumer/KafkaConsumerRunner.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.consumer; + +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; + +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.errors.WakeupException; + +import java.time.Duration; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class KafkaConsumerRunner implements Runnable { + + private final AtomicBoolean closed = new AtomicBoolean(false); + private final KafkaConsumer consumer; + private ConcurrentHashMap cloudEventToOffset; + private EventListener listener; + + public KafkaConsumerRunner(KafkaConsumer kafkaConsumer) { + this.consumer = kafkaConsumer; + cloudEventToOffset = new ConcurrentHashMap<>(); + } + + public synchronized void setListener(EventListener listener) { + this.listener = listener; + } + + public long getOffset(CloudEvent cloudEvent) { + return cloudEventToOffset.getOrDefault(cloudEvent, 0L); + } + + @Override + public void run() { + try { + while (!closed.get()) { + if (consumer.subscription().isEmpty()) { + // consumer cannot poll if it is subscribe to nothing + continue; + } + ConsumerRecords records = consumer.poll(Duration.ofMillis(10000)); + // Handle new records + records.forEach(rec -> { + try { + CloudEvent cloudEvent = rec.value(); + String topicName = cloudEvent.getSubject(); + EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + switch (action) { + case CommitMessage: + // update offset + log.info("message commit, topic: {}, current offset:{}", topicName, + rec.offset()); + break; + case ManualAck: + // update offset + log.info("message ack, topic: {}, current offset:{}", topicName, rec.offset()); + break; + case ReconsumeLater: + default: + } + } + }; + cloudEventToOffset.put(cloudEvent, rec.offset()); + if (listener != null) { + listener.consume(cloudEvent, eventMeshAsyncConsumeContext); + } + } catch (Exception e) { + log.info("Error parsing cloudevents: {}", e.getMessage()); + } + }); + } + } catch (WakeupException e) { + // Ignore exception if closing + if (!closed.get()) { + throw e; + } + } finally { + consumer.close(); + } + } + + // Shutdown hook which can be called from a separate thread + public void shutdown() { + closed.set(true); + consumer.wakeup(); + } +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/producer/KafkaProducerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/producer/KafkaProducerImpl.java new file mode 100644 index 0000000000..fbc9352a84 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/producer/KafkaProducerImpl.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.kafka.config.ClientConfiguration; + +import org.apache.kafka.clients.producer.ProducerConfig; + +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +@Config(field = "clientConfiguration") +public class KafkaProducerImpl implements Producer { + + private ProducerImpl producer; + + /** + * Unified configuration class corresponding to kafka-client.properties + */ + private ClientConfiguration clientConfiguration; + + @Override + public synchronized void init(Properties keyValue) { + String namesrvAddr = clientConfiguration.getNamesrvAddr(); + + keyValue.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, namesrvAddr); + this.producer = new ProducerImpl(keyValue); + } + + @Override + public boolean isStarted() { + return producer.isStarted(); + } + + @Override + public boolean isClosed() { + return producer.isClosed(); + } + + @Override + public void start() { + producer.start(); + } + + @Override + public synchronized void shutdown() { + producer.shutdown(); + } + + @Override + public void publish(CloudEvent message, SendCallback sendCallback) throws Exception { + producer.sendAsync(message, sendCallback); + } + + @Override + public void request(CloudEvent message, RequestReplyCallback rrCallback, long timeout) throws Exception { + producer.request(message, rrCallback, timeout); + } + + @Override + public boolean reply(final CloudEvent message, final SendCallback sendCallback) throws Exception { + producer.reply(message, sendCallback); + return true; + } + + @Override + public void checkTopicExist(String topic) throws Exception { + this.producer.checkTopicExist(topic); + } + + @Override + public void setExtFields() { + // producer.setExtFields(); + } + + @Override + public void sendOneway(CloudEvent message) { + producer.sendOneway(message); + } + + public ClientConfiguration getClientConfiguration() { + return this.clientConfiguration; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/producer/ProducerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/producer/ProducerImpl.java new file mode 100644 index 0000000000..0a41a42f2a --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/producer/ProducerImpl.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.exception.StorageRuntimeException; + +import org.apache.kafka.clients.admin.Admin; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringSerializer; + +import java.util.Objects; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; +import io.cloudevents.kafka.CloudEventSerializer; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@SuppressWarnings("deprecation") +public class ProducerImpl { + + private final KafkaProducer producer; + private final Properties properties = new Properties(); + private final AtomicBoolean isStarted = new AtomicBoolean(false); + + public ProducerImpl(Properties props) { + properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, + props.getProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG)); + properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, CloudEventSerializer.class); + this.producer = new KafkaProducer<>(properties); + } + + public boolean isStarted() { + return isStarted.get(); + } + + public boolean isClosed() { + return !isStarted.get(); + } + + public void start() { + isStarted.compareAndSet(false, true); + } + + public void shutdown() { + isStarted.compareAndSet(true, false); + } + + public void init(Properties properties) { + this.properties.putAll(properties); + } + + public void send(CloudEvent cloudEvent) { + try { + this.producer.send(new ProducerRecord<>(Objects.requireNonNull(cloudEvent.getSubject()), cloudEvent)); + } catch (Exception e) { + log.error(String.format("Send message oneway Exception, %s", cloudEvent), e); + } + } + + public void checkTopicExist(String topic) throws ExecutionException, InterruptedException, StorageRuntimeException { + try (Admin admin = Admin.create(properties)) { + Set topicNames = admin.listTopics().names().get(); + boolean exist = topicNames.contains(topic); + if (!exist) { + throw new StorageRuntimeException(String.format("topic:%s is not exist", topic)); + } + } + } + + public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) throws Exception { + throw new StorageRuntimeException("Request is not supported"); + } + + public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + throw new StorageRuntimeException("Reply is not supported"); + } + + public void sendOneway(CloudEvent message) { + } + + public void sendAsync(CloudEvent cloudEvent, SendCallback sendCallback) { + try { + this.producer.send(new ProducerRecord<>(Objects.requireNonNull(cloudEvent.getSubject()), cloudEvent), (metadata, exception) -> { + if (exception != null) { + StorageRuntimeException onsEx = new StorageRuntimeException(exception.getMessage(), exception); + OnExceptionContext context = new OnExceptionContext(); + context.setTopic(cloudEvent.getSubject()); + context.setException(onsEx); + sendCallback.onException(context); + } else { + SendResult sendResult = new SendResult(); + sendResult.setTopic(cloudEvent.getSubject()); + sendResult.setMessageId(cloudEvent.getId()); + sendCallback.onSuccess(sendResult); + } + }); + } catch (Exception e) { + log.error(String.format("Send message oneway Exception, %s", cloudEvent), e); + } + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/storage/StorageResourceServiceKafkaImpl.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/storage/StorageResourceServiceKafkaImpl.java new file mode 100644 index 0000000000..5ee4b8eb8c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/java/org/apache/eventmesh/storage/kafka/storage/StorageResourceServiceKafkaImpl.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.storage; + +import org.apache.eventmesh.api.storage.StorageResourceService; + +public class StorageResourceServiceKafkaImpl implements StorageResourceService { + + @Override + public void init() throws Exception { + + } + + @Override + public void release() throws Exception { + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin new file mode 100644 index 0000000000..9f8cb52ae3 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin @@ -0,0 +1,16 @@ +# 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. + +kafka=org.apache.eventmesh.storage.kafka.admin.KafkaAdminAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer new file mode 100644 index 0000000000..015cc5c7a1 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer @@ -0,0 +1,16 @@ +# 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. + +kafka=org.apache.eventmesh.storage.kafka.consumer.KafkaConsumerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer new file mode 100644 index 0000000000..15ad334712 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer @@ -0,0 +1,16 @@ +# 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. + +kafka=org.apache.eventmesh.storage.kafka.producer.KafkaProducerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService new file mode 100644 index 0000000000..6b314f5c5e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService @@ -0,0 +1,16 @@ +# 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. + +kafka=org.apache.eventmesh.storage.kafka.storage.StorageResourceServiceKafkaImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/kafka-client.properties b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/kafka-client.properties new file mode 100644 index 0000000000..cbe0a036fa --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/main/resources/kafka-client.properties @@ -0,0 +1,141 @@ +# +# 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. +# + +# Configurations started with 'eventMesh.server.kafka' are required for EventMesh. +# You may see kafka.server.KafkaConfig for additional details and defaults of the rest of the configurations. + +############################# EventMesh Kafka Client ############################# + +eventMesh.server.kafka.namesrvAddr=localhost:9092;localhost:9092 +eventMesh.server.kafka.cluster=DefaultCluster +eventMesh.server.kafka.accessKey=******** +eventMesh.server.kafka.secretKey=******** + +############################# EventMesh Log Basics ############################# + +# the number of partitions per topic +eventMesh.server.kafka.num.partitions=1 +# the number of replication factors per topic +eventMesh.server.kafka.num.replicationFactors=1 + +############################# Server Basics ############################# + +# The id of the broker. This must be set to a unique integer for each broker. +broker.id=0 + +############################# Socket Server Settings ############################# + +# Hostname the broker will bind to. If not set, the server will bind to all interfaces +#host.name=localhost + +# Hostname the broker will advertise to producers and consumers. If not set, it uses the +# value for "host.name" if configured. Otherwise, it will use the value returned from +# java.net.InetAddress.getCanonicalHostName(). +#advertised.host.name= + +# The port to publish to ZooKeeper for clients to use. If this is not set, +# it will publish the same port that the broker binds to. +#advertised.port= + +# The number of threads handling network requests +num.network.threads=2 + +# The number of threads doing disk I/O +num.io.threads=8 + +# The send buffer (SO_SNDBUF) used by the socket server +socket.send.buffer.bytes=1048576 + +# The receive buffer (SO_RCVBUF) used by the socket server +socket.receive.buffer.bytes=1048576 + +# The maximum size of a request that the socket server will accept (protection against OOM) +socket.request.max.bytes=104857600 + + +############################# Log Basics ############################# + +# A comma seperated list of directories under which to store log files +log.dirs=c:/tmp/kafka-logs/broker0 + +# The default number of log partitions per topic. More partitions allow greater +# parallelism for consumption, but this will also result in more files across +# the brokers. +num.partitions=2 + +############################# Log Flush Policy ############################# + +# Messages are immediately written to the filesystem but by default we only fsync() to sync +# the OS cache lazily. The following configurations control the flush of data to disk. +# There are a few important trade-offs here: +# 1. Durability: Unflushed data may be lost if you are not using replication. +# 2. Latency: Very large flush intervals may lead to latency spikes when the flush does occur as there will be a lot of data to flush. +# 3. Throughput: The flush is generally the most expensive operation, and a small flush interval may lead to exceessive seeks. +# The settings below allow one to configure the flush policy to flush data after a period of time or +# every N messages (or both). This can be done globally and overridden on a per-topic basis. + +# The number of messages to accept before forcing a flush of data to disk +#log.flush.interval.messages=10000 + +# The maximum amount of time a message can sit in a log before we force a flush +#log.flush.interval.ms=1000 + +############################# Log Retention Policy ############################# + +# The following configurations control the disposal of log segments. The policy can +# be set to delete segments after a period of time, or after a given size has accumulated. +# A segment will be deleted whenever *either* of these criteria are met. Deletion always happens +# from the end of the log. + +# The minimum age of a log file to be eligible for deletion +log.retention.hours=168 + +# A size-based retention policy for logs. Segments are pruned from the log as long as the remaining +# segments don't drop below log.retention.bytes. +#log.retention.bytes=1073741824 + +# The maximum size of a log segment file. When this size is reached a new log segment will be created. +log.segment.bytes=536870912 + +# The interval at which log segments are checked to see if they can be deleted according +# to the retention policies +log.retention.check.interval.ms=60000 + +# By default the log cleaner is disabled and the log retention policy will default to just delete segments after their retention expires. +# If log.cleaner.enable=true is set the cleaner will be enabled and individual logs can then be marked for log compaction. +log.cleaner.enable=false + +############################# Zookeeper ############################# + +# Zookeeper connection string (see zookeeper docs for details). +# This is a comma separated host:port pairs, each corresponding to a zk +# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002". +# You can also append an optional chroot string to the urls to specify the +# root directory for all kafka znodes. +zookeeper.connect=localhost:2181 + +# Timeout in ms for connecting to zookeeper +zookeeper.connection.timeout.ms=1000000 + +############################# Producer Basics ############################# + +# list of brokers used for bootstrapping knowledge about the rest of the cluster +# format: host1:port1,host2:port2 ... +metadata.broker.list=localhost:9092 + +# specifies whether the messages are sent asynchronously (async) or synchronously (sync) +producer.type=async \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/java/org/apache/eventmesh/storage/kafka/config/ClientConfigurationTest.java b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/java/org/apache/eventmesh/storage/kafka/config/ClientConfigurationTest.java new file mode 100644 index 0000000000..d9a0c8ca0f --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/java/org/apache/eventmesh/storage/kafka/config/ClientConfigurationTest.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.kafka.config; + +import org.apache.eventmesh.api.factory.StoragePluginFactory; +import org.apache.eventmesh.storage.kafka.consumer.KafkaConsumerImpl; +import org.apache.eventmesh.storage.kafka.producer.KafkaProducerImpl; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * test config of Kafka SPI Impl + */ +public class ClientConfigurationTest { + + /** + * test KafkaConsumerImpl config init when ConnectorPluginFactory get it + */ + @Test + public void getConfigWhenKafkaConsumerImplInit() { + KafkaConsumerImpl consumer = (KafkaConsumerImpl) StoragePluginFactory.getMeshMQPushConsumer("kafka"); + ClientConfiguration config = consumer.getClientConfiguration(); + assertConfig(config); + } + + /** + * test KafkaProducerImpl config init when ConnectorPluginFactory get it + */ + @Test + public void getConfigWhenKafkaProducerImplInit() { + KafkaProducerImpl producer = (KafkaProducerImpl) StoragePluginFactory.getMeshMQProducer("kafka"); + ClientConfiguration config = producer.getClientConfiguration(); + assertConfig(config); + } + + private void assertConfig(ClientConfiguration config) { + Assertions.assertEquals("127.0.0.1:9092;127.0.0.1:9092", config.getNamesrvAddr()); + Assertions.assertEquals("username-succeed!!!", config.getClientUserName()); + Assertions.assertEquals("password-succeed!!!", config.getClientPass()); + Assertions.assertEquals(Integer.valueOf(1816), config.getConsumeThreadMin()); + Assertions.assertEquals(Integer.valueOf(2816), config.getConsumeThreadMax()); + Assertions.assertEquals(Integer.valueOf(3816), config.getConsumeQueueSize()); + Assertions.assertEquals(Integer.valueOf(4816), config.getPullBatchSize()); + Assertions.assertEquals(Integer.valueOf(5816), config.getAckWindow()); + Assertions.assertEquals(Integer.valueOf(6816), config.getPubWindow()); + Assertions.assertEquals(7816, config.getConsumeTimeout()); + Assertions.assertEquals(Integer.valueOf(8816), config.getPollNameServerInterval()); + Assertions.assertEquals(Integer.valueOf(9816), config.getHeartbeatBrokerInterval()); + Assertions.assertEquals(Integer.valueOf(11816), config.getRebalanceInterval()); + Assertions.assertEquals("cluster-succeed!!!", config.getClusterName()); + Assertions.assertEquals("accessKey-succeed!!!", config.getAccessKey()); + Assertions.assertEquals("secretKey-succeed!!!", config.getSecretKey()); + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer new file mode 100644 index 0000000000..250a802e47 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer @@ -0,0 +1,19 @@ +# +# 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. +# + + +org.apache.eventmesh.connector.kafka.producer.ProducerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/resources/kafka-client.properties b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/resources/kafka-client.properties new file mode 100644 index 0000000000..d8517aad16 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-kafka/src/test/resources/kafka-client.properties @@ -0,0 +1,33 @@ +# +# 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. +# +#######################kafka-client################## +eventMesh.server.kafka.namesrvAddr=127.0.0.1:9092;127.0.0.1:9092 +eventMesh.server.kafka.username=username-succeed!!! +eventMesh.server.kafka.password=password-succeed!!! +eventMesh.server.kafka.client.consumeThreadMin=1816 +eventMesh.server.kafka.client.consumeThreadMax=2816 +eventMesh.server.kafka.client.consumeThreadPoolQueueSize=3816 +eventMesh.server.kafka.client.pullBatchSize=4816 +eventMesh.server.kafka.client.ackwindow=5816 +eventMesh.server.kafka.client.pubwindow=6816 +eventMesh.server.kafka.client.comsumeTimeoutInMin=7816 +eventMesh.server.kafka.client.pollNameServerInterval=8816 +eventMesh.server.kafka.client.heartbeatBrokerInterval=9816 +eventMesh.server.kafka.client.rebalanceInterval=11816 +eventMesh.server.kafka.cluster=cluster-succeed!!! +eventMesh.server.kafka.accessKey=accessKey-succeed!!! +eventMesh.server.kafka.secretKey=secretKey-succeed!!! \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-pulsar/build.gradle new file mode 100644 index 0000000000..9bdffd0027 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/build.gradle @@ -0,0 +1,54 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + + /* + * TODO: This is a shaded artifact that contains 20 MiB of external libraries. It could probably be replaced by: + * + * implementation "org.apache.pulsar:pulsar-client-api:$pulsar_version" + * runtimeOnly "org.apache.pulsar:pulsar-client-original:$pulsar_version" + * + * The exclusions can be removed after an upgrade of the transitive: + * + * "org.apache.bookkeeper:bookkeeper" + * + * dependency to 4.15.4 or higher (used by Pulsar 2.11.2 or higher). + */ + implementation('org.apache.pulsar:pulsar-client:2.11.4') { + // Remove logging backend implementations + exclude group: 'org.apache.logging.log4j', module: 'log4j-core' + exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' + } + + testImplementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + testImplementation project(":eventmesh-common") + + implementation 'io.cloudevents:cloudevents-json-jackson' + + testImplementation 'io.cloudevents:cloudevents-json-jackson' + + testImplementation "org.mockito:mockito-core" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-pulsar/gradle.properties new file mode 100644 index 0000000000..da19b5bdda --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# + +pluginType=storage +pluginName=pulsar \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/admin/PulsarAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/admin/PulsarAdmin.java new file mode 100644 index 0000000000..f75f655f9c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/admin/PulsarAdmin.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.admin; + +import org.apache.eventmesh.api.admin.AbstractAdmin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +public class PulsarAdmin extends AbstractAdmin { + + public PulsarAdmin() { + super(new AtomicBoolean(false)); + } + + @Override + public List getTopic() { + // TODO implement admin functions + return new ArrayList<>(); + } + + @Override + public void createTopic(String topicName) { + } + + @Override + public void deleteTopic(String topicName) { + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + } + + @Override + public void shutdown() { + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/admin/PulsarAdminAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/admin/PulsarAdminAdaptor.java new file mode 100644 index 0000000000..e2e58c6b7e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/admin/PulsarAdminAdaptor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.admin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +public class PulsarAdminAdaptor implements Admin { + + private final PulsarAdmin admin; + + public PulsarAdminAdaptor() { + admin = new PulsarAdmin(); + } + + @Override + public boolean isStarted() { + return admin.isStarted(); + } + + @Override + public boolean isClosed() { + return admin.isClosed(); + } + + @Override + public void start() { + admin.start(); + } + + @Override + public void shutdown() { + admin.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + admin.init(properties); + } + + @Override + public List getTopic() throws Exception { + return admin.getTopic(); + } + + @Override + public void createTopic(String topicName) { + admin.createTopic(topicName); + } + + @Override + public void deleteTopic(String topicName) { + admin.deleteTopic(topicName); + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return admin.getEvent(topicName, offset, length); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + admin.publish(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/client/PulsarClientWrapper.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/client/PulsarClientWrapper.java new file mode 100644 index 0000000000..a164b69e64 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/client/PulsarClientWrapper.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.client; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.storage.pulsar.config.ClientConfiguration; +import org.apache.eventmesh.storage.pulsar.utils.CloudEventUtils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.pulsar.client.api.AuthenticationFactory; +import org.apache.pulsar.client.api.ClientBuilder; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.jackson.JsonFormat; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PulsarClientWrapper { + + private final ClientConfiguration config; + private final PulsarClient pulsarClient; + private final Map> producerMap = new HashMap<>(); + + public PulsarClientWrapper(ClientConfiguration config, Properties properties) { + this.config = config; + String token = properties.getProperty(Constants.PRODUCER_TOKEN); + try { + ClientBuilder clientBuilder = PulsarClient.builder() + .serviceUrl(config.getServiceAddr()); + + if (config.getAuthPlugin() != null) { + Preconditions.checkNotNull(config.getAuthParams(), + "Authentication Enabled in pulsar cluster, Please set authParams in pulsar-client.properties"); + clientBuilder.authentication( + config.getAuthPlugin(), + config.getAuthParams()); + } + if (StringUtils.isNotBlank(token)) { + clientBuilder.authentication( + AuthenticationFactory.token(token)); + } + + this.pulsarClient = clientBuilder.build(); + } catch (PulsarClientException ex) { + throw new StorageRuntimeException( + String.format("Failed to connect pulsar cluster %s with exception: %s", config.getServiceAddr(), ex.getMessage())); + } + } + + private Producer createProducer(String topic) { + try { + return this.pulsarClient.newProducer() + .topic(topic) + .batchingMaxPublishDelay(10, TimeUnit.MILLISECONDS) + .sendTimeout(10, TimeUnit.SECONDS) + .blockIfQueueFull(true) + .create(); + } catch (PulsarClientException ex) { + throw new StorageRuntimeException( + String.format("Failed to create pulsar producer for %s with exception: %s", topic, ex.getMessage())); + } + } + + public void publish(CloudEvent cloudEvent, SendCallback sendCallback) { + String topic = config.getTopicPrefix() + cloudEvent.getSubject(); + Producer producer = producerMap.computeIfAbsent(topic, k -> createProducer(topic)); + try { + byte[] serializedCloudEvent = Objects.requireNonNull(EventFormatProvider + .getInstance() + .resolveFormat(JsonFormat.CONTENT_TYPE)) + .serialize(cloudEvent); + producer.sendAsync(serializedCloudEvent).thenAccept(messageId -> { + sendCallback.onSuccess(CloudEventUtils.convertSendResult(cloudEvent)); + }); + } catch (Exception ex) { + log.error("Failed to publish cloudEvent for {} with exception: {}", + cloudEvent.getSubject(), ex.getMessage()); + } + } + + public void shutdown() throws PulsarClientException { + pulsarClient.close(); + for (Map.Entry> producerEntry : producerMap.entrySet()) { + producerEntry.getValue().close(); + } + producerMap.clear(); + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/config/ClientConfiguration.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/config/ClientConfiguration.java new file mode 100644 index 0000000000..f84628cf05 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/config/ClientConfiguration.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Config(prefix = "eventMesh.server.pulsar", path = "classPath://pulsar-client.properties") +public class ClientConfiguration { + + @ConfigField(field = "service") + private String serviceAddr; + + @ConfigField(field = "authPlugin") + private String authPlugin; + + @ConfigField(field = "authParams") + private String authParams; + + /* + * the full format of topic needs a prefix, but the prefix cannot be passed in the url when the topic is carried + * + */ + @ConfigField(field = "topicPrefix") + private String topicPrefix; +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/constant/PulsarConstant.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/constant/PulsarConstant.java new file mode 100644 index 0000000000..9c14f2aac2 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/constant/PulsarConstant.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.constant; + +public class PulsarConstant { + + public static final String KEY_SEPARATOR = "/"; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/consumer/PulsarConsumerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/consumer/PulsarConsumerImpl.java new file mode 100644 index 0000000000..6dbcd8d68c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/consumer/PulsarConsumerImpl.java @@ -0,0 +1,208 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.pulsar.config.ClientConfiguration; +import org.apache.eventmesh.storage.pulsar.constant.PulsarConstant; + +import org.apache.commons.lang3.StringUtils; +import org.apache.pulsar.client.api.AuthenticationFactory; +import org.apache.pulsar.client.api.ClientBuilder; +import org.apache.pulsar.client.api.MessageListener; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.SubscriptionMode; +import org.apache.pulsar.client.api.SubscriptionType; + +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.format.EventDeserializationException; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.jackson.JsonFormat; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Config(field = "clientConfiguration") +public class PulsarConsumerImpl implements Consumer { + + private final AtomicBoolean started = new AtomicBoolean(false); + private Properties properties; + private PulsarClient pulsarClient; + private EventListener eventListener; + + private final ConcurrentHashMap> consumerMap = new ConcurrentHashMap<>(); + + /** + * Unified configuration class corresponding to pulsar-client.properties + */ + private ClientConfiguration clientConfiguration; + + @Override + public void init(Properties properties) throws Exception { + this.properties = properties; + String token = properties.getProperty(Constants.CONSUMER_TOKEN); + + try { + ClientBuilder clientBuilder = PulsarClient.builder() + .serviceUrl(clientConfiguration.getServiceAddr()); + + if (clientConfiguration.getAuthPlugin() != null) { + Preconditions.checkNotNull(clientConfiguration.getAuthParams(), + "Authentication Enabled in pulsar cluster, Please set authParams in pulsar-client.properties"); + clientBuilder.authentication( + clientConfiguration.getAuthPlugin(), + clientConfiguration.getAuthParams()); + } + if (StringUtils.isNotBlank(token)) { + clientBuilder.authentication( + AuthenticationFactory.token(token)); + } + + this.pulsarClient = clientBuilder.build(); + } catch (Exception ex) { + throw new StorageRuntimeException( + String.format("Failed to connect pulsar with exception: %s", ex.getMessage())); + } + } + + @Override + public void start() { + this.started.compareAndSet(false, true); + } + + @Override + public void subscribe(String topic) throws Exception { + String subTopic = clientConfiguration.getTopicPrefix() + topic; + if (pulsarClient == null) { + throw new StorageRuntimeException( + String.format("Cann't find the pulsar client for topic: %s", subTopic)); + } + + EventMeshAsyncConsumeContext consumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + log.debug("message action: {} for topic: {}", action.name(), subTopic); + } + }; + + SubscriptionType type = SubscriptionType.Shared; + + String consumerKey = topic + PulsarConstant.KEY_SEPARATOR + properties.getProperty(Constants.CONSUMER_GROUP) + + PulsarConstant.KEY_SEPARATOR + properties.getProperty(Constants.CLIENT_ADDRESS); + org.apache.pulsar.client.api.Consumer consumer = pulsarClient.newConsumer() + .topic(subTopic) + .subscriptionName(properties.getProperty(Constants.CONSUMER_GROUP)) + .subscriptionMode(SubscriptionMode.Durable) + .subscriptionType(type) + .messageListener( + (MessageListener) (ackConsumer, msg) -> { + EventFormat eventFormat = Objects.requireNonNull( + EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE)); + CloudEvent cloudEvent = eventFormat.deserialize(msg.getData()); + eventListener.consume(cloudEvent, consumeContext); + try { + ackConsumer.acknowledge(msg); + } catch (PulsarClientException ex) { + throw new StorageRuntimeException( + String.format("Failed to unsubscribe the topic:%s with exception: %s", subTopic, ex.getMessage())); + } catch (EventDeserializationException ex) { + log.warn("The Message isn't json format, with exception:{}", ex.getMessage()); + } + }) + .subscribe(); + + consumerMap.putIfAbsent(consumerKey, consumer); + + } + + @Override + public void unsubscribe(String topic) { + try { + String consumerKey = topic + PulsarConstant.KEY_SEPARATOR + properties.getProperty(Constants.CONSUMER_GROUP) + + PulsarConstant.KEY_SEPARATOR + properties.getProperty(Constants.CLIENT_ADDRESS); + org.apache.pulsar.client.api.Consumer consumer = consumerMap.get(consumerKey); + consumer.unsubscribe(); + consumerMap.remove(consumerKey); + } catch (PulsarClientException ex) { + throw new StorageRuntimeException( + String.format("Failed to unsubscribe the topic:%s with exception: %s", topic, ex.getMessage())); + } + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + } + + @Override + public void registerEventListener(EventListener listener) { + this.eventListener = listener; + } + + @Override + public boolean isStarted() { + return this.started.get(); + } + + @Override + public boolean isClosed() { + return !this.isStarted(); + } + + @Override + public void shutdown() { + this.started.compareAndSet(true, false); + try { + + consumerMap.forEach((key, consumer) -> { + try { + consumer.close(); + } catch (PulsarClientException e) { + throw new StorageRuntimeException( + String.format("Failed to close the pulsar consumer with exception: %s", e.getMessage())); + } + }); + this.pulsarClient.close(); + consumerMap.clear(); + } catch (PulsarClientException ex) { + throw new StorageRuntimeException( + String.format("Failed to close the pulsar client with exception: %s", ex.getMessage())); + } + } + + public ClientConfiguration getClientConfiguration() { + return this.clientConfiguration; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/AbstractProducer.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/AbstractProducer.java new file mode 100644 index 0000000000..de3a4c5b9c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/AbstractProducer.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.producer; + +import org.apache.eventmesh.api.exception.StorageRuntimeException; + +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +public abstract class AbstractProducer { + + protected final AtomicBoolean started = new AtomicBoolean(false); + final Properties properties; + + AbstractProducer(final Properties properties) { + this.properties = properties; + } + + public Properties properties() { + return this.properties; + } + + StorageRuntimeException checkProducerException(CloudEvent cloudEvent, Throwable e) { + if (cloudEvent.getData() == null) { + return new StorageRuntimeException(String.format("CloudEvent message data does not exist, %s", e.getMessage())); + } + return new StorageRuntimeException(String.format("Unknown connector runtime exception, %s", e.getMessage())); + } + + public boolean isStarted() { + return this.started.get(); + } + + public boolean isClosed() { + return !this.isStarted(); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/ProducerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/ProducerImpl.java new file mode 100644 index 0000000000..3436343932 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/ProducerImpl.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.producer; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.storage.pulsar.client.PulsarClientWrapper; +import org.apache.eventmesh.storage.pulsar.config.ClientConfiguration; + +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ProducerImpl extends AbstractProducer { + + private final AtomicBoolean started = new AtomicBoolean(false); + + private ClientConfiguration config; + private PulsarClientWrapper pulsarClient; + + public ProducerImpl(final Properties properties, ClientConfiguration config) { + this(properties); + setConfig(config); + } + + public ProducerImpl(final Properties properties) { + super(properties); + } + + public void publish(CloudEvent cloudEvent, SendCallback sendCallback) { + this.pulsarClient.publish(cloudEvent, sendCallback); + } + + public void init(Properties properties) { + new ProducerImpl(properties); + } + + public void start() { + this.started.compareAndSet(false, true); + this.pulsarClient = new PulsarClientWrapper(config, properties); + } + + public void shutdown() { + try { + this.started.compareAndSet(true, false); + this.pulsarClient.shutdown(); + } catch (Exception ignored) { + // ignored + } + } + + @Override + public boolean isStarted() { + return this.started.get(); + } + + @Override + public boolean isClosed() { + return !this.isStarted(); + } + + public void setConfig(ClientConfiguration config) { + this.config = config; + } +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/PulsarProducerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/PulsarProducerImpl.java new file mode 100644 index 0000000000..781700d96a --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/producer/PulsarProducerImpl.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.pulsar.config.ClientConfiguration; + +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +@Config(field = "clientConfiguration") +public class PulsarProducerImpl implements Producer { + + private ProducerImpl producer; + + /** + * Unified configuration class corresponding to pulsar-client.properties + */ + private ClientConfiguration clientConfiguration; + + @Override + public synchronized void init(Properties properties) { + producer = new ProducerImpl(properties, clientConfiguration); + } + + @Override + public void publish(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + producer.publish(cloudEvent, sendCallback); + } + + @Override + public boolean isStarted() { + return producer.isStarted(); + } + + @Override + public boolean isClosed() { + return producer.isClosed(); + } + + @Override + public void start() { + producer.start(); + } + + @Override + public void shutdown() { + producer.shutdown(); + } + + @Override + public void sendOneway(CloudEvent cloudEvent) { + throw new StorageRuntimeException("SendOneWay is not supported"); + } + + @Override + public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) throws Exception { + throw new StorageRuntimeException("Request is not supported"); + } + + @Override + public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + throw new StorageRuntimeException("Reply is not supported"); + } + + @Override + public void checkTopicExist(String topic) throws Exception { + throw new StorageRuntimeException("CheckTopicExist is not supported"); + } + + @Override + public void setExtFields() { + throw new StorageRuntimeException("SetExtFields is not supported"); + } + + public ClientConfiguration getClientConfiguration() { + return this.clientConfiguration; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/storage/StorageResourceServicePulsarImpl.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/storage/StorageResourceServicePulsarImpl.java new file mode 100644 index 0000000000..7b09cc685f --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/storage/StorageResourceServicePulsarImpl.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.storage; + +import org.apache.eventmesh.api.storage.StorageResourceService; + +public class StorageResourceServicePulsarImpl implements StorageResourceService { + + @Override + public void init() throws Exception { + + } + + @Override + public void release() throws Exception { + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/utils/CloudEventUtils.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/utils/CloudEventUtils.java new file mode 100644 index 0000000000..71d40d29cb --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/java/org/apache/eventmesh/storage/pulsar/utils/CloudEventUtils.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.utils; + +import org.apache.eventmesh.api.SendResult; + +import io.cloudevents.CloudEvent; + +public class CloudEventUtils { + + public static SendResult convertSendResult(CloudEvent cloudEvent) { + SendResult sendResult = new SendResult(); + sendResult.setTopic(cloudEvent.getSubject()); + sendResult.setMessageId(cloudEvent.getId()); + return sendResult; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin new file mode 100644 index 0000000000..7c43228c45 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin @@ -0,0 +1,16 @@ +# 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. + +pulsar=org.apache.eventmesh.storage.pulsar.admin.PulsarAdminAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer new file mode 100644 index 0000000000..6716ddce4e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer @@ -0,0 +1,16 @@ +# 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. + +pulsar=org.apache.eventmesh.storage.pulsar.consumer.PulsarConsumerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer new file mode 100644 index 0000000000..235173dea1 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer @@ -0,0 +1,16 @@ +# 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. + +pulsar=org.apache.eventmesh.storage.pulsar.producer.PulsarProducerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService new file mode 100644 index 0000000000..4b210007a5 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService @@ -0,0 +1,16 @@ +# 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. + +pulsar=org.apache.eventmesh.storage.pulsar.storage.StorageResourceServicePulsarImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/pulsar-client.properties b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/pulsar-client.properties new file mode 100644 index 0000000000..cea69024e8 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/main/resources/pulsar-client.properties @@ -0,0 +1,18 @@ +# +# 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. +# + +eventMesh.server.pulsar.service=127.0.0.1:6650 diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/test/java/org/apache/eventmesh/storage/pulsar/config/ClientConfigurationTest.java b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/test/java/org/apache/eventmesh/storage/pulsar/config/ClientConfigurationTest.java new file mode 100644 index 0000000000..2f32715166 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/test/java/org/apache/eventmesh/storage/pulsar/config/ClientConfigurationTest.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.pulsar.config; + +import org.apache.eventmesh.api.factory.StoragePluginFactory; +import org.apache.eventmesh.storage.pulsar.consumer.PulsarConsumerImpl; +import org.apache.eventmesh.storage.pulsar.producer.PulsarProducerImpl; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ClientConfigurationTest { + + @Test + public void getConfigWhenPulsarConsumerInit() { + PulsarConsumerImpl consumer = (PulsarConsumerImpl) StoragePluginFactory.getMeshMQPushConsumer("pulsar"); + + ClientConfiguration config = consumer.getClientConfiguration(); + assertConfig(config); + } + + @Test + public void getConfigWhenPulsarProducerInit() { + PulsarProducerImpl producer = (PulsarProducerImpl) StoragePluginFactory.getMeshMQProducer("pulsar"); + + ClientConfiguration config = producer.getClientConfiguration(); + assertConfig(config); + } + + private void assertConfig(ClientConfiguration config) { + Assertions.assertEquals("127.0.0.1:6650", config.getServiceAddr()); + Assertions.assertEquals("authPlugin-success!!!", config.getAuthPlugin()); + Assertions.assertEquals("authParams-success!!!", config.getAuthParams()); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/test/resources/pulsar-client.properties b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/test/resources/pulsar-client.properties new file mode 100644 index 0000000000..645a5edb6e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-pulsar/src/test/resources/pulsar-client.properties @@ -0,0 +1,20 @@ +# +# 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. +# + +eventMesh.server.pulsar.service=127.0.0.1:6650 +eventMesh.server.pulsar.authPlugin=authPlugin-success!!! +eventMesh.server.pulsar.authParams=authParams-success!!! \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/build.gradle new file mode 100644 index 0000000000..41eb93965e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/build.gradle @@ -0,0 +1,41 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation project(":eventmesh-common") + // rabbitmq + implementation 'com.rabbitmq:amqp-client:5.22.0' + + testImplementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + testImplementation project(":eventmesh-common") + // rabbitmq + testImplementation 'com.rabbitmq:amqp-client:5.22.0' + + implementation 'io.cloudevents:cloudevents-json-jackson' + testImplementation 'io.cloudevents:cloudevents-json-jackson' + + testImplementation "org.mockito:mockito-core" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + + testImplementation('com.github.fridujo:rabbitmq-mock:1.2.0') +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/gradle.properties new file mode 100644 index 0000000000..bbf99dcbf2 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# + +pluginType=storage +pluginName=rabbitmq \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/README.md b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/README.md new file mode 100644 index 0000000000..fe90c2163e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/README.md @@ -0,0 +1,26 @@ +## Dashboard + +To enable eventmesh-dashboard admin UI for RabbitMQ, you need to add plugin rabbitmq_management. + +```bash +rabbitmq-plugins enable rabbitmq_management +``` + +## RabbitMQ Management + +The RabbitMQ management UI can be accessed using a Web browser at `http://{node-hostname}:15672/`. + +Users must be [granted permissions](https://www.rabbitmq.com/management.html#permissions) for management UI access. + +The following example creates a user with complete access to the management UI/HTTP API (as in, all virtual hosts and management features): + +```bash +# create a user +rabbitmqctl add_user full_access s3crEt +# tag the user with "administrator" for full management UI and HTTP API access +rabbitmqctl set_user_tags full_access administrator +``` + +eventmesh-dashboard does not support authenticating with OAuth 2 currently. If you are using OAuth 2 to authenticate, you should keep `management.disable_basic_auth` configuration at default value `false` to support HTTP basic authentication. + +> More information for developers to provide admin functions: https://github.com/apache/eventmesh/pull/4395 diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/admin/RabbitMQAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/admin/RabbitMQAdmin.java new file mode 100644 index 0000000000..902853bed9 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/admin/RabbitMQAdmin.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.admin; + +import org.apache.eventmesh.api.admin.AbstractAdmin; +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.storage.rabbitmq.config.ConfigurationHolder; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +public class RabbitMQAdmin extends AbstractAdmin { + + private ConfigurationHolder configurationHolder; + + private String mgmtHost; + + private int mgmtPort; + + private String mgmtProtocol; + + public RabbitMQAdmin() { + super(new AtomicBoolean(false)); + } + + public void init() throws Exception { + this.mgmtHost = configurationHolder.getHost(); + this.mgmtPort = configurationHolder.getMgmtPort(); + this.mgmtProtocol = configurationHolder.getMgmtProtocol(); + } + + @Override + public List getTopic() { + // Utilizing the RabbitMQ Management HTTP API is a favorable approach to list queues and historical message counts. + // To display topics, it would be necessary to retrieve the topic name from each message and use it to declare a corresponding queue. + return new ArrayList<>(); + } + + @Override + public void createTopic(String topicName) { + } + + @Override + public void deleteTopic(String topicName) { + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + } + + @Override + public void shutdown() { + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/admin/RabbitMQAdminAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/admin/RabbitMQAdminAdaptor.java new file mode 100644 index 0000000000..e2792f9511 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/admin/RabbitMQAdminAdaptor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.admin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +public class RabbitMQAdminAdaptor implements Admin { + + private final RabbitMQAdmin admin; + + public RabbitMQAdminAdaptor() { + admin = new RabbitMQAdmin(); + } + + @Override + public boolean isStarted() { + return admin.isStarted(); + } + + @Override + public boolean isClosed() { + return admin.isClosed(); + } + + @Override + public void start() { + admin.start(); + } + + @Override + public void shutdown() { + admin.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + admin.init(properties); + } + + @Override + public List getTopic() throws Exception { + return admin.getTopic(); + } + + @Override + public void createTopic(String topicName) { + admin.createTopic(topicName); + } + + @Override + public void deleteTopic(String topicName) { + admin.deleteTopic(topicName); + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return admin.getEvent(topicName, offset, length); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + admin.publish(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/client/RabbitmqClient.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/client/RabbitmqClient.java new file mode 100644 index 0000000000..678ba0884d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/client/RabbitmqClient.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.client; + +import org.apache.commons.lang3.StringUtils; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RabbitmqClient { + + private final RabbitmqConnectionFactory rabbitmqConnectionFactory; + + public RabbitmqClient(RabbitmqConnectionFactory rabbitmqConnectionFactory) { + this.rabbitmqConnectionFactory = rabbitmqConnectionFactory; + } + + /** + * get rabbitmq connection + * + * @param host host + * @param username username + * @param passwd password + * @param port port + * @param virtualHost virtual host + * @return connection + * @throws Exception Exception + */ + public Connection getConnection(String host, String username, + String passwd, int port, + String virtualHost) throws Exception { + ConnectionFactory factory = rabbitmqConnectionFactory.createConnectionFactory(); + factory.setHost(host.trim()); + factory.setPort(port); + if (StringUtils.isNotEmpty(virtualHost)) { + factory.setVirtualHost(virtualHost.trim()); + } + factory.setUsername(username); + factory.setPassword(passwd.trim()); + + return rabbitmqConnectionFactory.createConnection(factory); + } + + /** + * send message + * + * @param channel channel + * @param exchangeName exchange name + * @param routingKey routing key + * @param message message + * @throws Exception Exception + */ + public void publish(Channel channel, String exchangeName, + String routingKey, byte[] message) throws Exception { + channel.basicPublish(exchangeName, routingKey, null, message); + } + + /** + * binding queue + * + * @param channel channel + * @param builtinExchangeType exchange type + * @param exchangeName exchange name + * @param routingKey routing key + * @param queueName queue name + */ + public void binding(Channel channel, BuiltinExchangeType builtinExchangeType, + String exchangeName, String routingKey, String queueName) { + try { + channel.exchangeDeclare(exchangeName, builtinExchangeType.getType(), true, + false, false, null); + channel.queueDeclare(queueName, false, false, + false, null); + routingKey = builtinExchangeType.getType().equals(BuiltinExchangeType.FANOUT.getType()) ? "" : routingKey; + channel.queueBind(queueName, exchangeName, routingKey); + } catch (Exception ex) { + log.error("[RabbitmqClient] binding happen exception.", ex); + } + } + + /** + * unbinding queue + * + * @param channel channel + * @param exchangeName exchange name + * @param routingKey routing key + * @param queueName queue name + */ + public void unbinding(Channel channel, String exchangeName, String routingKey, String queueName) { + try { + channel.queueUnbind(queueName, exchangeName, routingKey); + } catch (Exception ex) { + log.error("[RabbitmqClient] unbinding happen exception.", ex); + } + } + + /** + * close connection + * + * @param connection connection + */ + public void closeConnection(Connection connection) { + if (connection != null) { + try { + connection.close(); + } catch (Exception ex) { + log.error("[RabbitmqClient] connection close happen exception.", ex); + } + } + } + + /** + * close channel + * + * @param channel channel + */ + public void closeChannel(Channel channel) { + if (channel != null) { + try { + channel.close(); + } catch (Exception ex) { + log.error("[RabbitmqClient] channel close happen exception.", ex); + } + } + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/client/RabbitmqConnectionFactory.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/client/RabbitmqConnectionFactory.java new file mode 100644 index 0000000000..c67487c021 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/client/RabbitmqConnectionFactory.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.client; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class RabbitmqConnectionFactory { + + public ConnectionFactory createConnectionFactory() { + return new ConnectionFactory(); + } + + public Connection createConnection(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + return connectionFactory.newConnection(); + } + + public Channel createChannel(Connection connection) throws IOException { + return connection.createChannel(); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEvent.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEvent.java new file mode 100644 index 0000000000..cc98af0375 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEvent.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.cloudevent; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.storage.rabbitmq.exception.RabbitmqStorageException; +import org.apache.eventmesh.storage.rabbitmq.utils.ByteArrayUtils; + +import java.io.Serializable; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import io.cloudevents.CloudEvent; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.builder.CloudEventBuilder; + +import com.fasterxml.jackson.core.type.TypeReference; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class RabbitmqCloudEvent implements Serializable { + + private SpecVersion version; + private String data; + private Map extensions = new HashMap<>(); + + public CloudEvent convertToCloudEvent() { + CloudEventBuilder builder; + switch (version) { + case V03: + builder = CloudEventBuilder.v03(); + break; + case V1: + builder = CloudEventBuilder.v1(); + break; + default: + throw new RabbitmqStorageException(String.format("CloudEvent version %s does not support.", version)); + } + builder.withData(data.getBytes(StandardCharsets.UTF_8)) + .withId(extensions.remove("id")) + .withSource(URI.create(extensions.remove("source"))) + .withType(extensions.remove("type")) + .withDataContentType(extensions.remove("datacontenttype")) + .withSubject(extensions.remove("subject")); + extensions.forEach(builder::withExtension); + + return builder.build(); + } + + public static byte[] toByteArray(RabbitmqCloudEvent rabbitmqCloudEvent) throws Exception { + Optional optionalBytes = ByteArrayUtils.objectToBytes(rabbitmqCloudEvent); + return optionalBytes.orElseGet(() -> new byte[]{}); + } + + public static RabbitmqCloudEvent getFromByteArray(byte[] body) { + return JsonUtils.parseTypeReferenceObject(new String(body, Constants.DEFAULT_CHARSET), new TypeReference() { + }); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEventWriter.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEventWriter.java new file mode 100644 index 0000000000..ef9a386a2b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEventWriter.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.cloudevent; + +import java.nio.charset.StandardCharsets; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import io.cloudevents.CloudEventData; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.message.MessageWriter; +import io.cloudevents.rw.CloudEventContextWriter; +import io.cloudevents.rw.CloudEventRWException; +import io.cloudevents.rw.CloudEventWriter; + +public class RabbitmqCloudEventWriter + implements MessageWriter, RabbitmqCloudEvent>, CloudEventWriter { + + private final RabbitmqCloudEvent rabbitmqCloudEvent; + + public RabbitmqCloudEventWriter() { + rabbitmqCloudEvent = new RabbitmqCloudEvent(); + } + + @Override + public RabbitmqCloudEvent setEvent(@Nullable EventFormat format, @Nonnull byte[] value) throws CloudEventRWException { + rabbitmqCloudEvent.setData(new String(value, StandardCharsets.UTF_8)); + return rabbitmqCloudEvent; + } + + @Override + public RabbitmqCloudEvent end(CloudEventData data) throws CloudEventRWException { + rabbitmqCloudEvent.setData(new String(data.toBytes(), StandardCharsets.UTF_8)); + return rabbitmqCloudEvent; + } + + @Override + public RabbitmqCloudEvent end() throws CloudEventRWException { + rabbitmqCloudEvent.setData(""); + return rabbitmqCloudEvent; + } + + @Override + public CloudEventContextWriter withContextAttribute(@Nonnull String name, @Nonnull String value) throws CloudEventRWException { + rabbitmqCloudEvent.getExtensions().put(name, value); + return this; + } + + @Override + public CloudEventWriter create(SpecVersion version) throws CloudEventRWException { + rabbitmqCloudEvent.setVersion(version); + return this; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/config/ConfigurationHolder.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/config/ConfigurationHolder.java new file mode 100644 index 0000000000..890e7d6d0d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/config/ConfigurationHolder.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import com.rabbitmq.client.BuiltinExchangeType; + +import lombok.Data; + +@Data +@Config(prefix = "eventMesh.server.rabbitmq", path = "classPath://rabbitmq-client.properties") +public class ConfigurationHolder { + + @ConfigField(field = "host") + private String host; + + @ConfigField(field = "port") + private int port; + + @ConfigField(field = "username") + private String username; + + @ConfigField(field = "passwd") + private String passwd; + + @ConfigField(field = "virtualHost") + private String virtualHost; + + @ConfigField(field = "exchangeType") + private BuiltinExchangeType exchangeType; + + @ConfigField(field = "exchangeName") + private String exchangeName; + + @ConfigField(field = "routingKey") + private String routingKey; + + @ConfigField(field = "queueName") + private String queueName; + + @ConfigField(field = "autoAck") + private boolean autoAck; + + @ConfigField(field = "mgmt.port") + private int mgmtPort; + + @ConfigField(field = "mgmt.protocol") + private String mgmtProtocol; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumer.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumer.java new file mode 100644 index 0000000000..140a1f56ab --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumer.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.common.ThreadPoolFactory; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.rabbitmq.client.RabbitmqClient; +import org.apache.eventmesh.storage.rabbitmq.client.RabbitmqConnectionFactory; +import org.apache.eventmesh.storage.rabbitmq.config.ConfigurationHolder; + +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ThreadPoolExecutor; + +import io.cloudevents.CloudEvent; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; + +import lombok.extern.slf4j.Slf4j; + +@Config(field = "configurationHolder") + +@Slf4j +public class RabbitmqConsumer implements Consumer { + + private RabbitmqConnectionFactory rabbitmqConnectionFactory = new RabbitmqConnectionFactory(); + + private RabbitmqClient rabbitmqClient; + + private Connection connection; + + private Channel channel; + + private volatile boolean started = false; + + /** + * Unified configuration class corresponding to rabbitmq-client.properties + */ + private ConfigurationHolder configurationHolder; + + private final ThreadPoolExecutor executor = ThreadPoolFactory.createThreadPoolExecutor( + Runtime.getRuntime().availableProcessors() * 2, + Runtime.getRuntime().availableProcessors() * 2, + "EventMesh-Rabbitmq-Consumer"); + + private RabbitmqConsumerHandler rabbitmqConsumerHandler; + + @Override + public boolean isStarted() { + return started; + } + + @Override + public boolean isClosed() { + return !isStarted(); + } + + @Override + public void start() { + if (!started) { + started = true; + } + } + + @Override + public void shutdown() { + if (started) { + try { + rabbitmqClient.closeConnection(connection); + rabbitmqClient.closeChannel(channel); + rabbitmqConsumerHandler.stop(); + } finally { + started = false; + } + } + } + + @Override + public void init(Properties keyValue) throws Exception { + this.rabbitmqClient = new RabbitmqClient(rabbitmqConnectionFactory); + this.connection = rabbitmqClient.getConnection(configurationHolder.getHost(), configurationHolder.getUsername(), + configurationHolder.getPasswd(), configurationHolder.getPort(), configurationHolder.getVirtualHost()); + this.channel = rabbitmqConnectionFactory.createChannel(connection); + this.rabbitmqConsumerHandler = new RabbitmqConsumerHandler(channel, configurationHolder); + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + + } + + @Override + public void subscribe(String topic) { + rabbitmqClient.binding(channel, configurationHolder.getExchangeType(), configurationHolder.getExchangeName(), + configurationHolder.getRoutingKey(), configurationHolder.getQueueName()); + executor.execute(rabbitmqConsumerHandler); + } + + @Override + public void unsubscribe(String topic) { + try { + rabbitmqClient.unbinding(channel, configurationHolder.getExchangeName(), + configurationHolder.getRoutingKey(), configurationHolder.getQueueName()); + rabbitmqConsumerHandler.stop(); + } catch (Exception ex) { + log.error("[RabbitmqConsumer] unsubscribe happen exception.", ex); + } + } + + @Override + public void registerEventListener(EventListener listener) { + rabbitmqConsumerHandler.setEventListener(listener); + } + + public void setRabbitmqConnectionFactory(RabbitmqConnectionFactory rabbitmqConnectionFactory) { + this.rabbitmqConnectionFactory = rabbitmqConnectionFactory; + } + + public ConfigurationHolder getClientConfiguration() { + return this.configurationHolder; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumerHandler.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumerHandler.java new file mode 100644 index 0000000000..1872610c71 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumerHandler.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.consumer; + +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; +import org.apache.eventmesh.storage.rabbitmq.cloudevent.RabbitmqCloudEvent; +import org.apache.eventmesh.storage.rabbitmq.config.ConfigurationHolder; + +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.GetResponse; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RabbitmqConsumerHandler implements Runnable { + + private final Channel channel; + private final ConfigurationHolder configurationHolder; + private final AtomicBoolean stop = new AtomicBoolean(false); + private EventListener eventListener; + + public RabbitmqConsumerHandler(Channel channel, ConfigurationHolder configurationHolder) { + this.channel = channel; + this.configurationHolder = configurationHolder; + } + + @Override + public void run() { + while (!stop.get()) { + try { + GetResponse response = channel.basicGet(configurationHolder.getQueueName(), configurationHolder.isAutoAck()); + if (response != null) { + RabbitmqCloudEvent rabbitmqCloudEvent = RabbitmqCloudEvent.getFromByteArray(response.getBody()); + CloudEvent cloudEvent = rabbitmqCloudEvent.convertToCloudEvent(); + final EventMeshAsyncConsumeContext consumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + log.info("[RabbitmqConsumerHandler] Rabbitmq consumer context commit."); + } + }; + if (eventListener != null) { + eventListener.consume(cloudEvent, consumeContext); + } + if (!configurationHolder.isAutoAck()) { + channel.basicAck(response.getEnvelope().getDeliveryTag(), false); + } + } + } catch (Exception ex) { + log.error("[RabbitmqConsumerHandler] thread run happen exception.", ex); + } + } + } + + public void setEventListener(EventListener eventListener) { + this.eventListener = eventListener; + } + + public void stop() { + stop.set(true); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/exception/RabbitmqStorageException.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/exception/RabbitmqStorageException.java new file mode 100644 index 0000000000..f694ab0933 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/exception/RabbitmqStorageException.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.exception; + +import org.apache.eventmesh.api.exception.StorageRuntimeException; + +public class RabbitmqStorageException extends StorageRuntimeException { + + public RabbitmqStorageException(String message) { + super(message); + } + + public RabbitmqStorageException(Throwable throwable) { + super(throwable); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/producer/RabbitmqProducer.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/producer/RabbitmqProducer.java new file mode 100644 index 0000000000..f3963d7647 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/producer/RabbitmqProducer.java @@ -0,0 +1,166 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.rabbitmq.client.RabbitmqClient; +import org.apache.eventmesh.storage.rabbitmq.client.RabbitmqConnectionFactory; +import org.apache.eventmesh.storage.rabbitmq.cloudevent.RabbitmqCloudEvent; +import org.apache.eventmesh.storage.rabbitmq.cloudevent.RabbitmqCloudEventWriter; +import org.apache.eventmesh.storage.rabbitmq.config.ConfigurationHolder; +import org.apache.eventmesh.storage.rabbitmq.utils.ByteArrayUtils; + +import java.util.Optional; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; + +import lombok.extern.slf4j.Slf4j; + +@Config(field = "configurationHolder") +@Slf4j +public class RabbitmqProducer implements Producer { + + private RabbitmqConnectionFactory rabbitmqConnectionFactory = new RabbitmqConnectionFactory(); + + private RabbitmqClient rabbitmqClient; + + private Connection connection; + + private Channel channel; + + private volatile boolean started = false; + + /** + * Unified configuration class corresponding to rabbitmq-client.properties + */ + private ConfigurationHolder configurationHolder; + + @Override + public boolean isStarted() { + return started; + } + + @Override + public boolean isClosed() { + return !isStarted(); + } + + @Override + public void start() { + if (!started) { + started = true; + } + } + + @Override + public void shutdown() { + if (started) { + try { + rabbitmqClient.closeConnection(connection); + rabbitmqClient.closeChannel(channel); + } finally { + started = false; + } + } + } + + @Override + public void init(Properties properties) throws Exception { + this.rabbitmqClient = new RabbitmqClient(rabbitmqConnectionFactory); + this.connection = rabbitmqClient.getConnection(configurationHolder.getHost(), configurationHolder.getUsername(), + configurationHolder.getPasswd(), configurationHolder.getPort(), configurationHolder.getVirtualHost()); + this.channel = rabbitmqConnectionFactory.createChannel(connection); + } + + @Override + public void publish(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + try { + RabbitmqCloudEventWriter writer = new RabbitmqCloudEventWriter(); + RabbitmqCloudEvent rabbitmqCloudEvent = writer.writeBinary(cloudEvent); + byte[] data = RabbitmqCloudEvent.toByteArray(rabbitmqCloudEvent); + if (data != null) { + rabbitmqClient.publish(channel, configurationHolder.getExchangeName(), configurationHolder.getRoutingKey(), data); + + SendResult sendResult = new SendResult(); + sendResult.setTopic(cloudEvent.getSubject()); + sendResult.setMessageId(cloudEvent.getId()); + sendCallback.onSuccess(sendResult); + } + } catch (Exception ex) { + log.error("[RabbitmqProducer] publish happen exception.", ex); + sendCallback.onException( + OnExceptionContext.builder() + .topic(cloudEvent.getSubject()) + .messageId(cloudEvent.getId()) + .exception(new StorageRuntimeException(ex)) + .build()); + } + } + + @Override + public void sendOneway(CloudEvent cloudEvent) { + try { + Optional optionalBytes = ByteArrayUtils.objectToBytes(cloudEvent); + if (optionalBytes.isPresent()) { + byte[] data = optionalBytes.get(); + rabbitmqClient.publish(channel, configurationHolder.getExchangeName(), + configurationHolder.getRoutingKey(), data); + } + } catch (Exception ex) { + log.error("[RabbitmqProducer] sendOneway happen exception.", ex); + } + } + + @Override + public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) throws Exception { + + } + + @Override + public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { + return false; + } + + @Override + public void checkTopicExist(String topic) throws Exception { + + } + + @Override + public void setExtFields() { + + } + + public void setRabbitmqConnectionFactory(RabbitmqConnectionFactory rabbitmqConnectionFactory) { + this.rabbitmqConnectionFactory = rabbitmqConnectionFactory; + } + + public ConfigurationHolder getClientConfiguration() { + return this.configurationHolder; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/storage/RabbitmqStorageResourceService.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/storage/RabbitmqStorageResourceService.java new file mode 100644 index 0000000000..85f44e6497 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/storage/RabbitmqStorageResourceService.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.storage; + +import org.apache.eventmesh.api.storage.StorageResourceService; + +public class RabbitmqStorageResourceService implements StorageResourceService { + + @Override + public void init() throws Exception { + + } + + @Override + public void release() throws Exception { + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/utils/ByteArrayUtils.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/utils/ByteArrayUtils.java new file mode 100644 index 0000000000..a362767ca9 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/java/org/apache/eventmesh/storage/rabbitmq/utils/ByteArrayUtils.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.utils; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.JsonUtils; + +import java.io.IOException; +import java.util.Optional; + +import com.fasterxml.jackson.core.type.TypeReference; + +@SuppressWarnings("all") +public class ByteArrayUtils { + + public static Optional objectToBytes(T obj) throws IOException { + String s = JsonUtils.toJSONString(obj); + byte[] bytes = s.getBytes(Constants.DEFAULT_CHARSET); + return Optional.ofNullable(bytes); + } + + public static Optional bytesToObject(byte[] bytes) throws IOException, ClassNotFoundException { + T t = JsonUtils.parseTypeReferenceObject(new String(bytes, Constants.DEFAULT_CHARSET), new TypeReference() { + }); + return Optional.ofNullable(t); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin new file mode 100644 index 0000000000..3d2bdc8116 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin @@ -0,0 +1,16 @@ +# 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. + +rabbitmq=org.apache.eventmesh.storage.rabbitmq.admin.RabbitMQAdminAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer new file mode 100644 index 0000000000..1599d924fd --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer @@ -0,0 +1,16 @@ +# 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. + +rabbitmq=org.apache.eventmesh.storage.rabbitmq.consumer.RabbitmqConsumer \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer new file mode 100644 index 0000000000..80c89f0f11 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer @@ -0,0 +1,16 @@ +# 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. + +rabbitmq=org.apache.eventmesh.storage.rabbitmq.producer.RabbitmqProducer \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService new file mode 100644 index 0000000000..31a4aecfcb --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService @@ -0,0 +1,16 @@ +# 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. + +rabbitmq=org.apache.eventmesh.storage.rabbitmq.storage.RabbitmqStorageResourceService diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/rabbitmq-client.properties b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/rabbitmq-client.properties new file mode 100644 index 0000000000..0a282dff4e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/main/resources/rabbitmq-client.properties @@ -0,0 +1,36 @@ +# +# 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. +# + +####################### rabbitmq server ################## +eventMesh.server.rabbitmq.host=127.0.0.1 +eventMesh.server.rabbitmq.port=5672 +eventMesh.server.rabbitmq.username=guest +eventMesh.server.rabbitmq.passwd=guest +eventMesh.server.rabbitmq.virtualHost=/ + +####################### rabbitmq queue setting ################## +# DIRECT, FANOUT, TOPIC, HEADERS +eventMesh.server.rabbitmq.exchangeType=TOPIC +eventMesh.server.rabbitmq.exchangeName=eventmesh.default +eventMesh.server.rabbitmq.routingKey=# +eventMesh.server.rabbitmq.queueName=DefaultQueue +eventMesh.server.rabbitmq.autoAck=true + +####################### rabbitmq management ################## +eventMesh.server.rabbitmq.mgmt.port=15672 +# HTTP, HTTPS +eventMesh.server.rabbitmq.mgmt.protocol=HTTP \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/RabbitmqMockConnectionFactory.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/RabbitmqMockConnectionFactory.java new file mode 100644 index 0000000000..94da1fab04 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/RabbitmqMockConnectionFactory.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq; + +import org.apache.eventmesh.storage.rabbitmq.client.RabbitmqConnectionFactory; + +import com.github.fridujo.rabbitmq.mock.MockConnectionFactory; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class RabbitmqMockConnectionFactory extends RabbitmqConnectionFactory { + + private final ConnectionFactory myConnectionFactory; + + private final Connection myConnection; + + private final Channel myChannel; + + public RabbitmqMockConnectionFactory() throws Exception { + this.myConnectionFactory = new MockConnectionFactory(); + this.myConnectionFactory.setHost("127.0.0.1"); + this.myConnectionFactory.setPort(5672); + this.myConnectionFactory.setUsername("root"); + this.myConnectionFactory.setPassword("123456"); + this.myConnection = this.myConnectionFactory.newConnection(); + this.myChannel = myConnection.createChannel(); + } + + @Override + public ConnectionFactory createConnectionFactory() { + return this.myConnectionFactory; + } + + @Override + public Connection createConnection(ConnectionFactory connectionFactory) { + return this.myConnection; + } + + @Override + public Channel createChannel(Connection connection) { + return this.myChannel; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/RabbitmqServer.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/RabbitmqServer.java new file mode 100644 index 0000000000..e7fba2d3fb --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/RabbitmqServer.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq; + +import org.apache.eventmesh.api.factory.StoragePluginFactory; +import org.apache.eventmesh.storage.rabbitmq.consumer.RabbitmqConsumer; +import org.apache.eventmesh.storage.rabbitmq.producer.RabbitmqProducer; + +import java.util.Properties; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +public class RabbitmqServer { + + protected RabbitmqConsumer rabbitmqConsumer; + protected RabbitmqProducer rabbitmqProducer; + + @BeforeEach + public void setup() throws Exception { + RabbitmqMockConnectionFactory rabbitmqMockConnectionFactory = new RabbitmqMockConnectionFactory(); + + rabbitmqConsumer = + (RabbitmqConsumer) StoragePluginFactory.getMeshMQPushConsumer("rabbitmq"); + rabbitmqConsumer.setRabbitmqConnectionFactory(rabbitmqMockConnectionFactory); + rabbitmqConsumer.init(new Properties()); + rabbitmqConsumer.start(); + + rabbitmqProducer = (RabbitmqProducer) StoragePluginFactory.getMeshMQProducer("rabbitmq"); + rabbitmqProducer.setRabbitmqConnectionFactory(rabbitmqMockConnectionFactory); + rabbitmqProducer.init(new Properties()); + rabbitmqProducer.start(); + } + + @AfterEach + public void shutdown() { + rabbitmqConsumer.shutdown(); + rabbitmqProducer.shutdown(); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEventTest.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEventTest.java new file mode 100644 index 0000000000..95620bd738 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/cloudevent/RabbitmqCloudEventTest.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.cloudevent; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class RabbitmqCloudEventTest { + + private CloudEvent cloudEvent; + + @BeforeEach + public void before() { + cloudEvent = CloudEventBuilder.v1() + .withId("1") + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject("topic") + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes(StandardCharsets.UTF_8)) + .build(); + } + + @Test + public void toByteArray() throws Exception { + RabbitmqCloudEventWriter writer = new RabbitmqCloudEventWriter(); + RabbitmqCloudEvent rabbitmqCloudEvent = writer.writeBinary(cloudEvent); + Assertions.assertEquals("topic", cloudEvent.getSubject()); + + byte[] data = RabbitmqCloudEvent.toByteArray(rabbitmqCloudEvent); + Assertions.assertNotNull(data); + } + + @Test + public void getFromByteArray() throws Exception { + RabbitmqCloudEventWriter writer = new RabbitmqCloudEventWriter(); + RabbitmqCloudEvent rabbitmqCloudEvent = writer.writeBinary(cloudEvent); + Assertions.assertEquals("topic", cloudEvent.getSubject()); + + byte[] data = RabbitmqCloudEvent.toByteArray(rabbitmqCloudEvent); + Assertions.assertNotNull(data); + + RabbitmqCloudEvent event = RabbitmqCloudEvent.getFromByteArray(data); + Assertions.assertEquals("topic", event.getExtensions().get("subject")); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/config/ConfigurationHolderTest.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/config/ConfigurationHolderTest.java new file mode 100644 index 0000000000..ac83e0b600 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/config/ConfigurationHolderTest.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.config; + +import org.apache.eventmesh.api.factory.StoragePluginFactory; +import org.apache.eventmesh.storage.rabbitmq.consumer.RabbitmqConsumer; +import org.apache.eventmesh.storage.rabbitmq.producer.RabbitmqProducer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.rabbitmq.client.BuiltinExchangeType; + +public class ConfigurationHolderTest { + + @Test + public void getConfigWhenRabbitmqConsumerInit() { + RabbitmqConsumer consumer = + (RabbitmqConsumer) StoragePluginFactory.getMeshMQPushConsumer("rabbitmq"); + + ConfigurationHolder config = consumer.getClientConfiguration(); + assertConfig(config); + } + + @Test + public void getConfigWhenRabbitmqProducerInit() { + RabbitmqProducer producer = + (RabbitmqProducer) StoragePluginFactory.getMeshMQProducer("rabbitmq"); + + ConfigurationHolder config = producer.getClientConfiguration(); + assertConfig(config); + } + + private void assertConfig(ConfigurationHolder config) { + Assertions.assertEquals("127.0.0.1", config.getHost()); + Assertions.assertEquals(5672, config.getPort()); + Assertions.assertEquals("username-success!!!", config.getUsername()); + Assertions.assertEquals("passwd-success!!!", config.getPasswd()); + Assertions.assertEquals("virtualHost-success!!!", config.getVirtualHost()); + + Assertions.assertEquals(BuiltinExchangeType.TOPIC, config.getExchangeType()); + Assertions.assertEquals("exchangeName-success!!!", config.getExchangeName()); + Assertions.assertEquals("routingKey-success!!!", config.getRoutingKey()); + Assertions.assertEquals("queueName-success!!!", config.getQueueName()); + Assertions.assertTrue(config.isAutoAck()); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumerTest.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumerTest.java new file mode 100644 index 0000000000..5a4493dbb7 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/consumer/RabbitmqConsumerTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.consumer; + +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.storage.rabbitmq.RabbitmqServer; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class RabbitmqConsumerTest extends RabbitmqServer { + + @Test + public void isStarted() { + Assertions.assertTrue(rabbitmqConsumer.isStarted()); + } + + @Test + public void isClosed() { + Assertions.assertFalse(rabbitmqConsumer.isClosed()); + } + + @Test + public void subscribe() throws Exception { + final int expectedCount = 5; + final CountDownLatch downLatch = new CountDownLatch(expectedCount); + + rabbitmqConsumer.registerEventListener((cloudEvent, context) -> { + downLatch.countDown(); + context.commit(EventMeshAction.CommitMessage); + Assertions.assertEquals(cloudEvent.getSubject(), "topic"); + }); + + rabbitmqConsumer.subscribe("topic"); + + ThreadUtils.sleep(1, TimeUnit.SECONDS); + for (int i = 0; i < expectedCount; i++) { + CloudEvent cloudEvent = CloudEventBuilder.v1() + .withId(String.valueOf(i)) + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject("topic") + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes(StandardCharsets.UTF_8)) + .build(); + + rabbitmqProducer.publish(cloudEvent, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + Assertions.assertEquals(cloudEvent.getId(), sendResult.getMessageId()); + Assertions.assertEquals(cloudEvent.getSubject(), sendResult.getTopic()); + } + + @Override + public void onException(OnExceptionContext context) { + Assertions.assertEquals(cloudEvent.getId(), context.getMessageId()); + Assertions.assertEquals(cloudEvent.getSubject(), context.getTopic()); + } + }); + } + + Assertions.assertTrue(downLatch.await(5, TimeUnit.MINUTES)); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/producer/RabbitmqProducerTest.java b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/producer/RabbitmqProducerTest.java new file mode 100644 index 0000000000..58012b07fe --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/java/org/apache/eventmesh/storage/rabbitmq/producer/RabbitmqProducerTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rabbitmq.producer; + +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.storage.rabbitmq.RabbitmqServer; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class RabbitmqProducerTest extends RabbitmqServer { + + @Test + public void isStarted() { + Assertions.assertTrue(rabbitmqProducer.isStarted()); + } + + @Test + public void isClosed() { + Assertions.assertFalse(rabbitmqProducer.isClosed()); + } + + @Test + public void publish() throws Exception { + final int expectedCount = 5; + final CountDownLatch downLatch = new CountDownLatch(expectedCount); + + rabbitmqConsumer.registerEventListener((cloudEvent, context) -> { + downLatch.countDown(); + context.commit(EventMeshAction.CommitMessage); + Assertions.assertEquals(cloudEvent.getSubject(), "topic"); + }); + + rabbitmqConsumer.subscribe("topic"); + + ThreadUtils.sleep(1, TimeUnit.SECONDS); + for (int i = 0; i < expectedCount; i++) { + CloudEvent cloudEvent = CloudEventBuilder.v1() + .withId(String.valueOf(i)) + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject("topic") + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes(StandardCharsets.UTF_8)) + .build(); + + rabbitmqProducer.publish(cloudEvent, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + Assertions.assertEquals(cloudEvent.getId(), sendResult.getMessageId()); + Assertions.assertEquals(cloudEvent.getSubject(), sendResult.getTopic()); + } + + @Override + public void onException(OnExceptionContext context) { + Assertions.assertEquals(cloudEvent.getId(), context.getMessageId()); + Assertions.assertEquals(cloudEvent.getSubject(), context.getTopic()); + } + }); + } + + Assertions.assertTrue(downLatch.await(5, TimeUnit.MINUTES)); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/resources/rabbitmq-client.properties b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/resources/rabbitmq-client.properties new file mode 100644 index 0000000000..082fbe5b45 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rabbitmq/src/test/resources/rabbitmq-client.properties @@ -0,0 +1,31 @@ +# +# 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. +# + +####################### rabbitmq server ################## +eventMesh.server.rabbitmq.host=127.0.0.1 +eventMesh.server.rabbitmq.port=5672 +eventMesh.server.rabbitmq.username=username-success!!! +eventMesh.server.rabbitmq.passwd=passwd-success!!! +eventMesh.server.rabbitmq.virtualHost=virtualHost-success!!! + +####################### rabbitmq queue setting ################## +# DIRECT, FANOUT, TOPIC, HEADERS +eventMesh.server.rabbitmq.exchangeType=TOPIC +eventMesh.server.rabbitmq.exchangeName=exchangeName-success!!! +eventMesh.server.rabbitmq.routingKey=routingKey-success!!! +eventMesh.server.rabbitmq.queueName=queueName-success!!! +eventMesh.server.rabbitmq.autoAck=true \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-redis/build.gradle new file mode 100644 index 0000000000..4fb1645414 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/build.gradle @@ -0,0 +1,44 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + + // redisson + implementation 'org.redisson:redisson:3.38.1' + + // netty + implementation 'io.netty:netty-all' + + // auxiliary serialize + api 'io.cloudevents:cloudevents-json-jackson' + + // test dependencies + testImplementation 'com.github.fppt:jedis-mock:1.1.3' + testImplementation "org.mockito:mockito-core" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} + +test { + systemProperty "io.netty.tryUnsafe", "false" +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-redis/gradle.properties new file mode 100644 index 0000000000..6f2a7b3f8b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=storage +pluginName=redis \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/admin/RedisAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/admin/RedisAdmin.java new file mode 100644 index 0000000000..3143c134b3 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/admin/RedisAdmin.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.admin; + +import org.apache.eventmesh.api.admin.AbstractAdmin; +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.storage.redis.client.RedissonClient; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +import org.redisson.Redisson; +import org.redisson.api.RPatternTopic; +import org.redisson.api.RTopic; + +import io.cloudevents.CloudEvent; + +public class RedisAdmin extends AbstractAdmin { + + private final Redisson redisson; + + public RedisAdmin() { + super(new AtomicBoolean(false)); + redisson = RedissonClient.INSTANCE; + } + + @Override + public List getTopic() throws Exception { + // TODO: match all the topic with pattern "*" for now. + RPatternTopic patternTopic = redisson.getPatternTopic("*"); + return patternTopic.getPatternNames() + .stream() + .map(s -> new TopicProperties(s, 0)) + .collect(Collectors.toList()); + } + + @Override + public void createTopic(String topicName) throws Exception { + // Just subscribe it directly, no need to create it first. + } + + @Override + public void deleteTopic(String topicName) throws Exception { + RTopic topic = redisson.getTopic(topicName); + topic.removeAllListeners(); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + RTopic topic = redisson.getTopic(cloudEvent.getSubject()); + topic.publish(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/admin/RedisAdminAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/admin/RedisAdminAdaptor.java new file mode 100644 index 0000000000..7275fc70b0 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/admin/RedisAdminAdaptor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.admin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +public class RedisAdminAdaptor implements Admin { + + private final RedisAdmin admin; + + public RedisAdminAdaptor() { + admin = new RedisAdmin(); + } + + @Override + public boolean isStarted() { + return admin.isStarted(); + } + + @Override + public boolean isClosed() { + return admin.isClosed(); + } + + @Override + public void start() { + admin.start(); + } + + @Override + public void shutdown() { + admin.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + admin.init(properties); + } + + @Override + public List getTopic() throws Exception { + return admin.getTopic(); + } + + @Override + public void createTopic(String topicName) throws Exception { + admin.createTopic(topicName); + } + + @Override + public void deleteTopic(String topicName) throws Exception { + admin.deleteTopic(topicName); + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return admin.getEvent(topicName, offset, length); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + admin.publish(cloudEvent); + } +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/client/RedissonClient.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/client/RedissonClient.java new file mode 100644 index 0000000000..9a02064747 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/client/RedissonClient.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.client; + +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.storage.redis.cloudevent.CloudEventCodec; +import org.apache.eventmesh.storage.redis.config.RedisProperties; + +import java.util.Arrays; + +import org.redisson.Redisson; +import org.redisson.config.Config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +/** + * Within EventMesh's JVM, there is no multi-connector server, and redisson itself is pooled management, so a single instance is fine, and it can save + * resources and improve performance. + */ +public final class RedissonClient { + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + public static final Redisson INSTANCE; + + static { + OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + + INSTANCE = create(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + INSTANCE.shutdown(); + } catch (Exception ignore) { + // + } + })); + } + + public static Redisson create() { + ConfigService configService = ConfigService.getInstance(); + RedisProperties properties = configService.buildConfigInstance(RedisProperties.class); + + return create(properties); + } + + private static Redisson create(RedisProperties properties) { + RedisProperties.ServerType serverType; + try { + serverType = properties.getServerType(); + } catch (IllegalArgumentException ie) { + final String message = "Invalid Redis server type: " + properties.getServerType() + + ", supported values are: " + + Arrays.toString(RedisProperties.ServerType.values()); + throw new StorageRuntimeException(message, ie); + } + + Config config = new Config(); + config.setCodec(CloudEventCodec.getInstance()); + config.setThreads(properties.getRedissonThreads()); + config.setNettyThreads(properties.getRedissonNettyThreads()); + + String serverAddress = properties.getServerAddress(); + String serverPassword = properties.getServerPassword(); + String masterName = properties.getServerMasterName(); + + switch (serverType) { + case SINGLE: + config.useSingleServer() + .setAddress(serverAddress) + .setPassword(serverPassword); + break; + case CLUSTER: + config.useClusterServers() + .addNodeAddress(serverAddress.split(Constants.COMMA)) + .setPassword(serverPassword); + break; + case SENTINEL: + config.useSentinelServers() + .setMasterName(masterName) + .addSentinelAddress(serverAddress) + .setPassword(serverPassword); + break; + default: + final String message = "Invalid Redis server type: " + properties.getServerType() + + ", supported values are: " + + Arrays.toString(RedisProperties.ServerType.values()); + throw new StorageRuntimeException(message); + } + + return (Redisson) Redisson.create(config); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/cloudevent/CloudEventCodec.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/cloudevent/CloudEventCodec.java new file mode 100644 index 0000000000..e05903d46f --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/cloudevent/CloudEventCodec.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.cloudevent; + +import org.redisson.client.codec.BaseCodec; +import org.redisson.client.protocol.Decoder; +import org.redisson.client.protocol.Encoder; + +import io.cloudevents.CloudEvent; +import io.cloudevents.jackson.JsonFormat; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +public class CloudEventCodec extends BaseCodec { + + private static final CloudEventCodec INSTANCE = new CloudEventCodec(); + + private static final JsonFormat jsonFormat = new JsonFormat(false, true); + + private CloudEventCodec() { + // To prevent class instantiation + } + + public static CloudEventCodec getInstance() { + return INSTANCE; + } + + private static final Encoder encoder = in -> { + ByteBuf out = ByteBufAllocator.DEFAULT.buffer(); + if (in instanceof CloudEvent) { + out.writeBytes(jsonFormat.serialize((CloudEvent) in)); + return out; + } + throw new IllegalStateException("Illegal object type: " + in.getClass().getSimpleName()); + }; + + private static final Decoder decoder = (buf, state) -> { + final byte[] bytes = new byte[buf.readableBytes()]; + buf.getBytes(buf.readerIndex(), bytes); + return jsonFormat.deserialize(bytes); + }; + + @Override + public Decoder getValueDecoder() { + return decoder; + } + + @Override + public Encoder getValueEncoder() { + return encoder; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/config/RedisProperties.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/config/RedisProperties.java new file mode 100644 index 0000000000..b1e9f1a3af --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/config/RedisProperties.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.Data; + +@Data +@Config(prefix = "eventMesh.server.redis", path = "classPath://redis-client.properties") +public class RedisProperties { + + /** + * The redis server configuration to be used. + */ + @ConfigField(field = "serverType") + private ServerType serverType = ServerType.SINGLE; + + /** + * The master server name used by Redis Sentinel servers and master change monitoring task. + */ + @ConfigField(field = "serverMasterName") + private String serverMasterName = "master"; + + /** + * The address of the redis server following format -- host1:port1,host2:port2,…… + */ + @ConfigField(field = "serverAddress") + private String serverAddress = "redis://127.0.0.1:6379"; + + /** + * The password for redis authentication. + */ + @ConfigField(field = "serverPassword") + private String serverPassword; + + /** + * The redisson options, redisson properties prefix is `eventMesh.server.redis.redisson` + */ + @ConfigField(field = "redisson.threads") + private int redissonThreads = 16; + + @ConfigField(field = "redisson.nettyThreads") + private int redissonNettyThreads = 32; + + public enum ServerType { + SINGLE, + CLUSTER, + SENTINEL + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumer.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumer.java new file mode 100644 index 0000000000..0a14e4d2f5 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumer.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.storage.redis.client.RedissonClient; + +import java.util.List; +import java.util.Properties; + +import org.redisson.Redisson; +import org.redisson.api.listener.MessageListener; + +import io.cloudevents.CloudEvent; + +import com.google.common.base.Preconditions; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RedisConsumer implements Consumer { + + private Redisson redisson; + + private EventMeshMessageListener messageListener; + + private volatile boolean started = false; + + @Override + public boolean isStarted() { + return started; + } + + @Override + public boolean isClosed() { + return !isStarted(); + } + + @Override + public synchronized void start() { + if (!started) { + started = true; + } + } + + @Override + public synchronized void shutdown() { + if (started) { + redisson = null; + messageListener = null; + started = false; + } + } + + @Override + public void init(Properties keyValue) { + // Currently, 'keyValue' does not pass useful configuration information. + redisson = RedissonClient.INSTANCE; + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + + } + + @Override + public void subscribe(String topic) { + Preconditions.checkNotNull(topic); + Preconditions.checkNotNull(messageListener); + + redisson.getTopic(topic).addListenerAsync(CloudEvent.class, messageListener); + } + + @Override + public void unsubscribe(String topic) { + Preconditions.checkNotNull(topic); + Preconditions.checkNotNull(messageListener); + + redisson.getTopic(topic).removeListenerAsync(messageListener); + } + + @Override + public void registerEventListener(EventListener listener) { + Preconditions.checkNotNull(listener); + + messageListener = new EventMeshMessageListener(listener); + } + + static class EventMeshMessageListener implements MessageListener { + + private final EventListener listener; + + EventMeshMessageListener(EventListener listener) { + this.listener = listener; + } + + @Override + public void onMessage(CharSequence channel, CloudEvent msg) { + + final EventMeshAsyncConsumeContext consumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + log.info("channel: {} consumer event: {} finish action: {}", + channel, msg.getId(), action); + } + }; + + listener.consume(msg, consumeContext); + } + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/producer/RedisProducer.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/producer/RedisProducer.java new file mode 100644 index 0000000000..532f950b6d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/producer/RedisProducer.java @@ -0,0 +1,137 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.storage.redis.client.RedissonClient; + +import java.util.Properties; + +import org.redisson.Redisson; +import org.redisson.api.RTopic; + +import io.cloudevents.CloudEvent; + +import com.google.common.base.Preconditions; + +public class RedisProducer implements Producer { + + private Redisson redisson; + + private volatile boolean started = false; + + @Override + public boolean isStarted() { + return started; + } + + @Override + public boolean isClosed() { + return !isStarted(); + } + + @Override + public synchronized void start() { + if (!started) { + started = true; + } + } + + @Override + public synchronized void shutdown() { + if (started) { + try { + redisson = null; + } finally { + started = false; + } + } + } + + @Override + public void init(Properties properties) { + // Currently, 'properties' does not pass useful configuration information. + redisson = RedissonClient.INSTANCE; + } + + @Override + public void publish(CloudEvent cloudEvent, SendCallback sendCallback) { + Preconditions.checkNotNull(cloudEvent); + Preconditions.checkNotNull(sendCallback); + + try { + RTopic topic = redisson.getTopic(cloudEvent.getSubject()); + + topic.publishAsync(cloudEvent).whenCompleteAsync((stage, throwable) -> { + if (throwable != null) { + sendCallback.onException( + OnExceptionContext.builder() + .topic(cloudEvent.getSubject()) + .messageId(cloudEvent.getId()) + .exception(new StorageRuntimeException(throwable)) + .build()); + } else { + SendResult sendResult = new SendResult(); + sendResult.setTopic(cloudEvent.getSubject()); + sendResult.setMessageId(cloudEvent.getId()); + sendCallback.onSuccess(sendResult); + } + }); + } catch (Exception e) { + sendCallback.onException( + OnExceptionContext.builder() + .topic(cloudEvent.getSubject()) + .messageId(cloudEvent.getId()) + .exception(new StorageRuntimeException(e)) + .build()); + } + } + + @Override + public void sendOneway(CloudEvent cloudEvent) { + Preconditions.checkNotNull(cloudEvent); + + RTopic topic = redisson.getTopic(cloudEvent.getSubject()); + topic.publish(cloudEvent); + } + + @Override + public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) { + throw new StorageRuntimeException("Request is not supported"); + } + + @Override + public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) { + throw new StorageRuntimeException("Reply is not supported"); + } + + @Override + public void checkTopicExist(String topic) { + // Because redis has the feature of creating topics when used, there is no need to check existence. + } + + @Override + public void setExtFields() { + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/storage/RedisStorageResourceService.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/storage/RedisStorageResourceService.java new file mode 100644 index 0000000000..043680fb26 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/storage/RedisStorageResourceService.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.storage; + +import org.apache.eventmesh.api.storage.StorageResourceService; + +public class RedisStorageResourceService implements StorageResourceService { + + @Override + public void init() throws Exception { + + } + + @Override + public void release() throws Exception { + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin new file mode 100644 index 0000000000..cc86b755fa --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin @@ -0,0 +1,16 @@ +# 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. + +redis=org.apache.eventmesh.storage.redis.admin.RedisAdminAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer new file mode 100644 index 0000000000..695ea9aba5 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer @@ -0,0 +1,16 @@ +# 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. + +redis=org.apache.eventmesh.storage.redis.consumer.RedisConsumer \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer new file mode 100644 index 0000000000..553bf31ce6 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer @@ -0,0 +1,16 @@ +# 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. + +redis=org.apache.eventmesh.storage.redis.producer.RedisProducer \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService new file mode 100644 index 0000000000..9dd64fbb72 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService @@ -0,0 +1,16 @@ +# 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. + +redis=org.apache.eventmesh.storage.redis.storage.RedisStorageResourceService \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/redis-client.properties b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/redis-client.properties new file mode 100644 index 0000000000..9baf41f360 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/main/resources/redis-client.properties @@ -0,0 +1,23 @@ +# +# 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. +# + +eventMesh.server.redis.serverAddress=redis://127.0.0.1:6379 +eventMesh.server.redis.serverPassword= +eventMesh.server.redis.serverType=SINGLE +eventMesh.server.redis.serverMasterName=master +eventMesh.server.redis.redisson.threads= +eventMesh.server.redis.redisson.nettyThreads= diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/AbstractRedisServer.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/AbstractRedisServer.java new file mode 100644 index 0000000000..cefca9ea4b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/AbstractRedisServer.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis; + +import java.io.IOException; + +import com.github.fppt.jedismock.RedisServer; + +public abstract class AbstractRedisServer { + + private static final RedisServer redisServer; + + static { + try { + redisServer = RedisServer.newRedisServer(6379).start(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/client/RedissonClientTest.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/client/RedissonClientTest.java new file mode 100644 index 0000000000..8833808fb9 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/client/RedissonClientTest.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.client; + +import org.apache.eventmesh.storage.redis.AbstractRedisServer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RedissonClientTest extends AbstractRedisServer { + + @Test + public void testInstance() { + Assertions.assertNotNull(RedissonClient.INSTANCE); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/config/RedisPropertiesTest.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/config/RedisPropertiesTest.java new file mode 100644 index 0000000000..c284fb89da --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/config/RedisPropertiesTest.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.config; + +import org.apache.eventmesh.common.config.ConfigService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RedisPropertiesTest { + + @Test + public void getRedisProperties() { + ConfigService configService = ConfigService.getInstance(); + RedisProperties config = configService.buildConfigInstance(RedisProperties.class); + assertConfig(config); + } + + private void assertConfig(RedisProperties config) { + Assertions.assertEquals("redis://127.0.0.1:6379", config.getServerAddress()); + Assertions.assertEquals(RedisProperties.ServerType.SINGLE, config.getServerType()); + Assertions.assertEquals("serverMasterName-success!!!", config.getServerMasterName()); + Assertions.assertEquals(2, config.getRedissonThreads()); + Assertions.assertEquals(2, config.getRedissonNettyThreads()); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/connector/UnitTest.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/connector/UnitTest.java new file mode 100644 index 0000000000..fe3aed8de1 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/connector/UnitTest.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.connector; + +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.storage.redis.AbstractRedisServer; +import org.apache.eventmesh.storage.redis.consumer.RedisConsumer; +import org.apache.eventmesh.storage.redis.consumer.RedisConsumerTest; +import org.apache.eventmesh.storage.redis.producer.RedisProducer; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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 io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class UnitTest extends AbstractRedisServer { + + private RedisProducer redisProducer; + + private RedisConsumer redisConsumer; + + @BeforeEach + public void setup() { + redisProducer = new RedisProducer(); + redisProducer.init(new Properties()); + redisProducer.start(); + + redisConsumer = new RedisConsumer(); + redisConsumer.init(new Properties()); + redisConsumer.start(); + } + + @AfterEach + public void shutdown() { + redisProducer.shutdown(); + redisConsumer.shutdown(); + } + + @Test + public void testPubSub() throws Exception { + + final int expectedCount = 3; + final CountDownLatch downLatch = new CountDownLatch(expectedCount); + + redisConsumer.registerEventListener((cloudEvent, context) -> { + downLatch.countDown(); + context.commit(EventMeshAction.CommitMessage); + }); + + final String topic = RedisConsumerTest.class.getSimpleName(); + + redisConsumer.subscribe(topic); + + for (int i = 0; i < expectedCount; i++) { + CloudEvent cloudEvent = CloudEventBuilder.v1() + .withId(String.valueOf(i)) + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject(topic) + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes(StandardCharsets.UTF_8)) + .build(); + + redisProducer.publish(cloudEvent, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + } + + @Override + public void onException(OnExceptionContext context) { + } + }); + } + + Assertions.assertTrue(downLatch.await(5, TimeUnit.MINUTES)); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumerTest.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumerTest.java new file mode 100644 index 0000000000..93ca0472cc --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumerTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.consumer; + +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.storage.redis.AbstractRedisServer; +import org.apache.eventmesh.storage.redis.client.RedissonClient; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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.redisson.api.RTopic; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class RedisConsumerTest extends AbstractRedisServer { + + private RedisConsumer redisConsumer; + + @BeforeEach + public void setup() { + redisConsumer = new RedisConsumer(); + redisConsumer.init(new Properties()); + redisConsumer.start(); + } + + @AfterEach + public void shutdown() { + redisConsumer.shutdown(); + } + + @Test + public void testSubscribe() throws Exception { + + final int expectedCount = 3; + final CountDownLatch downLatch = new CountDownLatch(expectedCount); + + redisConsumer.registerEventListener((cloudEvent, context) -> { + downLatch.countDown(); + context.commit(EventMeshAction.CommitMessage); + }); + + final String topic = RedisConsumerTest.class.getSimpleName(); + + redisConsumer.subscribe(topic); + + RTopic redissonTopic = RedissonClient.INSTANCE.getTopic(topic); + for (int i = 0; i < expectedCount; i++) { + CloudEvent cloudEvent = CloudEventBuilder.v1() + .withId(String.valueOf(i)) + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject("topic") + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes(StandardCharsets.UTF_8)) + .build(); + + redissonTopic.publish(cloudEvent); + } + + Assertions.assertTrue(downLatch.await(5, TimeUnit.MINUTES)); + + redisConsumer.unsubscribe(topic); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/producer/RedisProducerTest.java b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/producer/RedisProducerTest.java new file mode 100644 index 0000000000..da8ea04a52 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/producer/RedisProducerTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.redis.producer; + +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.storage.redis.AbstractRedisServer; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; + +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 io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class RedisProducerTest extends AbstractRedisServer { + + private RedisProducer redisProducer; + + @BeforeEach + public void setup() { + redisProducer = new RedisProducer(); + redisProducer.init(new Properties()); + redisProducer.start(); + } + + @AfterEach + public void shutdown() { + redisProducer.shutdown(); + } + + @Test + public void testPublish() throws Exception { + final int expectedCount = 3; + final CountDownLatch downLatch = new CountDownLatch(expectedCount); + + for (int i = 0; i < expectedCount; i++) { + CloudEvent cloudEvent = CloudEventBuilder.v1() + .withId(String.valueOf(i)) + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject(RedisProducerTest.class.getSimpleName()) + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes(StandardCharsets.UTF_8)) + .build(); + + redisProducer.publish(cloudEvent, new SendCallback() { + + @Override + public void onSuccess(SendResult sendResult) { + downLatch.countDown(); + Assertions.assertEquals(cloudEvent.getId(), sendResult.getMessageId()); + Assertions.assertEquals(cloudEvent.getSubject(), sendResult.getTopic()); + } + + @Override + public void onException(OnExceptionContext context) { + downLatch.countDown(); + Assertions.assertEquals(cloudEvent.getId(), context.getMessageId()); + Assertions.assertEquals(cloudEvent.getSubject(), context.getTopic()); + } + }); + } + + downLatch.await(); + } + + @Test + public void testSendOneway() { + + final String topic = RedisProducerTest.class.getSimpleName(); + + CloudEvent cloudEvent = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withTime(OffsetDateTime.now()) + .withSource(URI.create("testsource")) + .withSubject(topic) + .withType(String.class.getCanonicalName()) + .withDataContentType("text/plain") + .withData("data".getBytes()) + .build(); + + redisProducer.sendOneway(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/resources/redis-client.properties b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/resources/redis-client.properties new file mode 100644 index 0000000000..7c89643f73 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-redis/src/test/resources/redis-client.properties @@ -0,0 +1,21 @@ +# +# 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. +# +eventMesh.server.redis.serverAddress=redis://127.0.0.1:6379 +eventMesh.server.redis.serverType=SINGLE +eventMesh.server.redis.serverMasterName=serverMasterName-success!!! +eventMesh.server.redis.redisson.threads=2 +eventMesh.server.redis.redisson.nettyThreads=2 \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/build.gradle new file mode 100644 index 0000000000..fd14357fb9 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/build.gradle @@ -0,0 +1,58 @@ +/* + * 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. + */ + +List rocketmq = [ + "org.apache.rocketmq:rocketmq-client:$rocketmq_version", + "org.apache.rocketmq:rocketmq-broker:$rocketmq_version", + "org.apache.rocketmq:rocketmq-common:$rocketmq_version", + "org.apache.rocketmq:rocketmq-store:$rocketmq_version", + "org.apache.rocketmq:rocketmq-namesrv:$rocketmq_version", + "org.apache.rocketmq:rocketmq-tools:$rocketmq_version", + "org.apache.rocketmq:rocketmq-remoting:$rocketmq_version", + "org.apache.rocketmq:rocketmq-logging:$rocketmq_version", + "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", + "org.apache.rocketmq:rocketmq-filter:$rocketmq_version", + "org.apache.rocketmq:rocketmq-acl:$rocketmq_version", + "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version", + +] + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + /* + * The exclusions can be removed after this issue is fixed: + * https://github.com/apache/rocketmq/issues/5347 + */ + rocketmq.each { + implementation(it) { + exclude group: 'ch.qos.logback', module: 'logback-classic' + } + } + + testImplementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + testImplementation project(":eventmesh-common") + + testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-junit-jupiter" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/gradle.properties new file mode 100644 index 0000000000..9a01616c0d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# +rocketmq_version=4.9.5 +pluginType=storage +pluginName=rocketmq diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/RocketMQAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/RocketMQAdmin.java new file mode 100644 index 0000000000..9175f0674c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/RocketMQAdmin.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.admin; + +import org.apache.eventmesh.api.admin.AbstractAdmin; +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.storage.rocketmq.config.ClientConfiguration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.common.admin.TopicOffset; +import org.apache.rocketmq.common.admin.TopicStatsTable; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.apache.rocketmq.tools.command.CommandUtil; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +public class RocketMQAdmin extends AbstractAdmin { + + private final RPCHook rpcHook; + + protected String nameServerAddr; + + protected String clusterName; + + private int numOfQueue = 4; + private int queuePermission = 6; + + public RocketMQAdmin() { + super(new AtomicBoolean(false)); + + ConfigService configService = ConfigService.getInstance(); + ClientConfiguration clientConfiguration = configService.buildConfigInstance(ClientConfiguration.class); + + nameServerAddr = clientConfiguration.getNamesrvAddr(); + clusterName = clientConfiguration.getClusterName(); + String accessKey = clientConfiguration.getAccessKey(); + String secretKey = clientConfiguration.getSecretKey(); + rpcHook = new AclClientRPCHook(new SessionCredentials(accessKey, secretKey)); + } + + @Override + public List getTopic() throws Exception { + DefaultMQAdminExt adminExt = createMQAdminExt(); + try { + List result = new ArrayList<>(); + + adminExt.start(); + Set topicList = adminExt.fetchAllTopicList().getTopicList(); + for (String topic : topicList) { + long messageCount = 0; + TopicStatsTable topicStats = adminExt.examineTopicStats(topic); + HashMap offsetTable = topicStats.getOffsetTable(); + for (TopicOffset topicOffset : offsetTable.values()) { + messageCount += topicOffset.getMaxOffset() - topicOffset.getMinOffset(); + } + result.add(new TopicProperties( + topic, messageCount)); + } + + result.sort(Comparator.comparing(t -> t.name)); + return result; + } finally { + adminExt.shutdown(); + } + } + + @Override + public void createTopic(String topicName) throws Exception { + if (StringUtils.isBlank(topicName)) { + throw new Exception("Topic name can not be blank"); + } + DefaultMQAdminExt adminExt = createMQAdminExt(); + try { + adminExt.start(); + Set brokerAddress = CommandUtil.fetchMasterAddrByClusterName(adminExt, clusterName); + for (String masterAddress : brokerAddress) { + TopicConfig topicConfig = new TopicConfig(); + topicConfig.setTopicName(topicName); + topicConfig.setReadQueueNums(numOfQueue); + topicConfig.setWriteQueueNums(numOfQueue); + topicConfig.setPerm(queuePermission); + adminExt.createAndUpdateTopicConfig(masterAddress, topicConfig); + } + } finally { + adminExt.shutdown(); + } + } + + @Override + public void deleteTopic(String topicName) throws Exception { + if (StringUtils.isBlank(topicName)) { + throw new Exception("Topic name can not be blank."); + } + DefaultMQAdminExt adminExt = createMQAdminExt(); + try { + adminExt.start(); + Set brokerAddress = CommandUtil.fetchMasterAddrByClusterName(adminExt, clusterName); + adminExt.deleteTopicInBroker(brokerAddress, topicName); + } finally { + adminExt.shutdown(); + } + } + + private DefaultMQAdminExt createMQAdminExt() { + DefaultMQAdminExt adminExt = new DefaultMQAdminExt(rpcHook); + String groupId = UUID.randomUUID().toString(); + adminExt.setAdminExtGroup("admin_ext_group-" + groupId); + adminExt.setNamesrvAddr(nameServerAddr); + return adminExt; + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/RocketMQAdminAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/RocketMQAdminAdaptor.java new file mode 100644 index 0000000000..5899cb803f --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/RocketMQAdminAdaptor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.admin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +public class RocketMQAdminAdaptor implements Admin { + + private final RocketMQAdmin admin; + + public RocketMQAdminAdaptor() { + admin = new RocketMQAdmin(); + } + + @Override + public boolean isStarted() { + return admin.isStarted(); + } + + @Override + public boolean isClosed() { + return admin.isClosed(); + } + + @Override + public void start() { + admin.start(); + } + + @Override + public void shutdown() { + admin.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + admin.init(properties); + } + + @Override + public List getTopic() throws Exception { + return admin.getTopic(); + } + + @Override + public void createTopic(String topicName) throws Exception { + admin.createTopic(topicName); + } + + @Override + public void deleteTopic(String topicName) throws Exception { + admin.deleteTopic(topicName); + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return admin.getEvent(topicName, offset, length); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + admin.publish(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/command/Command.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/command/Command.java new file mode 100644 index 0000000000..3a9971be03 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/admin/command/Command.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.admin.command; + +import org.apache.eventmesh.common.config.ConfigService; +import org.apache.eventmesh.storage.rocketmq.config.ClientConfiguration; + +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; + +import java.util.UUID; + +import lombok.Data; + +@Data +public abstract class Command { + + protected DefaultMQAdminExt adminExt; + + protected String nameServerAddr; + protected String clusterName; + + public void init() { + ConfigService configService = ConfigService.getInstance(); + ClientConfiguration clientConfiguration = configService.buildConfigInstance(ClientConfiguration.class); + + nameServerAddr = clientConfiguration.getNamesrvAddr(); + clusterName = clientConfiguration.getClusterName(); + String accessKey = clientConfiguration.getAccessKey(); + String secretKey = clientConfiguration.getSecretKey(); + + RPCHook rpcHook = new AclClientRPCHook(new SessionCredentials(accessKey, secretKey)); + adminExt = new DefaultMQAdminExt(rpcHook); + String groupId = UUID.randomUUID().toString(); + adminExt.setAdminExtGroup("admin_ext_group-" + groupId); + adminExt.setNamesrvAddr(nameServerAddr); + } + + public abstract void execute() throws Exception; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/RocketMQMessageFactory.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/RocketMQMessageFactory.java new file mode 100644 index 0000000000..be9cc3fcad --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/RocketMQMessageFactory.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.cloudevent; + +import org.apache.eventmesh.storage.rocketmq.cloudevent.impl.RocketMQBinaryMessageReader; +import org.apache.eventmesh.storage.rocketmq.cloudevent.impl.RocketMQHeaders; +import org.apache.eventmesh.storage.rocketmq.cloudevent.impl.RocketMQMessageWriter; + +import org.apache.rocketmq.common.message.Message; + +import java.util.Map; + +import javax.annotation.ParametersAreNonnullByDefault; + +import io.cloudevents.core.message.MessageReader; +import io.cloudevents.core.message.MessageWriter; +import io.cloudevents.core.message.impl.MessageUtils; +import io.cloudevents.lang.Nullable; +import io.cloudevents.rw.CloudEventRWException; +import io.cloudevents.rw.CloudEventWriter; + +@ParametersAreNonnullByDefault +public final class RocketMQMessageFactory { + + private RocketMQMessageFactory() { + // prevent instantiation + } + + public static MessageReader createReader(final Message message) throws CloudEventRWException { + return createReader(message.getProperties(), message.getBody()); + } + + public static MessageReader createReader(final Map props, + @Nullable final byte[] body) + throws CloudEventRWException { + + return MessageUtils.parseStructuredOrBinaryMessage( + () -> null, + format -> null, + () -> props.get(RocketMQHeaders.SPEC_VERSION), + sv -> new RocketMQBinaryMessageReader(sv, props, body)); + } + + public static MessageWriter, Message> createWriter(String topic) { + return new RocketMQMessageWriter<>(topic); + } + + public static MessageWriter, Message> createWriter(String topic, + String keys) { + return new RocketMQMessageWriter<>(topic, keys); + } + + public static MessageWriter, Message> createWriter(String topic, + String keys, + String tags) { + return new RocketMQMessageWriter<>(topic, keys, tags); + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQBinaryMessageReader.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQBinaryMessageReader.java new file mode 100644 index 0000000000..d47ab0d8a2 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQBinaryMessageReader.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.cloudevent.impl; + +import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; + +import io.cloudevents.SpecVersion; +import io.cloudevents.core.data.BytesCloudEventData; +import io.cloudevents.core.message.impl.BaseGenericBinaryMessageReaderImpl; + +public class RocketMQBinaryMessageReader + extends BaseGenericBinaryMessageReaderImpl { + + private final Map headers; + + public RocketMQBinaryMessageReader(SpecVersion version, Map headers, + byte[] payload) { + super(version, + payload != null && payload.length > 0 ? BytesCloudEventData.wrap(payload) : null); + + Objects.requireNonNull(headers); + this.headers = headers; + } + + @Override + protected boolean isContentTypeHeader(String key) { + return key.equals(RocketMQHeaders.CONTENT_TYPE); + } + + @Override + protected boolean isCloudEventsHeader(String key) { + return true; + } + + @Override + protected String toCloudEventsKey(String key) { + return key.toLowerCase(); + } + + @Override + protected void forEachHeader(BiConsumer fn) { + this.headers.forEach(fn); + } + + @Override + protected String toCloudEventsValue(String value) { + return value; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQHeaders.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQHeaders.java new file mode 100644 index 0000000000..ec9b95dcaa --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQHeaders.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.cloudevent.impl; + +import java.util.Map; + +import io.cloudevents.core.message.impl.MessageUtils; +import io.cloudevents.core.v1.CloudEventV1; + +public class RocketMQHeaders { + + public static final String CE_PREFIX = "CE_"; + + protected static final Map ATTRIBUTES_TO_HEADERS = + MessageUtils.generateAttributesToHeadersMapping(v -> v); + + public static final String CONTENT_TYPE = + ATTRIBUTES_TO_HEADERS.get(CloudEventV1.DATACONTENTTYPE); + + public static final String SPEC_VERSION = ATTRIBUTES_TO_HEADERS.get(CloudEventV1.SPECVERSION); + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQMessageWriter.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQMessageWriter.java new file mode 100644 index 0000000000..6a7f522c13 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/cloudevent/impl/RocketMQMessageWriter.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.cloudevent.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.message.Message; + +import javax.annotation.Nonnull; + +import io.cloudevents.CloudEventData; +import io.cloudevents.SpecVersion; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.message.MessageWriter; +import io.cloudevents.rw.CloudEventContextWriter; +import io.cloudevents.rw.CloudEventRWException; +import io.cloudevents.rw.CloudEventWriter; + +public final class RocketMQMessageWriter + implements MessageWriter, Message>, CloudEventWriter { + + private final Message message = new Message(); + + public RocketMQMessageWriter(String topic) { + message.setTopic(topic); + } + + public RocketMQMessageWriter(String topic, String keys) { + message.setTopic(topic); + + if (StringUtils.isNotEmpty(keys)) { + message.setKeys(keys); + } + } + + public RocketMQMessageWriter(String topic, String keys, String tags) { + message.setTopic(topic); + + if (StringUtils.isNotEmpty(tags)) { + message.setTags(tags); + } + + if (StringUtils.isNotEmpty(keys)) { + message.setKeys(keys); + } + } + + @Override + public CloudEventContextWriter withContextAttribute(@Nonnull String name, @Nonnull String value) + throws CloudEventRWException { + message.putUserProperty(name, value); + return this; + } + + @Override + public RocketMQMessageWriter create(final SpecVersion version) { + message.putUserProperty(RocketMQHeaders.SPEC_VERSION, version.toString()); + return this; + } + + @Override + public Message setEvent(@Nonnull final EventFormat format, @Nonnull final byte[] value) + throws CloudEventRWException { + message.putUserProperty(RocketMQHeaders.CONTENT_TYPE, format.serializedContentType()); + message.setBody(value); + return message; + } + + @Override + public Message end(final CloudEventData data) throws CloudEventRWException { + message.setBody(data.toBytes()); + return message; + } + + @Override + public Message end() { + return message; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/common/EventMeshConstants.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/common/EventMeshConstants.java new file mode 100644 index 0000000000..925d0b28ae --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/common/EventMeshConstants.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.common; + +public class EventMeshConstants { + + public static final String EVENTMESH_CONF_FILE = "rocketmq-client.properties"; + + public static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 3000; + + public static final String STORE_TIMESTAMP = "storetime"; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/common/TopicNameHelperImpl.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/common/TopicNameHelperImpl.java new file mode 100644 index 0000000000..e0ee8843ee --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/common/TopicNameHelperImpl.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.common; + +import org.apache.eventmesh.api.TopicNameHelper; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.MixAll; + +public class TopicNameHelperImpl implements TopicNameHelper { + + @Override + public boolean isRetryTopic(String retryTopic) { + if (StringUtils.isBlank(retryTopic)) { + return false; + } + return retryTopic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfig.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfig.java new file mode 100644 index 0000000000..7a31a17314 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfig.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.config; + +import org.apache.eventmesh.storage.rocketmq.domain.NonStandardKeys; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@Getter +@Setter +public class ClientConfig implements NonStandardKeys { + + private String driverImpl; + private String accessPoints; + private String namespace; + private String producerId; + private String consumerId; + private int operationTimeout = 5000; + private String region; + private String routingSource; + private String routingDestination; + private String routingExpression; + private String rmqConsumerGroup; + private String rmqProducerGroup = "__OMS_PRODUCER_DEFAULT_GROUP"; + private int rmqMaxRedeliveryTimes = 16; + private int rmqMessageConsumeTimeout = 15; // In minutes + private int rmqMaxConsumeThreadNums = 64; + private int rmqMinConsumeThreadNums = 20; + private String rmqMessageDestination; + private int rmqPullMessageBatchNums = 32; + private int rmqPullMessageCacheCapacity = 1000; + private String messageModel; + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfiguration.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfiguration.java new file mode 100644 index 0000000000..b1748de895 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfiguration.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Config(prefix = "eventMesh.server.rocketmq", path = "classPath://rocketmq-client.properties") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ClientConfiguration { + + @ConfigField(field = "namesrvAddr", notEmpty = true) + @Builder.Default + private String namesrvAddr = ""; + + @ConfigField(field = "username") + @Builder.Default + private String clientUserName = "username"; + + @ConfigField(field = "password") + @Builder.Default + private String clientPass = "password"; + + @ConfigField(field = "client.consumeThreadMin") + @Builder.Default + private Integer consumeThreadMin = 2; + + @ConfigField(field = "client.consumeThreadMax") + @Builder.Default + private Integer consumeThreadMax = 2; + + @ConfigField(field = "client.consumeThreadPoolQueueSize") + @Builder.Default + private Integer consumeQueueSize = 10000; + + @ConfigField(field = "client.pullBatchSize") + @Builder.Default + private Integer pullBatchSize = 32; + + @ConfigField(field = "client.ackwindow") + @Builder.Default + private Integer ackWindow = 1000; + + @ConfigField(field = "client.pubwindow") + @Builder.Default + private Integer pubWindow = 100; + + @ConfigField(field = "client.comsumeTimeoutInMin") + @Builder.Default + private long consumeTimeout = 0L; + + @ConfigField(field = "client.pollNameServerInterval") + @Builder.Default + private Integer pollNameServerInterval = 10 * 1000; + + @ConfigField(field = "client.heartbeatBrokerInterval") + @Builder.Default + private Integer heartbeatBrokerInterval = 30 * 1000; + + @ConfigField(field = "client.rebalanceInterval") + @Builder.Default + private Integer rebalanceInterval = 20 * 1000; + + @ConfigField(field = "cluster") + @Builder.Default + private String clusterName = ""; + + @ConfigField(field = "accessKey") + @Builder.Default + private String accessKey = ""; + + @ConfigField(field = "secretKey") + @Builder.Default + private String secretKey = ""; +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/consumer/PushConsumerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/consumer/PushConsumerImpl.java new file mode 100644 index 0000000000..4a7e0869c9 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/consumer/PushConsumerImpl.java @@ -0,0 +1,309 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.storage.rocketmq.cloudevent.RocketMQMessageFactory; +import org.apache.eventmesh.storage.rocketmq.common.EventMeshConstants; +import org.apache.eventmesh.storage.rocketmq.config.ClientConfig; +import org.apache.eventmesh.storage.rocketmq.domain.NonStandardKeys; +import org.apache.eventmesh.storage.rocketmq.patch.EventMeshConsumeConcurrentlyContext; +import org.apache.eventmesh.storage.rocketmq.patch.EventMeshConsumeConcurrentlyStatus; +import org.apache.eventmesh.storage.rocketmq.patch.EventMeshMessageListenerConcurrently; +import org.apache.eventmesh.storage.rocketmq.utils.BeanUtils; +import org.apache.eventmesh.storage.rocketmq.utils.CloudEventUtils; +import org.apache.eventmesh.storage.rocketmq.utils.OMSUtil; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService; +import org.apache.rocketmq.client.impl.consumer.ConsumeMessageService; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +public class PushConsumerImpl { + + private final DefaultMQPushConsumer rocketmqPushConsumer; + private final Properties properties; + private AtomicBoolean started = new AtomicBoolean(false); + private EventListener eventListener; + private final ClientConfig clientConfig; + + public PushConsumerImpl(final Properties properties) { + this.rocketmqPushConsumer = new DefaultMQPushConsumer(); + this.properties = properties; + this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); + + String accessPoints = clientConfig.getAccessPoints(); + if (accessPoints == null || accessPoints.isEmpty()) { + throw new StorageRuntimeException("OMS AccessPoints is null or empty."); + } + this.rocketmqPushConsumer.setNamesrvAddr(accessPoints.replace(',', ';')); + String consumerGroup = clientConfig.getConsumerId(); + if (consumerGroup == null || consumerGroup.isEmpty()) { + throw new StorageRuntimeException( + "Consumer Group is necessary for RocketMQ, please set it."); + } + this.rocketmqPushConsumer.setConsumerGroup(consumerGroup); + this.rocketmqPushConsumer.setMaxReconsumeTimes(clientConfig.getRmqMaxRedeliveryTimes()); + this.rocketmqPushConsumer.setConsumeTimeout(clientConfig.getRmqMessageConsumeTimeout()); + this.rocketmqPushConsumer.setConsumeThreadMax(clientConfig.getRmqMaxConsumeThreadNums()); + this.rocketmqPushConsumer.setConsumeThreadMin(clientConfig.getRmqMinConsumeThreadNums()); + this.rocketmqPushConsumer.setMessageModel( + MessageModel.valueOf(clientConfig.getMessageModel())); + + String consumerId = OMSUtil.buildInstanceName(); + // this.rocketmqPushConsumer.setInstanceName(consumerId); + this.rocketmqPushConsumer.setInstanceName(properties.getProperty("instanceName")); + properties.put("CONSUMER_ID", consumerId); + this.rocketmqPushConsumer.setLanguage(LanguageCode.OMS); + + if (clientConfig.getMessageModel().equalsIgnoreCase(MessageModel.BROADCASTING.name())) { + rocketmqPushConsumer.registerMessageListener(new BroadCastingMessageListener()); + } else { + rocketmqPushConsumer.registerMessageListener(new ClusteringMessageListener()); + } + } + + public Properties attributes() { + return properties; + } + + public void start() { + if (this.started.compareAndSet(false, true)) { + try { + this.rocketmqPushConsumer.start(); + } catch (Exception e) { + throw new StorageRuntimeException(e.getMessage()); + } + } + } + + public synchronized void shutdown() { + if (this.started.compareAndSet(true, false)) { + this.rocketmqPushConsumer.shutdown(); + } + } + + public boolean isStarted() { + return this.started.get(); + } + + public boolean isClosed() { + return !this.isStarted(); + } + + public DefaultMQPushConsumer getRocketmqPushConsumer() { + return rocketmqPushConsumer; + } + + public void subscribe(String topic, String subExpression) { + try { + this.rocketmqPushConsumer.subscribe(topic, subExpression); + } catch (MQClientException e) { + throw new StorageRuntimeException(String.format("RocketMQ push consumer can't attach to %s.", topic)); + } + } + + public void unsubscribe(String topic) { + try { + this.rocketmqPushConsumer.unsubscribe(topic); + } catch (Exception e) { + throw new StorageRuntimeException(String.format("RocketMQ push consumer fails to unsubscribe topic: %s", topic)); + } + } + + @SuppressWarnings("deprecation") + public void updateOffset(List cloudEvents, AbstractContext context) { + ConsumeMessageService consumeMessageService = rocketmqPushConsumer + .getDefaultMQPushConsumerImpl().getConsumeMessageService(); + List msgExtList = new ArrayList<>(cloudEvents.size()); + for (CloudEvent msg : cloudEvents) { + if (msg != null) { + msgExtList.add(CloudEventUtils.msgConvertExt( + RocketMQMessageFactory.createWriter(Objects.requireNonNull(msg.getSubject())).writeBinary(msg))); + } + } + ((ConsumeMessageConcurrentlyService) consumeMessageService) + .updateOffset(msgExtList, (EventMeshConsumeConcurrentlyContext) context); + } + + private class BroadCastingMessageListener extends EventMeshMessageListenerConcurrently { + + @Override + public EventMeshConsumeConcurrentlyStatus handleMessage(MessageExt msg, + EventMeshConsumeConcurrentlyContext context) { + if (msg == null) { + return EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + msg.putUserProperty(Constants.PROPERTY_MESSAGE_BORN_TIMESTAMP, + String.valueOf(msg.getBornTimestamp())); + msg.putUserProperty(Constants.PROPERTY_MESSAGE_STORE_TIMESTAMP, + String.valueOf(msg.getStoreTimestamp())); + + // for rr request/reply + CloudEvent cloudEvent = + RocketMQMessageFactory.createReader(CloudEventUtils.msgConvert(msg)).toEvent(); + + CloudEventBuilder cloudEventBuilder = null; + for (String sysPropKey : MessageConst.STRING_HASH_SET) { + if (StringUtils.isNotEmpty(msg.getProperty(sysPropKey))) { + String prop = msg.getProperty(sysPropKey); + sysPropKey = sysPropKey.toLowerCase().replace("_", Constants.MESSAGE_PROP_SEPARATOR); + cloudEventBuilder = CloudEventBuilder.from(cloudEvent).withExtension(sysPropKey, prop); + } + } + if (cloudEventBuilder != null) { + cloudEvent = cloudEventBuilder.build(); + } + + if (eventListener == null) { + throw new StorageRuntimeException(String.format("The topic/queue %s isn't attached to this consumer", + msg.getTopic())); + } + + final Properties contextProperties = new Properties(); + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); + EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + switch (action) { + case CommitMessage: + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS.name()); + break; + case ReconsumeLater: + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); + break; + case ManualAck: + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.CONSUME_FINISH.name()); + break; + default: + break; + } + } + }; + + eventMeshAsyncConsumeContext.setAbstractContext(context); + + eventListener.consume(cloudEvent, eventMeshAsyncConsumeContext); + + return EventMeshConsumeConcurrentlyStatus.valueOf( + contextProperties.getProperty(NonStandardKeys.MESSAGE_CONSUME_STATUS)); + } + + } + + private class ClusteringMessageListener extends EventMeshMessageListenerConcurrently { + + @Override + public EventMeshConsumeConcurrentlyStatus handleMessage(MessageExt msg, + EventMeshConsumeConcurrentlyContext context) { + if (msg == null) { + return EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + msg.putUserProperty(Constants.PROPERTY_MESSAGE_BORN_TIMESTAMP, + String.valueOf(msg.getBornTimestamp())); + msg.putUserProperty(EventMeshConstants.STORE_TIMESTAMP, + String.valueOf(msg.getStoreTimestamp())); + + CloudEvent cloudEvent = + RocketMQMessageFactory.createReader(CloudEventUtils.msgConvert(msg)).toEvent(); + + CloudEventBuilder cloudEventBuilder = null; + + for (String sysPropKey : MessageConst.STRING_HASH_SET) { + if (StringUtils.isNotEmpty(msg.getProperty(sysPropKey))) { + String prop = msg.getProperty(sysPropKey); + sysPropKey = sysPropKey.toLowerCase().replace("_", Constants.MESSAGE_PROP_SEPARATOR); + cloudEventBuilder = CloudEventBuilder.from(cloudEvent).withExtension(sysPropKey, prop); + } + } + if (cloudEventBuilder != null) { + cloudEvent = cloudEventBuilder.build(); + } + + if (eventListener == null) { + throw new StorageRuntimeException(String.format("The topic/queue %s isn't attached to this consumer", + msg.getTopic())); + } + + final Properties contextProperties = new Properties(); + + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); + + EventMeshAsyncConsumeContext eventMeshAsyncConsumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + switch (action) { + case CommitMessage: + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.CONSUME_SUCCESS.name()); + break; + case ReconsumeLater: + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.RECONSUME_LATER.name()); + break; + case ManualAck: + contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, + EventMeshConsumeConcurrentlyStatus.CONSUME_FINISH.name()); + break; + default: + break; + } + } + }; + + eventMeshAsyncConsumeContext.setAbstractContext(context); + + eventListener.consume(cloudEvent, eventMeshAsyncConsumeContext); + + return EventMeshConsumeConcurrentlyStatus.valueOf( + contextProperties.getProperty(NonStandardKeys.MESSAGE_CONSUME_STATUS)); + } + } + + public void registerEventListener(EventListener listener) { + this.eventListener = listener; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/consumer/RocketMQConsumerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/consumer/RocketMQConsumerImpl.java new file mode 100644 index 0000000000..ed9d744341 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/consumer/RocketMQConsumerImpl.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.rocketmq.config.ClientConfiguration; + +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Config(field = "clientConfiguration") +public class RocketMQConsumerImpl implements Consumer { + + private PushConsumerImpl pushConsumer; + + private ClientConfiguration clientConfiguration; + + @Override + public synchronized void init(Properties keyValue) { + boolean isBroadcast = Boolean.parseBoolean(keyValue.getProperty("isBroadcast")); + + String consumerGroup = keyValue.getProperty("consumerGroup"); + if (isBroadcast) { + consumerGroup = Constants.BROADCAST_PREFIX + consumerGroup; + } + + String namesrvAddr = clientConfiguration.getNamesrvAddr(); + String instanceName = keyValue.getProperty("instanceName"); + Properties properties = new Properties(); + properties.put("ACCESS_POINTS", namesrvAddr); + properties.put("REGION", "namespace"); + properties.put("instanceName", instanceName); + properties.put("CONSUMER_ID", consumerGroup); + if (isBroadcast) { + properties.put("MESSAGE_MODEL", MessageModel.BROADCASTING.name()); + } else { + properties.put("MESSAGE_MODEL", MessageModel.CLUSTERING.name()); + } + + pushConsumer = new PushConsumerImpl(properties); + } + + @Override + public void subscribe(String topic) { + pushConsumer.subscribe(topic, "*"); + } + + @Override + public boolean isStarted() { + return pushConsumer.isStarted(); + } + + @Override + public boolean isClosed() { + return pushConsumer.isClosed(); + } + + @Override + public synchronized void start() { + pushConsumer.start(); + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + pushConsumer.updateOffset(cloudEvents, context); + } + + @Override + public void unsubscribe(String topic) { + pushConsumer.unsubscribe(topic); + } + + @Override + public void registerEventListener(EventListener listener) { + pushConsumer.registerEventListener(listener); + } + + @Override + public synchronized void shutdown() { + pushConsumer.shutdown(); + } + + public Properties attributes() { + return pushConsumer.attributes(); + } + + public ClientConfiguration getClientConfiguration() { + return clientConfiguration; + } +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/domain/NonStandardKeys.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/domain/NonStandardKeys.java similarity index 95% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/domain/NonStandardKeys.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/domain/NonStandardKeys.java index 209557dc9f..2323f6cfdb 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/domain/NonStandardKeys.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/domain/NonStandardKeys.java @@ -15,15 +15,16 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.domain; +package org.apache.eventmesh.storage.rocketmq.domain; /** * NonStandardKeys */ public interface NonStandardKeys { + String CONSUMER_GROUP = "rmq.consumer.group"; String MAX_REDELIVERY_TIMES = "rmq.max.redelivery.times"; String MESSAGE_CONSUME_TIMEOUT = "rmq.message.consume.timeout"; String MESSAGE_CONSUME_STATUS = "rmq.message.consume.status"; String MESSAGE_DESTINATION = "rmq.message.destination"; -} \ No newline at end of file +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/exception/RMQMessageFormatException.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/exception/RMQMessageFormatException.java similarity index 84% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/exception/RMQMessageFormatException.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/exception/RMQMessageFormatException.java index 703b7ea2bf..6257737be4 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/exception/RMQMessageFormatException.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/exception/RMQMessageFormatException.java @@ -15,11 +15,11 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.exception; +package org.apache.eventmesh.storage.rocketmq.exception; -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; +import org.apache.eventmesh.api.exception.StorageRuntimeException; -public class RMQMessageFormatException extends ConnectorRuntimeException { +public class RMQMessageFormatException extends StorageRuntimeException { public RMQMessageFormatException(String message) { super(message); diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/exception/RMQTimeoutException.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/exception/RMQTimeoutException.java similarity index 84% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/exception/RMQTimeoutException.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/exception/RMQTimeoutException.java index c2a6b03410..ae82bb3f1b 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/exception/RMQTimeoutException.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/exception/RMQTimeoutException.java @@ -15,11 +15,11 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.exception; +package org.apache.eventmesh.storage.rocketmq.exception; -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; +import org.apache.eventmesh.api.exception.StorageRuntimeException; -public class RMQTimeoutException extends ConnectorRuntimeException { +public class RMQTimeoutException extends StorageRuntimeException { public RMQTimeoutException(String message) { super(message); diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshConsumeConcurrentlyContext.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshConsumeConcurrentlyContext.java similarity index 96% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshConsumeConcurrentlyContext.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshConsumeConcurrentlyContext.java index 2dcfa95038..03fd516297 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshConsumeConcurrentlyContext.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshConsumeConcurrentlyContext.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.patch; +package org.apache.eventmesh.storage.rocketmq.patch; import org.apache.eventmesh.api.AbstractContext; @@ -24,6 +24,7 @@ import org.apache.rocketmq.common.message.MessageQueue; public class EventMeshConsumeConcurrentlyContext extends ConsumeConcurrentlyContext implements AbstractContext { + private final ProcessQueue processQueue; private boolean manualAck = true; diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshConsumeConcurrentlyStatus.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshConsumeConcurrentlyStatus.java similarity index 95% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshConsumeConcurrentlyStatus.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshConsumeConcurrentlyStatus.java index 468b14f568..9ba6d396d5 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshConsumeConcurrentlyStatus.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshConsumeConcurrentlyStatus.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.patch; +package org.apache.eventmesh.storage.rocketmq.patch; public enum EventMeshConsumeConcurrentlyStatus { /** diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshMessageListenerConcurrently.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java similarity index 86% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshMessageListenerConcurrently.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java index 0d32ba27d3..79ec322ad3 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/patch/EventMeshMessageListenerConcurrently.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/patch/EventMeshMessageListenerConcurrently.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.patch; +package org.apache.eventmesh.storage.rocketmq.patch; import org.apache.commons.collections4.CollectionUtils; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; @@ -25,16 +25,14 @@ import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; +@Slf4j public abstract class EventMeshMessageListenerConcurrently implements MessageListenerConcurrently { - private static final Logger LOG = LoggerFactory.getLogger(EventMeshMessageListenerConcurrently.class); - @Override public ConsumeConcurrentlyStatus consumeMessage(final List msgs, - final ConsumeConcurrentlyContext context) { + final ConsumeConcurrentlyContext context) { ConsumeConcurrentlyStatus status = null; if (CollectionUtils.isEmpty(msgs)) { @@ -58,14 +56,14 @@ public ConsumeConcurrentlyStatus consumeMessage(final List msgs, return status; } } catch (Throwable e) { - LOG.info("handleMessage fail", e); + log.info("handleMessage fail", e); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } } catch (Throwable e) { - LOG.info("handleMessage fail", e); + log.info("handleMessage fail", e); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } - //return status; + // return status; } public abstract EventMeshConsumeConcurrentlyStatus handleMessage(MessageExt msg, EventMeshConsumeConcurrentlyContext context); diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/AbstractProducer.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/AbstractProducer.java new file mode 100644 index 0000000000..c42b4927c6 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/AbstractProducer.java @@ -0,0 +1,161 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.producer; + +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.storage.rocketmq.config.ClientConfig; +import org.apache.eventmesh.storage.rocketmq.exception.RMQMessageFormatException; +import org.apache.eventmesh.storage.rocketmq.exception.RMQTimeoutException; +import org.apache.eventmesh.storage.rocketmq.utils.BeanUtils; +import org.apache.eventmesh.storage.rocketmq.utils.OMSUtil; + +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +public abstract class AbstractProducer { + + static final InternalLogger log = ClientLogger.getLog(); + final Properties properties; + final DefaultMQProducer rocketmqProducer; + protected final AtomicBoolean started = new AtomicBoolean(false); + // private boolean started = false; + private final ClientConfig clientConfig; + + AbstractProducer(final Properties properties) { + this.properties = properties; + this.rocketmqProducer = new DefaultMQProducer(); + this.clientConfig = BeanUtils.populate(properties, ClientConfig.class); + + String accessPoints = clientConfig.getAccessPoints(); + if (accessPoints == null || accessPoints.isEmpty()) { + throw new StorageRuntimeException("OMS AccessPoints is null or empty."); + } + + this.rocketmqProducer.setNamesrvAddr(accessPoints.replace(',', ';')); + + this.rocketmqProducer.setProducerGroup(clientConfig.getRmqProducerGroup()); + + String producerId = OMSUtil.buildInstanceName(); + this.rocketmqProducer.setSendMsgTimeout(clientConfig.getOperationTimeout()); + this.rocketmqProducer.setInstanceName(producerId); + this.rocketmqProducer.setMaxMessageSize(1024 * 1024 * 4); + this.rocketmqProducer.setLanguage(LanguageCode.OMS); + properties.put(Constants.PRODUCER_ID, producerId); + } + + public synchronized void start() { + if (!started.get()) { + try { + this.rocketmqProducer.start(); + } catch (MQClientException e) { + throw new StorageRuntimeException("-1", e); + } + } + this.started.set(true); + } + + public synchronized void shutdown() { + if (this.started.get()) { + this.rocketmqProducer.shutdown(); + } + this.started.set(false); + } + + public boolean isStarted() { + return this.started.get(); + } + + public boolean isClosed() { + return !this.isStarted(); + } + + StorageRuntimeException checkProducerException(String topic, String msgId, Throwable e) { + if (e instanceof MQClientException) { + if (e.getCause() != null) { + if (e.getCause() instanceof RemotingTimeoutException) { + return new RMQTimeoutException( + String.format("Send message to broker timeout, %dms, Topic=%s, msgId=%s", + this.rocketmqProducer.getSendMsgTimeout(), topic, msgId), + e); + } else if (e.getCause() instanceof MQBrokerException + || e.getCause() instanceof RemotingConnectException) { + if (e.getCause() instanceof MQBrokerException) { + MQBrokerException brokerException = (MQBrokerException) e.getCause(); + return new StorageRuntimeException(String.format("Received a broker exception, Topic=%s, msgId=%s, %s", + topic, msgId, brokerException.getErrorMessage()), e); + } + + if (e.getCause() instanceof RemotingConnectException) { + RemotingConnectException connectException = + (RemotingConnectException) e.getCause(); + return new StorageRuntimeException(String.format("Network connection experiences failures. Topic=%s, msgId=%s, %s", + topic, msgId, connectException.getMessage()), e); + } + } + } else { + // Exception thrown by local. + MQClientException clientException = (MQClientException) e; + if (-1 == clientException.getResponseCode()) { + return new StorageRuntimeException(String.format("Topic does not exist, Topic=%s, msgId=%s", + topic, msgId), e); + } else if (ResponseCode.MESSAGE_ILLEGAL == clientException.getResponseCode()) { + return new RMQMessageFormatException( + String.format("A illegal message for RocketMQ, Topic=%s, msgId=%s", + topic, msgId), + e); + } + } + } + return new StorageRuntimeException("Send message to RocketMQ broker failed.", e); + } + + protected void checkProducerServiceState(DefaultMQProducerImpl producer) { + switch (producer.getServiceState()) { + case CREATE_JUST: + throw new StorageRuntimeException( + String.format("You do not have start the producer, %s", + producer.getServiceState())); + case SHUTDOWN_ALREADY: + throw new StorageRuntimeException( + String.format("Your producer has been shut down, %s", + producer.getServiceState())); + case START_FAILED: + throw new StorageRuntimeException( + String.format("When you start your service throws an exception, %s", + producer.getServiceState())); + case RUNNING: + default: + } + } + + public DefaultMQProducer getRocketmqProducer() { + return rocketmqProducer; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/ProducerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/ProducerImpl.java new file mode 100644 index 0000000000..6789cdeb7e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/ProducerImpl.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.api.exception.OnExceptionContext; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.storage.rocketmq.cloudevent.RocketMQMessageFactory; +import org.apache.eventmesh.storage.rocketmq.utils.CloudEventUtils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.RequestCallback; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.remoting.exception.RemotingException; + +import java.util.Objects; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@SuppressWarnings("deprecation") +public class ProducerImpl extends AbstractProducer { + + public static final int eventMeshServerAsyncAccumulationThreshold = 1000; + + public ProducerImpl(final Properties properties) { + super(properties); + } + + public Properties attributes() { + return properties; + } + + public void setExtFields() { + super.getRocketmqProducer().setRetryTimesWhenSendFailed(0); + super.getRocketmqProducer().setRetryTimesWhenSendAsyncFailed(0); + super.getRocketmqProducer().setPollNameServerInterval(60000); + + super.getRocketmqProducer().getDefaultMQProducerImpl().getmQClientFactory().getNettyClientConfig() + .setClientAsyncSemaphoreValue(eventMeshServerAsyncAccumulationThreshold); + super.getRocketmqProducer().setCompressMsgBodyOverHowmuch(10); + } + + public SendResult send(CloudEvent cloudEvent) { + this.checkProducerServiceState(rocketmqProducer.getDefaultMQProducerImpl()); + org.apache.rocketmq.common.message.Message msg = + RocketMQMessageFactory.createWriter(Objects.requireNonNull(cloudEvent.getSubject())).writeBinary(cloudEvent); + supplySysProp(msg, cloudEvent); + String messageId = null; + try { + org.apache.rocketmq.client.producer.SendResult sendResultRmq = this.rocketmqProducer.send(msg); + SendResult sendResult = new SendResult(); + sendResult.setTopic(sendResultRmq.getMessageQueue().getTopic()); + messageId = sendResultRmq.getMsgId(); + sendResult.setMessageId(messageId); + return sendResult; + } catch (InterruptedException e) { + log.error("Send message InterruptedException", e); + Thread.currentThread().interrupt(); // Restore interrupted status + return new SendResult(); + } catch (Exception e) { + log.error(String.format("Send message Exception, %s", msg), e); + throw this.checkProducerException(msg.getTopic(), messageId, e); + } + } + + public void sendOneway(CloudEvent cloudEvent) { + this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); + org.apache.rocketmq.common.message.Message msg = + RocketMQMessageFactory.createWriter(Objects.requireNonNull(cloudEvent.getSubject())).writeBinary(cloudEvent); + supplySysProp(msg, cloudEvent); + try { + this.rocketmqProducer.sendOneway(msg); + } catch (InterruptedException e) { + log.error("Send message oneway InterruptedException", e); + Thread.currentThread().interrupt(); // Restore interrupted status + } catch (Exception e) { + log.error(String.format("Send message oneway Exception, %s", msg), e); + throw this.checkProducerException(msg.getTopic(), MessageClientIDSetter.getUniqID(msg), e); + } + } + + public void sendAsync(CloudEvent cloudEvent, SendCallback sendCallback) { + this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); + org.apache.rocketmq.common.message.Message msg = + RocketMQMessageFactory.createWriter(Objects.requireNonNull(cloudEvent.getSubject())).writeBinary(cloudEvent); + supplySysProp(msg, cloudEvent); + try { + this.rocketmqProducer.send(msg, this.sendCallbackConvert(msg, sendCallback)); + } catch (InterruptedException e) { + log.error("Send message async InterruptedException", e); + Thread.currentThread().interrupt(); // Restore interrupted status + } catch (Exception e) { + log.error(String.format("Send message async Exception, %s", msg), e); + throw this.checkProducerException(msg.getTopic(), MessageClientIDSetter.getUniqID(msg), e); + } + } + + public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) + throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + + this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); + org.apache.rocketmq.common.message.Message msg = + RocketMQMessageFactory.createWriter(Objects.requireNonNull(cloudEvent.getSubject())).writeBinary(cloudEvent); + + supplySysProp(msg, cloudEvent); + + rocketmqProducer.request(msg, rrCallbackConvert(msg, rrCallback), timeout); + } + + public void reply(final CloudEvent cloudEvent, final SendCallback sendCallback) { + this.checkProducerServiceState(this.rocketmqProducer.getDefaultMQProducerImpl()); + org.apache.rocketmq.common.message.Message msg = + RocketMQMessageFactory.createWriter(Objects.requireNonNull(cloudEvent.getSubject())).writeBinary(cloudEvent); + MessageAccessor.putProperty(msg, MessageConst.PROPERTY_MESSAGE_TYPE, MixAll.REPLY_MESSAGE_FLAG); + supplySysProp(msg, cloudEvent); + + try { + this.rocketmqProducer.send(msg, this.sendCallbackConvert(msg, sendCallback)); + } catch (InterruptedException e) { + log.error("Send message async InterruptedException", e); + Thread.currentThread().interrupt(); // Restore interrupted status + } catch (Exception e) { + log.error(String.format("Send message async Exception, %s", msg), e); + throw this.checkProducerException(msg.getTopic(), MessageClientIDSetter.getUniqID(msg), e); + } + + } + + private Message supplySysProp(Message msg, CloudEvent cloudEvent) { + for (String sysPropKey : MessageConst.STRING_HASH_SET) { + String ceKey = sysPropKey.toLowerCase().replace("_", Constants.MESSAGE_PROP_SEPARATOR); + if (cloudEvent.getExtension(ceKey) != null && StringUtils.isNotEmpty(Objects.requireNonNull(cloudEvent.getExtension(ceKey)).toString())) { + MessageAccessor.putProperty(msg, sysPropKey, Objects.requireNonNull(cloudEvent.getExtension(ceKey)).toString()); + msg.getProperties().remove(ceKey); + } + } + return msg; + } + + private RequestCallback rrCallbackConvert(final Message message, final RequestReplyCallback rrCallback) { + return new RequestCallback() { + + @Override + public void onSuccess(org.apache.rocketmq.common.message.Message message) { + // clean the message property to lowercase + for (String sysPropKey : MessageConst.STRING_HASH_SET) { + if (StringUtils.isNotEmpty(message.getProperty(sysPropKey))) { + String prop = message.getProperty(sysPropKey); + String tmpPropKey = sysPropKey.toLowerCase().replace("_", Constants.MESSAGE_PROP_SEPARATOR); + MessageAccessor.putProperty(message, tmpPropKey, prop); + message.getProperties().remove(sysPropKey); + } + } + CloudEvent event = RocketMQMessageFactory.createReader(message).toEvent(); + rrCallback.onSuccess(event); + } + + @Override + public void onException(Throwable e) { + String topic = message.getTopic(); + StorageRuntimeException onsEx = ProducerImpl.this.checkProducerException(topic, null, e); + OnExceptionContext context = new OnExceptionContext(); + context.setTopic(topic); + context.setException(onsEx); + rrCallback.onException(e); + + } + }; + } + + private org.apache.rocketmq.client.producer.SendCallback sendCallbackConvert(final Message message, + final SendCallback sendCallback) { + return new org.apache.rocketmq.client.producer.SendCallback() { + + @Override + public void onSuccess(org.apache.rocketmq.client.producer.SendResult sendResult) { + sendCallback.onSuccess(CloudEventUtils.convertSendResult(sendResult)); + } + + @Override + public void onException(Throwable e) { + String topic = message.getTopic(); + StorageRuntimeException onsEx = ProducerImpl.this.checkProducerException(topic, null, e); + OnExceptionContext context = new OnExceptionContext(); + context.setTopic(topic); + context.setException(onsEx); + sendCallback.onException(context); + } + }; + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/RocketMQProducerImpl.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/RocketMQProducerImpl.java new file mode 100644 index 0000000000..1eba8c21fd --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/producer/RocketMQProducerImpl.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.producer; + +import org.apache.eventmesh.api.RequestReplyCallback; +import org.apache.eventmesh.api.SendCallback; +import org.apache.eventmesh.api.producer.Producer; +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.storage.rocketmq.common.EventMeshConstants; +import org.apache.eventmesh.storage.rocketmq.config.ClientConfiguration; + +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.remoting.exception.RemotingException; + +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@SuppressWarnings("deprecation") +@Config(field = "clientConfiguration") +public class RocketMQProducerImpl implements Producer { + + private ProducerImpl producer; + + private ClientConfiguration clientConfiguration; + + @Override + public synchronized void init(Properties keyValue) { + String producerGroup = + keyValue.getProperty(Constants.PRODUCER_GROUP) == null ? "RMQ-producerGroup" : keyValue.getProperty(Constants.PRODUCER_GROUP); + + String omsNamesrv = clientConfiguration.getNamesrvAddr(); + Properties properties = new Properties(); + properties.put(Constants.ACCESS_POINTS, omsNamesrv); + properties.put(Constants.REGION, Constants.NAMESPACE); + properties.put(Constants.RMQ_PRODUCER_GROUP, producerGroup); + properties.put(Constants.OPERATION_TIMEOUT, 3000); + properties.put(Constants.PRODUCER_ID, producerGroup); + + producer = new ProducerImpl(properties); + + } + + @Override + public boolean isStarted() { + return producer.isStarted(); + } + + @Override + public boolean isClosed() { + return producer.isClosed(); + } + + @Override + public void start() { + producer.start(); + } + + @Override + public synchronized void shutdown() { + producer.shutdown(); + } + + @Override + public void publish(CloudEvent message, SendCallback sendCallback) throws Exception { + producer.sendAsync(message, sendCallback); + } + + @Override + public void request(CloudEvent message, RequestReplyCallback rrCallback, long timeout) + throws InterruptedException, RemotingException, MQClientException, MQBrokerException { + producer.request(message, rrCallback, timeout); + } + + @Override + public boolean reply(final CloudEvent message, final SendCallback sendCallback) throws Exception { + producer.reply(message, sendCallback); + return true; + } + + @Override + public void checkTopicExist(String topic) throws Exception { + this.producer.getRocketmqProducer() + .getDefaultMQProducerImpl() + .getmQClientFactory() + .getMQClientAPIImpl() + .getDefaultTopicRouteInfoFromNameServer(topic, EventMeshConstants.DEFAULT_TIMEOUT_IN_MILLISECONDS); + } + + @Override + public void setExtFields() { + producer.setExtFields(); + } + + @Override + public void sendOneway(CloudEvent message) { + producer.sendOneway(message); + } + + public ClientConfiguration getClientConfiguration() { + return clientConfiguration; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/storage/StorageResourceServiceRocketmqImpl.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/storage/StorageResourceServiceRocketmqImpl.java new file mode 100644 index 0000000000..8a280357a4 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/storage/StorageResourceServiceRocketmqImpl.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.storage; + +import org.apache.eventmesh.api.storage.StorageResourceService; + +public class StorageResourceServiceRocketmqImpl implements StorageResourceService { + + @Override + public void init() throws Exception { + + } + + @Override + public void release() throws Exception { + + } +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/BeanUtils.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/BeanUtils.java similarity index 84% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/BeanUtils.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/BeanUtils.java index ee9644502c..d8291d5e83 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/BeanUtils.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/BeanUtils.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.utils; +package org.apache.eventmesh.storage.rocketmq.utils; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.log.ClientLogger; @@ -25,6 +25,7 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Set; @@ -35,7 +36,7 @@ public final class BeanUtils { /** * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. */ - private static Map, Class> primitiveWrapperMap = new HashMap<>(); + private static final Map, Class> primitiveWrapperMap = new HashMap<>(); static { primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); @@ -49,36 +50,31 @@ public final class BeanUtils { primitiveWrapperMap.put(Void.TYPE, Void.TYPE); } - private static Map, Class> wrapperMap = new HashMap<>(); + private static final Map, Class> wrapperMap = new HashMap<>(); static { - for (final Class primitiveClass : primitiveWrapperMap.keySet()) { - final Class wrapperClass = primitiveWrapperMap.get(primitiveClass); - if (!primitiveClass.equals(wrapperClass)) { + primitiveWrapperMap.forEach((primitiveClass, wrapperClass) -> { + if (!Objects.equals(wrapperClass, primitiveClass)) { wrapperMap.put(wrapperClass, primitiveClass); } - } + }); wrapperMap.put(String.class, String.class); } /** *

Populate the JavaBeans properties of the specified bean, based on - * the specified name/value pairs. This method uses Java reflection APIs - * to identify corresponding "property setter" method names, and deals - * with setter arguments of type String, boolean, + * the specified name/value pairs. This method uses Java reflection APIs to identify corresponding "property setter" method names, and deals with + * setter arguments of type String, boolean, * int, long, float, and * double.

* *

The particular setter method to be called for each property is - * determined using the usual JavaBeans introspection mechanisms. Thus, - * you may identify custom setter methods using a BeanInfo class that is - * associated with the class of the bean itself. If no such BeanInfo - * class is available, the standard method name conversion ("set" plus - * the capitalized name of the property in question) is used.

+ * determined using the usual JavaBeans introspection mechanisms. Thus, you may identify custom setter methods using a BeanInfo class that is + * associated with the class of the bean itself. If no such BeanInfo class is available, the standard method name conversion ("set" plus the + * capitalized name of the property in question) is used.

* *

NOTE: It is contrary to the JavaBeans Specification - * to have more than one setter method (with different argument - * signatures) for the same property.

+ * to have more than one setter method (with different argument signatures) for the same property.

* * @param clazz JavaBean class whose properties are being populated * @param properties Map keyed by property name, with the corresponding (String or String[]) value(s) to be set @@ -112,7 +108,7 @@ public static T populate(final Properties properties, final T obj) { try { setProperties(clazz, obj, "set" + beanFieldNameWithCapitalization, entry.getValue()); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - //ignored... + // ignored... } } } catch (RuntimeException e) { @@ -132,7 +128,7 @@ public static Class getMethodClass(Class clazz, String methodName) { } public static void setProperties(Class clazz, Object obj, String methodName, - Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class parameterClass = getMethodClass(clazz, methodName); Method setterMethod = clazz.getMethod(methodName, parameterClass); if (parameterClass == Boolean.TYPE) { @@ -150,4 +146,3 @@ public static void setProperties(Class clazz, Object obj, String methodName, } } } - diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/CloudEventUtils.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/CloudEventUtils.java new file mode 100644 index 0000000000..50ccc6e93b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/CloudEventUtils.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.utils; + +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.common.Constants; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; + +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CloudEventUtils { + + public static SendResult convertSendResult( + org.apache.rocketmq.client.producer.SendResult rmqResult) { + SendResult sendResult = new SendResult(); + sendResult.setTopic(rmqResult.getMessageQueue().getTopic()); + sendResult.setMessageId(rmqResult.getMsgId()); + return sendResult; + } + + public static Message msgConvert(MessageExt rmqMsg) { + Message message = new Message(); + initProperty(rmqMsg, message, MessageExt::getTopic, Message::setTopic); + initProperty(rmqMsg, message, MessageExt::getKeys, Message::setKeys); + initProperty(rmqMsg, message, MessageExt::getTags, Message::setTags); + if (rmqMsg.getBody() != null) { + message.setBody(rmqMsg.getBody()); + } + rmqMsg.getProperties().forEach((k, v) -> MessageAccessor.putProperty(message, k, v)); + + if (rmqMsg.getMsgId() != null) { + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_MESSAGE_ID, rmqMsg.getMsgId()); + } + + if (rmqMsg.getTopic() != null) { + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_DESTINATION, rmqMsg.getTopic()); + } + + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_BORN_HOST, String.valueOf(rmqMsg.getBornHost())); + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_BORN_TIMESTAMP, + String.valueOf(rmqMsg.getBornTimestamp())); + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_STORE_HOST, + String.valueOf(rmqMsg.getStoreHost())); + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_STORE_TIMESTAMP, + String.valueOf(rmqMsg.getStoreTimestamp())); + + // use in manual ack + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_QUEUE_ID, String.valueOf(rmqMsg.getQueueId())); + MessageAccessor.putProperty(message, Constants.PROPERTY_MESSAGE_QUEUE_OFFSET, + String.valueOf(rmqMsg.getQueueOffset())); + + for (String sysPropKey : MessageConst.STRING_HASH_SET) { + if (StringUtils.isNotEmpty(message.getProperty(sysPropKey))) { + String prop = message.getProperty(sysPropKey); + String tmpPropKey = sysPropKey.toLowerCase().replace("_", Constants.MESSAGE_PROP_SEPARATOR); + MessageAccessor.putProperty(message, tmpPropKey, prop); + message.getProperties().remove(sysPropKey); + } + } + + return message; + } + + public static MessageExt msgConvertExt(Message message) { + MessageExt rmqMessageExt = new MessageExt(); + try { + initProperty(message, rmqMessageExt, Message::getKeys, Message::setKeys); + initProperty(message, rmqMessageExt, Message::getTags, Message::setTags); + + if (message.getBody() != null) { + rmqMessageExt.setBody(message.getBody()); + } + + // All destinations in RocketMQ use Topic + rmqMessageExt.setTopic(message.getTopic()); + + int queueId = Integer.parseInt(message.getProperty(Constants.PROPERTY_MESSAGE_QUEUE_ID)); + long queueOffset = Long.parseLong(message.getProperty(Constants.PROPERTY_MESSAGE_QUEUE_OFFSET)); + // use in manual ack + rmqMessageExt.setQueueId(queueId); + rmqMessageExt.setQueueOffset(queueOffset); + + message.getProperties().forEach((k, v) -> MessageAccessor.putProperty(rmqMessageExt, k, v)); + } catch (Exception e) { + log.error("Error with msgConvertExt", e); + } + return rmqMessageExt; + } + + /** + * Populate the target with properties whose source is not empty + * + * @param source source + * @param target target + * @param function function + * @param biConsumer biConsumer + * @param t + * @param v + */ + private static void initProperty(T source, V target, Function function, BiConsumer biConsumer) { + String apply = function.apply(source); + if (Objects.nonNull(apply)) { + biConsumer.accept(target, apply); + } + } + +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/OMSUtil.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/OMSUtil.java similarity index 95% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/OMSUtil.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/OMSUtil.java index f42e640321..73dce7f7f7 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/eventmesh/connector/rocketmq/utils/OMSUtil.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/eventmesh/storage/rocketmq/utils/OMSUtil.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.rocketmq.utils; +package org.apache.eventmesh.storage.rocketmq.utils; import org.apache.rocketmq.common.UtilAll; diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java similarity index 75% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java index 1fe8dc3172..08b7b4aaf8 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java @@ -17,7 +17,9 @@ package org.apache.rocketmq.client.impl.consumer; -import org.apache.eventmesh.connector.rocketmq.patch.EventMeshConsumeConcurrentlyContext; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.common.utils.ThreadUtils; +import org.apache.eventmesh.storage.rocketmq.patch.EventMeshConsumeConcurrentlyContext; import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; @@ -28,7 +30,6 @@ import org.apache.rocketmq.client.log.ClientLogger; import org.apache.rocketmq.client.stat.ConsumerStatsManager; import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; @@ -41,9 +42,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; @@ -53,6 +53,7 @@ import java.util.concurrent.TimeUnit; public class ConsumeMessageConcurrentlyService implements ConsumeMessageService { + private static final InternalLogger log = ClientLogger.getLog(); private final DefaultMQPushConsumerImpl defaultMQPushConsumerImpl; private final DefaultMQPushConsumer defaultMQPushConsumer; @@ -69,48 +70,45 @@ public class ConsumeMessageConcurrentlyService implements ConsumeMessageService private final ScheduledExecutorService cleanExpireMsgExecutors; public ConsumeMessageConcurrentlyService(DefaultMQPushConsumerImpl defaultMQPushConsumerImpl, - MessageListenerConcurrently messageListener) { + MessageListenerConcurrently messageListener) { this.defaultMQPushConsumerImpl = defaultMQPushConsumerImpl; this.messageListener = messageListener; this.defaultMQPushConsumer = this.defaultMQPushConsumerImpl.getDefaultMQPushConsumer(); this.consumerGroup = this.defaultMQPushConsumer.getConsumerGroup(); - this.consumeRequestQueue = new LinkedBlockingQueue(); + this.consumeRequestQueue = new LinkedBlockingQueue<>(); this.consumeExecutor = new ThreadPoolExecutor( - this.defaultMQPushConsumer.getConsumeThreadMin(), - this.defaultMQPushConsumer.getConsumeThreadMax(), - 1000 * 60, - TimeUnit.MILLISECONDS, - this.consumeRequestQueue, - new ThreadFactoryImpl("ConsumeMessageThread_" + consumerGroup + "_")); + this.defaultMQPushConsumer.getConsumeThreadMin(), + this.defaultMQPushConsumer.getConsumeThreadMax(), + 1000 * 60, + TimeUnit.MILLISECONDS, + this.consumeRequestQueue, + new EventMeshThreadFactory("ConsumeMessageThread_" + consumerGroup + "_")); - this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("ConsumeMessageScheduledThread_")); - this.cleanExpireMsgExecutors = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("CleanExpireMsgScheduledThread_")); + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new EventMeshThreadFactory("ConsumeMessageScheduledThread_")); + this.cleanExpireMsgExecutors = Executors.newSingleThreadScheduledExecutor(new EventMeshThreadFactory("CleanExpireMsgScheduledThread_")); log.info("new ConsumeMessageConcurrentlyService instance for eventMesh has been created "); } public void start() { if (this.defaultMQPushConsumer.getConsumeTimeout() > 0) { - this.cleanExpireMsgExecutors.scheduleAtFixedRate(new Runnable() { - - @Override - public void run() { - try { - cleanExpireMsg(); - } catch (Exception e) { - log.warn("cleanExpireMsg ", e); - } + this.cleanExpireMsgExecutors.scheduleAtFixedRate(() -> { + try { + cleanExpireMsg(); + } catch (Exception e) { + log.warn("cleanExpireMsg ", e); } - }, this.defaultMQPushConsumer.getConsumeTimeout(), this.defaultMQPushConsumer.getConsumeTimeout(), TimeUnit.MINUTES); } } @Override public void shutdown(long awaitTerminateMillis) { - + this.scheduledExecutorService.shutdown(); + org.apache.rocketmq.common.utils.ThreadUtils.shutdownGracefully(this.consumeExecutor, awaitTerminateMillis, TimeUnit.MILLISECONDS); + this.cleanExpireMsgExecutors.shutdown(); } public void shutdown() { @@ -126,17 +124,19 @@ public ThreadPoolExecutor getConsumeExecutor() { @Override public void updateCorePoolSize(int corePoolSize) { if (corePoolSize > 0 - && corePoolSize <= Short.MAX_VALUE - && corePoolSize < this.defaultMQPushConsumer.getConsumeThreadMax()) { + && corePoolSize <= Short.MAX_VALUE + && corePoolSize < this.defaultMQPushConsumer.getConsumeThreadMax()) { this.consumeExecutor.setCorePoolSize(corePoolSize); } } @Override - public void incCorePoolSize() { } + public void incCorePoolSize() { + } @Override - public void decCorePoolSize() { } + public void decCorePoolSize() { + } @Override public int getCorePoolSize() { @@ -185,10 +185,10 @@ public ConsumeMessageDirectlyResult consumeMessageDirectly(MessageExt msg, Strin result.setRemark(RemotingHelper.exceptionSimpleDesc(e)); log.warn(String.format("consumeMessageDirectly exception: %s Group: %s Msgs: %s MQ: %s", - RemotingHelper.exceptionSimpleDesc(e), - ConsumeMessageConcurrentlyService.this.consumerGroup, - msgs, - mq), e); + RemotingHelper.exceptionSimpleDesc(e), + ConsumeMessageConcurrentlyService.this.consumerGroup, + msgs, + mq), e); } result.setSpentTimeMills(System.currentTimeMillis() - beginTime); @@ -200,10 +200,10 @@ public ConsumeMessageDirectlyResult consumeMessageDirectly(MessageExt msg, Strin @Override public void submitConsumeRequest( - final List msgs, - final ProcessQueue processQueue, - final MessageQueue messageQueue, - final boolean dispatchToConsume) { + final List msgs, + final ProcessQueue processQueue, + final MessageQueue messageQueue, + final boolean dispatchToConsume) { final int consumeBatchSize = this.defaultMQPushConsumer.getConsumeMessageBatchMaxSize(); if (msgs.size() <= consumeBatchSize) { ConsumeRequest consumeRequest = new ConsumeRequest(msgs, processQueue, messageQueue); @@ -213,8 +213,8 @@ public void submitConsumeRequest( this.submitConsumeRequestLater(consumeRequest); } } else { - for (int total = 0; total < msgs.size(); ) { - List msgThis = new ArrayList(consumeBatchSize); + for (int total = 0; total < msgs.size();) { + List msgThis = new ArrayList<>(consumeBatchSize); for (int i = 0; i < consumeBatchSize; i++, total++) { if (total < msgs.size()) { msgThis.add(msgs.get(total)); @@ -248,19 +248,15 @@ public void resetRetryTopic(final List msgs) { } private void cleanExpireMsg() { - Iterator> it = - this.defaultMQPushConsumerImpl.getRebalanceImpl().getProcessQueueTable().entrySet().iterator(); - while (it.hasNext()) { - Map.Entry next = it.next(); - ProcessQueue pq = next.getValue(); + this.defaultMQPushConsumerImpl.getRebalanceImpl().getProcessQueueTable().forEach((k, pq) -> { pq.cleanExpiredMsg(this.defaultMQPushConsumer); - } + }); } public void processConsumeResult( - final ConsumeConcurrentlyStatus status, - final EventMeshConsumeConcurrentlyContext context, - final ConsumeRequest consumeRequest) { + final ConsumeConcurrentlyStatus status, + final EventMeshConsumeConcurrentlyContext context, + final ConsumeRequest consumeRequest) { int ackIndex = context.getAckIndex(); if (consumeRequest.getMsgs().isEmpty()) { @@ -280,7 +276,7 @@ public void processConsumeResult( case RECONSUME_LATER: ackIndex = -1; this.getConsumerStatsManager().incConsumeFailedTPS(consumerGroup, consumeRequest.getMessageQueue().getTopic(), - consumeRequest.getMsgs().size()); + consumeRequest.getMsgs().size()); break; default: break; @@ -331,7 +327,6 @@ public void updateOffset(List msgs, ConsumeConcurrentlyContext conte } } - public ConsumerStatsManager getConsumerStatsManager() { return this.defaultMQPushConsumerImpl.getConsumerStatsManager(); } @@ -343,61 +338,48 @@ public boolean sendMessageBack(final MessageExt msg, final ConsumeConcurrentlyCo this.defaultMQPushConsumerImpl.sendMessageBack(msg, delayLevel, context.getMessageQueue().getBrokerName()); return true; } catch (Exception e) { - log.error("sendMessageBack exception, group: " + this.consumerGroup + " msg: " + msg.toString(), e); + log.error("sendMessageBack exception, group: {}" + " msg: {}", this.consumerGroup, msg, e); } return false; } private void submitConsumeRequestLater( - final List msgs, - final ProcessQueue processQueue, - final MessageQueue messageQueue - ) { - - this.scheduledExecutorService.schedule(new Runnable() { + final List msgs, + final ProcessQueue processQueue, + final MessageQueue messageQueue) { - @Override - public void run() { - ConsumeMessageConcurrentlyService.this.submitConsumeRequest(msgs, processQueue, messageQueue, true); - } - }, 5000, TimeUnit.MILLISECONDS); + this.scheduledExecutorService.schedule( + () -> ConsumeMessageConcurrentlyService.this.submitConsumeRequest(msgs, processQueue, messageQueue, true), 5000, TimeUnit.MILLISECONDS); } private void submitConsumeRequestLater(final ConsumeRequest consumeRequest) { final int times = defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getMaxReconsumeTimes(); log.warn("rejected by thread pool, try resubmit {} times, consumerGroup:{}", times, - defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getConsumerGroup()); - this.scheduledExecutorService.schedule(new Runnable() { - - @Override - public void run() { - boolean success = false; - for (int i = 0; i < times; i++) { - try { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - //ignore - } - ConsumeMessageConcurrentlyService.this.consumeExecutor.submit(consumeRequest); - success = true; - break; - } catch (RejectedExecutionException e) { - //ignore - } + defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getConsumerGroup()); + this.scheduledExecutorService.schedule(() -> { + boolean success = false; + for (int i = 0; i < times; i++) { + try { + ThreadUtils.sleep(1, TimeUnit.SECONDS); + ConsumeMessageConcurrentlyService.this.consumeExecutor.submit(consumeRequest); + success = true; + break; + } catch (RejectedExecutionException e) { + // ignore } - if (!success) { - for (MessageExt messageExt : consumeRequest.getMsgs()) { - log.warn("discard rejected messages {} after retry {} times", messageExt, times); - } - consumeRequest.getProcessQueue().removeMessage(consumeRequest.getMsgs()); + } + if (!success) { + for (MessageExt messageExt : consumeRequest.getMsgs()) { + log.warn("discard rejected messages {} after retry {} times", messageExt, times); } + consumeRequest.getProcessQueue().removeMessage(consumeRequest.getMsgs()); } }, 1000, TimeUnit.MILLISECONDS); } class ConsumeRequest implements Runnable { + private final List msgs; private final ProcessQueue processQueue; private final MessageQueue messageQueue; @@ -420,11 +402,10 @@ public ProcessQueue getProcessQueue() { public void run() { if (this.processQueue.isDropped()) { log.info("the message queue not be able to consume, because it's dropped. group={} {}", - ConsumeMessageConcurrentlyService.this.consumerGroup, this.messageQueue); + ConsumeMessageConcurrentlyService.this.consumerGroup, this.messageQueue); return; } - MessageListenerConcurrently listener = ConsumeMessageConcurrentlyService.this.messageListener; EventMeshConsumeConcurrentlyContext context = new EventMeshConsumeConcurrentlyContext(messageQueue, processQueue); ConsumeConcurrentlyStatus status = null; @@ -432,7 +413,7 @@ public void run() { if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { consumeMessageContext = new ConsumeMessageContext(); consumeMessageContext.setConsumerGroup(defaultMQPushConsumer.getConsumerGroup()); - consumeMessageContext.setProps(new HashMap()); + consumeMessageContext.setProps(new HashMap<>()); consumeMessageContext.setMq(messageQueue); consumeMessageContext.setMsgList(msgs); consumeMessageContext.setSuccess(false); @@ -444,24 +425,23 @@ public void run() { ConsumeReturnType returnType = ConsumeReturnType.SUCCESS; try { ConsumeMessageConcurrentlyService.this.resetRetryTopic(msgs); - if (msgs != null && !msgs.isEmpty()) { + if (!msgs.isEmpty()) { for (MessageExt msg : msgs) { MessageAccessor.setConsumeStartTimeStamp(msg, String.valueOf(System.currentTimeMillis())); } - } - status = listener.consumeMessage(Collections.unmodifiableList(msgs), context); + status = ConsumeMessageConcurrentlyService.this.messageListener.consumeMessage(Collections.unmodifiableList(msgs), context); } catch (Throwable e) { log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}", - RemotingHelper.exceptionSimpleDesc(e), - ConsumeMessageConcurrentlyService.this.consumerGroup, - msgs, - messageQueue); + RemotingHelper.exceptionSimpleDesc(e), + ConsumeMessageConcurrentlyService.this.consumerGroup, + msgs, + messageQueue); hasException = true; } long consumeRT = System.currentTimeMillis() - beginTimestamp; - if (null == status) { + if (status == null) { if (hasException) { returnType = ConsumeReturnType.EXCEPTION; } else { @@ -471,30 +451,28 @@ public void run() { returnType = ConsumeReturnType.TIME_OUT; } else if (ConsumeConcurrentlyStatus.RECONSUME_LATER == status) { returnType = ConsumeReturnType.FAILED; - } else if (ConsumeConcurrentlyStatus.CONSUME_SUCCESS == status) { - returnType = ConsumeReturnType.SUCCESS; } if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { - consumeMessageContext.getProps().put(MixAll.CONSUME_CONTEXT_TYPE, returnType.name()); + Objects.requireNonNull(consumeMessageContext).getProps().put(MixAll.CONSUME_CONTEXT_TYPE, returnType.name()); } - if (null == status) { + if (status == null) { log.warn("consumeMessage return null, Group: {} Msgs: {} MQ: {}", - ConsumeMessageConcurrentlyService.this.consumerGroup, - msgs, - messageQueue); + ConsumeMessageConcurrentlyService.this.consumerGroup, + msgs, + messageQueue); status = ConsumeConcurrentlyStatus.RECONSUME_LATER; } if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { - consumeMessageContext.setStatus(status.toString()); + Objects.requireNonNull(consumeMessageContext).setStatus(status.toString()); consumeMessageContext.setSuccess(ConsumeConcurrentlyStatus.CONSUME_SUCCESS == status); ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.executeHookAfter(consumeMessageContext); } ConsumeMessageConcurrentlyService.this.getConsumerStatsManager() - .incConsumeRT(ConsumeMessageConcurrentlyService.this.consumerGroup, messageQueue.getTopic(), consumeRT); + .incConsumeRT(ConsumeMessageConcurrentlyService.this.consumerGroup, messageQueue.getTopic(), consumeRT); ConsumeMessageConcurrentlyService.this.processConsumeResult(status, context, this); } @@ -504,4 +482,4 @@ public MessageQueue getMessageQueue() { } } -} \ No newline at end of file +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.TopicNameHelper b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.TopicNameHelper new file mode 100644 index 0000000000..4670fbc91f --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.TopicNameHelper @@ -0,0 +1,16 @@ +# 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. + +rocketmq=org.apache.eventmesh.storage.rocketmq.common.TopicNameHelperImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin new file mode 100644 index 0000000000..ddb8c045dc --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin @@ -0,0 +1,16 @@ +# 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. + +rocketmq=org.apache.eventmesh.storage.rocketmq.admin.RocketMQAdminAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer new file mode 100644 index 0000000000..36ef49344b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer @@ -0,0 +1,16 @@ +# 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. + +rocketmq=org.apache.eventmesh.storage.rocketmq.consumer.RocketMQConsumerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer new file mode 100644 index 0000000000..1e21f03208 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer @@ -0,0 +1,16 @@ +# 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. + +rocketmq=org.apache.eventmesh.storage.rocketmq.producer.RocketMQProducerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService new file mode 100644 index 0000000000..d3d41f2e57 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService @@ -0,0 +1,16 @@ +# 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. + +rocketmq=org.apache.eventmesh.storage.rocketmq.storage.StorageResourceServiceRocketmqImpl \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/rocketmq-client.properties b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/rocketmq-client.properties similarity index 100% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/main/resources/rocketmq-client.properties rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/main/resources/rocketmq-client.properties diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/cloudevent/RocketMQMessageFactoryTest.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/cloudevent/RocketMQMessageFactoryTest.java new file mode 100644 index 0000000000..4ecfdcfd6c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/cloudevent/RocketMQMessageFactoryTest.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.cloudevent; + +import org.apache.eventmesh.storage.rocketmq.cloudevent.impl.RocketMQHeaders; + +import org.apache.rocketmq.common.message.Message; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.SpecVersion; + +public class RocketMQMessageFactoryTest { + + private Message message; + + @BeforeEach + public void setUp() { + message = new Message(); + message.putUserProperty(RocketMQHeaders.SPEC_VERSION, SpecVersion.V03.toString()); + message.setBody("BODY".getBytes()); + } + + @Test + public void testCreateReader() { + Assertions.assertNotNull(RocketMQMessageFactory.createReader(message)); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfigurationTest.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfigurationTest.java new file mode 100644 index 0000000000..3ec41e1419 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/config/ClientConfigurationTest.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.config; + +import org.apache.eventmesh.api.factory.StoragePluginFactory; +import org.apache.eventmesh.storage.rocketmq.consumer.RocketMQConsumerImpl; +import org.apache.eventmesh.storage.rocketmq.producer.RocketMQProducerImpl; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ClientConfigurationTest { + + @Test + public void getConfigWhenRocketMQConsumerInit() { + RocketMQConsumerImpl consumer = (RocketMQConsumerImpl) StoragePluginFactory.getMeshMQPushConsumer("rocketmq"); + + ClientConfiguration config = consumer.getClientConfiguration(); + assertConfig(config); + } + + @Test + public void getConfigWhenRocketMQProducerInit() { + RocketMQProducerImpl producer = (RocketMQProducerImpl) StoragePluginFactory.getMeshMQProducer("rocketmq"); + + ClientConfiguration config = producer.getClientConfiguration(); + assertConfig(config); + } + + private void assertConfig(ClientConfiguration config) { + Assertions.assertEquals("127.0.0.1:9876;127.0.0.1:9876", config.getNamesrvAddr()); + Assertions.assertEquals("username-succeed!!!", config.getClientUserName()); + Assertions.assertEquals("password-succeed!!!", config.getClientPass()); + Assertions.assertEquals(Integer.valueOf(1816), config.getConsumeThreadMin()); + Assertions.assertEquals(Integer.valueOf(2816), config.getConsumeThreadMax()); + Assertions.assertEquals(Integer.valueOf(3816), config.getConsumeQueueSize()); + Assertions.assertEquals(Integer.valueOf(4816), config.getPullBatchSize()); + Assertions.assertEquals(Integer.valueOf(5816), config.getAckWindow()); + Assertions.assertEquals(Integer.valueOf(6816), config.getPubWindow()); + Assertions.assertEquals(7816, config.getConsumeTimeout()); + Assertions.assertEquals(Integer.valueOf(8816), config.getPollNameServerInterval()); + Assertions.assertEquals(Integer.valueOf(9816), config.getHeartbeatBrokerInterval()); + Assertions.assertEquals(Integer.valueOf(11816), config.getRebalanceInterval()); + Assertions.assertEquals("cluster-succeed!!!", config.getClusterName()); + Assertions.assertEquals("accessKey-succeed!!!", config.getAccessKey()); + Assertions.assertEquals("secretKey-succeed!!!", config.getSecretKey()); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/consumer/PushConsumerImplTest.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/consumer/PushConsumerImplTest.java new file mode 100644 index 0000000000..19e40f2c00 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/consumer/PushConsumerImplTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.consumer; + +import org.apache.eventmesh.storage.rocketmq.domain.NonStandardKeys; + +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.common.message.MessageExt; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Properties; + +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 org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class PushConsumerImplTest { + + private PushConsumerImpl consumer; + + @Mock + private DefaultMQPushConsumer rocketmqPushConsumer; + + @BeforeEach + public void before() throws Exception { + Properties consumerProp = new Properties(); + // consumerProp.setProperty(OMSBuiltinKeys.DRIVER_IMPL, + // "org.apache.eventmesh.connector.rocketmq.MessagingAccessPointImpl"); + consumerProp.setProperty("access_points", "IP1:9876,IP2:9876"); + // final MessagingAccessPoint messagingAccessPoint = OMS.builder().build(consumerProp); + // .endpoint("oms:rocketmq://IP1:9876,IP2:9876/namespace").build(config); + + consumerProp.setProperty("message.model", "CLUSTERING"); + + // Properties consumerProp = new Properties(); + consumerProp.put("CONSUMER_ID", "TestGroup"); + consumer = new PushConsumerImpl(consumerProp); + + Field field = PushConsumerImpl.class.getDeclaredField("rocketmqPushConsumer"); + field.setAccessible(true); + DefaultMQPushConsumer innerConsumer = (DefaultMQPushConsumer) field.get(consumer); + field.set(consumer, rocketmqPushConsumer); // Replace + + Mockito.when(rocketmqPushConsumer.getMessageListener()).thenReturn(innerConsumer.getMessageListener()); + consumer.start(); + } + + @AfterEach + public void after() throws Exception { + Mockito.verify(rocketmqPushConsumer).getMessageListener(); + consumer.shutdown(); + } + + @Test + public void testConsumeMessage() { + final byte[] testBody = new byte[]{'a', 'b'}; + + MessageExt consumedMsg = new MessageExt(); + consumedMsg.setMsgId("NewMsgId"); + consumedMsg.setBody(testBody); + consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC"); + consumedMsg.setTopic("HELLO_QUEUE"); + consumer.subscribe("HELLO_QUEUE", "*"); + ((MessageListenerConcurrently) rocketmqPushConsumer + .getMessageListener()).consumeMessage(Collections.singletonList(consumedMsg), null); + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/producer/DefaultProducerImplTest.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/producer/DefaultProducerImplTest.java new file mode 100644 index 0000000000..8c93906d43 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/producer/DefaultProducerImplTest.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.producer; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +public class DefaultProducerImplTest { + + @BeforeEach + public void before() { + } + + @AfterEach + public void after() { + // TBD:Remove topic + } + + /** + * @Test + * public void testCreate_EmptyTopic() { + * MeshMQProducer meshPub = new RocketMQProducerImpl(); + * try { + * meshPub.createTopic(" "); + * catch (OMSRuntimeException e) { + * assertThat(e.getMessage()).isEqualToIgnoringWhitespace("RocketMQ can not create topic"); + * } + * } + * + * @Test + * public void testCreate_NullTopic() { + * MeshMQProducer meshPub = new RocketMQProducerImpl(); + * try { + * meshPub.createTopic(null); + * } catch (OMSRuntimeException e) { + * String errorMessage = e.getMessage(); + * assertThat(errorMessage).isEqualTo("RocketMQ can not create topic null"); + * } + * } + */ +} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/producer/ProducerImplTest.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/producer/ProducerImplTest.java similarity index 80% rename from eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/producer/ProducerImplTest.java rename to eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/producer/ProducerImplTest.java index d144bd2c4c..5d7d01b955 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/src/test/java/org/apache/rocketmq/producer/ProducerImplTest.java +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/producer/ProducerImplTest.java @@ -15,15 +15,13 @@ * limitations under the License. */ -package org.apache.rocketmq.producer; +package org.apache.eventmesh.storage.rocketmq.producer; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown; import static org.mockito.ArgumentMatchers.any; -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; -import org.apache.eventmesh.connector.rocketmq.producer.AbstractProducer; -import org.apache.eventmesh.connector.rocketmq.producer.ProducerImpl; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.common.Constants; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; @@ -40,25 +38,27 @@ import java.net.URI; import java.util.Properties; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +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 org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class ProducerImplTest { + private ProducerImpl producer; @Mock private DefaultMQProducer rocketmqProducer; - @Before + @BeforeEach public void before() throws NoSuchFieldException, IllegalAccessException { Properties config = new Properties(); config.setProperty("access_points", "IP1:9876,IP2:9876"); @@ -72,7 +72,7 @@ public void before() throws NoSuchFieldException, IllegalAccessException { } - @After + @AfterEach public void after() { producer.shutdown(); } @@ -92,16 +92,15 @@ public void testSend_OK() throws InterruptedException, RemotingException, MQClie defaultMQProducerImpl.setServiceState(ServiceState.RUNNING); Mockito.when(rocketmqProducer.getDefaultMQProducerImpl()).thenReturn(defaultMQProducerImpl); - CloudEvent cloudEvent = CloudEventBuilder.v1() - .withId("id1") - .withSource(URI.create("https://github.com/cloudevents/*****")) - .withType("producer.example") - .withSubject("HELLO_TOPIC") - .withData("hello world".getBytes()) - .build(); + .withId("id1") + .withSource(URI.create("https://github.com/cloudevents/*****")) + .withType("producer.example") + .withSubject("HELLO_TOPIC") + .withData("hello world".getBytes(Constants.DEFAULT_CHARSET)) + .build(); org.apache.eventmesh.api.SendResult result = - producer.send(cloudEvent); + producer.send(cloudEvent); assertThat(result.getMessageId()).isEqualTo("TestMsgID"); Mockito.verify(rocketmqProducer).getDefaultMQProducerImpl(); @@ -118,21 +117,19 @@ public void testSend_WithException() throws InterruptedException, RemotingExcept MQClientException exception = new MQClientException("Send message to RocketMQ broker failed.", new Exception()); Mockito.when(rocketmqProducer.send(any(Message.class))).thenThrow(exception); - try { + StorageRuntimeException e = Assertions.assertThrows(StorageRuntimeException.class, () -> { CloudEvent cloudEvent = CloudEventBuilder.v1() - .withId("id1") - .withSource(URI.create("https://github.com/cloudevents/*****")) - .withType("producer.example") - .withSubject("HELLO_TOPIC") - .withData(new byte[]{'a'}) - .build(); + .withId("id1") + .withSource(URI.create("https://github.com/cloudevents/*****")) + .withType("producer.example") + .withSubject("HELLO_TOPIC") + .withData(new byte[]{'a'}) + .build(); producer.send(cloudEvent); - failBecauseExceptionWasNotThrown(ConnectorRuntimeException.class); - } catch (Exception e) { - assertThat(e).hasMessageContaining("Send message to RocketMQ broker failed."); - } + }); + assertThat(e).hasMessageContaining("Send message to RocketMQ broker failed."); Mockito.verify(rocketmqProducer).send(any(Message.class)); } -} \ No newline at end of file +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/utils/BeanUtilsTest.java b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/utils/BeanUtilsTest.java new file mode 100644 index 0000000000..e949086ec4 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/java/org/apache/eventmesh/storage/rocketmq/utils/BeanUtilsTest.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.rocketmq.utils; + +import org.apache.eventmesh.storage.rocketmq.config.ClientConfig; +import org.apache.eventmesh.storage.rocketmq.domain.NonStandardKeys; + +import java.util.Properties; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BeanUtilsTest { + + private final Properties properties = new Properties(); + + public static class CustomizedConfig extends ClientConfig { + + static final String STRING_TEST = "string.test"; + String stringTest = "foobar"; + + static final String DOUBLE_TEST = "double.test"; + double doubleTest = 123.0; + + static final String LONG_TEST = "long.test"; + long longTest = 123L; + + String getStringTest() { + return stringTest; + } + + public void setStringTest(String stringTest) { + this.stringTest = stringTest; + } + + double getDoubleTest() { + return doubleTest; + } + + public void setDoubleTest(final double doubleTest) { + this.doubleTest = doubleTest; + } + + long getLongTest() { + return longTest; + } + + public void setLongTest(final long longTest) { + this.longTest = longTest; + } + + public CustomizedConfig() { + } + } + + @BeforeEach + public void before() { + properties.put(NonStandardKeys.MAX_REDELIVERY_TIMES, 120); + properties.put(CustomizedConfig.STRING_TEST, "kaka"); + properties.put(NonStandardKeys.CONSUMER_GROUP, "Default_Consumer_Group"); + properties.put(NonStandardKeys.MESSAGE_CONSUME_TIMEOUT, 101); + + properties.put(CustomizedConfig.LONG_TEST, 1234567890L); + properties.put(CustomizedConfig.DOUBLE_TEST, 10.234); + } + + @Test + public void testPopulate() { + CustomizedConfig config = BeanUtils.populate(properties, CustomizedConfig.class); + + Assertions.assertEquals(120, config.getRmqMaxRedeliveryTimes()); + Assertions.assertEquals("kaka", config.getStringTest()); + Assertions.assertEquals("Default_Consumer_Group", config.getRmqConsumerGroup()); + Assertions.assertEquals(101, config.getRmqMessageConsumeTimeout()); + Assertions.assertEquals(1234567890L, config.getLongTest()); + Assertions.assertEquals(10.234, config.getDoubleTest(), 0.000001); + } + + @Test + public void testPopulate_ExistObj() { + CustomizedConfig config = new CustomizedConfig(); + config.setConsumerId("NewConsumerId"); + + Assertions.assertEquals("NewConsumerId", config.getConsumerId()); + + BeanUtils.populate(properties, config); + + Assertions.assertEquals(120, config.getRmqMaxRedeliveryTimes()); + Assertions.assertEquals("kaka", config.getStringTest()); + Assertions.assertEquals("Default_Consumer_Group", config.getRmqConsumerGroup()); + Assertions.assertEquals(101, config.getRmqMessageConsumeTimeout()); + Assertions.assertEquals(1234567890L, config.getLongTest()); + Assertions.assertEquals(10.234, config.getDoubleTest(), 0.000001); + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer new file mode 100644 index 0000000000..3041042c69 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/resources/META-INF/services/org.apache.io.openmessaging.producer.Producer @@ -0,0 +1,19 @@ +# +# 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. +# + + +ProducerImpl \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/resources/rocketmq-client.properties b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/resources/rocketmq-client.properties new file mode 100644 index 0000000000..e9e78992d0 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-rocketmq/src/test/resources/rocketmq-client.properties @@ -0,0 +1,33 @@ +# +# 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. +# +#######################rocketmq-client################## +eventMesh.server.rocketmq.namesrvAddr=127.0.0.1:9876;127.0.0.1:9876 +eventMesh.server.rocketmq.username=username-succeed!!! +eventMesh.server.rocketmq.password=password-succeed!!! +eventMesh.server.rocketmq.client.consumeThreadMin=1816 +eventMesh.server.rocketmq.client.consumeThreadMax=2816 +eventMesh.server.rocketmq.client.consumeThreadPoolQueueSize=3816 +eventMesh.server.rocketmq.client.pullBatchSize=4816 +eventMesh.server.rocketmq.client.ackwindow=5816 +eventMesh.server.rocketmq.client.pubwindow=6816 +eventMesh.server.rocketmq.client.comsumeTimeoutInMin=7816 +eventMesh.server.rocketmq.client.pollNameServerInterval=8816 +eventMesh.server.rocketmq.client.heartbeatBrokerInterval=9816 +eventMesh.server.rocketmq.client.rebalanceInterval=11816 +eventMesh.server.rocketmq.cluster=cluster-succeed!!! +eventMesh.server.rocketmq.accessKey=accessKey-succeed!!! +eventMesh.server.rocketmq.secretKey=secretKey-succeed!!! \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/build.gradle b/eventmesh-storage-plugin/eventmesh-storage-standalone/build.gradle new file mode 100644 index 0000000000..22271fb57d --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/build.gradle @@ -0,0 +1,28 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-common") + implementation project(":eventmesh-storage-plugin:eventmesh-storage-api") + implementation "com.lmax:disruptor" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation "org.mockito:mockito-inline" + testImplementation "org.mockito:mockito-junit-jupiter" +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/gradle.properties b/eventmesh-storage-plugin/eventmesh-storage-standalone/gradle.properties new file mode 100644 index 0000000000..629866f3bf --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/gradle.properties @@ -0,0 +1,17 @@ +# 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. +# +pluginType=storage +pluginName=standalone \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdmin.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdmin.java new file mode 100644 index 0000000000..72257647ad --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdmin.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.admin; + +import org.apache.eventmesh.api.admin.AbstractAdmin; +import org.apache.eventmesh.api.admin.TopicProperties; +import org.apache.eventmesh.storage.standalone.broker.Channel; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +public class StandaloneAdmin extends AbstractAdmin { + + private final StandaloneBroker standaloneBroker; + + public StandaloneAdmin() { + super(new AtomicBoolean(false)); + this.standaloneBroker = StandaloneBroker.getInstance(); + } + + @Override + public List getTopic() throws Exception { + ConcurrentHashMap messageContainer = this.standaloneBroker.getMessageContainer(); + List topicList = new ArrayList<>(); + messageContainer.keySet().forEach(topicMetadata -> { + Channel channel = messageContainer.get(topicMetadata); + final int messageCount = channel.getMessageCount(); + topicList.add(new TopicProperties( + topicMetadata.getTopicName(), + messageCount)); + }); + topicList.sort(Comparator.comparing(t -> t.name)); + return topicList; + } + + @Override + public void createTopic(String topicName) { + standaloneBroker.createTopicIfAbsent(topicName); + } + + @Override + public void deleteTopic(String topicName) { + standaloneBroker.deleteTopicIfExist(topicName); + } + + + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + this.standaloneBroker.putMessage(cloudEvent.getSubject(), cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdminAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdminAdaptor.java new file mode 100644 index 0000000000..a68978663e --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdminAdaptor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.admin; + +import org.apache.eventmesh.api.admin.Admin; +import org.apache.eventmesh.api.admin.TopicProperties; + +import java.util.List; +import java.util.Properties; + +import io.cloudevents.CloudEvent; + +public class StandaloneAdminAdaptor implements Admin { + + private final StandaloneAdmin admin; + + public StandaloneAdminAdaptor() { + admin = new StandaloneAdmin(); + } + + @Override + public boolean isStarted() { + return admin.isStarted(); + } + + @Override + public boolean isClosed() { + return admin.isClosed(); + } + + @Override + public void start() { + admin.start(); + } + + @Override + public void shutdown() { + admin.shutdown(); + } + + @Override + public void init(Properties properties) throws Exception { + admin.init(properties); + } + + @Override + public List getTopic() throws Exception { + return admin.getTopic(); + } + + @Override + public void createTopic(String topicName) throws Exception { + admin.createTopic(topicName); + } + + @Override + public void deleteTopic(String topicName) throws Exception { + admin.deleteTopic(topicName); + } + + @Override + public List getEvent(String topicName, int offset, int length) throws Exception { + return admin.getEvent(topicName, offset, length); + } + + @Override + public void publish(CloudEvent cloudEvent) throws Exception { + admin.publish(cloudEvent); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/Channel.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/Channel.java new file mode 100644 index 0000000000..8de0ca1c54 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/Channel.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker; + +import org.apache.eventmesh.api.LifeCycle; +import org.apache.eventmesh.common.EventMeshThreadFactory; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; +import org.apache.eventmesh.storage.standalone.broker.provider.DisruptorProvider; + +import com.lmax.disruptor.BlockingWaitStrategy; +import com.lmax.disruptor.EventHandler; +import com.lmax.disruptor.IgnoreExceptionHandler; +import com.lmax.disruptor.RingBuffer; +import com.lmax.disruptor.dsl.Disruptor; +import com.lmax.disruptor.dsl.ProducerType; + +import lombok.Getter; +import lombok.Setter; + + +public class Channel implements LifeCycle { + + public static final Integer DEFAULT_SIZE = 4096 << 1 << 1; + @Getter + private DisruptorProvider provider; + private final Integer size; + @Setter + private EventHandler eventHandler; + private volatile boolean started = false; + private final TopicMetadata topic; + private static final String THREAD_NAME_PREFIX = "standalone_disruptor_provider_"; + + public Channel(TopicMetadata topic) { + this(DEFAULT_SIZE, topic, null); + } + + public Channel(TopicMetadata topic, EventHandler eventHandler) { + this(DEFAULT_SIZE, topic, eventHandler); + } + + + public Channel(final Integer ringBufferSize, final TopicMetadata topic, final EventHandler eventHandler) { + this.size = ringBufferSize; + this.topic = topic; + this.eventHandler = eventHandler; + } + + + @Override + public boolean isStarted() { + return started; + } + + @Override + public boolean isClosed() { + return !isStarted(); + } + + public synchronized void start() { + if (isClosed()) { + doStart(); + started = true; + } + } + + public void doStart() { + Disruptor disruptor = new Disruptor<>( + MessageEntity::new, + size, + new EventMeshThreadFactory(THREAD_NAME_PREFIX + topic.getTopicName(), true), + ProducerType.MULTI, + new BlockingWaitStrategy() + ); + + disruptor.handleEventsWith(eventHandler); + disruptor.setDefaultExceptionHandler(new IgnoreExceptionHandler()); + RingBuffer ringBuffer = disruptor.getRingBuffer(); + provider = new DisruptorProvider(ringBuffer, disruptor); + provider.start(); + } + + public int getMessageCount() { + return provider.getMessageCount(); + } + + @Override + public synchronized void shutdown() { + if (isStarted()) { + provider.shutdown(); + provider = null; + started = false; + } + } + +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/MessageQueue.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/MessageQueue.java new file mode 100644 index 0000000000..64b8fe4629 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/MessageQueue.java @@ -0,0 +1,255 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker; + +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import com.google.common.base.Preconditions; + +import lombok.Getter; + +/** + * This is a block queue, can get entity by offset. The queue is a FIFO data structure. + */ +public class MessageQueue { + + @Getter + private final MessageEntity[] items; + + private volatile int takeIndex; + + private volatile int putIndex; + + private volatile int count; + + private final ReentrantLock lock; + + private final Condition notEmpty; + + private final Condition notFull; + + public MessageQueue() { + this(2 << 10); + } + + public MessageQueue(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException("capacity is illegal"); + } + this.items = new MessageEntity[capacity]; + this.lock = new ReentrantLock(); + this.notEmpty = lock.newCondition(); + this.notFull = lock.newCondition(); + } + + /** + * Inserts the specified MessageEntity object into the queue. + * + * @param messageEntity The MessageEntity object to be inserted into the queue. + * @throws InterruptedException if the current thread is interrupted while waiting for space to become available in the queue. + */ + public void put(MessageEntity messageEntity) throws InterruptedException { + Preconditions.checkNotNull(messageEntity); + ReentrantLock reentrantLock = this.lock; + reentrantLock.lockInterruptibly(); + try { + while (count == items.length) { + notFull.await(); + } + enqueue(messageEntity); + } finally { + reentrantLock.unlock(); + } + } + + /** + * Get the first message at this queue, waiting for the message is available if the queue is empty, this method will not remove the message + * + * @return The MessageEntity object at the head of the queue. + * @throws InterruptedException if the current thread is interrupted while waiting for an element to become available in the queue. + */ + public MessageEntity take() throws InterruptedException { + ReentrantLock reentrantLock = this.lock; + reentrantLock.lockInterruptibly(); + try { + while (count == 0) { + notEmpty.await(); + } + return dequeue(); + } finally { + reentrantLock.unlock(); + } + } + + /** + * Get the first message at this queue, if the queue is empty return null immediately + * + * @return MessageEntity + */ + public MessageEntity peek() { + ReentrantLock reentrantLock = this.lock; + reentrantLock.lock(); + try { + return itemAt(takeIndex); + } finally { + reentrantLock.unlock(); + } + } + + /** + * Get the head in this queue + * + * @return MessageEntity + */ + public MessageEntity getHead() { + return peek(); + } + + /** + * Get the tail in this queue + * + * @return MessageEntity + */ + public MessageEntity getTail() { + ReentrantLock reentrantLock = this.lock; + reentrantLock.lock(); + try { + if (count == 0) { + return null; + } + int tailIndex = putIndex - 1; + if (tailIndex < 0) { + tailIndex += items.length; + } + return itemAt(tailIndex); + } finally { + reentrantLock.unlock(); + } + } + + /** + * Get the message by offset, since the offset is increment, so we can get the first message in this queue and calculate the index of this offset + * + * @param offset The offset of the MessageEntity object to be retrieved. + * @return The MessageEntity object with the specified offset, or null if no such object exists in the queue. + * @throws RuntimeException if the specified offset is less than the offset of the head MessageEntity object. + */ + public MessageEntity getByOffset(long offset) { + ReentrantLock reentrantLock = this.lock; + reentrantLock.lock(); + try { + if (count == 0) { + return null; + } + int tailIndex = putIndex - 1; + MessageEntity head = itemAt(takeIndex); + if (head.getOffset() > offset) { + throw new RuntimeException(String.format("The message has been deleted, offset: %s", offset)); + } + if (tailIndex < 0) { + tailIndex += items.length; + } + MessageEntity tail = itemAt(tailIndex); + if (tail == null || tail.getOffset() < offset) { + return null; + } + int offsetDis = (int) (head.getOffset() - offset); + int offsetIndex = takeIndex - offsetDis; + if (offsetIndex < 0) { + offsetIndex += items.length; + } + return itemAt(offsetIndex); + } finally { + reentrantLock.unlock(); + } + } + + /** + * Removes the MessageEntity object at the head of the queue. + */ + public void removeHead() { + ReentrantLock reentrantLock = this.lock; + reentrantLock.lock(); + try { + if (count == 0) { + return; + } + items[takeIndex++] = null; + if (takeIndex == items.length) { + takeIndex = 0; + } + notFull.signalAll(); + } finally { + reentrantLock.unlock(); + } + } + + public int getSize() { + return count; + } + + /** + * Returns the MessageEntity object at the specified index. + * + * @param index The index of the MessageEntity object to be returned. + * @return The MessageEntity object at the specified index. + */ + private MessageEntity itemAt(int index) { + return items[index]; + } + + /** + * Insert the message at the tail of this queue, waiting for space to become available if the queue is full + * + * @param messageEntity The MessageEntity object to be inserted into the queue. + */ + private void enqueue(MessageEntity messageEntity) { + items[putIndex++] = messageEntity; + if (putIndex == items.length) { + putIndex = 0; + } + count++; + notEmpty.signalAll(); + } + + /** + * Removes and returns the MessageEntity object at the head of the queue. + * + * @return The MessageEntity object at the head of the queue. + */ + private MessageEntity dequeue() { + final MessageEntity item = items[takeIndex++]; + if (takeIndex == items.length) { + takeIndex = 0; + } + count--; + notFull.signalAll(); + return item; + } + + public int getTakeIndex() { + return takeIndex; + } + + public int getPutIndex() { + return putIndex; + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/StandaloneBroker.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/StandaloneBroker.java new file mode 100644 index 0000000000..99cc30fff9 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/StandaloneBroker.java @@ -0,0 +1,157 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker; + +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import java.util.concurrent.ConcurrentHashMap; + +import io.cloudevents.CloudEvent; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * This broker used to store event, it just support standalone mode, you shouldn't use this module in production environment + */ +@Slf4j +public class StandaloneBroker { + + // message source by topic + @Getter + private final ConcurrentHashMap messageContainer; + + @Getter + private final ConcurrentHashMap subscribeContainer; + + private StandaloneBroker() { + this.messageContainer = new ConcurrentHashMap<>(); + this.subscribeContainer = new ConcurrentHashMap<>(); + } + + + public static StandaloneBroker getInstance() { + return StandaloneBrokerInstanceHolder.INSTANCE; + } + + /** + * put message + * + * @param topicName topic name + * @param message message + */ + public MessageEntity putMessage(String topicName, CloudEvent message) { + TopicMetadata topicMetadata = new TopicMetadata(topicName); + if (!messageContainer.containsKey(topicMetadata)) { + throw new RuntimeException(String.format("The topic:%s is not created", topicName)); + } + Channel channel = messageContainer.get(topicMetadata); + if (channel.isClosed()) { + throw new RuntimeException(String.format("The topic:%s is not subscribed", topicName)); + } + MessageEntity messageEntity = new MessageEntity(new TopicMetadata(topicName), message); + channel.getProvider().onData(messageEntity); + return messageEntity; + } + + public Channel createTopic(String topicName) { + TopicMetadata topicMetadata = new TopicMetadata(topicName); + return messageContainer.computeIfAbsent(topicMetadata, k -> new Channel(topicMetadata)); + } + + /** + * Get the message, if the queue is empty then await + * + * @param topicName + */ + public CloudEvent takeMessage(String topicName) throws InterruptedException { + return null; + } + + /** + * Get the message, if the queue is empty return null + * + * @param topicName + */ + public CloudEvent getMessage(String topicName) { + return null; + } + + /** + * Get the message by offset + * + * @param topicName topic name + * @param offset offset + * @return CloudEvent + */ + public CloudEvent getMessage(String topicName, long offset) { + return null; + } + + + public boolean checkTopicExist(String topicName) { + return messageContainer.containsKey(new TopicMetadata(topicName)); + } + + /** + * if the topic does not exist, create the topic + * + * @param topicName topicName + * @return Channel + */ + public Channel createTopicIfAbsent(String topicName) { + return createTopic(topicName); + } + + /** + * if the topic exists, delete the topic + * + * @param topicName topicName + */ + public void deleteTopicIfExist(String topicName) { + TopicMetadata topicMetadata = new TopicMetadata(topicName); + Channel channel = createTopicIfAbsent(topicName); + channel.shutdown(); + messageContainer.remove(topicMetadata); + subscribeContainer.remove(topicMetadata); + } + + public void subscribed(String topicName, Subscribe subscribe) { + TopicMetadata topicMetadata = new TopicMetadata(topicName); + if (subscribeContainer.containsKey(topicMetadata)) { + log.warn("the topic:{} already subscribed", topicName); + return; + } + Channel channel = getMessageContainer().get(topicMetadata); + if (channel == null) { + log.warn("the topic:{} is not created", topicName); + return; + } + channel.setEventHandler(subscribe); + channel.start(); + subscribeContainer.put(topicMetadata, subscribe); + } + + + private static class StandaloneBrokerInstanceHolder { + + private static final StandaloneBroker INSTANCE = new StandaloneBroker(); + } +} \ No newline at end of file diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/model/MessageEntity.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/model/MessageEntity.java similarity index 83% rename from eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/model/MessageEntity.java rename to eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/model/MessageEntity.java index 0225874b7c..3662b30255 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/model/MessageEntity.java +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/model/MessageEntity.java @@ -15,17 +15,22 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.standalone.broker.model; +package org.apache.eventmesh.storage.standalone.broker.model; import java.io.Serializable; import io.cloudevents.CloudEvent; +import lombok.NoArgsConstructor; + +@NoArgsConstructor public class MessageEntity implements Serializable { + private static final long serialVersionUID = 6646148767540524786L; + private TopicMetadata topicMetadata; - private CloudEvent message; + private transient CloudEvent message; private long offset; @@ -38,6 +43,11 @@ public MessageEntity(TopicMetadata topicMetadata, CloudEvent message, long offse this.createTimeMills = currentTimeMills; } + public MessageEntity(TopicMetadata topicMetadata, CloudEvent message) { + this.topicMetadata = topicMetadata; + this.message = message; + } + public TopicMetadata getTopicMetadata() { return topicMetadata; } diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/model/TopicMetadata.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/model/TopicMetadata.java similarity index 82% rename from eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/model/TopicMetadata.java rename to eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/model/TopicMetadata.java index 9b6c673e3a..fd8ed6c7bb 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/broker/model/TopicMetadata.java +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/model/TopicMetadata.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.standalone.broker.model; +package org.apache.eventmesh.storage.standalone.broker.model; import java.io.Serializable; import java.util.Objects; @@ -25,12 +25,17 @@ */ public class TopicMetadata implements Serializable { - private String topicName; + private static final long serialVersionUID = -9011507202771676415L; + + private final String topicName; public TopicMetadata(String topicName) { this.topicName = topicName; } + public String getTopicName() { + return this.topicName; + } @Override public boolean equals(Object o) { @@ -52,9 +57,9 @@ public int hashCode() { @Override public String toString() { return "TopicMetadata{" - + - "topic='" + topicName + '\'' - + - '}'; + + + "topic='" + topicName + '\'' + + + '}'; } } diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/provider/DisruptorProvider.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/provider/DisruptorProvider.java new file mode 100644 index 0000000000..47b2665a2c --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/provider/DisruptorProvider.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker.provider; + +import org.apache.eventmesh.api.LifeCycle; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; + +import com.lmax.disruptor.EventTranslatorOneArg; +import com.lmax.disruptor.RingBuffer; +import com.lmax.disruptor.dsl.Disruptor; + +import lombok.extern.slf4j.Slf4j; + +/** + * DisruptorProvider. disruptor provider definition. + */ +@Slf4j +public class DisruptorProvider implements LifeCycle { + + private final RingBuffer ringBuffer; + + private final Disruptor disruptor; + + private volatile boolean start = false; + + private final EventTranslatorOneArg translatorOneArg = (messageEntity, sequence, arg0) -> { + arg0.setOffset(sequence); + arg0.setCreateTimeMills(System.currentTimeMillis()); + messageEntity.setOffset(arg0.getOffset()); + messageEntity.setCreateTimeMills(arg0.getCreateTimeMills()); + messageEntity.setTopicMetadata(arg0.getTopicMetadata()); + messageEntity.setMessage(arg0.getMessage()); + }; + + + /** + * Instantiates a new Disruptor provider. + * + * @param ringBuffer the ring buffer + * @param disruptor the disruptor + */ + public DisruptorProvider(final RingBuffer ringBuffer, final Disruptor disruptor) { + this.ringBuffer = ringBuffer; + this.disruptor = disruptor; + } + + /** + * @param data the data + */ + public MessageEntity onData(final MessageEntity data) { + if (isClosed()) { + throw new IllegalArgumentException("the disruptor is close"); + } + try { + ringBuffer.publishEvent(translatorOneArg, data); + } catch (Exception ex) { + throw new IllegalStateException("send data fail."); + } + return data; + } + + + @Override + public boolean isStarted() { + return start; + } + + @Override + public boolean isClosed() { + return !isStarted(); + } + + @Override + public void start() { + if (null != disruptor) { + disruptor.start(); + start = true; + } + } + + /** + * Shutdown. + */ + public void shutdown() { + if (null != disruptor) { + disruptor.shutdown(); + start = false; + } + } + + public int getMessageCount() { + return ringBuffer.getBufferSize(); + } +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClear.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClear.java new file mode 100644 index 0000000000..ca43729853 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClear.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker.task; + +import org.apache.eventmesh.storage.standalone.broker.MessageQueue; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; + +import java.util.concurrent.ConcurrentHashMap; + +import lombok.extern.slf4j.Slf4j; + +/** + * This task used to clear the history message, the element in message queue can only be cleaned by this task. + */ +@Slf4j +public class HistoryMessageClear { + + private final ConcurrentHashMap messageContainer; + + /** + * If the currentTimeMills - messageCreateTimeMills >= MESSAGE_STORE_WINDOW, then the message will be clear + */ + private static final long MESSAGE_STORE_WINDOW = 60 * 60 * 1000; + + public HistoryMessageClear(ConcurrentHashMap messageContainer) { + this.messageContainer = messageContainer; + } + + public void clearMessages() { + messageContainer.forEach((topicMetadata, messageQueue) -> { + long currentTimeMillis = System.currentTimeMillis(); + MessageEntity oldestMessage = messageQueue.getHead(); + if (oldestMessage == null) { + return; + } + if (currentTimeMillis - oldestMessage.getCreateTimeMills() >= MESSAGE_STORE_WINDOW) { + messageQueue.removeHead(); + } + }); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClearTask.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClearTask.java new file mode 100644 index 0000000000..6dbcd33680 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClearTask.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker.task; + +import org.apache.eventmesh.common.utils.ThreadUtils; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HistoryMessageClearTask implements Runnable { + + private HistoryMessageClear historyMessageClear; + + public HistoryMessageClearTask(HistoryMessageClear historyMessageClear) { + this.historyMessageClear = historyMessageClear; + } + + @Override + public void run() { + while (true) { + historyMessageClear.clearMessages(); + try { + ThreadUtils.sleepWithThrowException(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + log.error("Thread is interrupted, thread name: {}", Thread.currentThread().getName(), e); + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/Subscribe.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/Subscribe.java new file mode 100644 index 0000000000..4c84849ac7 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/broker/task/Subscribe.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker.task; + +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.EventMeshAction; +import org.apache.eventmesh.api.EventMeshAsyncConsumeContext; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; + + +import io.cloudevents.CloudEvent; + +import com.lmax.disruptor.EventHandler; +import com.lmax.disruptor.WorkHandler; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Subscribe implements WorkHandler, EventHandler { + + @Getter + private final String topicName; + private final StandaloneBroker standaloneBroker; + private final EventListener listener; + @Getter + private volatile boolean isRunning; + + public Subscribe(String topicName, + StandaloneBroker standaloneBroker, + EventListener listener) { + this.topicName = topicName; + this.standaloneBroker = standaloneBroker; + this.listener = listener; + this.isRunning = true; + } + + public void subscribe() { + standaloneBroker.subscribed(topicName, this); + } + + public void shutdown() { + isRunning = false; + standaloneBroker.deleteTopicIfExist(topicName); + } + + @Override + public void onEvent(MessageEntity event, long sequence, boolean endOfBatch) { + onEvent(event); + } + + @Override + public void onEvent(MessageEntity event) { + try { + if (!isRunning) { + return; + } + CloudEvent message = event.getMessage(); + if (message != null) { + EventMeshAsyncConsumeContext consumeContext = new EventMeshAsyncConsumeContext() { + + @Override + public void commit(EventMeshAction action) { + switch (action) { + case CommitMessage: + // update offset + log.info("message commit, topic: {}, current offset:{}", topicName, event.getOffset()); + break; + case ManualAck: + // update offset + log.info("message ack, topic: {}, current offset:{}", topicName, event.getOffset()); + break; + case ReconsumeLater: + default: + } + } + }; + listener.consume(message, consumeContext); + } + } catch (Exception ex) { + log.error("consumer error, topic: {}, offset: {}", topicName, event.getOffset(), ex); + } + } + +} \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumer.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumer.java new file mode 100644 index 0000000000..edb66703f7 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumer.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.consumer; + +import org.apache.eventmesh.api.AbstractContext; +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.api.consumer.Consumer; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.cloudevents.CloudEvent; + +public class StandaloneConsumer implements Consumer { + + private final StandaloneBroker standaloneBroker; + + private EventListener listener; + + private final AtomicBoolean isStarted; + + private final ConcurrentHashMap subscribeTable; + + public StandaloneConsumer(Properties properties) { + this.standaloneBroker = StandaloneBroker.getInstance(); + this.subscribeTable = new ConcurrentHashMap<>(16); + this.isStarted = new AtomicBoolean(false); + } + + @Override + public boolean isStarted() { + return isStarted.get(); + } + + @Override + public boolean isClosed() { + return !isStarted.get(); + } + + @Override + public void start() { + isStarted.compareAndSet(false, true); + } + + @Override + public void shutdown() { + isStarted.compareAndSet(true, false); + subscribeTable.forEach(((topic, subScribe) -> subScribe.shutdown())); + subscribeTable.clear(); + } + + @Override + public void init(Properties keyValue) throws Exception { + + } + + @Override + public void updateOffset(List cloudEvents, AbstractContext context) { + + } + + @Override + public void subscribe(String topic) throws Exception { + if (subscribeTable.containsKey(topic)) { + return; + } + synchronized (subscribeTable) { + standaloneBroker.createTopicIfAbsent(topic); + Subscribe subscribe = new Subscribe(topic, standaloneBroker, listener); + subscribe.subscribe(); + subscribeTable.put(topic, subscribe); + } + } + + @Override + public void unsubscribe(String topic) { + if (!subscribeTable.containsKey(topic)) { + return; + } + synchronized (subscribeTable) { + Subscribe subScribe = subscribeTable.get(topic); + subScribe.shutdown(); + subscribeTable.remove(topic); + } + } + + @Override + public void registerEventListener(EventListener listener) { + this.listener = listener; + } +} diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumerAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumerAdaptor.java similarity index 92% rename from eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumerAdaptor.java rename to eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumerAdaptor.java index 79c5aadd5e..328faeeffd 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/consumer/StandaloneConsumerAdaptor.java +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumerAdaptor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.standalone.consumer; +package org.apache.eventmesh.storage.standalone.consumer; import org.apache.eventmesh.api.AbstractContext; import org.apache.eventmesh.api.EventListener; @@ -24,18 +24,15 @@ import java.util.List; import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; +import lombok.NoArgsConstructor; + +@NoArgsConstructor public class StandaloneConsumerAdaptor implements Consumer { private StandaloneConsumer consumer; - public StandaloneConsumerAdaptor() { - } - @Override public boolean isStarted() { return consumer.isStarted(); diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducer.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducer.java similarity index 75% rename from eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducer.java rename to eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducer.java index c6aaf43a32..a89afd70e7 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducer.java +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducer.java @@ -15,29 +15,27 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.standalone.producer; +package org.apache.eventmesh.storage.standalone.producer; import org.apache.eventmesh.api.RequestReplyCallback; import org.apache.eventmesh.api.SendCallback; import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.ConnectorRuntimeException; import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.connector.standalone.broker.StandaloneBroker; -import org.apache.eventmesh.connector.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.api.exception.StorageRuntimeException; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.cloudevents.CloudEvent; import com.google.common.base.Preconditions; -public class StandaloneProducer { +import lombok.extern.slf4j.Slf4j; - private Logger logger = LoggerFactory.getLogger(StandaloneProducer.class); +@Slf4j +public class StandaloneProducer { private StandaloneBroker standaloneBroker; @@ -77,9 +75,9 @@ public SendResult publish(CloudEvent cloudEvent) { sendResult.setMessageId(String.valueOf(messageEntity.getOffset())); return sendResult; } catch (Exception e) { - logger.error("send message error, topic: {}", cloudEvent.getSubject(), e); - throw new ConnectorRuntimeException( - String.format("Send message error, topic: %s", cloudEvent.getSubject())); + log.error("send message error, topic: {}", cloudEvent.getSubject(), e); + throw new StorageRuntimeException( + String.format("Send message error, topic: %s", cloudEvent.getSubject())); } } @@ -92,10 +90,10 @@ public void publish(CloudEvent cloudEvent, SendCallback sendCallback) throws Exc sendCallback.onSuccess(sendResult); } catch (Exception ex) { OnExceptionContext onExceptionContext = OnExceptionContext.builder() - .messageId(cloudEvent.getId()) - .topic(cloudEvent.getSubject()) - .exception(new ConnectorRuntimeException(ex)) - .build(); + .messageId(cloudEvent.getId()) + .topic(cloudEvent.getSubject()) + .exception(new StorageRuntimeException(ex)) + .build(); sendCallback.onException(onExceptionContext); } } @@ -113,26 +111,26 @@ public void sendAsync(CloudEvent cloudEvent, SendCallback sendCallback) { sendCallback.onSuccess(sendResult); } catch (Exception ex) { OnExceptionContext onExceptionContext = OnExceptionContext.builder() - .messageId(cloudEvent.getId()) - .topic(cloudEvent.getSubject()) - .exception(new ConnectorRuntimeException(ex)) - .build(); + .messageId(cloudEvent.getId()) + .topic(cloudEvent.getSubject()) + .exception(new StorageRuntimeException(ex)) + .build(); sendCallback.onException(onExceptionContext); } } public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) throws Exception { - throw new ConnectorRuntimeException("Request is not supported"); + throw new StorageRuntimeException("Request is not supported"); } public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { - throw new ConnectorRuntimeException("Reply is not supported"); + throw new StorageRuntimeException("Reply is not supported"); } public void checkTopicExist(String topic) throws Exception { boolean exist = standaloneBroker.checkTopicExist(topic); if (!exist) { - throw new ConnectorRuntimeException(String.format("topic:%s is not exist", topic)); + throw new StorageRuntimeException(String.format("topic:%s is not exist", topic)); } } diff --git a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducerAdaptor.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducerAdaptor.java similarity index 97% rename from eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducerAdaptor.java rename to eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducerAdaptor.java index d85161a54a..7236155e25 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-standalone/src/main/java/org/apache/eventmesh/connector/standalone/producer/StandaloneProducerAdaptor.java +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducerAdaptor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.eventmesh.connector.standalone.producer; +package org.apache.eventmesh.storage.standalone.producer; import org.apache.eventmesh.api.RequestReplyCallback; import org.apache.eventmesh.api.SendCallback; diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/resource/StandaloneStorageResourceService.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/resource/StandaloneStorageResourceService.java new file mode 100644 index 0000000000..db13d8b381 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/java/org/apache/eventmesh/storage/standalone/resource/StandaloneStorageResourceService.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.resource; + +import org.apache.eventmesh.api.storage.StorageResourceService; + +public class StandaloneStorageResourceService implements StorageResourceService { + + @Override + public void init() throws Exception { + + } + + @Override + public void release() throws Exception { + + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin new file mode 100644 index 0000000000..25ac1b73a3 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.admin.Admin @@ -0,0 +1,16 @@ +# 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. + +standalone=org.apache.eventmesh.storage.standalone.admin.StandaloneAdminAdaptor diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer new file mode 100644 index 0000000000..401ef5a791 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer @@ -0,0 +1,16 @@ +# 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. + +standalone=org.apache.eventmesh.storage.standalone.consumer.StandaloneConsumerAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer new file mode 100644 index 0000000000..075c556e46 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer @@ -0,0 +1,16 @@ +# 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. + +standalone=org.apache.eventmesh.storage.standalone.producer.StandaloneProducerAdaptor \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService new file mode 100644 index 0000000000..bc56bd000a --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService @@ -0,0 +1,16 @@ +# 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. + +standalone=org.apache.eventmesh.storage.standalone.resource.StandaloneStorageResourceService \ No newline at end of file diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/TestUtils.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/TestUtils.java new file mode 100644 index 0000000000..5571cda950 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/TestUtils.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone; + +import org.apache.eventmesh.storage.standalone.broker.Channel; +import org.apache.eventmesh.storage.standalone.broker.MessageQueue; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import org.apache.commons.lang3.tuple.Pair; + +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + + +public class TestUtils { + + public static final String TEST_TOPIC = "test-topic"; + public static final int OFF_SET = 0; + public static final int LENGTH = 5; + public static final int EXCEEDED_MESSAGE_STORE_WINDOW = 60 * 60 * 1000 + 1000; + + public static Pair, ConcurrentHashMap> createDefaultMessageContainer( + StandaloneBroker broker) { + ConcurrentHashMap messageContainer = new ConcurrentHashMap<>(1); + ConcurrentHashMap subscribeContainer = new ConcurrentHashMap<>(1); + + Subscribe subscribe = createSubscribe(broker); + subscribe.subscribe(); + subscribeContainer.put(new TopicMetadata(TEST_TOPIC), subscribe); + return Pair.of(messageContainer, subscribeContainer); + } + + + public static ConcurrentHashMap createMessageContainer(TopicMetadata topicMetadata, MessageEntity messageEntity) + throws InterruptedException { + ConcurrentHashMap messageContainer = new ConcurrentHashMap<>(1); + MessageQueue messageQueue = new MessageQueue(); + messageQueue.put(messageEntity); + messageContainer.put(topicMetadata, messageQueue); + return messageContainer; + } + + public static CloudEvent createDefaultCloudEvent() { + return CloudEventBuilder.v1() + .withId("test") + .withSubject(TEST_TOPIC) + .withSource(URI.create("testsource")) + .withType("testType") + .build(); + } + + public static List createCloudEvents() { + return Collections.singletonList(createDefaultCloudEvent()); + } + + public static MessageEntity createDefaultMessageEntity() { + return new MessageEntity( + new TopicMetadata(TEST_TOPIC), + createDefaultCloudEvent(), + OFF_SET, + System.currentTimeMillis()); + } + + public static MessageEntity createMessageEntity(TopicMetadata topicMetadata, CloudEvent cloudEvent, long offSet, long currentTimeMillis) { + return new MessageEntity( + topicMetadata, + cloudEvent, + offSet, + currentTimeMillis); + } + + public static Subscribe createSubscribe(StandaloneBroker standaloneBroker) { + standaloneBroker.createTopic(TEST_TOPIC); + return new Subscribe(TEST_TOPIC, standaloneBroker, (cloudEvent, context) -> { + }); + } + + public static Subscribe createSubscribe(StandaloneBroker standaloneBroker, List cloudEvents) { + standaloneBroker.createTopic(TEST_TOPIC); + return new Subscribe(TEST_TOPIC, standaloneBroker, (cloudEvent, context) -> { + cloudEvents.add(cloudEvent); + }); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdminTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdminTest.java new file mode 100644 index 0000000000..7200f902ec --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/admin/StandaloneAdminTest.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.admin; + +import static org.apache.eventmesh.storage.standalone.TestUtils.TEST_TOPIC; +import static org.apache.eventmesh.storage.standalone.TestUtils.createDefaultCloudEvent; +import static org.apache.eventmesh.storage.standalone.TestUtils.createDefaultMessageContainer; +import static org.apache.eventmesh.storage.standalone.TestUtils.createDefaultMessageEntity; + +import org.apache.eventmesh.storage.standalone.broker.Channel; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import org.apache.commons.lang3.tuple.Pair; + +import java.util.concurrent.ConcurrentHashMap; + +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 org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +import io.cloudevents.CloudEvent; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class StandaloneAdminTest { + + @Mock + private StandaloneBroker standaloneBroker; + + private StandaloneAdmin standaloneAdmin; + + + @BeforeEach + public void setUp() { + initStaticInstance(); + } + + @Test + public void testIsStarted() { + standaloneAdmin.start(); + Assertions.assertTrue(standaloneAdmin.isStarted()); + } + + @Test + public void testIsClosed() { + standaloneAdmin.shutdown(); + Assertions.assertTrue(standaloneAdmin.isClosed()); + } + + @Test + public void testCreateTopic() { + standaloneAdmin.createTopic(TEST_TOPIC); + Mockito.verify(standaloneBroker).createTopicIfAbsent(TEST_TOPIC); + } + + @Test + public void testDeleteTopic() { + standaloneAdmin.deleteTopic(TEST_TOPIC); + Mockito.verify(standaloneBroker).deleteTopicIfExist(TEST_TOPIC); + } + + + @Test + public void testPublish() throws Exception { + CloudEvent cloudEvent = createDefaultCloudEvent(); + MessageEntity messageEntity = createDefaultMessageEntity(); + Mockito.when(standaloneBroker.putMessage(TEST_TOPIC, cloudEvent)).thenReturn(messageEntity); + standaloneAdmin.publish(cloudEvent); + Mockito.verify(standaloneBroker).putMessage(TEST_TOPIC, cloudEvent); + } + + private void initStaticInstance() { + try (MockedStatic standaloneBrokerMockedStatic = Mockito.mockStatic(StandaloneBroker.class)) { + standaloneBrokerMockedStatic.when(StandaloneBroker::getInstance).thenReturn(standaloneBroker); + Pair, ConcurrentHashMap> pair = + createDefaultMessageContainer(standaloneBroker); + Mockito.when(standaloneBroker.getSubscribeContainer()).thenReturn(pair.getRight()); + Mockito.when(standaloneBroker.getMessageContainer()).thenReturn(pair.getLeft()); + + standaloneAdmin = new StandaloneAdmin(); + } + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/MessageQueueTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/MessageQueueTest.java new file mode 100644 index 0000000000..1dc6a39479 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/MessageQueueTest.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker; + +import static org.apache.eventmesh.storage.standalone.TestUtils.createDefaultMessageEntity; + +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; + +import java.util.Arrays; +import java.util.Objects; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class MessageQueueTest { + + private static final int DEFAULT_SIZE = 5; + private static final int ITEMS_COUNT = 1; + private static final int DEFAULT_OFFSET = 0; + private static final int WRONG_OFFSET = 4; + private MessageQueue messageQueue; + + @BeforeEach + public void setUp() throws InterruptedException { + initMessageQueue(); + } + + @Test + public void testPut() { + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).findAny().isPresent()); + } + + @Test + public void testTake() throws InterruptedException { + MessageEntity takeMessage = messageQueue.take(); + Assertions.assertNotNull(takeMessage); + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).findAny().isPresent()); + } + + @Test + public void testPeek() { + MessageEntity peekMessage = messageQueue.peek(); + Assertions.assertNotNull(peekMessage); + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).findAny().isPresent()); + } + + @Test + public void testGetHead() { + MessageEntity headMessage = messageQueue.getHead(); + Assertions.assertNotNull(headMessage); + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).findAny().isPresent()); + } + + @Test + public void testGetTail() { + MessageEntity tailMessage = messageQueue.getHead(); + Assertions.assertNotNull(tailMessage); + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).findAny().isPresent()); + } + + @Test + public void testGetByOffset() { + MessageEntity offSetMessageEntity = messageQueue.getByOffset(DEFAULT_OFFSET); + Assertions.assertNotNull(offSetMessageEntity); + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).findAny().isPresent()); + Assertions.assertEquals(DEFAULT_OFFSET, offSetMessageEntity.getOffset()); + } + + @Test + public void testGetByOffset_whenOffSetIsWrong_thenReturnsNull() { + MessageEntity offSetMessageEntity = messageQueue.getByOffset(WRONG_OFFSET); + Assertions.assertNull(offSetMessageEntity); + } + + @Test + public void testRemoveHead() { + messageQueue.removeHead(); + Assertions.assertTrue(Arrays.stream(messageQueue.getItems()).anyMatch(Objects::isNull)); + } + + @Test + public void testGetSize() { + Assertions.assertEquals(ITEMS_COUNT, messageQueue.getSize()); + } + + @Test + public void testGetTakeIndex() throws InterruptedException { + MessageEntity takeIndexMessageEntity = messageQueue.take(); + Assertions.assertNotNull(takeIndexMessageEntity); + Assertions.assertEquals(1, messageQueue.getPutIndex()); + } + + @Test + public void testGetPutIndex() { + Assertions.assertEquals(1, messageQueue.getPutIndex()); + } + + private void initMessageQueue() throws InterruptedException { + messageQueue = new MessageQueue(DEFAULT_SIZE); + MessageEntity messageEntity = createDefaultMessageEntity(); + messageQueue.put(messageEntity); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/StandaloneBrokerTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/StandaloneBrokerTest.java new file mode 100644 index 0000000000..d57ba6523b --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/StandaloneBrokerTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker; + +import static org.apache.eventmesh.storage.standalone.TestUtils.TEST_TOPIC; +import static org.apache.eventmesh.storage.standalone.TestUtils.createDefaultCloudEvent; +import static org.apache.eventmesh.storage.standalone.TestUtils.createSubscribe; + +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; + +public class StandaloneBrokerTest { + + + public StandaloneBroker getStandaloneBroker() { + StandaloneBroker instance = StandaloneBroker.getInstance(); + Subscribe subscribe = createSubscribe(instance); + subscribe.subscribe(); + return instance; + } + + @Test + public void testGetInstance() { + Assertions.assertNotNull(StandaloneBroker.getInstance()); + } + + @Test + public void testCreateTopicIfAbsent() { + StandaloneBroker instance = getStandaloneBroker(); + Channel pair = instance.createTopicIfAbsent(TEST_TOPIC); + Assertions.assertNotNull(pair); + } + + @Test + public void testPutMessage() throws InterruptedException { + StandaloneBroker instance = getStandaloneBroker(); + CloudEvent cloudEvent = createDefaultCloudEvent(); + MessageEntity messageEntity = instance.putMessage(TEST_TOPIC, cloudEvent); + Assertions.assertNotNull(messageEntity); + } + + + @Test + public void testCheckTopicExist() throws InterruptedException { + StandaloneBroker instance = getStandaloneBroker(); + CloudEvent cloudEvent = createDefaultCloudEvent(); + instance.putMessage(TEST_TOPIC, cloudEvent); + boolean exists = instance.checkTopicExist(TEST_TOPIC); + Assertions.assertTrue(exists); + } + +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClearTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClearTest.java new file mode 100644 index 0000000000..9a9b50fce3 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/task/HistoryMessageClearTest.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker.task; + +import static org.apache.eventmesh.storage.standalone.TestUtils.EXCEEDED_MESSAGE_STORE_WINDOW; +import static org.apache.eventmesh.storage.standalone.TestUtils.OFF_SET; +import static org.apache.eventmesh.storage.standalone.TestUtils.TEST_TOPIC; +import static org.apache.eventmesh.storage.standalone.TestUtils.createDefaultCloudEvent; +import static org.apache.eventmesh.storage.standalone.TestUtils.createMessageContainer; +import static org.apache.eventmesh.storage.standalone.TestUtils.createMessageEntity; + +import org.apache.eventmesh.storage.standalone.broker.MessageQueue; +import org.apache.eventmesh.storage.standalone.broker.model.MessageEntity; +import org.apache.eventmesh.storage.standalone.broker.model.TopicMetadata; + +import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class HistoryMessageClearTest { + + private MessageEntity messageEntity; + private ConcurrentHashMap messageContainer; + private HistoryMessageClear historyMessageClear; + + @BeforeEach + public void setUp() throws InterruptedException { + messageEntity = createMessageEntity(new TopicMetadata(TEST_TOPIC), createDefaultCloudEvent(), OFF_SET, EXCEEDED_MESSAGE_STORE_WINDOW); + messageContainer = createMessageContainer(new TopicMetadata(TEST_TOPIC), messageEntity); + historyMessageClear = new HistoryMessageClear(messageContainer); + } + + @Test + public void testClearMessages() { + historyMessageClear.clearMessages(); + MessageQueue updatedMessageQueue = messageContainer.get(new TopicMetadata(TEST_TOPIC)); + Assertions.assertTrue(Arrays.stream(updatedMessageQueue.getItems()).allMatch(Objects::isNull)); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/task/SubscribeTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/task/SubscribeTest.java new file mode 100644 index 0000000000..3ef86bdd20 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/broker/task/SubscribeTest.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.broker.task; + +import static org.apache.eventmesh.storage.standalone.TestUtils.TEST_TOPIC; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; + +import org.apache.eventmesh.api.EventListener; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class SubscribeTest { + + @Mock + private StandaloneBroker standaloneBroker; + @Mock + private EventListener eventListener; + private Subscribe subscribe; + + @Test + public void testSubscribe() { + subscribe = new Subscribe(TEST_TOPIC, standaloneBroker, eventListener); + subscribe.subscribe(); + Mockito.verify(standaloneBroker).subscribed(anyString(), any(Subscribe.class)); + } + + @Test + public void testShutdown() { + subscribe = new Subscribe(TEST_TOPIC, standaloneBroker, eventListener); + Assertions.assertTrue(subscribe.isRunning()); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumerTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumerTest.java new file mode 100644 index 0000000000..1a74ebbb48 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/consumer/StandaloneConsumerTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.consumer; + +import static org.apache.eventmesh.storage.standalone.TestUtils.createCloudEvents; + +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + +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 org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import io.cloudevents.CloudEvent; + +@ExtendWith(MockitoExtension.class) +public class StandaloneConsumerTest { + + @Mock + private ConcurrentHashMap subscribeTable; + private StandaloneConsumer standaloneConsumer; + private List cloudEvents; + + @BeforeEach + public void setUp() { + standaloneConsumer = new StandaloneConsumer(new Properties()); + cloudEvents = createCloudEvents(); + } + + @Test + public void testIsStarted() { + Assertions.assertFalse(standaloneConsumer.isStarted()); + } + + @Test + public void testIsClosed() { + Assertions.assertTrue(standaloneConsumer.isClosed()); + } + + @Test + public void testStart() { + standaloneConsumer.start(); + Assertions.assertTrue(standaloneConsumer.isStarted()); + } + + @Test + public void testShutdown() { + standaloneConsumer.shutdown(); + Assertions.assertTrue(standaloneConsumer.isClosed()); + } +} diff --git a/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducerTest.java b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducerTest.java new file mode 100644 index 0000000000..20db666831 --- /dev/null +++ b/eventmesh-storage-plugin/eventmesh-storage-standalone/src/test/java/org/apache/eventmesh/storage/standalone/producer/StandaloneProducerTest.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.storage.standalone.producer; + +import static org.apache.eventmesh.storage.standalone.TestUtils.TEST_TOPIC; +import static org.apache.eventmesh.storage.standalone.TestUtils.createSubscribe; + +import org.apache.eventmesh.api.SendResult; +import org.apache.eventmesh.storage.standalone.TestUtils; +import org.apache.eventmesh.storage.standalone.broker.StandaloneBroker; +import org.apache.eventmesh.storage.standalone.broker.task.Subscribe; + +import java.util.Properties; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.cloudevents.CloudEvent; + + + +public class StandaloneProducerTest { + + private StandaloneProducer standaloneProducer; + + + @BeforeEach + public void setUp() { + standaloneProducer = new StandaloneProducer(new Properties()); + } + + @Test + public void testIsStarted() { + Assertions.assertFalse(standaloneProducer.isStarted()); + } + + @Test + public void testIsClosed() { + Assertions.assertTrue(standaloneProducer.isClosed()); + } + + @Test + public void testStart() { + standaloneProducer.start(); + Assertions.assertTrue(standaloneProducer.isStarted()); + } + + @Test + public void testShutdown() { + standaloneProducer.shutdown(); + Assertions.assertTrue(standaloneProducer.isClosed()); + } + + @Test + public void testPublish() { + StandaloneBroker standaloneBroker = StandaloneBroker.getInstance(); + standaloneBroker.createTopicIfAbsent(TEST_TOPIC); + CloudEvent cloudEvent = TestUtils.createDefaultCloudEvent(); + Subscribe subscribe = createSubscribe(standaloneBroker); + subscribe.subscribe(); + SendResult sendResult = standaloneProducer.publish(cloudEvent); + Assertions.assertNotNull(sendResult); + } +} diff --git a/eventmesh-storage-plugin/gradle.properties b/eventmesh-storage-plugin/gradle.properties new file mode 100644 index 0000000000..a9fd83fea0 --- /dev/null +++ b/eventmesh-storage-plugin/gradle.properties @@ -0,0 +1,16 @@ +# +# 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. +# \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/build.gradle b/eventmesh-trace-plugin/eventmesh-trace-api/build.gradle index f8b885f881..af37761f42 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-api/build.gradle +++ b/eventmesh-trace-plugin/eventmesh-trace-api/build.gradle @@ -23,10 +23,9 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-api' implementation 'io.opentelemetry:opentelemetry-sdk' - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' - testImplementation project(":eventmesh-trace-plugin:eventmesh-trace-zipkin") -} \ No newline at end of file + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/AbstractTraceService.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/AbstractTraceService.java new file mode 100644 index 0000000000..318025f74f --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/AbstractTraceService.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.api; + +import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; +import org.apache.eventmesh.trace.api.config.ExporterConfiguration; +import org.apache.eventmesh.trace.api.exception.TraceException; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapGetter; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; +import io.opentelemetry.sdk.trace.SpanProcessor; + +import lombok.Getter; +import lombok.Setter; + +/** + * The abstract base class for EventMeshTraceService's implementations + */ +@Getter +@Setter +public abstract class AbstractTraceService implements EventMeshTraceService { + + protected transient SdkTracerProvider sdkTracerProvider; + + protected transient Tracer tracer; + + protected transient TextMapPropagator textMapPropagator; + + /** + * Unified configuration class corresponding to exporter.properties + */ + protected transient ExporterConfiguration exporterConfiguration; + + protected transient Thread shutdownHook; + + @Override + public Context extractFrom(final Context context, final Map carrier) throws TraceException { + textMapPropagator.extract(context, carrier, new TextMapGetter>() { + + @Override + public Iterable keys(@Nonnull final Map carrier) { + return carrier.keySet(); + } + + @Nullable + @Override + public String get(final @Nonnull Map carrier, final String key) { + return Optional.ofNullable(carrier.get(key)).map(Objects::toString).orElse(null); + } + }); + return context; + } + + @Override + public void inject(Context context, Map map) { + textMapPropagator.inject(context, map, (carrier, key, value) -> map.put(key, value)); + } + + @Override + public Span createSpan(final String spanName, + final SpanKind spanKind, + final long startTimestamp, + final TimeUnit timeUnit, + final Context context, + final boolean isSpanFinishInOtherThread) throws TraceException { + return tracer.spanBuilder(spanName) + .setParent(context) + .setSpanKind(spanKind) + .setStartTimestamp(startTimestamp, timeUnit) + .startSpan(); + } + + @Override + public Span createSpan(String spanName, SpanKind spanKind, Context context, + boolean isSpanFinishInOtherThread) throws TraceException { + return tracer.spanBuilder(spanName) + .setParent(context) + .setSpanKind(spanKind) + .setStartTimestamp(System.currentTimeMillis(), TimeUnit.MILLISECONDS) + .startSpan(); + } + + @Override + public void shutdown() throws TraceException { + try { + if (sdkTracerProvider != null) { + sdkTracerProvider.close(); + } + } catch (Exception e) { + throw new TraceException("trace close error", e); + } + } + + /** + * Init the common fields + * + * @param spanProcessor + * @param serviceNameResource + */ + protected void initVars(SpanProcessor spanProcessor, Resource serviceNameResource) { + SdkTracerProviderBuilder builder = SdkTracerProvider.builder() + .addSpanProcessor(spanProcessor); + if (serviceNameResource != null) { + builder.setResource(Resource.getDefault().merge(serviceNameResource)); + } + sdkTracerProvider = builder.build(); + + final OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .setTracerProvider(sdkTracerProvider) + .build(); + + tracer = openTelemetry.getTracer(EventMeshTraceConstants.SERVICE_NAME); + textMapPropagator = openTelemetry.getPropagators().getTextMapPropagator(); + shutdownHook = new Thread(sdkTracerProvider::close); + shutdownHook.setDaemon(true); + Runtime.getRuntime().addShutdownHook(shutdownHook); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/EventMeshTraceService.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/EventMeshTraceService.java index c7d5661990..d20a03f4cc 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/EventMeshTraceService.java +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/EventMeshTraceService.java @@ -31,21 +31,22 @@ /** * EventMeshTraceService */ -@EventMeshSPI(isSingleton = true, eventMeshExtensionType = EventMeshExtensionType.TRACE) +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.TRACE) public interface EventMeshTraceService { + void init() throws TraceException; - //extract attr from carrier to context + // extract attr from carrier to context Context extractFrom(Context context, Map carrier) throws TraceException; - //inject attr from context to carrier + // inject attr from context to carrier void inject(Context context, Map carrier); Span createSpan(String spanName, SpanKind spanKind, long startTimestamp, TimeUnit timeUnit, - Context context, boolean isSpanFinishInOtherThread) throws TraceException; + Context context, boolean isSpanFinishInOtherThread) throws TraceException; Span createSpan(String spanName, SpanKind spanKind, Context context, - boolean isSpanFinishInOtherThread) throws TraceException; + boolean isSpanFinishInOtherThread) throws TraceException; void shutdown() throws TraceException; } diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/TracePluginFactory.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/TracePluginFactory.java index e0bac19ed1..7e78043c2b 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/TracePluginFactory.java +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/TracePluginFactory.java @@ -17,10 +17,10 @@ package org.apache.eventmesh.trace.api; -import static com.google.common.base.Preconditions.checkNotNull; - import org.apache.eventmesh.spi.EventMeshExtensionFactory; +import java.util.Objects; + import lombok.experimental.UtilityClass; /** @@ -28,16 +28,19 @@ */ @UtilityClass public class TracePluginFactory { + /** * to get TraceService * * @param traceServiceType * @return */ - public static EventMeshTraceService getEventMeshTraceService(String traceServiceType) { - checkNotNull(traceServiceType, "traceServiceType cannot be null"); + public static EventMeshTraceService getEventMeshTraceService(final String traceServiceType) { + Objects.requireNonNull(traceServiceType, "traceServiceType cannot be null"); - EventMeshTraceService eventMeshTraceService = EventMeshExtensionFactory.getExtension(EventMeshTraceService.class, traceServiceType); - return checkNotNull(eventMeshTraceService, "traceServiceType: " + traceServiceType + " is not supported"); + EventMeshTraceService eventMeshTraceService = EventMeshExtensionFactory.getExtension(EventMeshTraceService.class, + traceServiceType); + return Objects.requireNonNull(eventMeshTraceService, + "traceServiceType: " + traceServiceType + " is not supported"); } } diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/common/EventMeshTraceConstants.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/common/EventMeshTraceConstants.java index 82dc63ead4..544da60a57 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/common/EventMeshTraceConstants.java +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/common/EventMeshTraceConstants.java @@ -17,7 +17,6 @@ package org.apache.eventmesh.trace.api.common; - public class EventMeshTraceConstants { public static final String TRACE_EVENTMESH_SDK_CLIENT_SPAN = "eventmesh-sdk-client-span"; @@ -30,4 +29,6 @@ public class EventMeshTraceConstants { public static final String TRACE_EVENTMESH_SDK_SERVER_SPAN = "eventmesh-sdk-server-span"; + // Name of the service(using the instrumentationName) + public static final String SERVICE_NAME = "eventmesh_trace"; } diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/config/ExporterConfiguration.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/config/ExporterConfiguration.java index 44d54d032c..ab42241e0a 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/config/ExporterConfiguration.java +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/main/java/org/apache/eventmesh/trace/api/config/ExporterConfiguration.java @@ -17,101 +17,27 @@ package org.apache.eventmesh.trace.api.config; -import org.apache.commons.lang3.StringUtils; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.Properties; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; +import lombok.Data; /** * to load the properties form exporter.properties */ -@Slf4j -@UtilityClass +@Data +@Config(prefix = "eventmesh.trace", path = "classPath://exporter.properties") public class ExporterConfiguration { - private static final String CONFIG_FILE = "exporter.properties"; - private static final Properties properties = new Properties(); - + @ConfigField(field = "max.export.size") private int eventMeshTraceMaxExportSize = 512; - private int eventMeshTraceMaxQueueSize = 2048; - private int eventMeshTraceExportTimeout = 30; - private int eventMeshTraceExportInterval = 5; - - static { - loadProperties(); - initializeConfig(); - } - - public static int getEventMeshTraceMaxExportSize() { - return eventMeshTraceMaxExportSize; - } - - public static int getEventMeshTraceMaxQueueSize() { - return eventMeshTraceMaxQueueSize; - } - public static int getEventMeshTraceExportTimeout() { - return eventMeshTraceExportTimeout; - } - - public static int getEventMeshTraceExportInterval() { - return eventMeshTraceExportInterval; - } - - private void initializeConfig() { - String eventMeshTraceMaxExportSizeStr = properties.getProperty("eventmesh.trace.max.export.size"); - if (StringUtils.isNotEmpty(eventMeshTraceMaxExportSizeStr)) { - eventMeshTraceMaxExportSize = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshTraceMaxExportSizeStr)); - } - - String eventMeshTraceMaxQueueSizeStr = properties.getProperty("eventmesh.trace.max.queue.size"); - if (StringUtils.isNotEmpty(eventMeshTraceMaxQueueSizeStr)) { - eventMeshTraceMaxQueueSize = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshTraceMaxQueueSizeStr)); - } - - String eventMeshTraceExportTimeoutStr = properties.getProperty("eventmesh.trace.export.timeout"); - if (StringUtils.isNotEmpty(eventMeshTraceExportTimeoutStr)) { - eventMeshTraceExportTimeout = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshTraceExportTimeoutStr)); - } + @ConfigField(field = "max.queue.size") + private int eventMeshTraceMaxQueueSize = 2048; - String eventMeshTraceExportIntervalStr = properties.getProperty("eventmesh.trace.export.interval"); - if (StringUtils.isNotEmpty(eventMeshTraceExportIntervalStr)) { - eventMeshTraceExportInterval = - Integer.parseInt(StringUtils.deleteWhitespace(eventMeshTraceExportIntervalStr)); - } - } + @ConfigField(field = "export.timeout") + private int eventMeshTraceExportTimeout = 30; - private void loadProperties() { - URL resource = ExporterConfiguration.class.getClassLoader().getResource(CONFIG_FILE); - if (resource != null) { - try (InputStream inputStream = resource.openStream()) { - if (inputStream.available() > 0) { - properties.load(new BufferedReader(new InputStreamReader(inputStream))); - } - } catch (IOException e) { - throw new RuntimeException("Load exporter.properties file from classpath error"); - } - } - // get from config home - try { - String configPath = - System.getProperty("confPath", System.getenv("confPath")) + File.separator + CONFIG_FILE; - if (new File(configPath).exists()) { - properties.load(new BufferedReader(new FileReader(configPath))); - } - } catch (IOException e) { - throw new IllegalArgumentException("Cannot load exporter.properties file from conf"); - } - } + @ConfigField(field = "export.interval") + private int eventMeshTraceExportInterval = 5; } diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/test/java/org/apache/eventmesh/trace/api/TracePluginFactoryTest.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/test/java/org/apache/eventmesh/trace/api/TracePluginFactoryTest.java deleted file mode 100644 index 58583fa063..0000000000 --- a/eventmesh-trace-plugin/eventmesh-trace-api/src/test/java/org/apache/eventmesh/trace/api/TracePluginFactoryTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.trace.api; - -import static org.hamcrest.CoreMatchers.is; - -import org.apache.eventmesh.trace.zipkin.ZipkinTraceService; - -import org.hamcrest.MatcherAssert; -import org.junit.Assert; -import org.junit.Test; - -public class TracePluginFactoryTest { - - @Test - public void testFailedGetTraceService() { - NullPointerException nullPointerException1 = Assert.assertThrows(NullPointerException.class, - () -> TracePluginFactory.getEventMeshTraceService(null)); - MatcherAssert.assertThat(nullPointerException1.getMessage(), is("traceServiceType cannot be null")); - - String traceServiceType = "non-Existing"; - NullPointerException nullPointerException2 = - Assert.assertThrows(NullPointerException.class, () -> TracePluginFactory.getEventMeshTraceService(traceServiceType)); - MatcherAssert.assertThat(nullPointerException2.getMessage(), is("traceServiceType: " + traceServiceType + " is not supported")); - } - - @Test - public void testSuccessfulGetTraceService() { - EventMeshTraceService zipkinTraceService = TracePluginFactory.getEventMeshTraceService("zipkin"); - Assert.assertNotNull(zipkinTraceService); - Assert.assertTrue(zipkinTraceService instanceof ZipkinTraceService); - } -} diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/test/java/org/apache/eventmesh/trace/api/config/ExporterConfigurationTest.java b/eventmesh-trace-plugin/eventmesh-trace-api/src/test/java/org/apache/eventmesh/trace/api/config/ExporterConfigurationTest.java new file mode 100644 index 0000000000..35b3bfb58b --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/test/java/org/apache/eventmesh/trace/api/config/ExporterConfigurationTest.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.api.config; + +import org.apache.eventmesh.common.config.ConfigService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ExporterConfigurationTest { + + @Test + public void testGetExporterConfiguration() { + ConfigService configService = ConfigService.getInstance(); + ExporterConfiguration config = configService.buildConfigInstance(ExporterConfiguration.class); + + Assertions.assertEquals(816, config.getEventMeshTraceMaxExportSize()); + Assertions.assertEquals(1816, config.getEventMeshTraceMaxQueueSize()); + Assertions.assertEquals(2816, config.getEventMeshTraceExportTimeout()); + Assertions.assertEquals(3816, config.getEventMeshTraceExportInterval()); + } +} \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-api/src/test/resources/exporter.properties b/eventmesh-trace-plugin/eventmesh-trace-api/src/test/resources/exporter.properties new file mode 100644 index 0000000000..a951d48918 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-api/src/test/resources/exporter.properties @@ -0,0 +1,25 @@ +# +# 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. +# + +#set the maximum batch size to use +eventmesh.trace.max.export.size=816 +#set the queue size. This must be >= the export batch size +eventmesh.trace.max.queue.size=1816 +#set the max amount of time an export can run before getting(TimeUnit=SECONDS) +eventmesh.trace.export.timeout=2816 +#set time between two different exports(TimeUnit=SECONDS) +eventmesh.trace.export.interval=3816 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/build.gradle b/eventmesh-trace-plugin/eventmesh-trace-jaeger/build.gradle new file mode 100644 index 0000000000..76a50cffe0 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/build.gradle @@ -0,0 +1,40 @@ +/* + * 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. + */ + +dependencies { + implementation project(":eventmesh-trace-plugin:eventmesh-trace-api") + implementation project(":eventmesh-common") + implementation 'org.slf4j:slf4j-api' + implementation 'org.apache.commons:commons-lang3' + implementation 'com.google.guava:guava' + + implementation 'io.opentelemetry:opentelemetry-exporter-jaeger' + implementation 'io.opentelemetry:opentelemetry-semconv' + + // grpc + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty" + implementation "io.grpc:grpc-netty-shaded" + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + testImplementation "org.mockito:mockito-inline" +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/gradle.properties b/eventmesh-trace-plugin/eventmesh-trace-jaeger/gradle.properties new file mode 100644 index 0000000000..2999bfdbeb --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=trace +pluginName=jaeger \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/java/org/apache/eventmesh/trace/jaeger/JaegerTraceService.java b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/java/org/apache/eventmesh/trace/jaeger/JaegerTraceService.java new file mode 100644 index 0000000000..57b61421e9 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/java/org/apache/eventmesh/trace/jaeger/JaegerTraceService.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.jaeger; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.trace.api.AbstractTraceService; +import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; +import org.apache.eventmesh.trace.api.exception.TraceException; +import org.apache.eventmesh.trace.jaeger.config.JaegerConfiguration; + +import java.util.concurrent.TimeUnit; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; + +import lombok.Getter; +import lombok.Setter; + +@Config(field = "jaegerConfiguration") +@Config(field = "exporterConfiguration") +public class JaegerTraceService extends AbstractTraceService { + + /** + * Unified configuration class corresponding to jaeger.properties + */ + @Getter + @Setter + private transient JaegerConfiguration jaegerConfiguration; + + @Override + public void init() throws TraceException { + // jaeger's config + final String eventMeshJaegerIp = jaegerConfiguration.getEventMeshJaegerIp(); + final int eventMeshJaegerPort = jaegerConfiguration.getEventMeshJaegerPort(); + // exporter's config + final int eventMeshTraceExportInterval = exporterConfiguration.getEventMeshTraceExportInterval(); + final int eventMeshTraceExportTimeout = exporterConfiguration.getEventMeshTraceExportTimeout(); + final int eventMeshTraceMaxExportSize = exporterConfiguration.getEventMeshTraceMaxExportSize(); + final int eventMeshTraceMaxQueueSize = exporterConfiguration.getEventMeshTraceMaxQueueSize(); + + final String httpEndpoint = String.format("http://%s:%s", eventMeshJaegerIp, eventMeshJaegerPort); + final JaegerGrpcSpanExporter jaegerExporter = JaegerGrpcSpanExporter.builder() + .setEndpoint(httpEndpoint) + .build(); + + final SpanProcessor spanProcessor = BatchSpanProcessor.builder(jaegerExporter) + .setScheduleDelay(eventMeshTraceExportInterval, TimeUnit.SECONDS) + .setExporterTimeout(eventMeshTraceExportTimeout, TimeUnit.SECONDS) + .setMaxExportBatchSize(eventMeshTraceMaxExportSize) + .setMaxQueueSize(eventMeshTraceMaxQueueSize) + .build(); + + // set the trace service's name + final Resource serviceNameResource = + Resource.create(Attributes.of(stringKey("service.name"), EventMeshTraceConstants.SERVICE_NAME)); + + initVars(spanProcessor, serviceNameResource); + } + + public JaegerConfiguration getClientConfiguration() { + return this.jaegerConfiguration; + } + +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/java/org/apache/eventmesh/trace/jaeger/config/JaegerConfiguration.java b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/java/org/apache/eventmesh/trace/jaeger/config/JaegerConfiguration.java new file mode 100644 index 0000000000..2284a4f22c --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/java/org/apache/eventmesh/trace/jaeger/config/JaegerConfiguration.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.jaeger.config; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; + +import lombok.Data; + +@Data +@Config(prefix = "eventmesh.trace.jaeger", path = "classPath://jaeger.properties") +public class JaegerConfiguration { + + @ConfigField(field = "ip", notEmpty = true) + private String eventMeshJaegerIp = "localhost"; + + @ConfigField(field = "port", notEmpty = true) + private int eventMeshJaegerPort = 14250; +} \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.trace.api.EventMeshTraceService b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.trace.api.EventMeshTraceService new file mode 100644 index 0000000000..9dd7e61169 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.trace.api.EventMeshTraceService @@ -0,0 +1,16 @@ +# 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. + +jaeger=org.apache.eventmesh.trace.jaeger.JaegerTraceService \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/resources/jaeger.properties b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/resources/jaeger.properties new file mode 100644 index 0000000000..1347748a5f --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/main/resources/jaeger.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +eventmesh.trace.jaeger.ip=localhost +eventmesh.trace.jaeger.port=14250 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/java/org/apache/eventmesh/trace/jaeger/JaegerTraceServiceTest.java b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/java/org/apache/eventmesh/trace/jaeger/JaegerTraceServiceTest.java new file mode 100644 index 0000000000..45c4d4a06a --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/java/org/apache/eventmesh/trace/jaeger/JaegerTraceServiceTest.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.jaeger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.apache.eventmesh.common.utils.ReflectUtils; +import org.apache.eventmesh.trace.api.TracePluginFactory; + +import java.lang.reflect.Field; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.opentelemetry.sdk.trace.SdkTracerProvider; + +public class JaegerTraceServiceTest { + + @Test + public void testInit() { + JaegerTraceService jaegerTraceService = + (JaegerTraceService) TracePluginFactory.getEventMeshTraceService("jaeger"); + jaegerTraceService.init(); + + assertNotNull(jaegerTraceService.getSdkTracerProvider()); + assertNotNull(jaegerTraceService.getShutdownHook()); + + IllegalArgumentException illegalArgumentException = + assertThrows(IllegalArgumentException.class, () -> Runtime.getRuntime().addShutdownHook(jaegerTraceService.getShutdownHook())); + assertEquals(illegalArgumentException.getMessage(), "Hook previously registered"); + } + + @Test + public void testShutdown() throws NoSuchFieldException, IllegalAccessException { + JaegerTraceService jaegerTraceService = + (JaegerTraceService) TracePluginFactory.getEventMeshTraceService("jaeger"); + jaegerTraceService.init(); + Field sdkTracerProviderField = null; + try { + sdkTracerProviderField = JaegerTraceService.class.getDeclaredField("sdkTracerProvider"); + } catch (NoSuchFieldException e) { + sdkTracerProviderField = ReflectUtils.lookUpFieldByParentClass(JaegerTraceService.class, "sdkTracerProvider"); + if (sdkTracerProviderField == null) { + throw e; + } + } + sdkTracerProviderField.setAccessible(true); + SdkTracerProvider mockSdkTracerProvider = Mockito.mock(SdkTracerProvider.class); + sdkTracerProviderField.set(jaegerTraceService, mockSdkTracerProvider); + + jaegerTraceService.shutdown(); + Mockito.verify(mockSdkTracerProvider, Mockito.times(1)).close(); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/java/org/apache/eventmesh/trace/jaeger/config/JaegerConfigurationTest.java b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/java/org/apache/eventmesh/trace/jaeger/config/JaegerConfigurationTest.java new file mode 100644 index 0000000000..c5e1eb2297 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/java/org/apache/eventmesh/trace/jaeger/config/JaegerConfigurationTest.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.jaeger.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.eventmesh.trace.api.TracePluginFactory; +import org.apache.eventmesh.trace.api.config.ExporterConfiguration; +import org.apache.eventmesh.trace.jaeger.JaegerTraceService; + +import org.junit.jupiter.api.Test; + +public class JaegerConfigurationTest { + + @Test + public void testGetConfiguration() { + JaegerTraceService jaegerTrace = + (JaegerTraceService) TracePluginFactory.getEventMeshTraceService("jaeger"); + + JaegerConfiguration config = jaegerTrace.getClientConfiguration(); + assertClientConfig(config); + ExporterConfiguration exporterConfig = jaegerTrace.getExporterConfiguration(); + assertBaseConfig(exporterConfig); + } + + private void assertClientConfig(JaegerConfiguration config) { + assertEquals("localhost", config.getEventMeshJaegerIp()); + assertEquals(14250, config.getEventMeshJaegerPort()); + } + + private void assertBaseConfig(ExporterConfiguration config) { + assertEquals(816, config.getEventMeshTraceMaxExportSize()); + assertEquals(1816, config.getEventMeshTraceMaxQueueSize()); + assertEquals(2816, config.getEventMeshTraceExportTimeout()); + assertEquals(3816, config.getEventMeshTraceExportInterval()); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/resources/exporter.properties b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/resources/exporter.properties new file mode 100644 index 0000000000..14f6980df0 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/resources/exporter.properties @@ -0,0 +1,20 @@ +# +# 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. +# +eventmesh.trace.max.export.size=816 +eventmesh.trace.max.queue.size=1816 +eventmesh.trace.export.timeout=2816 +eventmesh.trace.export.interval=3816 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/resources/jaeger.properties b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/resources/jaeger.properties new file mode 100644 index 0000000000..1347748a5f --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-jaeger/src/test/resources/jaeger.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +eventmesh.trace.jaeger.ip=localhost +eventmesh.trace.jaeger.port=14250 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/build.gradle b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/build.gradle new file mode 100644 index 0000000000..fcb492d692 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/build.gradle @@ -0,0 +1,50 @@ +/* + * 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. + */ + +def pinpointVersion = "3.0.0" + +dependencies { + implementation project(":eventmesh-trace-plugin:eventmesh-trace-api") + implementation project(":eventmesh-common") + implementation 'org.slf4j:slf4j-api' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + implementation 'io.opentelemetry:opentelemetry-api' + implementation 'io.opentelemetry:opentelemetry-semconv' + implementation 'io.opentelemetry:opentelemetry-sdk' + + implementation("com.navercorp.pinpoint:pinpoint-profiler:${pinpointVersion}") { + exclude group: 'org.apache.thrift', module: 'libthrift' + exclude group: 'com.navercorp.pinpoint', module: 'pinpoint-thrift' + exclude group: 'com.navercorp.pinpoint', module: 'pinpoint-plugins-loader' + exclude group: 'com.navercorp.pinpoint', module: 'pinpoint-profiler-logging' + exclude group: 'io.grpc', module: 'grpc-protobuf' + exclude group: 'io.grpc', module: 'grpc-stub' + exclude group: 'io.grpc', module: 'grpc-netty' + exclude group: 'io.grpc', module: 'grpc-netty-shaded' + } + + // grpc + implementation "io.grpc:grpc-protobuf" + implementation "io.grpc:grpc-stub" + implementation "io.grpc:grpc-netty" + implementation "io.grpc:grpc-netty-shaded" + + testImplementation "org.mockito:mockito-inline" +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/gradle.properties b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/gradle.properties new file mode 100644 index 0000000000..718a1c8ca3 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/gradle.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +pluginType=trace +pluginName=pinpoint \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/PinpointTraceService.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/PinpointTraceService.java new file mode 100644 index 0000000000..7513574e64 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/PinpointTraceService.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint; + +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.trace.api.AbstractTraceService; +import org.apache.eventmesh.trace.api.exception.TraceException; +import org.apache.eventmesh.trace.pinpoint.config.PinpointConfiguration; +import org.apache.eventmesh.trace.pinpoint.exporter.PinpointSpanExporter; + +import java.util.concurrent.TimeUnit; + +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; + +import lombok.Getter; +import lombok.Setter; + +/** + * https://github.com/pinpoint-apm/pinpoint + */ +@Config(field = "pinpointConfiguration") +@Config(field = "exporterConfiguration") +public class PinpointTraceService extends AbstractTraceService { + + /** + * Unified configuration class corresponding to pinpoint.properties + */ + @Getter + @Setter + private transient PinpointConfiguration pinpointConfiguration; + + @Override + public void init() throws TraceException { + final long eventMeshTraceExportInterval = exporterConfiguration.getEventMeshTraceExportInterval(); + final long eventMeshTraceExportTimeout = exporterConfiguration.getEventMeshTraceExportTimeout(); + final int eventMeshTraceMaxExportSize = exporterConfiguration.getEventMeshTraceMaxExportSize(); + final int eventMeshTraceMaxQueueSize = exporterConfiguration.getEventMeshTraceMaxQueueSize(); + + SpanProcessor spanProcessor = BatchSpanProcessor.builder( + new PinpointSpanExporter( + pinpointConfiguration.getAgentId(), + pinpointConfiguration.getAgentName(), + pinpointConfiguration.getApplicationName(), + pinpointConfiguration.getGrpcTransportConfig())) + .setScheduleDelay(eventMeshTraceExportInterval, TimeUnit.SECONDS) + .setExporterTimeout(eventMeshTraceExportTimeout, TimeUnit.SECONDS) + .setMaxExportBatchSize(eventMeshTraceMaxExportSize) + .setMaxQueueSize(eventMeshTraceMaxQueueSize) + .build(); + + initVars(spanProcessor, null); + } + + public PinpointConfiguration getClientConfiguration() { + return this.pinpointConfiguration; + } + +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/common/PinpointConstants.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/common/PinpointConstants.java new file mode 100644 index 0000000000..c704a0e879 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/common/PinpointConstants.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint.common; + +public class PinpointConstants { + + public static final String REQ_IP = "req0ip"; + + public static final String UNKNOWN_REQ_IP = "unknown"; +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/config/PinpointConfiguration.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/config/PinpointConfiguration.java new file mode 100644 index 0000000000..dd29412521 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/config/PinpointConfiguration.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint.config; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; +import org.apache.eventmesh.common.exception.JsonException; +import org.apache.eventmesh.common.utils.RandomStringUtils; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Properties; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.navercorp.pinpoint.profiler.context.grpc.config.GrpcTransportConfig; + +import lombok.Data; + +@Data +@Config(prefix = "eventmesh.trace.pinpoint", path = "classPath://pinpoint.properties") +public final class PinpointConfiguration { + + @ConfigField(field = "agentId", reload = true) + private String agentId; + + @ConfigField(field = "agentName", reload = true) + private String agentName; + + @ConfigField(field = "applicationName", findEnv = true, notNull = true) + private String applicationName; + + @ConfigField(field = "", reload = true) + private Properties grpcTransportProperties; + + private GrpcTransportConfig grpcTransportConfig; + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + public void reload() { + if (StringUtils.isBlank(agentName)) { + agentName = applicationName; + } + + if (StringUtils.isBlank(agentId)) { + // refer to: com.navercorp.pinpoint.common.util.IdValidateUtils#validateId + agentId = StringUtils.substring(agentName, 0, 15) + + Constants.HYPHEN + + RandomStringUtils.generateNum(8); + } + + // Map to Pinpoint property configuration. + grpcTransportConfig = convertValue(grpcTransportProperties, GrpcTransportConfig.class); + } + + public static T convertValue(Object fromValue, Class toValueType) { + try { + return OBJECT_MAPPER.convertValue(fromValue, toValueType); + } catch (IllegalArgumentException e) { + throw new JsonException("convertValue fromValue to toValueType instance error", e); + } + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/exporter/PinpointSpanExporter.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/exporter/PinpointSpanExporter.java new file mode 100644 index 0000000000..61186c3062 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/java/org/apache/eventmesh/trace/pinpoint/exporter/PinpointSpanExporter.java @@ -0,0 +1,426 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint.exporter; + +import static org.apache.eventmesh.trace.pinpoint.common.PinpointConstants.REQ_IP; +import static org.apache.eventmesh.trace.pinpoint.common.PinpointConstants.UNKNOWN_REQ_IP; + +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import org.apache.eventmesh.common.Constants; +import org.apache.eventmesh.common.utils.IPUtils; +import org.apache.eventmesh.common.utils.JsonUtils; +import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; + +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import org.mapstruct.factory.Mappers; + +import io.grpc.NameResolverProvider; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.internal.OtelEncodingUtils; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.internal.ThrottlingLogger; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; + +import com.navercorp.pinpoint.bootstrap.context.SpanId; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.common.profiler.util.TransactionIdUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.SystemPropertyKey; +import com.navercorp.pinpoint.grpc.AgentHeaderFactory; +import com.navercorp.pinpoint.grpc.client.ChannelFactory; +import com.navercorp.pinpoint.grpc.client.ChannelFactoryBuilder; +import com.navercorp.pinpoint.grpc.client.DefaultChannelFactoryBuilder; +import com.navercorp.pinpoint.grpc.client.HeaderFactory; +import com.navercorp.pinpoint.profiler.AgentInfoSender; +import com.navercorp.pinpoint.profiler.JvmInformation; +import com.navercorp.pinpoint.profiler.context.DefaultServerMetaDataRegistryService; +import com.navercorp.pinpoint.profiler.context.DefaultSpanFactory; +import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.annotation.Annotations; +import com.navercorp.pinpoint.profiler.context.compress.GrpcSpanProcessorV2; +import com.navercorp.pinpoint.profiler.context.grpc.GrpcAgentInfoMessageConverter; +import com.navercorp.pinpoint.profiler.context.grpc.GrpcSpanMessageConverter; +import com.navercorp.pinpoint.profiler.context.grpc.config.GrpcTransportConfig; +import com.navercorp.pinpoint.profiler.context.grpc.config.SpanAutoUriGetter; +import com.navercorp.pinpoint.profiler.context.grpc.config.SpanUriGetter; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.AgentInfoMapper; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.AgentInfoMapperImpl; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.AnnotationValueMapper; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.JvmGcTypeMapper; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.JvmGcTypeMapperImpl; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.SpanMessageMapper; +import com.navercorp.pinpoint.profiler.context.grpc.mapper.SpanMessageMapperImpl; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceIdFactory; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRootFactory; +import com.navercorp.pinpoint.profiler.context.id.TraceIdFactory; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.id.TraceRootFactory; +import com.navercorp.pinpoint.profiler.context.provider.AgentInformationProvider; +import com.navercorp.pinpoint.profiler.context.provider.grpc.DnsExecutorServiceProvider; +import com.navercorp.pinpoint.profiler.context.provider.grpc.GrpcNameResolverProvider; +import com.navercorp.pinpoint.profiler.context.provider.grpc.SSLContextProvider; +import com.navercorp.pinpoint.profiler.metadata.MetaDataType; +import com.navercorp.pinpoint.profiler.monitor.metric.gc.JvmGcType; +import com.navercorp.pinpoint.profiler.receiver.ProfilerCommandLocatorBuilder; +import com.navercorp.pinpoint.profiler.sender.grpc.AgentGrpcDataSender; +import com.navercorp.pinpoint.profiler.sender.grpc.ReconnectExecutor; +import com.navercorp.pinpoint.profiler.sender.grpc.SimpleStreamState; +import com.navercorp.pinpoint.profiler.sender.grpc.SpanGrpcDataSender; +import com.navercorp.pinpoint.profiler.sender.grpc.StreamState; +import com.navercorp.pinpoint.profiler.util.AgentInfoFactory; + +public final class PinpointSpanExporter implements SpanExporter { + + private static final ThrottlingLogger THROTTLING_LOGGER = + new ThrottlingLogger(Logger.getLogger(PinpointSpanExporter.class.getName())); + + private static final String AGENT_CHANNEL_FACTORY = "agentChannelFactory"; + private static final String SPAN_CHANNEL_FACTORY = "spanChannelFactory"; + + private final long agentStartTime = System.currentTimeMillis(); + + private final ScheduledExecutorService scheduledExecutorService = + Executors.newSingleThreadScheduledExecutor(); + + private final ReconnectExecutor reconnectExecutor = + new ReconnectExecutor(scheduledExecutorService); + + private final NameResolverProvider nameResolverProvider = + new GrpcNameResolverProvider(new DnsExecutorServiceProvider()).get(); + + private final String agentId; + + private final String agentName; + + private final String applicationName; + + private final GrpcTransportConfig grpcTransportConfig; + private final SSLContextProvider sslContextProvider; + + private final HeaderFactory headerFactory; + + private final AgentInfoSender agentInfoSender; + + private final SpanGrpcDataSender spanGrpcDataSender; + + private final JvmGcTypeMapper jvmGcTypeMapper = new JvmGcTypeMapperImpl(); + private final AgentInfoMapper agentInfoMapper = new AgentInfoMapperImpl(jvmGcTypeMapper); + + private final SpanUriGetter spanUriGetter = new SpanAutoUriGetter(); + private final AnnotationValueMapper annotationValueMapper = Mappers.getMapper(AnnotationValueMapper.class); + private final SpanMessageMapper spanMessageMapper = new SpanMessageMapperImpl(annotationValueMapper, spanUriGetter); + + public PinpointSpanExporter(final String agentId, + final String agentName, + final String applicationName, + final GrpcTransportConfig grpcTransportConfig) { + + this.agentId = Objects.requireNonNull(agentId, "agentId cannot be null"); + this.agentName = Objects.requireNonNull(agentName, "agentName cannot be null"); + this.applicationName = Objects.requireNonNull(applicationName, "applicationName cannot be null"); + this.grpcTransportConfig = Objects.requireNonNull(grpcTransportConfig, "grpcTransportConfig cannot be null"); + + if (grpcTransportConfig.getSslOption() != null) { + this.sslContextProvider = new SSLContextProvider(grpcTransportConfig); + } else { + this.sslContextProvider = null; + } + + this.headerFactory = new AgentHeaderFactory( + agentId, + agentName, + applicationName, + ServiceType.UNDEFINED.getCode(), + agentStartTime); + + this.agentInfoSender = createAgentInfoSender(); + this.agentInfoSender.start(); + + this.spanGrpcDataSender = createSpanGrpcDataSender(); + } + + private AgentInfoSender createAgentInfoSender() { + final ChannelFactory agentChannelFactory = createAgentChannelFactory(); + + final AgentGrpcDataSender agentGrpcDataSender = + new AgentGrpcDataSender<>( + grpcTransportConfig.getAgentCollectorIp(), + grpcTransportConfig.getAgentCollectorPort(), + grpcTransportConfig.getAgentSenderExecutorQueueSize(), + new GrpcAgentInfoMessageConverter(agentInfoMapper), + reconnectExecutor, + scheduledExecutorService, + agentChannelFactory, + new ProfilerCommandLocatorBuilder().build()); + + final AgentInformationProvider agentInformationProvider = + new AgentInformationProvider( + agentId, + agentName, + applicationName, + true, + agentStartTime, + ServiceType.STAND_ALONE); + + final JvmInformation jvmInformation = new JvmInformation( + JvmUtils.getSystemProperty(SystemPropertyKey.JAVA_VERSION), + JvmGcType.UNKNOWN); + + final ServerMetaDataRegistryService serverMetaDataRegistryService = new DefaultServerMetaDataRegistryService( + Collections.emptyList()); + serverMetaDataRegistryService.setServerName(EventMeshTraceConstants.SERVICE_NAME); + + final AgentInfoFactory agentInfoFactory = new AgentInfoFactory( + agentInformationProvider.createAgentInformation(), + serverMetaDataRegistryService, + jvmInformation); + + return new AgentInfoSender.Builder(agentGrpcDataSender, agentInfoFactory).build(); + } + + private SpanGrpcDataSender createSpanGrpcDataSender() { + final ChannelFactory spanChannelFactory = createSpanChannelFactory(); + + final GrpcSpanMessageConverter messageConverter = + new GrpcSpanMessageConverter( + agentId, + ServiceType.STAND_ALONE.getCode(), + new GrpcSpanProcessorV2(), + this.spanMessageMapper); + + final StreamState streamState = + new SimpleStreamState( + grpcTransportConfig.getSpanClientOption().getLimitCount(), + grpcTransportConfig.getSpanClientOption().getLimitTime()); + + return new SpanGrpcDataSender( + grpcTransportConfig.getSpanCollectorIp(), + grpcTransportConfig.getSpanCollectorPort(), + grpcTransportConfig.getSpanSenderExecutorQueueSize(), + messageConverter, + reconnectExecutor, + spanChannelFactory, + streamState, + grpcTransportConfig.getSpanRpcMaxAgeMillis()); + } + + private ChannelFactory createAgentChannelFactory() { + final ChannelFactoryBuilder channelFactoryBuilder = new DefaultChannelFactoryBuilder(AGENT_CHANNEL_FACTORY); + channelFactoryBuilder.setHeaderFactory(headerFactory); + channelFactoryBuilder.setNameResolverProvider(nameResolverProvider); + if (this.sslContextProvider != null) { + channelFactoryBuilder.setSslContext(this.sslContextProvider.get()); + } + channelFactoryBuilder.setClientOption(grpcTransportConfig.getAgentClientOption()); + channelFactoryBuilder.setExecutorQueueSize(grpcTransportConfig.getAgentChannelExecutorQueueSize()); + + return channelFactoryBuilder.build(); + } + + private ChannelFactory createSpanChannelFactory() { + final ChannelFactoryBuilder channelFactoryBuilder = new DefaultChannelFactoryBuilder(SPAN_CHANNEL_FACTORY); + channelFactoryBuilder.setHeaderFactory(headerFactory); + channelFactoryBuilder.setNameResolverProvider(nameResolverProvider); + if (this.sslContextProvider != null) { + channelFactoryBuilder.setSslContext(this.sslContextProvider.get()); + } + channelFactoryBuilder.setClientOption(grpcTransportConfig.getSpanClientOption()); + channelFactoryBuilder.setExecutorQueueSize(grpcTransportConfig.getSpanChannelExecutorQueueSize()); + + return channelFactoryBuilder.build(); + } + + @Override + public CompletableResultCode export(final Collection spans) { + if (spans.isEmpty()) { + return CompletableResultCode.ofSuccess(); + } + for (final SpanData spanData : spans) { + if (spanData == null) { + continue; + } + try { + if (!spanGrpcDataSender.send(toSpan(spanData))) { + return CompletableResultCode.ofFailure(); + } + } catch (Exception e) { + THROTTLING_LOGGER.log(Level.WARNING, "Failed to export span", e); + return CompletableResultCode.ofFailure(); + } + } + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + agentInfoSender.stop(); + spanGrpcDataSender.stop(); + try { + scheduledExecutorService.shutdown(); + } catch (Exception ignored) { + // ignored + } + try { + reconnectExecutor.close(); + } catch (Exception ignored) { + // ignored + } + return CompletableResultCode.ofSuccess(); + } + + private Span toSpan(final SpanData spanData) { + final long startTimestamp = toMillis(spanData.getStartEpochNanos()); + final long transactionId = hex32StringToLong(spanData.getTraceId()); + final long spanId = hex16StringToLong(spanData.getSpanId()); + final long[] parentSpanId = {SpanId.NULL}; + + Optional.ofNullable(spanData.getParentSpanContext()).ifPresent(parentSpanContext -> { + if (parentSpanContext.isValid()) { + parentSpanId[0] = hex16StringToLong(parentSpanContext.getSpanId()); + } + }); + + final TraceIdFactory traceIdFactory = new DefaultTraceIdFactory(this.agentId, startTimestamp); + final TraceRootFactory traceRootFactory = new DefaultTraceRootFactory(this.agentId, traceIdFactory); + + final TraceRoot traceRoot; + if (parentSpanId[0] == SpanId.NULL) { + traceRoot = traceRootFactory.newTraceRoot(transactionId); + } else { + final TraceId traceId = traceIdFactory.continueTraceId( + TransactionIdUtils.formatString(this.agentId, startTimestamp, transactionId), parentSpanId[0], + spanId, (short) spanData.getKind().ordinal()); + traceRoot = traceRootFactory.continueTraceRoot(traceId, transactionId); + } + + final DefaultSpanFactory spanFactory = new DefaultSpanFactory(); + final Span span = spanFactory.newSpan(traceRoot); + + final StatusData statusData = spanData.getStatus(); + if (statusData != null) { + Optional.ofNullable(traceRoot.getShared()).ifPresent(shared -> { + shared.setRpcName(spanData.getName()); + shared.setEndPoint(getEndpoint(spanData.getResource())); + if (!StatusCode.OK.equals(statusData.getStatusCode())) { + shared.maskErrorCode(statusData.getStatusCode().ordinal()); + span.setExceptionInfo(statusData.getStatusCode().ordinal(), statusData.getDescription()); + } + }); + } + + span.setStartTime(startTimestamp); + final long endTimestamp = toMillis(spanData.getEndEpochNanos()); + span.setElapsedTime((int) (endTimestamp - startTimestamp)); + span.setServiceType(ServiceType.STAND_ALONE.getCode()); + span.setRemoteAddr(UNKNOWN_REQ_IP); + + Optional.ofNullable(spanData.getAttributes()) + .ifPresent(attributes -> { + span.addAnnotation(Annotations.of(AnnotationKey.HTTP_PARAM_ENTITY.getCode(), + JsonUtils.toJSONString(attributes))); + attributes.forEach((key, value) -> { + if (REQ_IP.equals(key.getKey())) { + span.setRemoteAddr(String.valueOf(value)); + } + }); + }); + + if (CollectionUtils.isNotEmpty(spanData.getEvents())) { + final AtomicInteger sequence = new AtomicInteger(); + span.setSpanEventList(spanData.getEvents().stream().map(event -> { + final SpanEvent spanEvent = toSpanEvent(event); + spanEvent.setSequence(sequence.getAndIncrement()); + return spanEvent; + }).collect(Collectors.toList())); + } + + return span; + } + + private SpanEvent toSpanEvent(final EventData eventData) { + final SpanEvent spanEvent = new SpanEvent(); + spanEvent.setServiceType(ServiceType.INTERNAL_METHOD.getCode()); + spanEvent.setEndPoint(eventData.getName()); + spanEvent.addAnnotation(Annotations.of(AnnotationKey.HTTP_PARAM_ENTITY.getCode(), + JsonUtils.toJSONString(eventData.getAttributes()))); + spanEvent.setElapsedTime((int) toMillis(eventData.getEpochNanos())); + return spanEvent; + } + + private static long toMillis(final long epochNanos) { + return NANOSECONDS.toMillis(epochNanos); + } + + private static long hex32StringToLong(final String hex32String) { + final CharSequence charSequence = new StringBuilder().append(hex32String); + return OtelEncodingUtils.isValidBase16String(charSequence) + ? OtelEncodingUtils.longFromBase16String(charSequence, 0) + & OtelEncodingUtils.longFromBase16String(charSequence, 16) + : hex32String.hashCode(); + } + + private static long hex16StringToLong(final String hex16String) { + final CharSequence charSequence = new StringBuilder().append(hex16String); + return OtelEncodingUtils.isValidBase16String(charSequence) + ? OtelEncodingUtils.longFromBase16String(charSequence, 0) + : hex16String.hashCode(); + } + + private static String getEndpoint(final Resource resource) { + if (resource == null) { + return null; + } + + final Attributes resourceAttributes = resource.getAttributes(); + Objects.requireNonNull(resourceAttributes, "resourceAttributes can not be null"); + + String serviceNameValue = resourceAttributes.get(ResourceAttributes.SERVICE_NAME); + if (serviceNameValue == null) { + serviceNameValue = Resource.getDefault().getAttributes().get(ResourceAttributes.SERVICE_NAME); + } + return serviceNameValue + Constants.POUND + IPUtils.getLocalAddress(); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.trace.api.EventMeshTraceService b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.trace.api.EventMeshTraceService new file mode 100644 index 0000000000..db985f0c8c --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.trace.api.EventMeshTraceService @@ -0,0 +1,16 @@ +# 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. + +pinpoint=org.apache.eventmesh.trace.pinpoint.PinpointTraceService \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/resources/pinpoint.properties b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/resources/pinpoint.properties new file mode 100644 index 0000000000..daf141e331 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/main/resources/pinpoint.properties @@ -0,0 +1,31 @@ +# +# 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. +# + +eventmesh.trace.pinpoint.agentId= +eventmesh.trace.pinpoint.agentName= +eventmesh.trace.pinpoint.applicationName= + +# pinpoint client property configuration, please refer to: +# com.navercorp.pinpoint.profiler.context.grpc.config.GrpcTransportConfig +# +# All properties need to contain the same prefix: eventmesh.trace.pinpoint. +# +eventmesh.trace.pinpoint.agentCollectorIp=127.0.0.1 +eventmesh.trace.pinpoint.agentCollectorPort=9991 + +eventmesh.trace.pinpoint.spanCollectorIp=127.0.0.1 +eventmesh.trace.pinpoint.spanCollectorPort=9993 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/PinpointTraceServiceTest.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/PinpointTraceServiceTest.java new file mode 100644 index 0000000000..2fba35b589 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/PinpointTraceServiceTest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.apache.eventmesh.common.utils.ReflectUtils; +import org.apache.eventmesh.trace.api.TracePluginFactory; + +import java.lang.reflect.Field; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.opentelemetry.sdk.trace.SdkTracerProvider; + +public class PinpointTraceServiceTest { + + @Test + public void testInit() { + PinpointTraceService pinpointTraceService = + (PinpointTraceService) TracePluginFactory.getEventMeshTraceService("pinpoint"); + pinpointTraceService.init(); + + IllegalArgumentException illegalArgumentException = + assertThrows(IllegalArgumentException.class, () -> Runtime.getRuntime().addShutdownHook(pinpointTraceService.getShutdownHook())); + Assertions.assertEquals(illegalArgumentException.getMessage(), "Hook previously registered"); + } + + @Test + public void testShutdown() throws Exception { + PinpointTraceService pinpointTraceService = + (PinpointTraceService) TracePluginFactory.getEventMeshTraceService("pinpoint"); + pinpointTraceService.init(); + Field sdkTracerProviderField = null; + try { + sdkTracerProviderField = PinpointTraceService.class.getDeclaredField("sdkTracerProvider"); + } catch (NoSuchFieldException e) { + sdkTracerProviderField = ReflectUtils.lookUpFieldByParentClass(PinpointTraceService.class, "sdkTracerProvider"); + if (sdkTracerProviderField == null) { + throw e; + } + } + sdkTracerProviderField.setAccessible(true); + SdkTracerProvider mockSdkTracerProvider = Mockito.mock(SdkTracerProvider.class); + sdkTracerProviderField.set(pinpointTraceService, mockSdkTracerProvider); + + pinpointTraceService.shutdown(); + Mockito.verify(mockSdkTracerProvider, Mockito.times(1)).close(); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/config/PinpointConfigurationTest.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/config/PinpointConfigurationTest.java new file mode 100644 index 0000000000..f2dc0d46b9 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/config/PinpointConfigurationTest.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint.config; + +import org.apache.eventmesh.trace.api.TracePluginFactory; +import org.apache.eventmesh.trace.api.config.ExporterConfiguration; +import org.apache.eventmesh.trace.pinpoint.PinpointTraceService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.navercorp.pinpoint.profiler.context.grpc.config.GrpcTransportConfig; + +public class PinpointConfigurationTest { + + @Test + public void getConfigWhenPinpointTraceInit() { + PinpointTraceService pinpointTrace = + (PinpointTraceService) TracePluginFactory.getEventMeshTraceService("pinpoint"); + + PinpointConfiguration config = pinpointTrace.getClientConfiguration(); + assertClientConfig(config); + ExporterConfiguration exporterConfig = pinpointTrace.getExporterConfiguration(); + assertBaseConfig(exporterConfig); + } + + private void assertClientConfig(PinpointConfiguration config) { + Assertions.assertEquals("eventmesh", config.getApplicationName()); + Assertions.assertEquals("eventmesh", config.getAgentName()); + Assertions.assertEquals("eventmesh-01", config.getAgentId()); + + GrpcTransportConfig grpcTransportConfig = config.getGrpcTransportConfig(); + Assertions.assertNotNull(grpcTransportConfig); + Assertions.assertEquals("127.0.0.1", grpcTransportConfig.getAgentCollectorIp()); + Assertions.assertEquals(9991, grpcTransportConfig.getAgentCollectorPort()); + Assertions.assertEquals("localhost", grpcTransportConfig.getSpanCollectorIp()); + Assertions.assertEquals(9993, grpcTransportConfig.getSpanCollectorPort()); + + Assertions.assertEquals(123, grpcTransportConfig.getSpanClientOption().getLimitCount()); + Assertions.assertEquals(6700, grpcTransportConfig.getSpanClientOption().getLimitTime()); + } + + private void assertBaseConfig(ExporterConfiguration config) { + Assertions.assertEquals(816, config.getEventMeshTraceMaxExportSize()); + Assertions.assertEquals(1816, config.getEventMeshTraceMaxQueueSize()); + Assertions.assertEquals(2816, config.getEventMeshTraceExportTimeout()); + Assertions.assertEquals(3816, config.getEventMeshTraceExportInterval()); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/exporter/PinpointSpanExporterTest.java b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/exporter/PinpointSpanExporterTest.java new file mode 100644 index 0000000000..6ae974825d --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/java/org/apache/eventmesh/trace/pinpoint/exporter/PinpointSpanExporterTest.java @@ -0,0 +1,290 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.pinpoint.exporter; + +import org.apache.eventmesh.common.utils.RandomStringUtils; +import org.apache.eventmesh.trace.api.TracePluginFactory; +import org.apache.eventmesh.trace.pinpoint.PinpointTraceService; +import org.apache.eventmesh.trace.pinpoint.config.PinpointConfiguration; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.data.StatusData; + +public class PinpointSpanExporterTest { + + private PinpointSpanExporter exporter; + public static final String AGENT_ID = "test"; + + @BeforeEach + public void setup() { + PinpointTraceService pinpointTrace = + (PinpointTraceService) TracePluginFactory.getEventMeshTraceService("pinpoint"); + + PinpointConfiguration config = pinpointTrace.getClientConfiguration(); + + this.exporter = new PinpointSpanExporter( + config.getAgentId(), + config.getAgentName(), + config.getApplicationName(), + config.getGrpcTransportConfig()); + } + + @Test + public void exportTest() { + Collection spans = new ArrayList<>(); + Assertions.assertEquals(CompletableResultCode.ofSuccess(), exporter.export(spans)); + + spans.add(null); + Assertions.assertEquals(CompletableResultCode.ofSuccess(), exporter.export(spans)); + + spans.clear(); + spans.add(new SpanDateTest()); + Assertions.assertEquals(CompletableResultCode.ofSuccess(), exporter.export(spans)); + + spans.clear(); + spans.add(new SpanDateTest()); + spans.add(new ChildSpanDateTest()); + Assertions.assertEquals(CompletableResultCode.ofSuccess(), exporter.export(spans)); + } + + @Test + public void flushTest() { + Assertions.assertEquals(CompletableResultCode.ofSuccess(), exporter.flush()); + } + + @Test + public void shutdownTest() { + Assertions.assertEquals(CompletableResultCode.ofSuccess(), exporter.shutdown()); + } + + /** + * for test + */ + private static class SpanDateTest implements SpanData { + + @Override + public SpanContext getSpanContext() { + return new SpanContextTest(); + } + + @Override + public SpanContext getParentSpanContext() { + return null; + } + + @Override + public Resource getResource() { + return null; + } + + @Override + public InstrumentationLibraryInfo getInstrumentationLibraryInfo() { + return null; + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public SpanKind getKind() { + return SpanKind.INTERNAL; + } + + @Override + public long getStartEpochNanos() { + return System.nanoTime(); + } + + @Override + public Attributes getAttributes() { + return null; + } + + @Override + public List getEvents() { + return null; + } + + @Override + public List getLinks() { + return null; + } + + @Override + public StatusData getStatus() { + return StatusData.ok(); + } + + @Override + public long getEndEpochNanos() { + return System.nanoTime(); + } + + @Override + public boolean hasEnded() { + return true; + } + + @Override + public int getTotalRecordedEvents() { + return 0; + } + + @Override + public int getTotalRecordedLinks() { + return 0; + } + + @Override + public int getTotalAttributeCount() { + return 0; + } + } + + private static class ChildSpanDateTest implements SpanData { + + @Override + public SpanContext getSpanContext() { + return new SpanContextTest(); + } + + @Override + public SpanContext getParentSpanContext() { + return new SpanContextTest(); + } + + @Override + public Resource getResource() { + return null; + } + + @Override + public InstrumentationLibraryInfo getInstrumentationLibraryInfo() { + return null; + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public SpanKind getKind() { + return SpanKind.INTERNAL; + } + + @Override + public long getStartEpochNanos() { + return System.nanoTime(); + } + + @Override + public Attributes getAttributes() { + return null; + } + + @Override + public List getEvents() { + return null; + } + + @Override + public List getLinks() { + return null; + } + + @Override + public StatusData getStatus() { + return StatusData.ok(); + } + + @Override + public long getEndEpochNanos() { + return System.nanoTime(); + } + + @Override + public boolean hasEnded() { + return true; + } + + @Override + public int getTotalRecordedEvents() { + return 0; + } + + @Override + public int getTotalRecordedLinks() { + return 0; + } + + @Override + public int getTotalAttributeCount() { + return 0; + } + } + + private static class SpanContextTest implements SpanContext { + + @Override + public String getTraceId() { + return UUID.randomUUID().toString(); + } + + @Override + public String getSpanId() { + return RandomStringUtils.generateNum(16); + } + + @Override + public TraceFlags getTraceFlags() { + return null; + } + + @Override + public TraceState getTraceState() { + return TraceState.getDefault(); + } + + @Override + public boolean isRemote() { + return false; + } + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/resources/exporter.properties b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/resources/exporter.properties new file mode 100644 index 0000000000..14f6980df0 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/resources/exporter.properties @@ -0,0 +1,20 @@ +# +# 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. +# +eventmesh.trace.max.export.size=816 +eventmesh.trace.max.queue.size=1816 +eventmesh.trace.export.timeout=2816 +eventmesh.trace.export.interval=3816 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/resources/pinpoint.properties b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/resources/pinpoint.properties new file mode 100644 index 0000000000..7c8e790145 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-pinpoint/src/test/resources/pinpoint.properties @@ -0,0 +1,32 @@ +# +# 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. +# + +eventmesh.trace.pinpoint.agentId=eventmesh-01 +eventmesh.trace.pinpoint.agentName=eventmesh +eventmesh.trace.pinpoint.applicationName=eventmesh + +# pinpoint client property configuration, please refer to: +# com.navercorp.pinpoint.profiler.context.grpc.config.GrpcTransportConfig +eventmesh.trace.pinpoint.agentCollectorIp=127.0.0.1 +eventmesh.trace.pinpoint.agentCollectorPort=9991 + +eventmesh.trace.pinpoint.spanCollectorIp=localhost +eventmesh.trace.pinpoint.spanCollectorPort=9993 + +# for test +eventmesh.trace.pinpoint.spanClientOption.limitCount=123 +eventmesh.trace.pinpoint.spanClientOption.limitTime=6700 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/build.gradle b/eventmesh-trace-plugin/eventmesh-trace-zipkin/build.gradle index 7daff5d46f..d687bb609c 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-zipkin/build.gradle +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/build.gradle @@ -25,11 +25,10 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-exporter-zipkin' implementation 'io.opentelemetry:opentelemetry-semconv' - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' - testImplementation "org.mockito:mockito-core" + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' testImplementation "org.mockito:mockito-inline" -} \ No newline at end of file +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceService.java b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceService.java index c6426b30cf..ed98b5a3b0 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceService.java +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceService.java @@ -19,70 +19,55 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; -import org.apache.eventmesh.trace.api.EventMeshTraceService; -import org.apache.eventmesh.trace.api.config.ExporterConfiguration; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.trace.api.AbstractTraceService; +import org.apache.eventmesh.trace.api.common.EventMeshTraceConstants; import org.apache.eventmesh.trace.api.exception.TraceException; import org.apache.eventmesh.trace.zipkin.common.ZipkinConstants; import org.apache.eventmesh.trace.zipkin.config.ZipkinConfiguration; -import java.util.Map; import java.util.concurrent.TimeUnit; -import javax.annotation.Nullable; - -import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.TextMapGetter; -import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.context.propagation.TextMapSetter; import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; -import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SpanProcessor; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import lombok.Getter; +import lombok.Setter; /** - * + * ZipkinTraceService */ -public class ZipkinTraceService implements EventMeshTraceService { - private String eventMeshZipkinIP; - private int eventMeshZipkinPort; - private int eventMeshTraceExportInterval; - private int eventMeshTraceExportTimeout; - private int eventMeshTraceMaxExportSize; - private int eventMeshTraceMaxQueueSize; - protected SdkTracerProvider sdkTracerProvider; - - protected OpenTelemetry openTelemetry; +@Config(field = "zipkinConfiguration") +@Config(field = "exporterConfiguration") +@Getter +@Setter +public class ZipkinTraceService extends AbstractTraceService { - protected Thread shutdownHook; + /** + * Unified configuration class corresponding to zipkin.properties + */ + private transient ZipkinConfiguration zipkinConfiguration; - private Tracer tracer; - private TextMapPropagator textMapPropagator; + private transient ZipkinSpanExporter zipkinExporter; @Override public void init() { - //zipkin's config - eventMeshZipkinIP = ZipkinConfiguration.getEventMeshZipkinIP(); - eventMeshZipkinPort = ZipkinConfiguration.getEventMeshZipkinPort(); - //exporter's config - eventMeshTraceExportInterval = ExporterConfiguration.getEventMeshTraceExportInterval(); - eventMeshTraceExportTimeout = ExporterConfiguration.getEventMeshTraceExportTimeout(); - eventMeshTraceMaxExportSize = ExporterConfiguration.getEventMeshTraceMaxExportSize(); - eventMeshTraceMaxQueueSize = ExporterConfiguration.getEventMeshTraceMaxQueueSize(); - - String httpUrl = String.format("http://%s:%s", eventMeshZipkinIP, eventMeshZipkinPort); - ZipkinSpanExporter zipkinExporter = + // zipkin's config + final String eventMeshZipkinIP = zipkinConfiguration.getEventMeshZipkinIP(); + final int eventMeshZipkinPort = zipkinConfiguration.getEventMeshZipkinPort(); + + // exporter's config + final int eventMeshTraceExportInterval = exporterConfiguration.getEventMeshTraceExportInterval(); + final int eventMeshTraceExportTimeout = exporterConfiguration.getEventMeshTraceExportTimeout(); + final int eventMeshTraceMaxExportSize = exporterConfiguration.getEventMeshTraceMaxExportSize(); + final int eventMeshTraceMaxQueueSize = exporterConfiguration.getEventMeshTraceMaxQueueSize(); + + final String httpUrl = String.format("http://%s:%s", eventMeshZipkinIP, eventMeshZipkinPort); + zipkinExporter = ZipkinSpanExporter.builder().setEndpoint(httpUrl + ZipkinConstants.ENDPOINT_V2_SPANS).build(); - SpanProcessor spanProcessor = BatchSpanProcessor.builder(zipkinExporter) .setScheduleDelay(eventMeshTraceExportInterval, TimeUnit.SECONDS) .setExporterTimeout(eventMeshTraceExportTimeout, TimeUnit.SECONDS) @@ -90,81 +75,42 @@ public void init() { .setMaxQueueSize(eventMeshTraceMaxQueueSize) .build(); - //set the trace service's name - Resource serviceNameResource = - Resource.create(Attributes.of(stringKey("service.name"), ZipkinConstants.SERVICE_NAME)); - - sdkTracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(spanProcessor) - .setResource(Resource.getDefault().merge(serviceNameResource)) - .build(); - - openTelemetry = OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(sdkTracerProvider) - .build(); + // set the trace service's name + final Resource serviceNameResource = + Resource.create(Attributes.of(stringKey("service.name"), EventMeshTraceConstants.SERVICE_NAME)); - //TODO serviceName??? - tracer = openTelemetry.getTracer(ZipkinConstants.SERVICE_NAME); - textMapPropagator = openTelemetry.getPropagators().getTextMapPropagator(); - - shutdownHook = new Thread(sdkTracerProvider::close); - Runtime.getRuntime().addShutdownHook(shutdownHook); + initVars(spanProcessor, serviceNameResource); } @Override - public Context extractFrom(Context context, Map map) throws TraceException { - textMapPropagator.extract(context, map, new TextMapGetter>() { - @Override - public Iterable keys(Map carrier) { - return carrier.keySet(); - } + public void shutdown() throws TraceException { - @Override - public String get(Map carrier, String key) { - return carrier.get(key).toString(); + Exception ex = null; + + try { + if (sdkTracerProvider != null) { + sdkTracerProvider.close(); } - }); - return context; - } + } catch (Exception e) { + ex = e; + } - @Override - public void inject(Context context, Map map) { - textMapPropagator.inject(context, map, new TextMapSetter>() { - @Override - public void set(@Nullable Map carrier, String key, String value) { - map.put(key, value); + try { + if (zipkinExporter != null) { + zipkinExporter.close(); } - }); - } + } catch (Exception e) { + ex = e; + } - @Override - public Span createSpan(String spanName, SpanKind spanKind, long startTime, TimeUnit timeUnit, - Context context, boolean isSpanFinishInOtherThread) - throws TraceException { - return tracer.spanBuilder(spanName) - .setParent(context) - .setSpanKind(spanKind) - .setStartTimestamp(startTime, timeUnit) - .startSpan(); - } + if (ex != null) { + throw new TraceException("trace close error", ex); + } - @Override - public Span createSpan(String spanName, SpanKind spanKind, Context context, - boolean isSpanFinishInOtherThread) throws TraceException { - return tracer.spanBuilder(spanName) - .setParent(context) - .setSpanKind(spanKind) - .setStartTimestamp(System.currentTimeMillis(), TimeUnit.MILLISECONDS) - .startSpan(); + // todo: turn the value of useTrace in AbstractHTTPServer into false } - @Override - public void shutdown() { - //todo: check the spanProcessor if it was already close - - sdkTracerProvider.close(); - - //todo: turn the value of useTrace in AbstractHTTPServer into false + public ZipkinConfiguration getClientConfiguration() { + return this.zipkinConfiguration; } } diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/common/ZipkinConstants.java b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/common/ZipkinConstants.java index aa3ad33f1b..259fad4334 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/common/ZipkinConstants.java +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/common/ZipkinConstants.java @@ -18,11 +18,7 @@ package org.apache.eventmesh.trace.zipkin.common; public class ZipkinConstants { - // Name of the service(using the instrumentationName) - public static final String SERVICE_NAME = "eventmesh_trace"; + // Zipkin API Endpoints for uploading spans public static final String ENDPOINT_V2_SPANS = "/api/v2/spans"; - - public static final String KEY_ZIPKIN_IP = "eventmesh.trace.zipkin.ip"; - public static final String KEY_ZIPKIN_PORT = "eventmesh.trace.zipkin.port"; } diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfiguration.java b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfiguration.java index c567e9779d..ed24036878 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfiguration.java +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/main/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfiguration.java @@ -17,82 +17,22 @@ package org.apache.eventmesh.trace.zipkin.config; -import org.apache.eventmesh.common.Constants; -import org.apache.eventmesh.trace.zipkin.common.ZipkinConstants; +import org.apache.eventmesh.common.config.Config; +import org.apache.eventmesh.common.config.ConfigField; -import org.apache.commons.lang3.StringUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.Properties; - -import com.google.common.base.Preconditions; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; +import lombok.Data; /** * to load the properties form zipkin.properties */ -@Slf4j -@UtilityClass -public class ZipkinConfiguration { - private static final String CONFIG_FILE = "zipkin.properties"; - private static final Properties properties = new Properties(); +@Data +@Config(prefix = "eventmesh.trace.zipkin", path = "classPath://zipkin.properties") +public class ZipkinConfiguration { + @ConfigField(field = "ip", notNull = true) private String eventMeshZipkinIP = "localhost"; - private int eventMeshZipkinPort = 9411; - static { - loadProperties(); - initializeConfig(); - } - - public static String getEventMeshZipkinIP() { - return eventMeshZipkinIP; - } - - public static int getEventMeshZipkinPort() { - return eventMeshZipkinPort; - } - - private void initializeConfig() { - String eventMeshZipkinIPStr = properties.getProperty(ZipkinConstants.KEY_ZIPKIN_IP); - Preconditions.checkState(StringUtils.isNotEmpty(eventMeshZipkinIPStr), - String.format("%s error", ZipkinConstants.KEY_ZIPKIN_IP)); - eventMeshZipkinIP = StringUtils.deleteWhitespace(eventMeshZipkinIPStr); - - String eventMeshZipkinPortStr = properties.getProperty(ZipkinConstants.KEY_ZIPKIN_PORT); - if (StringUtils.isNotEmpty(eventMeshZipkinPortStr)) { - eventMeshZipkinPort = Integer.parseInt(StringUtils.deleteWhitespace(eventMeshZipkinPortStr)); - } - } - - private void loadProperties() { - URL resource = ZipkinConfiguration.class.getClassLoader().getResource(CONFIG_FILE); - if (resource != null) { - try (InputStream inputStream = resource.openStream()) { - if (inputStream.available() > 0) { - properties.load(new BufferedReader(new InputStreamReader(inputStream))); - } - } catch (IOException e) { - throw new RuntimeException("Load zipkin.properties file from classpath error"); - } - } - // get from config home - try { - String configPath = Constants.EVENTMESH_CONF_HOME + File.separator + CONFIG_FILE; - if (new File(configPath).exists()) { - properties.load(new BufferedReader(new FileReader(configPath))); - } - } catch (IOException e) { - throw new IllegalArgumentException("Cannot load zipkin.properties file from conf"); - } - } + @ConfigField(field = "port") + private int eventMeshZipkinPort = 9411; } diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/TracePluginFactoryTest.java b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/TracePluginFactoryTest.java new file mode 100644 index 0000000000..f648a1dca5 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/TracePluginFactoryTest.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.zipkin; + +import org.apache.eventmesh.trace.api.EventMeshTraceService; +import org.apache.eventmesh.trace.api.TracePluginFactory; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TracePluginFactoryTest { + + @Test + public void testFailedGetTraceService() { + NullPointerException nullPointerException1 = Assertions.assertThrows(NullPointerException.class, + () -> TracePluginFactory.getEventMeshTraceService(null)); + Assertions.assertEquals("traceServiceType cannot be null", nullPointerException1.getMessage()); + + String traceServiceType = "non-Existing"; + NullPointerException nullPointerException2 = + Assertions.assertThrows(NullPointerException.class, () -> TracePluginFactory.getEventMeshTraceService(traceServiceType)); + Assertions.assertEquals("traceServiceType: " + traceServiceType + " is not supported", nullPointerException2.getMessage()); + } + + @Test + public void testSuccessfulGetTraceService() { + EventMeshTraceService zipkinTraceService = TracePluginFactory.getEventMeshTraceService("zipkin"); + Assertions.assertNotNull(zipkinTraceService); + Assertions.assertTrue(zipkinTraceService instanceof ZipkinTraceService); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceServiceTest.java b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceServiceTest.java index ccb102e5c3..9025405497 100644 --- a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceServiceTest.java +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/ZipkinTraceServiceTest.java @@ -17,12 +17,15 @@ package org.apache.eventmesh.trace.zipkin; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.apache.eventmesh.common.utils.ReflectUtils; +import org.apache.eventmesh.trace.api.TracePluginFactory; import java.lang.reflect.Field; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import io.opentelemetry.sdk.trace.SdkTracerProvider; @@ -31,25 +34,35 @@ public class ZipkinTraceServiceTest { @Test public void testInit() { - ZipkinTraceService zipkinTraceService = new ZipkinTraceService(); + ZipkinTraceService zipkinTraceService = + (ZipkinTraceService) TracePluginFactory.getEventMeshTraceService("zipkin"); zipkinTraceService.init(); - Assert.assertNotNull(zipkinTraceService.sdkTracerProvider); - Assert.assertNotNull(zipkinTraceService.openTelemetry); - Assert.assertNotNull(zipkinTraceService.shutdownHook); + Assertions.assertNotNull(zipkinTraceService.getSdkTracerProvider()); + Assertions.assertNotNull(zipkinTraceService.getShutdownHook()); IllegalArgumentException illegalArgumentException = - assertThrows(IllegalArgumentException.class, () -> Runtime.getRuntime().addShutdownHook(zipkinTraceService.shutdownHook)); - Assert.assertEquals(illegalArgumentException.getMessage(), "Hook previously registered"); + assertThrows(IllegalArgumentException.class, + () -> Runtime.getRuntime().addShutdownHook(zipkinTraceService.getShutdownHook())); + Assertions.assertEquals(illegalArgumentException.getMessage(), "Hook previously registered"); } @Test public void testShutdown() throws Exception { - SdkTracerProvider mockSdkTracerProvider = Mockito.mock(SdkTracerProvider.class); - ZipkinTraceService zipkinTraceService = new ZipkinTraceService(); + ZipkinTraceService zipkinTraceService = + (ZipkinTraceService) TracePluginFactory.getEventMeshTraceService("zipkin"); zipkinTraceService.init(); - Field sdkTracerProviderField = ZipkinTraceService.class.getDeclaredField("sdkTracerProvider"); + Field sdkTracerProviderField = null; + try { + sdkTracerProviderField = ZipkinTraceService.class.getDeclaredField("sdkTracerProvider"); + } catch (NoSuchFieldException e) { + sdkTracerProviderField = ReflectUtils.lookUpFieldByParentClass(ZipkinTraceService.class, "sdkTracerProvider"); + if (sdkTracerProviderField == null) { + throw e; + } + } sdkTracerProviderField.setAccessible(true); + SdkTracerProvider mockSdkTracerProvider = Mockito.mock(SdkTracerProvider.class); sdkTracerProviderField.set(zipkinTraceService, mockSdkTracerProvider); zipkinTraceService.shutdown(); diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfigurationTest.java b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfigurationTest.java new file mode 100644 index 0000000000..3fb8e4e5f5 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/java/org/apache/eventmesh/trace/zipkin/config/ZipkinConfigurationTest.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.eventmesh.trace.zipkin.config; + +import org.apache.eventmesh.trace.api.TracePluginFactory; +import org.apache.eventmesh.trace.api.config.ExporterConfiguration; +import org.apache.eventmesh.trace.zipkin.ZipkinTraceService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ZipkinConfigurationTest { + + @Test + public void getConfigWhenZipkinTraceInit() { + ZipkinTraceService zipkinTraceService = + (ZipkinTraceService) TracePluginFactory.getEventMeshTraceService("zipkin"); + + ZipkinConfiguration config = zipkinTraceService.getClientConfiguration(); + assertConfig(config); + ExporterConfiguration exporterConfig = zipkinTraceService.getExporterConfiguration(); + assertBaseConfig(exporterConfig); + } + + private void assertConfig(ZipkinConfiguration config) { + Assertions.assertEquals("127.0.0.1", config.getEventMeshZipkinIP()); + Assertions.assertEquals(816, config.getEventMeshZipkinPort()); + } + + private void assertBaseConfig(ExporterConfiguration config) { + Assertions.assertEquals(816, config.getEventMeshTraceMaxExportSize()); + Assertions.assertEquals(1816, config.getEventMeshTraceMaxQueueSize()); + Assertions.assertEquals(2816, config.getEventMeshTraceExportTimeout()); + Assertions.assertEquals(3816, config.getEventMeshTraceExportInterval()); + } +} diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/resources/exporter.properties b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/resources/exporter.properties new file mode 100644 index 0000000000..14f6980df0 --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/resources/exporter.properties @@ -0,0 +1,20 @@ +# +# 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. +# +eventmesh.trace.max.export.size=816 +eventmesh.trace.max.queue.size=1816 +eventmesh.trace.export.timeout=2816 +eventmesh.trace.export.interval=3816 \ No newline at end of file diff --git a/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/resources/zipkin.properties b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/resources/zipkin.properties new file mode 100644 index 0000000000..e62cf9b02c --- /dev/null +++ b/eventmesh-trace-plugin/eventmesh-trace-zipkin/src/test/resources/zipkin.properties @@ -0,0 +1,20 @@ +# +# 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. +# + +#zipkin's working ip and port +eventmesh.trace.zipkin.ip=127.0.0.1 +eventmesh.trace.zipkin.port=816 \ No newline at end of file diff --git a/eventmesh-webhook/build.gradle b/eventmesh-webhook/build.gradle deleted file mode 100644 index 8d8657a4e6..0000000000 --- a/eventmesh-webhook/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -task copyEventMeshAdmin(dependsOn: ['jar']) { - doFirst { - new File(projectDir, '../eventmesh-webhook/dist/apps').mkdir() - new File(projectDir, '../dist/webhook/').mkdirs() - } - doLast { - copy { - into('../eventmesh-webhook/dist/apps/') - from project.jar.getArchivePath() - exclude { - "eventmesh-webhook-${version}.jar" - } - } - copy { - into '../dist/webhook' - from "../eventmesh-webhook/dist/apps/eventmesh-webhook-api.jar" - from "../eventmesh-webhook/dist/apps/eventmesh-webhook-admin.jar" - from "../eventmesh-webhook/dist/apps/eventmesh-webhook-receive.jar" - } - } -} diff --git a/eventmesh-webhook/eventmesh-webhook-admin/bin/.gitignore b/eventmesh-webhook/eventmesh-webhook-admin/bin/.gitignore deleted file mode 100644 index ddf9c65631..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-admin/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/main/ diff --git a/eventmesh-webhook/eventmesh-webhook-admin/build.gradle b/eventmesh-webhook/eventmesh-webhook-admin/build.gradle deleted file mode 100644 index af232747a0..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-admin/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -dependencies { - - implementation project(":eventmesh-common") - implementation project(":eventmesh-webhook:eventmesh-webhook-api") - - implementation 'org.slf4j:slf4j-api' - implementation "com.alibaba.nacos:nacos-client:2.0.4" - implementation "com.fasterxml.jackson.core:jackson-databind" - implementation "com.fasterxml.jackson.core:jackson-core" - implementation "com.fasterxml.jackson.core:jackson-annotations" - - testImplementation project(":eventmesh-webhook:eventmesh-webhook-api") - - -} diff --git a/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/AdminWebHookConfigOperationManage.java b/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/AdminWebHookConfigOperationManage.java deleted file mode 100644 index 84ecf7014a..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/AdminWebHookConfigOperationManage.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.admin; - -import org.apache.eventmesh.common.config.ConfigurationWrapper; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; -import org.apache.eventmesh.webhook.api.WebHookOperationConstant; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class AdminWebHookConfigOperationManage { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static final Map> map = new HashMap<>(); - - static { - map.put("file", FileWebHookConfigOperation.class); - map.put("nacos", NacosWebHookConfigOperation.class); - } - - private ConfigurationWrapper configurationWrapper; - - private WebHookConfigOperation webHookConfigOperation; - - public void setConfigurationWrapper(ConfigurationWrapper configurationWrapper) { - this.configurationWrapper = configurationWrapper; - } - - public WebHookConfigOperation getWebHookConfigOperation() { - return webHookConfigOperation; - } - - public void init() throws Exception { - - if (!configurationWrapper.getBoolProp(WebHookOperationConstant.ADMIN_START_CONFIG_NAME, false)) { - return; - } - - String operationMode = configurationWrapper.getProp(WebHookOperationConstant.OPERATION_MODE_CONFIG_NAME); - - if (!map.containsKey(operationMode)) { - throw new IllegalStateException("operationMode is not supported."); - } - - Constructor constructor = map.get(operationMode).getDeclaredConstructor(Properties.class); - constructor.setAccessible(true); - try { - Properties properties = configurationWrapper.getPropertiesByConfig("eventMesh.webHook." + operationMode + "Mode", true); - logger.info("operationMode is {} properties is {} ", operationMode, properties); - this.webHookConfigOperation = constructor.newInstance(properties); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - logger.error("can't find WebHookConfigOperation implementation"); - throw new Exception("can't find WebHookConfigOperation implementation"); - } - } -} diff --git a/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/FileWebHookConfigOperation.java b/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/FileWebHookConfigOperation.java deleted file mode 100644 index c443382655..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/FileWebHookConfigOperation.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.admin; - -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; -import org.apache.eventmesh.webhook.api.WebHookOperationConstant; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.channels.FileLock; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FileWebHookConfigOperation implements WebHookConfigOperation { - - private static final Logger logger = LoggerFactory.getLogger(FileWebHookConfigOperation.class); - - private final String webHookFilePath; - - - public FileWebHookConfigOperation(Properties properties) throws FileNotFoundException { - String webHookFilePath = WebHookOperationConstant.getFilePath(properties.getProperty("filePath")); - - assert webHookFilePath != null; - File webHookFileDir = new File(webHookFilePath); - if (!webHookFileDir.isDirectory()) { - throw new FileNotFoundException("File path " + webHookFilePath + " is not directory"); - } - if (!webHookFileDir.exists()) { - webHookFileDir.mkdirs(); - } - this.webHookFilePath = webHookFilePath; - } - - @Override - public Integer insertWebHookConfig(WebHookConfig webHookConfig) { - if (!webHookConfig.getCallbackPath().startsWith(WebHookOperationConstant.CALLBACK_PATH_PREFIX)) { - logger.error("webhookConfig callback path must start with {}", WebHookOperationConstant.CALLBACK_PATH_PREFIX); - return 0; - } - File manuDir = new File(getWebhookConfigManuDir(webHookConfig)); - if (!manuDir.exists()) { - manuDir.mkdir(); - } - File webhookConfigFile = getWebhookConfigFile(webHookConfig); - if (webhookConfigFile.exists()) { - logger.error("webhookConfig {} is existed", webHookConfig.getCallbackPath()); - return 0; - } - return writeToFile(webhookConfigFile, webHookConfig) ? 1 : 0; - } - - @Override - public Integer updateWebHookConfig(WebHookConfig webHookConfig) { - File webhookConfigFile = getWebhookConfigFile(webHookConfig); - if (!webhookConfigFile.exists()) { - logger.error("webhookConfig {} is not existed", webHookConfig.getCallbackPath()); - return 0; - } - return writeToFile(webhookConfigFile, webHookConfig) ? 1 : 0; - } - - @Override - public Integer deleteWebHookConfig(WebHookConfig webHookConfig) { - File webhookConfigFile = getWebhookConfigFile(webHookConfig); - if (!webhookConfigFile.exists()) { - logger.error("webhookConfig {} is not existed", webHookConfig.getCallbackPath()); - return 0; - } - return webhookConfigFile.delete() ? 1 : 0; - } - - @Override - public WebHookConfig queryWebHookConfigById(WebHookConfig webHookConfig) { - File webhookConfigFile = getWebhookConfigFile(webHookConfig); - if (!webhookConfigFile.exists()) { - logger.error("webhookConfig {} is not existed", webHookConfig.getCallbackPath()); - return null; - } - return getWebHookConfigFromFile(webhookConfigFile); - } - - @Override - public List queryWebHookConfigByManufacturer(WebHookConfig webHookConfig, Integer pageNum, - Integer pageSize) { - String manuDirPath = getWebhookConfigManuDir(webHookConfig); - File manuDir = new File(manuDirPath); - if (!manuDir.exists()) { - logger.warn("webhookConfig dir {} is not existed", manuDirPath); - return new ArrayList<>(); - } - List webHookConfigs = new ArrayList<>(); - - File[] webhookFiles = manuDir.listFiles(); - if (webhookFiles == null || webhookFiles.length == 0) { - return webHookConfigs; - } - - int startIndex = (pageNum - 1) * pageSize; - int endIndex = pageNum * pageSize - 1; - if (webhookFiles.length > startIndex) { - for (int i = startIndex; i < endIndex && i < webhookFiles.length; i++) { - webHookConfigs.add(getWebHookConfigFromFile(webhookFiles[i])); - } - } - return webHookConfigs; - } - - private WebHookConfig getWebHookConfigFromFile(File webhookConfigFile) { - StringBuffer fileContent = new StringBuffer(); - try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(webhookConfigFile)))) { - String line = null; - while ((line = br.readLine()) != null) { - fileContent.append(line); - } - } catch (IOException e) { - logger.error("get webhook from file {} error", webhookConfigFile.getPath(), e); - return null; - } - return JsonUtils.deserialize(fileContent.toString(), WebHookConfig.class); - } - - private boolean writeToFile(File webhookConfigFile, WebHookConfig webHookConfig) { - FileLock lock = null; - try (FileOutputStream fos = new FileOutputStream(webhookConfigFile); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos))) { - // lock this file - lock = fos.getChannel().lock(); - bw.write(JsonUtils.serialize(webHookConfig)); - } catch (IOException e) { - logger.error("write webhookConfig {} to file error", webHookConfig.getCallbackPath()); - return false; - } finally { - try { - if (lock != null) { - lock.release(); - } - } catch (IOException e) { - logger.warn("writeToFile finally caught an exception", e); - } - } - return true; - } - - private String getWebhookConfigManuDir(WebHookConfig webHookConfig) { - return webHookFilePath + WebHookOperationConstant.FILE_SEPARATOR + webHookConfig.getManufacturerName(); - } - - private File getWebhookConfigFile(WebHookConfig webHookConfig) { - String webhookConfigFilePath = null; - try { - // use URLEncoder.encode before, because the path may contain some speacial char like '/', which is illegal as a file name. - webhookConfigFilePath = this.getWebhookConfigManuDir(webHookConfig) - + WebHookOperationConstant.FILE_SEPARATOR + URLEncoder.encode(webHookConfig.getCallbackPath(), "UTF-8") - + WebHookOperationConstant.FILE_EXTENSION; - } catch (UnsupportedEncodingException e) { - logger.error("get webhookConfig file path {} failed", webHookConfig.getCallbackPath(), e); - } - assert webhookConfigFilePath != null; - return new File(webhookConfigFilePath); - } - - -} diff --git a/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/NacosWebHookConfigOperation.java b/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/NacosWebHookConfigOperation.java deleted file mode 100644 index 14972dc0ec..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-admin/src/main/java/org/apache/eventmesh/webhook/admin/NacosWebHookConfigOperation.java +++ /dev/null @@ -1,205 +0,0 @@ -package org.apache.eventmesh.webhook.admin; - -/* - * 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. - */ - -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.DATA_ID_EXTENSION; -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.GROUP_PREFIX; -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.MANUFACTURERS_DATA_ID; -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.TIMEOUT_MS; - - - -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.webhook.api.ManufacturerObject; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; -import org.apache.eventmesh.webhook.api.WebHookOperationConstant; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.alibaba.nacos.api.config.ConfigFactory; -import com.alibaba.nacos.api.config.ConfigService; -import com.alibaba.nacos.api.config.ConfigType; -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.StringUtil; - - -public class NacosWebHookConfigOperation implements WebHookConfigOperation { - - private static final Logger logger = LoggerFactory.getLogger(NacosWebHookConfigOperation.class); - - private final ConfigService configService; - - - public NacosWebHookConfigOperation(Properties properties) throws NacosException { - configService = ConfigFactory.createConfigService(properties); - - String manufacturers = configService.getConfig(MANUFACTURERS_DATA_ID, "webhook", TIMEOUT_MS); - if (manufacturers == null) { - configService.publishConfig(MANUFACTURERS_DATA_ID, "webhook", JsonUtils.serialize(new ManufacturerObject()), ConfigType.JSON.getType()); - } - - } - - @Override - public Integer insertWebHookConfig(WebHookConfig webHookConfig) { - if (!webHookConfig.getCallbackPath().startsWith(WebHookOperationConstant.CALLBACK_PATH_PREFIX)) { - logger.error("webhookConfig callback path must start with {}", WebHookOperationConstant.CALLBACK_PATH_PREFIX); - return 0; - } - Boolean result; - String manufacturerName = webHookConfig.getManufacturerName(); - try { - if (configService.getConfig(getWebHookConfigDataId(webHookConfig), getManuGroupId(webHookConfig), TIMEOUT_MS) != null) { - logger.error("insertWebHookConfig failed, config has existed"); - return 0; - } - result = configService.publishConfig(getWebHookConfigDataId(webHookConfig), getManuGroupId(webHookConfig), - JsonUtils.serialize(webHookConfig), ConfigType.JSON.getType()); - } catch (NacosException e) { - logger.error("insertWebHookConfig failed", e); - return 0; - } - if (result) { - // update manufacturer config - try { - ManufacturerObject manufacturerObject = getManufacturersInfo(); - manufacturerObject.addManufacturer(manufacturerName); - manufacturerObject.getManufacturerEvents(manufacturerName).add(getWebHookConfigDataId(webHookConfig)); - configService.publishConfig(MANUFACTURERS_DATA_ID, "webhook", - JsonUtils.serialize(manufacturerObject), ConfigType.JSON.getType()); - } catch (NacosException e) { - logger.error("update manufacturersInfo error", e); - //rollback insert - try { - configService.removeConfig(getWebHookConfigDataId(webHookConfig), getManuGroupId(webHookConfig)); - } catch (NacosException ex) { - logger.error("rollback insertWebHookConfig failed", e); - } - } - } - return result ? 1 : 0; - } - - @Override - public Integer updateWebHookConfig(WebHookConfig webHookConfig) { - Boolean result = false; - try { - if (configService.getConfig(getWebHookConfigDataId(webHookConfig), getManuGroupId(webHookConfig), TIMEOUT_MS) == null) { - logger.error("updateWebHookConfig failed, config is not existed"); - return 0; - } - result = configService.publishConfig(getWebHookConfigDataId(webHookConfig), - getManuGroupId(webHookConfig), JsonUtils.serialize(webHookConfig), ConfigType.JSON.getType()); - } catch (NacosException e) { - logger.error("updateWebHookConfig failed", e); - } - return result ? 1 : 0; - } - - @Override - public Integer deleteWebHookConfig(WebHookConfig webHookConfig) { - Boolean result = false; - String manufacturerName = webHookConfig.getManufacturerName(); - try { - result = configService.removeConfig(getWebHookConfigDataId(webHookConfig), getManuGroupId(webHookConfig)); - } catch (NacosException e) { - logger.error("deleteWebHookConfig failed", e); - } - if (result) { - try { - ManufacturerObject manufacturerObject = getManufacturersInfo(); - manufacturerObject.getManufacturerEvents(manufacturerName).remove(getWebHookConfigDataId(webHookConfig)); - configService.publishConfig(MANUFACTURERS_DATA_ID, "webhook", - JsonUtils.serialize(manufacturerObject), ConfigType.JSON.getType()); - } catch (NacosException e) { - logger.error("update manufacturersInfo error", e); - } - } - return result ? 1 : 0; - } - - @Override - public WebHookConfig queryWebHookConfigById(WebHookConfig webHookConfig) { - try { - String content = configService.getConfig(getWebHookConfigDataId(webHookConfig), getManuGroupId(webHookConfig), TIMEOUT_MS); - return JsonUtils.deserialize(content, WebHookConfig.class); - } catch (NacosException e) { - logger.error("queryWebHookConfigById failed", e); - } - return null; - } - - @Override - public List queryWebHookConfigByManufacturer(WebHookConfig webHookConfig, Integer pageNum, - Integer pageSize) { - List webHookConfigs = new ArrayList<>(); - String manufacturerName = webHookConfig.getManufacturerName(); - // get manufacturer event list - try { - ManufacturerObject manufacturerObject = getManufacturersInfo(); - List manufacturerEvents = manufacturerObject.getManufacturerEvents(manufacturerName); - int startIndex = (pageNum - 1) * pageSize; - int endIndex = pageNum * pageSize - 1; - if (manufacturerEvents.size() > startIndex) { - // nacos API is not able to get all config, so use foreach - for (int i = startIndex; i < endIndex && i < manufacturerEvents.size(); i++) { - String content = configService.getConfig(manufacturerEvents.get(i) + DATA_ID_EXTENSION, - getManuGroupId(webHookConfig), TIMEOUT_MS); - webHookConfigs.add(JsonUtils.deserialize(content, WebHookConfig.class)); - } - } - } catch (NacosException e) { - logger.error("queryWebHookConfigByManufacturer failed", e); - } - return webHookConfigs; - } - - /** - * @param webHookConfig - * @return - */ - private String getWebHookConfigDataId(WebHookConfig webHookConfig) { - try { - // use URLEncoder.encode before, because the path may contain some speacial char like '/', which is illegal as a data id. - return URLEncoder.encode(webHookConfig.getCallbackPath(), "UTF-8") + DATA_ID_EXTENSION; - } catch (UnsupportedEncodingException e) { - logger.error("get webhookConfig dataId {} failed", webHookConfig.getCallbackPath(), e); - } - return webHookConfig.getCallbackPath() + DATA_ID_EXTENSION; - } - - private String getManuGroupId(WebHookConfig webHookConfig) { - return GROUP_PREFIX + webHookConfig.getManufacturerName(); - } - - private ManufacturerObject getManufacturersInfo() throws NacosException { - String manufacturersContent = configService.getConfig(MANUFACTURERS_DATA_ID, "webhook", TIMEOUT_MS); - return StringUtil.isNullOrEmpty(manufacturersContent) - ? new ManufacturerObject() : JsonUtils.deserialize(manufacturersContent, ManufacturerObject.class); - } - -} diff --git a/eventmesh-webhook/eventmesh-webhook-api/bin/.gitignore b/eventmesh-webhook/eventmesh-webhook-api/bin/.gitignore deleted file mode 100644 index ddf9c65631..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-api/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/main/ diff --git a/eventmesh-webhook/eventmesh-webhook-api/build.gradle b/eventmesh-webhook/eventmesh-webhook-api/build.gradle deleted file mode 100644 index 52c44a50ff..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-api/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -dependencies { - - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' - - testCompileOnly 'org.projectlombok:lombok:1.18.22' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' - -} diff --git a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/ManufacturerObject.java b/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/ManufacturerObject.java deleted file mode 100644 index 88f79264fd..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/ManufacturerObject.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.api; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class ManufacturerObject { - - private Set manufacturerSet = new HashSet<>(); - - private Map> manufacturerEventMap = new HashMap<>(); - - - public Set getManufacturerSet() { - return manufacturerSet; - } - - public Set addManufacturer(String manufacturer) { - manufacturerSet.add(manufacturer); - return manufacturerSet; - } - - public Set removeManufacturer(String manufacturer) { - manufacturerSet.remove(manufacturer); - return manufacturerSet; - } - - public Map> getManufacturerEventMap() { - return manufacturerEventMap; - } - - public void setManufacturerEventMap(Map> manufacturerEventMap) { - this.manufacturerEventMap = manufacturerEventMap; - } - - public List getManufacturerEvents(String manufacturerName) { - if (!manufacturerEventMap.containsKey(manufacturerName)) { - List m = new ArrayList<>(); - manufacturerEventMap.put(manufacturerName, m); - return m; - } - return manufacturerEventMap.get(manufacturerName); - } -} diff --git a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookConfig.java b/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookConfig.java deleted file mode 100644 index dce5422d0a..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookConfig.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.api; - -import lombok.Data; - -@Data -public class WebHookConfig { - - /** - * manufacturer callback path - */ - private String callbackPath; - - /** - * manufacturer name ,like github - */ - private String manufacturerName; - - /** - * webhook event name ,like rep-push - */ - private String manufacturerEventName; - - /** - * http header content type - */ - private String contentType = "application/json"; - - /** - * description of this WebHookConfig - */ - private String description; - - /** - * secret key ,for authentication - */ - private String secret; - - /** - * userName ,for HTTP authentication - */ - private String userName; - - /** - * password ,for HTTP authentication - */ - private String password; - - /** - * roll out protocol ,like http/kafka - */ - private String cloudEventProtocol; - - /** - * roll out addr - */ - private String cloudEventServiceAddress; - - /** - * roll out event name ,like topic to mq - */ - private String cloudEventName; - - /** - * roll out data format -> CloudEvent serialization mode - * If HTTP protocol is used, the request header contentType needs to be marked - */ - private String dataContentType = "application/json"; - - /** - * source of event - */ - private String cloudEventSource; - - /** - * id of cloudEvent ,like uuid/manufacturerEventId - */ - private String cloudEventIdGenerateMode = "manufacturerEventId"; -} diff --git a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookConfigOperation.java b/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookConfigOperation.java deleted file mode 100644 index 1673c6e257..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookConfigOperation.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.api; - -import java.util.List; - -/** - * WebHookConfigOperation - */ -public interface WebHookConfigOperation { - - public Integer insertWebHookConfig(WebHookConfig webHookConfig); - - public Integer updateWebHookConfig(WebHookConfig webHookConfig); - - public Integer deleteWebHookConfig(WebHookConfig webHookConfig); - - public WebHookConfig queryWebHookConfigById(WebHookConfig webHookConfig); - - public List queryWebHookConfigByManufacturer(WebHookConfig webHookConfig, Integer pageNum, - Integer pageSize); -} diff --git a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookOperationConstant.java b/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookOperationConstant.java deleted file mode 100644 index 2a887f682f..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-api/src/main/java/org/apache/eventmesh/webhook/api/WebHookOperationConstant.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.api; - -import java.io.File; - -public class WebHookOperationConstant { - - public static final String FILE_SEPARATOR = File.separator; - - public static final String FILE_EXTENSION = ".json"; - - public static final String GROUP_PREFIX = "webhook_"; - - public static final String CALLBACK_PATH_PREFIX = "/webhook"; - - public static final String DATA_ID_EXTENSION = ".json"; - - public static final String MANUFACTURERS_DATA_ID = "manufacturers" + DATA_ID_EXTENSION; - - public static final long TIMEOUT_MS = 3 * 1000L; - - public static final String ADMIN_START_CONFIG_NAME = "eventMesh.webHook.admin.start"; - - public static final String OPERATION_MODE_CONFIG_NAME = "eventMesh.webHook.operationMode"; - - public static final String getFilePath(String filePath) { - if (filePath.startsWith("#{eventMeshHome}")) { - String configPath = System.getProperty("confPath", System.getenv("confPath")); - - filePath = filePath.replace("#{eventMeshHome}", configPath.substring(0, configPath.lastIndexOf(FILE_SEPARATOR))); - } - return filePath; - } - -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/bin/.gitignore b/eventmesh-webhook/eventmesh-webhook-receive/bin/.gitignore deleted file mode 100644 index ddf9c65631..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/main/ diff --git a/eventmesh-webhook/eventmesh-webhook-receive/build.gradle b/eventmesh-webhook/eventmesh-webhook-receive/build.gradle deleted file mode 100644 index 15a1489251..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -dependencies { - - compileOnly project(":eventmesh-common") - implementation project(":eventmesh-protocol-plugin:eventmesh-protocol-api") - implementation project(":eventmesh-webhook:eventmesh-webhook-api") - implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' - - implementation "io.openmessaging:openmessaging-api" - - implementation "io.cloudevents:cloudevents-core" - implementation "io.cloudevents:cloudevents-json-jackson" - implementation "com.alibaba.nacos:nacos-client:2.0.4" - implementation "com.fasterxml.jackson.core:jackson-databind" - implementation "com.fasterxml.jackson.core:jackson-core" - implementation "com.fasterxml.jackson.core:jackson-annotations" - - testImplementation project(":eventmesh-webhook:eventmesh-webhook-api") - - -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/ManufacturerProtocol.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/ManufacturerProtocol.java deleted file mode 100644 index db93baed72..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/ManufacturerProtocol.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive; - -import org.apache.eventmesh.webhook.api.WebHookConfig; - -import java.util.Map; - -/** - * Information and protocol resolution methods for different manufacturers - */ -public interface ManufacturerProtocol { - - String getManufacturerName(); - - - /** - * - 1.authentication - * - 2.parse webhook content to WebHookRequest - * - * @param webHookRequest formatted data - * @param webHookConfig webhook config - * @param header webhook content header - * @throws Exception authenticate failed ,or content parse failed - */ - void execute(WebHookRequest webHookRequest, WebHookConfig webHookConfig, Map header) throws Exception; -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookController.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookController.java deleted file mode 100644 index 0d0279f38b..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookController.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive; - -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.SendResult; -import org.apache.eventmesh.api.exception.OnExceptionContext; -import org.apache.eventmesh.common.config.ConfigurationWrapper; -import org.apache.eventmesh.common.protocol.ProtocolTransportObject; -import org.apache.eventmesh.common.protocol.http.WebhookProtocolTransportObject; -import org.apache.eventmesh.protocol.api.ProtocolAdaptor; -import org.apache.eventmesh.protocol.api.ProtocolPluginFactory; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.receive.protocol.ProtocolManage; -import org.apache.eventmesh.webhook.receive.storage.HookConfigOperationManage; - -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -import lombok.Setter; - -public class WebHookController { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - /** - * protocol pool - */ - private final ProtocolManage protocolManage = new ProtocolManage(); - - /** - * config pool - */ - private HookConfigOperationManage hookConfigOperationManage; - - private WebHookMQProducer webHookMQProducer; - - private ProtocolAdaptor protocolAdaptor; - - @Setter - private ConfigurationWrapper configurationWrapper; - - public void init() throws Exception { - this.webHookMQProducer = new WebHookMQProducer( - configurationWrapper.getProp("eventMesh.webHook.producer.connector")); - this.hookConfigOperationManage = new HookConfigOperationManage(configurationWrapper); - this.protocolAdaptor = ProtocolPluginFactory.getProtocolAdaptor("webhookProtocolAdaptor"); - - } - - /** - * 1. get webhookConfig from path 2. get ManufacturerProtocol and execute 3. - * convert to cloudEvent obj 4. send cloudEvent - * - * @param path CallbackPath - * @param header map of webhook request header - * @param body data - */ - public void execute(String path, Map header, byte[] body) throws Exception { - - // 1. get webhookConfig from path - WebHookConfig webHookConfig = new WebHookConfig(); - webHookConfig.setCallbackPath(path); - webHookConfig = hookConfigOperationManage.queryWebHookConfigById(webHookConfig); - if (webHookConfig == null) { - throw new Exception("No matching webhookConfig."); - } - - if (!Objects.equals(webHookConfig.getContentType(), header.get("content-type"))) { - throw new Exception( - "http request header content-type value is mismatch. current value " + header.get("content-type")); - } - - // 2. get ManufacturerProtocol and execute - String manufacturerName = webHookConfig.getManufacturerName(); - ManufacturerProtocol protocol = protocolManage.getManufacturerProtocol(manufacturerName); - WebHookRequest webHookRequest = new WebHookRequest(); - webHookRequest.setData(body); - try { - protocol.execute(webHookRequest, webHookConfig, header); - } catch (Exception e) { - throw new Exception("Webhook Message Parse Failed."); - } - - // 3. convert to cloudEvent obj - String cloudEventId = "uuid".equals(webHookConfig.getCloudEventIdGenerateMode()) ? UUID.randomUUID().toString() - : webHookRequest.getManufacturerEventId(); - String eventType = manufacturerName + "." + webHookConfig.getManufacturerEventName(); - - WebhookProtocolTransportObject webhookProtocolTransportObject = WebhookProtocolTransportObject.builder() - .cloudEventId(cloudEventId).eventType(eventType).cloudEventName(webHookConfig.getCloudEventName()) - .dataContentType(webHookConfig.getDataContentType()).body(body).build(); - - // 4. send cloudEvent - webHookMQProducer.send(this.protocolAdaptor.toCloudEvent(webhookProtocolTransportObject), new SendCallback() { - @Override - public void onSuccess(SendResult sendResult) { - if (logger.isDebugEnabled()) { - logger.debug(sendResult.toString()); - } - } - - @Override - public void onException(OnExceptionContext context) { - logger.warn("", context.getException()); - } - - }); - } - -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookMQProducer.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookMQProducer.java deleted file mode 100644 index 4058b233fb..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookMQProducer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive; - -import org.apache.eventmesh.api.RequestReplyCallback; -import org.apache.eventmesh.api.SendCallback; -import org.apache.eventmesh.api.factory.ConnectorPluginFactory; -import org.apache.eventmesh.api.producer.Producer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.cloudevents.CloudEvent; - -public class WebHookMQProducer { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - protected Producer hookMQProducer; - - public WebHookMQProducer(String connectorPluginType) { - this.hookMQProducer = ConnectorPluginFactory.getMeshMQProducer(connectorPluginType); - if (hookMQProducer == null) { - logger.error("can't load the hookMQProducer plugin, please check."); - throw new RuntimeException("doesn't load the hookMQProducer plugin, please check."); - } - } - - public void send(CloudEvent cloudEvent, SendCallback sendCallback) throws Exception { - hookMQProducer.publish(cloudEvent, sendCallback); - } - - public void request(CloudEvent cloudEvent, RequestReplyCallback rrCallback, long timeout) - throws Exception { - hookMQProducer.request(cloudEvent, rrCallback, timeout); - } - - public boolean reply(final CloudEvent cloudEvent, final SendCallback sendCallback) throws Exception { - return hookMQProducer.reply(cloudEvent, sendCallback); - } - - public Producer getHookMQProducer() { - return hookMQProducer; - } - -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookRequest.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookRequest.java deleted file mode 100644 index 7fdc78bd86..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/WebHookRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive; - -import lombok.Data; - -@Data -public class WebHookRequest { - - /** - * manufacturer event id - */ - private String manufacturerEventId; - - /** - * manufacturer event name - */ - private String manufacturerEventName; - - /** - * manufacturer name - */ - private String manufacturerSource; - - /** - * webhook request body - */ - private byte[] data; -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/protocol/GithubProtocol.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/protocol/GithubProtocol.java deleted file mode 100644 index 6f20db94e5..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/protocol/GithubProtocol.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive.protocol; - - -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.receive.ManufacturerProtocol; -import org.apache.eventmesh.webhook.receive.WebHookRequest; - -import java.util.Map; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class GithubProtocol implements ManufacturerProtocol { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Override - public String getManufacturerName() { - return "github"; - } - - @Override - public void execute(WebHookRequest webHookRequest, WebHookConfig webHookConfig, Map header) throws Exception { - - String fromSignature = header.get("X-Hub-Signature-256"); - if (!isValid(fromSignature, webHookRequest.getData(), webHookConfig.getSecret())) { - throw new Exception("webhook-GithubProtocol authenticate failed"); - } - - try { - webHookRequest.setManufacturerEventId(header.get("X-GitHub-Delivery")); - webHookRequest.setManufacturerEventName(webHookConfig.getManufacturerEventName()); - webHookRequest.setManufacturerSource(getManufacturerName()); - } catch (Exception e) { - throw new Exception("webhook-GithubProtocol parse failed"); - } - } - - /** - * Authentication - * - * @param fromSignature Signature received - * @param data data - * @param secret secret key - * @return Authentication result - */ - private Boolean isValid(String fromSignature, byte[] data, String secret) { - String hash = "sha256="; - try { - Mac sha = Mac.getInstance("HmacSHA256"); - SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); - sha.init(secretKey); - byte[] bytes = sha.doFinal(data); - hash += byteArrayToHexString(bytes); - } catch (Exception e) { - logger.error("Error HmacSHA256", e); - } - return hash.equals(fromSignature); - } - - /** - * byte array -> hexadecimal character string - * - * @param b byte array - * @return hexadecimal character string - */ - private String byteArrayToHexString(byte[] b) { - StringBuilder hs = new StringBuilder(); - String stmp; - for (int n = 0; b != null && n < b.length; n++) { - stmp = Integer.toHexString(b[n] & 0XFF); - if (stmp.length() == 1) { - hs.append('0'); - } - hs.append(stmp); - } - return hs.toString().toLowerCase(); - } -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/protocol/ProtocolManage.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/protocol/ProtocolManage.java deleted file mode 100644 index 9c10efe874..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/protocol/ProtocolManage.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive.protocol; - -import org.apache.eventmesh.webhook.receive.ManufacturerProtocol; - -import java.util.HashMap; -import java.util.Map; - -public class ProtocolManage { - - /** - * ManufacturerProtocol pool - */ - private final Map protocolMap = new HashMap<>(); - - { - this.register(new GithubProtocol()); - } - - void register(ManufacturerProtocol manufacturerProtocol) { - protocolMap.put(manufacturerProtocol.getManufacturerName(), manufacturerProtocol); - } - - public ManufacturerProtocol getManufacturerProtocol(String manufacturerName) { - return protocolMap.get(manufacturerName); - } -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/AbstractWebHookConfigOperation.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/AbstractWebHookConfigOperation.java deleted file mode 100644 index cc06685ed2..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/AbstractWebHookConfigOperation.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive.storage; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractWebHookConfigOperation { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/HookConfigOperationManage.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/HookConfigOperationManage.java deleted file mode 100644 index d47c7f89ca..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/HookConfigOperationManage.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive.storage; - -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.DATA_ID_EXTENSION; -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.GROUP_PREFIX; -import static org.apache.eventmesh.webhook.api.WebHookOperationConstant.TIMEOUT_MS; - -import org.apache.eventmesh.common.config.ConfigurationWrapper; -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookConfigOperation; -import org.apache.eventmesh.webhook.api.WebHookOperationConstant; - -import java.io.FileNotFoundException; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; - - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.alibaba.nacos.api.config.ConfigFactory; -import com.alibaba.nacos.api.config.ConfigService; -import com.alibaba.nacos.api.exception.NacosException; - -public class HookConfigOperationManage implements WebHookConfigOperation { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private String operationMode; - - private ConfigService nacosConfigService; - - /** - * webhook config pool -> key is CallbackPath - */ - private final Map cacheWebHookConfig = new ConcurrentHashMap<>(); - - public HookConfigOperationManage() { - } - - /** - * Initialize according to operationMode - * - * @param configurationWrapper - */ - public HookConfigOperationManage(ConfigurationWrapper configurationWrapper) throws FileNotFoundException, NacosException { - - this.operationMode = configurationWrapper.getProp(WebHookOperationConstant.OPERATION_MODE_CONFIG_NAME); - - if ("file".equals(operationMode)) { - new WebhookFileListener(configurationWrapper.getProp("eventMesh.webHook.fileMode.filePath"), cacheWebHookConfig); - } else if ("nacos".equals(operationMode)) { - nacosModeInit(configurationWrapper.getPropertiesByConfig("eventMesh.webHook.nacosMode", true)); - } - } - - private void nacosModeInit(Properties config) throws NacosException { - nacosConfigService = ConfigFactory.createConfigService(config); - } - - @Override - public WebHookConfig queryWebHookConfigById(WebHookConfig webHookConfig) { - if ("file".equals(operationMode)) { - return cacheWebHookConfig.get(webHookConfig.getCallbackPath()); - } else if ("nacos".equals(operationMode)) { - try { - String content = nacosConfigService.getConfig(webHookConfig.getManufacturerEventName() + DATA_ID_EXTENSION, - GROUP_PREFIX + webHookConfig.getManufacturerName(), TIMEOUT_MS); - return JsonUtils.deserialize(content, WebHookConfig.class); - } catch (NacosException e) { - logger.error("queryWebHookConfigById failed", e); - } - } - return null; - } - - @Override - public List queryWebHookConfigByManufacturer(WebHookConfig webHookConfig, Integer pageNum, - Integer pageSize) { - return null; - } - - @Override - public Integer insertWebHookConfig(WebHookConfig webHookConfig) { - cacheWebHookConfig.put(webHookConfig.getCallbackPath(), webHookConfig); - return 1; - } - - @Override - public Integer updateWebHookConfig(WebHookConfig webHookConfig) { - cacheWebHookConfig.put(webHookConfig.getCallbackPath(), webHookConfig); - return 1; - } - - @Override - public Integer deleteWebHookConfig(WebHookConfig webHookConfig) { - cacheWebHookConfig.remove(webHookConfig.getCallbackPath()); - return 1; - } - -} diff --git a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/WebhookFileListener.java b/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/WebhookFileListener.java deleted file mode 100644 index c4e8410ffa..0000000000 --- a/eventmesh-webhook/eventmesh-webhook-receive/src/main/java/org/apache/eventmesh/webhook/receive/storage/WebhookFileListener.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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. - */ - -package org.apache.eventmesh.webhook.receive.storage; - -import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; - -import org.apache.eventmesh.common.utils.JsonUtils; -import org.apache.eventmesh.webhook.api.WebHookConfig; -import org.apache.eventmesh.webhook.api.WebHookOperationConstant; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.file.FileSystems; -import java.nio.file.Paths; -import java.nio.file.WatchEvent; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WebhookFileListener { - - public Logger logger = LoggerFactory.getLogger(this.getClass()); - - private String filePath; - - private Map cacheWebHookConfig; - - private final Set pathSet = new LinkedHashSet<>(); // monitored subdirectory - - private final Map watchKeyPathMap = new HashMap<>(); // WatchKey's path - - public WebhookFileListener() { - } - - public WebhookFileListener(String filePath, Map cacheWebHookConfig) throws FileNotFoundException { - this.filePath = WebHookOperationConstant.getFilePath(filePath); - this.cacheWebHookConfig = cacheWebHookConfig; - filePatternInit(); - } - - /** - * Read the directory and register the listener - * - */ - public void filePatternInit() { - File webHookFileDir = new File(filePath); - if (!webHookFileDir.exists()) { - webHookFileDir.mkdirs(); - } else { - readFiles(webHookFileDir); - } - fileWatchRegister(); - } - - /** - * Recursively traverse the folder - * - * @param file file - */ - public void readFiles(File file) { - File[] fs = file.listFiles(); - for (File f : Objects.requireNonNull(fs)) { - if (f.isDirectory()) { - readFiles(f); - } else if (f.isFile()) { - cacheInit(f); - } - } - } - - /** - * Read the file and cache it in map - * - * @param webhookConfigFile webhookConfigFile - */ - public void cacheInit(File webhookConfigFile) { - StringBuilder fileContent = new StringBuilder(); - try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(webhookConfigFile)))) { - String line = null; - while ((line = br.readLine()) != null) { - fileContent.append(line); - } - } catch (IOException e) { - logger.error("cacheInit failed", e); - } - WebHookConfig webHookConfig = JsonUtils.deserialize(fileContent.toString(), WebHookConfig.class); - cacheWebHookConfig.put(webHookConfig.getCallbackPath(), webHookConfig); - } - - /** - * Register listeners with folders - */ - public void fileWatchRegister() { - ExecutorService cachedThreadPool = Executors.newFixedThreadPool(1); - cachedThreadPool.execute(() -> { - File root = new File(filePath); - loopDirInsertToSet(root, pathSet); - - WatchService service = null; - try { - service = FileSystems.getDefault().newWatchService(); - } catch (Exception e) { - logger.error("getWatchService failed.", e); - } - - for (String path : pathSet) { - WatchKey key = null; - try { - key = Paths.get(path).register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); - } catch (IOException e) { - logger.error("registerWatchKey failed", e); - } - watchKeyPathMap.put(key, path); - } - - while (true) { - WatchKey key = null; - try { - assert service != null; - key = service.take(); - } catch (InterruptedException e) { - logger.error("Interrupted", e); - } - - assert key != null; - for (WatchEvent event : key.pollEvents()) { - String flashPath = watchKeyPathMap.get(key); - // manufacturer change - if (flashPath.equals(filePath)) { - if (ENTRY_CREATE == event.kind()) { - try { - key = Paths.get(filePath + event.context()).register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); - } catch (IOException e) { - logger.error("registerWatchKey failed", e); - } - watchKeyPathMap.put(key, filePath + event.context()); - } - } else { // config change - cacheInit(new File(flashPath + event.context())); - } - } - if (!key.reset()) { - break; - } - } - }); - } - - /** - * Recursive folder, adding folder's path to set - * - * @param parent parent folder - * @param pathSet folder's path set - */ - private void loopDirInsertToSet(File parent, Set pathSet) { - if (!parent.isDirectory()) { - return; - } - pathSet.add(parent.getPath()); - for (File child : Objects.requireNonNull(parent.listFiles())) { - loopDirInsertToSet(child, pathSet); - } - } -} diff --git a/eventmesh-webhook/webhook.jmx b/eventmesh-webhook/webhook.jmx deleted file mode 100644 index 9bc56e8073..0000000000 --- a/eventmesh-webhook/webhook.jmx +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - false - true - false - - - - - - - - continue - - false - 1 - - 1 - 1 - false - - - - - - - - content-type - application/json - - - - - - true - - - - false - { -"callbackPath":"/webhook/test", -"manufacturerName":"1111" -} - = - - - - 127.0.0.1 - 10106 - - - /webhook/insertWebHookConfig - POST - true - false - true - false - - - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - true - false - false - false - true - 0 - true - true - true - true - true - true - - - - - - - - - diff --git a/gradle.properties b/gradle.properties index 0b8550584a..d752fa3849 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ jdk=1.8 snapshot=false group=org.apache.eventmesh -version=1.3.0-release +version=1.12.0-release #last eight bits of public key signing.keyId= #passphrase for key pairs @@ -32,3 +32,5 @@ apachePassWord= signEnabled=false org.gradle.warning.mode=none +org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.caching=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2a..033e24c4cd 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fc9e13bc0c..1912c70206 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -17,6 +17,8 @@ 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.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index b20efadc69..fcb6fca147 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/bin/sh # # Copyright © 2015-2021 the original authors. @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -63,61 +63,52 @@ ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -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 +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -127,9 +118,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -138,88 +129,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 477c896641..93e3f59f13 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,15 +76,17 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal -:omega \ No newline at end of file +:omega diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 diff --git a/maturity.md b/maturity.md new file mode 100644 index 0000000000..509c21f775 --- /dev/null +++ b/maturity.md @@ -0,0 +1,86 @@ +# English +# Maturity Self Assessment for Apache EventMesh + +The goals of this maturity model are to describe how Apache projects operate in a concise and high-level way, and to provide a basic framework that projects may choose to use to evaluate themselves. + +More details can be found [here](https://community.apache.org/apache-way/apache-project-maturity-model.html). + +## Status of this assessment + +Mentors and community members are encouraged to contribute to this page and comment on it, the following tables summarize our self-assessment against the **Apache Project Maturity Model**. + +- :white_check_mark: means that the related item is in good status. +- :white_large_square: means that the related item need long-term attention. +- :x: means that the related item need to be fixed ASAP. + + +## Maturity model assessment + +**CODE** + +| **ID** | **Description** | **Status** | +| -------- | ----- | ---------- | +| **CD10** | The project produces Open Source software for distribution to the public, at no charge. | :white_check_mark: The project source code is licensed under the `Apache License 2.0`. | +| **CD20** | Anyone can easily discover and access the project's code. | :white_check_mark: The [offical website](https://eventmesh.apache.org/) includes `Github` link which can access GitHub directly. | +| **CD30** | Anyone using standard, widely-available tools, can build the code in a reproducible way. | :white_check_mark: Apache EventMesh provide [how-to-build](https://github.com/apache/eventmesh/blob/master/docs/en/instruction/02-runtime.md) document to tell user how to compile on bare metal. | +| **CD40** | The full history of the project's code is available via a source code control system, in a way that allows anyone to recreate any released version. | :white_check_mark: It depends on git, and anyone can view the full history of the project via commit logs. | +| **CD50** | The source code control system establishes the provenance of each line of code in a reliable way, based on strong authentication of the committer. When third parties contribute code, commit messages provide reliable information about the code provenance. | :white_check_mark: The project uses GitHub and managed by Apache Infra, it ensuring provenance of each line of code to a committer. | + +**Licenses and Copyright** + +| **ID** | **Description** | **Status** | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| **LC10** | The Apache License, version 2.0, covers the released code. | :white_check_mark: The [LICENSE](https://github.com/apache/eventmesh/blob/master/LICENSE) is in GitHub repository. And all source files are with APLv2 header, check by `apache-rat:check`. | +| **LC20** | Libraries that are mandatory dependencies of the project's code do not create more restrictions than the Apache License does. | :white_check_mark: All [dependencies](https://github.com/apache/eventmesh/blob/master/tools/third-party-licenses/LICENSE) has been checked and non of them create more restrictions than the Apache License does. | +| **LC30** | The libraries mentioned in LC20 are available as Open Source software. | :white_check_mark: See [dependencies](https://github.com/apache/eventmesh/blob/master/tools/third-party-licenses/LICENSE). | +| **LC40** | Committers are bound by an Individual Contributor Agreement (the "Apache iCLA") that defines which code they may commit and how they need to identify code that is not their own. | :white_check_mark: All committers have iCLAs. | +| **LC50** | The project clearly defines and documents the copyright ownership of everything that the project produces. | :white_check_mark: And all source files are with APLv2 header, check by `apache-rat:check`. | + +**Releases** + +| **ID** | **Description** | **Status** | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **RE10** | Releases consist of source code, distributed using standard and open archive formats that are expected to stay readable in the long term. | :white_check_mark: Source release is distributed via [dist.apache.org](https://dist.apache.org/repos/dist/release/incubator/eventmesh) and linked from [download page](https://eventmesh.apache.org/download). | +| **RE20** | The project's PMC (Project Management Committee, see CS10) approves each software release in order to make the release an act of the Foundation. | :white_check_mark: All releases have been voted at dev@eventmesh.apache.org and general@incubator, and have at least 3 PPMC's/IPMC's votes. | +| **RE30** | Releases are signed and/or distributed along with digests that anyone can reliably use to validate the downloaded archives. | :white_check_mark: All releases are signed, and the [KEYS](https://downloads.apache.org/incubator/eventmesh/KEYS) is available. | +| **RE40** | The project can distribute convenience binaries alongside source code, but they are not Apache Releases, they are provided with no guarantee. | :white_check_mark: User can easily build binaries from source code. Convenience binaries are distributed alongside source code at the same time via
  • [Maven Central Repository](https://mvnrepository.com/artifact/org.apache.eventmesh)
  • [dist.apache.org](https://dist.apache.org/repos/dist/release/incubator/eventmesh/)
| +| **RE50** | The project documents a repeatable release process so that someone new to the project can independently generate the complete set of artifacts required for a release. | :white_check_mark: We can follow the [release guide](https://eventmesh.apache.org/community/release) to make new Apache eventmesh release. And so far we had 6 different release managers.| + +**Quality** + +| **ID** | **Description** | **Status** | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| **QU10** | The project is open and honest about the quality of its code. Various levels of quality and maturity for various modules are natural and acceptable as long as they are clearly communicated. | :white_check_mark: We encourage user to [report issues](https://github.com/apache/eventmesh/issues) | +| **QU20** | The project puts a very high priority on producing secure software. | :white_check_mark: All safety issues will be resolved in priority. | +| **QU30** | The project provides a well-documented, secure and private channel to report security issues, along with a documented way of responding to them. | :white_check_mark: Website provides a [security page](https://www.apache.org/security/) | +| **QU40** | The project puts a high priority on backwards compatibility and aims to document any incompatible changes and provide tools and documentation to help users transition to new features. | :white_check_mark: All releases are backwards compatibility. Apache Eventmesh provides [upgrade guide](https://eventmesh.apache.org/docs/latest/upgrade/upgrade-guide) docs | +| **QU50** | The project strives to respond to documented bug reports in a timely manner. | :white_check_mark: The project has resolved 1300+ issues and 1600+ pull requests so far, with very prompt response. | + +**Community** + +| **ID** | **Description** | **Status** | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **CO10** | The project has a well-known homepage that points to all the information required to operate according to this maturity model. | :white_check_mark: The [website](https://eventmesh.apache.org/) includes all information user need to run Apache Eventmesh. | +| **CO20** | The community welcomes contributions from anyone who acts in good faith and in a respectful manner, and who adds value to the project. | :white_check_mark: Apache Eventmesh provides [code submission guide](https://eventmesh.apache.org/community/contribute) and welcome all good contributions. | +| **CO30** | Contributions include source code, documentation, constructive bug reports, constructive discussions, marketing and generally anything that adds value to the project. | :white_check_mark: All good contributions including code and non-code are welcomed. | +| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | :white_check_mark: The community has elected 5 new PPMC members and 21 new committers so far. | +| **CO50** | The project documents how contributors can earn more rights such as commit access or decision power, and applies these principles consistently. | :white_check_mark: With the document [committer guide](https://eventmesh.apache.org/community/contribute). | +| **CO60** | The community operates based on consensus of its members (see CS10) who have decision power. Dictators, benevolent or not, are not welcome in Apache projects. | :white_check_mark: All decisions are made after vote by community members. | +| **CO70** | The project strives to answer user questions in a timely manner. | :white_check_mark: We use dev@eventmesh.apache.org, [github issue](https://github.com/apache/eventmesh/issues) to do this in a timely manner. | + +**Consensus** + +| **ID** | **Description** | **Status** | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |--------------------------------------------------------------------------------------------------------------------| +| **CS10** | The project maintains a public list of its contributors who have decision power. The project's PMC (Project Management Committee) consists of those contributors. | :white_check_mark: See [members](https://eventmesh.apache.org/team/member) with all PPMC members and committers. | +| **CS20** | Decisions require a consensus among PMC members and are documented on the project's main communications channel. The PMC takes community opinions into account, but the PMC has the final word. | :white_check_mark: All decisions are made by votes on dev@eventmesh.apache.org, and with at least 3 PPMC's/IPMC's +1 binding | +| **CS30** | The project uses documented voting rules to build consensus when discussion is not sufficient. | :white_check_mark: The project uses the standard ASF voting rules. | +| **CS40** |In Apache projects, vetoes are only valid for code commits. The person exercising the veto must justify it with a technical explanation, as per the Apache voting rules defined in CS30. | :white_check_mark: Apache Eventmesh community has not used the veto power yet except for code commits. | +| **CS50** | All "important" discussions happen asynchronously in written form on the project's main communications channel. Offline, face-to-face or private discussions that affect the project are also documented on that channel. | :white_check_mark: All important discussions and conclusions are recorded in written form. | + +**Independence** + +| **ID** | **Description** | **Status** | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **IN10** | The project is independent from any corporate or organizational influence. | :white_check_mark: The PPMC members and committer of Apache EventMesh are from 10+ companies, and majority of them are NOT From the company that donated this project. | +| **IN20** | Contributors act as themselves, not as representatives of a corporation or organization. | :white_check_mark: The contributors act on their own initiative without representing a corporation or organization. | diff --git a/resources/dashboard.png b/resources/dashboard.png new file mode 100644 index 0000000000..7b90d139ba Binary files /dev/null and b/resources/dashboard.png differ diff --git a/resources/eventmesh-architecture-3.png b/resources/eventmesh-architecture-3.png new file mode 100644 index 0000000000..5206c53936 Binary files /dev/null and b/resources/eventmesh-architecture-3.png differ diff --git a/resources/eventmesh-architecture-4.png b/resources/eventmesh-architecture-4.png new file mode 100644 index 0000000000..9ab4a750a0 Binary files /dev/null and b/resources/eventmesh-architecture-4.png differ diff --git a/resources/eventmesh-architecture-5.png b/resources/eventmesh-architecture-5.png new file mode 100644 index 0000000000..40e1750707 Binary files /dev/null and b/resources/eventmesh-architecture-5.png differ diff --git a/resources/eventmesh-architecture-6.png b/resources/eventmesh-architecture-6.png new file mode 100644 index 0000000000..4d2af838c7 Binary files /dev/null and b/resources/eventmesh-architecture-6.png differ diff --git a/resources/eventmesh-operator.png b/resources/eventmesh-operator.png new file mode 100644 index 0000000000..efdc3d0e5c Binary files /dev/null and b/resources/eventmesh-operator.png differ diff --git a/docs/images/logo.png b/resources/logo.png similarity index 100% rename from docs/images/logo.png rename to resources/logo.png diff --git a/docs/images/contact/wechat-assistant.jpg b/resources/wechat-assistant.jpg similarity index 100% rename from docs/images/contact/wechat-assistant.jpg rename to resources/wechat-assistant.jpg diff --git a/docs/images/contact/wechat-official.jpg b/resources/wechat-official.jpg similarity index 100% rename from docs/images/contact/wechat-official.jpg rename to resources/wechat-official.jpg diff --git a/settings.gradle b/settings.gradle index 0b219b62e5..7e31b8a76e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,46 +15,120 @@ * limitations under the License. */ -rootProject.name = 'incubator-eventmesh' +plugins { + id 'com.gradle.develocity' version '3.18.2' + id 'com.gradle.common-custom-user-data-gradle-plugin' version '2.0.2' +} + +def isCiServer = System.getenv().containsKey("CI") + +develocity { + server = "https://develocity.apache.org" + projectId = "eventmesh" + buildScan { + uploadInBackground = !isCiServer + publishing.onlyIf { it.isAuthenticated() } + obfuscation { + ipAddresses { addresses -> addresses.collect { address -> "0.0.0.0"} } + } + } +} + +buildCache { + remote(develocity.buildCache) { + enabled = false + } +} + +rootProject.name = 'eventmesh' String jdkVersion = "${jdk}" include 'eventmesh-runtime' -include 'eventmesh-sdk-java' +include 'eventmesh-sdks:eventmesh-sdk-java' include 'eventmesh-common' include 'eventmesh-starter' include 'eventmesh-examples' include 'eventmesh-spi' -include 'eventmesh-connector-plugin:eventmesh-connector-api' -include 'eventmesh-connector-plugin:eventmesh-connector-rocketmq' -include 'eventmesh-connector-plugin:eventmesh-connector-standalone' + +include 'eventmesh-openconnect:eventmesh-openconnect-java' +include 'eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-api' +include 'eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-admin' +include 'eventmesh-openconnect:eventmesh-openconnect-offsetmgmt-plugin:eventmesh-openconnect-offsetmgmt-nacos' + +include 'eventmesh-connectors:eventmesh-connector-openfunction' +include 'eventmesh-connectors:eventmesh-connector-rocketmq' +include 'eventmesh-connectors:eventmesh-connector-rabbitmq' +include 'eventmesh-connectors:eventmesh-connector-redis' +include 'eventmesh-connectors:eventmesh-connector-mongodb' +include 'eventmesh-connectors:eventmesh-connector-pulsar' +include 'eventmesh-connectors:eventmesh-connector-kafka' +include 'eventmesh-connectors:eventmesh-connector-s3' +include 'eventmesh-connectors:eventmesh-connector-pravega' +include 'eventmesh-connectors:eventmesh-connector-knative' +include 'eventmesh-connectors:eventmesh-connector-jdbc' +include 'eventmesh-connectors:eventmesh-connector-file' +include 'eventmesh-connectors:eventmesh-connector-spring' +include 'eventmesh-connectors:eventmesh-connector-prometheus' +include 'eventmesh-connectors:eventmesh-connector-dingtalk' +include 'eventmesh-connectors:eventmesh-connector-lark' +include 'eventmesh-connectors:eventmesh-connector-wecom' +include 'eventmesh-connectors:eventmesh-connector-slack' +include 'eventmesh-connectors:eventmesh-connector-wechat' +include 'eventmesh-connectors:eventmesh-connector-http' +include 'eventmesh-connectors:eventmesh-connector-chatgpt' +include 'eventmesh-connectors:eventmesh-connector-canal' +include 'eventmesh-connectors:eventmesh-connector-mcp' + +include 'eventmesh-storage-plugin:eventmesh-storage-api' +include 'eventmesh-storage-plugin:eventmesh-storage-standalone' +include 'eventmesh-storage-plugin:eventmesh-storage-kafka' +include 'eventmesh-storage-plugin:eventmesh-storage-pulsar' +include 'eventmesh-storage-plugin:eventmesh-storage-redis' +include 'eventmesh-storage-plugin:eventmesh-storage-rocketmq' +include 'eventmesh-storage-plugin:eventmesh-storage-rabbitmq' + +include 'eventmesh-security-plugin' include 'eventmesh-security-plugin:eventmesh-security-api' include 'eventmesh-security-plugin:eventmesh-security-acl' -include 'eventmesh-registry-plugin:eventmesh-registry-api' -include 'eventmesh-registry-plugin:eventmesh-registry-nacos' -include 'eventmesh-registry-plugin:eventmesh-registry-etcd' -include 'eventmesh-registry-plugin:eventmesh-registry-consul' -include 'eventmesh-admin' +include 'eventmesh-security-plugin:eventmesh-security-auth-http-basic' +include 'eventmesh-security-plugin:eventmesh-security-auth-token' + +include 'eventmesh-meta:eventmesh-meta-api' +include 'eventmesh-meta:eventmesh-meta-nacos' +include 'eventmesh-meta:eventmesh-meta-etcd' +include 'eventmesh-meta:eventmesh-meta-consul' +include 'eventmesh-meta:eventmesh-meta-zookeeper' +include 'eventmesh-meta:eventmesh-meta-raft' + include 'eventmesh-protocol-plugin' include 'eventmesh-protocol-plugin:eventmesh-protocol-api' include 'eventmesh-protocol-plugin:eventmesh-protocol-openmessage' include 'eventmesh-protocol-plugin:eventmesh-protocol-cloudevents' include 'eventmesh-protocol-plugin:eventmesh-protocol-meshmessage' include 'eventmesh-protocol-plugin:eventmesh-protocol-http' -include 'eventmesh-admin:eventmesh-admin-rocketmq' include 'eventmesh-protocol-plugin:eventmesh-protocol-grpc' include 'eventmesh-protocol-plugin:eventmesh-protocol-grpcmessage' +include 'eventmesh-protocol-plugin:eventmesh-protocol-a2a' + include 'eventmesh-metrics-plugin' include 'eventmesh-metrics-plugin:eventmesh-metrics-api' include 'eventmesh-metrics-plugin:eventmesh-metrics-prometheus' -include 'eventmesh-security-plugin:eventmesh-security-auth-http-basic' - include 'eventmesh-trace-plugin' include 'eventmesh-trace-plugin:eventmesh-trace-api' include 'eventmesh-trace-plugin:eventmesh-trace-zipkin' +include 'eventmesh-trace-plugin:eventmesh-trace-pinpoint' +include 'eventmesh-trace-plugin:eventmesh-trace-jaeger' +include 'eventmesh-retry' +include 'eventmesh-retry:eventmesh-retry-api' +include 'eventmesh-retry:eventmesh-retry-rocketmq' +include 'eventmesh-runtime-v2' +include 'eventmesh-admin-server' +include 'eventmesh-registry' +include 'eventmesh-registry:eventmesh-registry-api' +include 'eventmesh-registry:eventmesh-registry-nacos' -include 'eventmesh-webhook' -include 'eventmesh-webhook:eventmesh-webhook-api' -include 'eventmesh-webhook:eventmesh-webhook-admin' -include 'eventmesh-webhook:eventmesh-webhook-receive' - +include 'eventmesh-function' +include 'eventmesh-function:eventmesh-function-api' +include 'eventmesh-function:eventmesh-function-filter' +include 'eventmesh-function:eventmesh-function-transformer' \ No newline at end of file diff --git a/style/checkStyle.xml b/style/checkStyle.xml index f573dd3f98..87930c8b02 100644 --- a/style/checkStyle.xml +++ b/style/checkStyle.xml @@ -14,7 +14,6 @@ ~ 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. - ~ --> - + + + + + + + + + + + + + + + + + + + + + + + @@ -46,6 +67,7 @@ + @@ -59,6 +81,10 @@ + + + + @@ -351,4 +377,4 @@ - + \ No newline at end of file diff --git a/style/checkstyle-header-c.txt b/style/checkstyle-header-c.txt new file mode 100644 index 0000000000..63f7276486 --- /dev/null +++ b/style/checkstyle-header-c.txt @@ -0,0 +1,14 @@ +// 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. diff --git a/style/checkstyle-header-java.txt b/style/checkstyle-header-java.txt new file mode 100644 index 0000000000..6a9c064171 --- /dev/null +++ b/style/checkstyle-header-java.txt @@ -0,0 +1,17 @@ +/* + * 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. + */ + diff --git a/style/checkstyle-header-shell.txt b/style/checkstyle-header-shell.txt new file mode 100644 index 0000000000..446e3fb424 --- /dev/null +++ b/style/checkstyle-header-shell.txt @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Licensed to 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. Apache Software Foundation (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. diff --git a/style/checkstyle-header-xml.txt b/style/checkstyle-header-xml.txt new file mode 100644 index 0000000000..4acb57c648 --- /dev/null +++ b/style/checkstyle-header-xml.txt @@ -0,0 +1,17 @@ + + diff --git a/style/checkstyle-header-yaml.txt b/style/checkstyle-header-yaml.txt new file mode 100644 index 0000000000..b1312a0905 --- /dev/null +++ b/style/checkstyle-header-yaml.txt @@ -0,0 +1,16 @@ +# +# 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. +# diff --git a/style/copyright/Apache.xml b/style/copyright/Apache.xml new file mode 100644 index 0000000000..a074c67cb2 --- /dev/null +++ b/style/copyright/Apache.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/style/eventmesh-code-style.xml b/style/eventmesh-code-style.xml new file mode 100644 index 0000000000..c8bddd49fe --- /dev/null +++ b/style/eventmesh-code-style.xml @@ -0,0 +1,299 @@ + + + + + + + + diff --git a/style/task/eventmesh-spotless-formatter.xml b/style/task/eventmesh-spotless-formatter.xml new file mode 100644 index 0000000000..e71522b7c6 --- /dev/null +++ b/style/task/eventmesh-spotless-formatter.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/dependency-check/check-dependencies.sh b/tools/dependency-check/check-dependencies.sh deleted file mode 100644 index ddf8701107..0000000000 --- a/tools/dependency-check/check-dependencies.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin bash -# -# 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. -# - -# ******************************************************************** -# This script used to check the dependencies are all in our exception. -# This will not check the license legality -# ******************************************************************** - -# Used to store the tmp files. -decompress_conf='build/tmp' -# store all dependencies from our binary jar. -all_dependencies_txt='tools/dependency-check/all-dependencies.txt' -# store all our known dependencies -known_third_party_dependencies_txt='tools/dependency-check/known-dependencies.txt' - -# Below files is generated by this script. -# store all EventMesh self module's name. -self_modules_txt='tools/dependency-check/self-modules.txt' -# store all third part dependencies -third_party_dependencies_txt='tools/dependency-check/third-party-dependencies.txt' - -mkdir $decompress_conf || true -tar -zxf build/incubator-eventmesh*.tar.gz -C $decompress_conf - -./gradlew printProjects | grep '.jar' > "$self_modules_txt" - -find "$decompress_conf" -name "*.jar" -exec basename {} \; | uniq | sort > "$all_dependencies_txt" - -grep -wvf "$self_modules_txt" "$all_dependencies_txt" | uniq | sort > "$third_party_dependencies_txt" - -# If the check is success it will return 0 -sort "$known_third_party_dependencies_txt" | diff - "$third_party_dependencies_txt" - -compareCode=$? -if [ $compareCode -eq 0 ] -then - echo "Dependencies check success" -else - echo "Dependencies check failed, please check if you add unknown dependencies" - exit $compareCode -fi diff --git a/tools/dependency-check/known-dependencies.txt b/tools/dependency-check/known-dependencies.txt deleted file mode 100644 index 6e051f5fb9..0000000000 --- a/tools/dependency-check/known-dependencies.txt +++ /dev/null @@ -1,138 +0,0 @@ -animal-sniffer-annotations-1.17.jar -assertj-core-2.6.0.jar -bcpkix-jdk15on-1.69.jar -bcprov-jdk15on-1.69.jar -bcutil-jdk15on-1.69.jar -checker-qual-3.12.0.jar -cloudevents-api-2.2.0.jar -cloudevents-core-2.2.0.jar -cloudevents-json-jackson-2.2.0.jar -commons-beanutils-1.9.4.jar -commons-cli-1.2.jar -commons-codec-1.11.jar -commons-collections-3.2.2.jar -commons-collections4-4.1.jar -commons-digester-2.1.jar -commons-lang3-3.6.jar -commons-logging-1.2.jar -commons-text-1.9.jar -commons-validator-1.7.jar -consul-api-1.4.5.jar -disruptor-3.4.2.jar -dledger-0.2.3.jar -error_prone_annotations-2.7.1.jar -failureaccess-1.0.1.jar -fastjson-1.2.76.jar -grpc-context-1.17.1.jar -grpc-core-1.17.1.jar -grpc-netty-1.17.1.jar -grpc-netty-shaded-1.17.1.jar -grpc-protobuf-1.17.1.jar -grpc-protobuf-lite-1.17.1.jar -grpc-stub-1.17.1.jar -grpc-grpclb-1.17.1.jar -gson-2.8.2.jar -guava-31.0.1-jre.jar -hamcrest-core-1.3.jar -httpasyncclient-4.1.3.jar -httpclient-4.5.13.jar -httpcore-4.4.13.jar -httpcore-nio-4.4.6.jar -ipaddress-5.3.3.jar -j2objc-annotations-1.3.jar -jackson-annotations-2.13.0.jar -jackson-core-2.13.0.jar -jackson-databind-2.13.0.jar -javassist-3.24.0-GA.jar -javax.annotation-api-1.3.2.jar -jcommander-1.72.jar -jetcd-core-0.3.0.jar -jetcd-common-0.3.0.jar -jetcd-resolver-0.3.0.jar -jna-4.2.2.jar -jsr305-3.0.2.jar -junit-4.13.2.jar -listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar -log4j-api-2.17.1.jar -log4j-core-2.17.1.jar -log4j-slf4j-impl-2.17.1.jar -metrics-annotation-4.1.0.jar -metrics-core-4.1.0.jar -metrics-healthchecks-4.1.0.jar -metrics-json-4.1.0.jar -nacos-client-2.0.4.jar -netty-all-4.1.73.Final.jar -netty-buffer-4.1.73.Final.jar -netty-codec-4.1.73.Final.jar -netty-codec-dns-4.1.73.Final.jar -netty-codec-haproxy-4.1.73.Final.jar -netty-codec-http-4.1.73.Final.jar -netty-codec-http2-4.1.73.Final.jar -netty-codec-memcache-4.1.73.Final.jar -netty-codec-mqtt-4.1.73.Final.jar -netty-codec-redis-4.1.73.Final.jar -netty-codec-smtp-4.1.73.Final.jar -netty-codec-socks-4.1.73.Final.jar -netty-codec-stomp-4.1.73.Final.jar -netty-codec-xml-4.1.73.Final.jar -netty-common-4.1.73.Final.jar -netty-handler-4.1.73.Final.jar -netty-handler-proxy-4.1.73.Final.jar -netty-resolver-4.1.73.Final.jar -netty-resolver-dns-4.1.73.Final.jar -netty-resolver-dns-classes-macos-4.1.73.Final.jar -netty-resolver-dns-native-macos-4.1.73.Final-osx-aarch_64.jar -netty-resolver-dns-native-macos-4.1.73.Final-osx-x86_64.jar -netty-tcnative-classes-2.0.46.Final.jar -netty-transport-4.1.73.Final.jar -netty-transport-classes-epoll-4.1.73.Final.jar -netty-transport-classes-kqueue-4.1.73.Final.jar -netty-transport-native-epoll-4.1.73.Final-linux-aarch_64.jar -netty-transport-native-epoll-4.1.73.Final-linux-x86_64.jar -netty-transport-native-kqueue-4.1.73.Final-osx-aarch_64.jar -netty-transport-native-kqueue-4.1.73.Final-osx-x86_64.jar -netty-transport-native-unix-common-4.1.73.Final.jar -netty-transport-rxtx-4.1.73.Final.jar -netty-transport-sctp-4.1.73.Final.jar -netty-transport-udt-4.1.73.Final.jar -okhttp-3.14.9.jar -okio-1.17.2.jar -opencensus-api-0.17.0.jar -opencensus-contrib-grpc-metrics-0.17.0.jar -openmessaging-api-2.2.1-pubsub.jar -opentelemetry-api-1.3.0.jar -opentelemetry-api-metrics-1.3.0-alpha.jar -opentelemetry-context-1.3.0.jar -opentelemetry-exporter-prometheus-1.3.0-alpha.jar -opentelemetry-exporter-zipkin-1.3.0.jar -opentelemetry-sdk-1.3.0.jar -opentelemetry-sdk-common-1.3.0.jar -opentelemetry-sdk-metrics-1.3.0-alpha.jar -opentelemetry-sdk-trace-1.3.0.jar -opentelemetry-semconv-1.3.0-alpha.jar -proto-google-common-protos-1.0.0.jar -protobuf-java-3.5.1.jar -protobuf-java-util-3.5.1.jar -reflections-0.9.11.jar -rocketmq-acl-4.9.3.jar -rocketmq-broker-4.9.3.jar -rocketmq-client-4.9.3.jar -rocketmq-common-4.9.3.jar -rocketmq-filter-4.9.3.jar -rocketmq-logging-4.9.3.jar -rocketmq-namesrv-4.9.3.jar -rocketmq-remoting-4.9.3.jar -rocketmq-srvutil-4.9.3.jar -rocketmq-store-4.9.3.jar -rocketmq-test-4.9.3.jar -rocketmq-tools-4.9.3.jar -simpleclient-0.8.1.jar -simpleclient_common-0.8.1.jar -simpleclient_httpserver-0.8.1.jar -slf4j-api-1.7.30.jar -snakeyaml-1.30.jar -system-rules-1.16.1.jar -truth-0.30.jar -zipkin-2.23.2.jar -zipkin-reporter-2.16.3.jar -zipkin-sender-okhttp3-2.16.3.jar \ No newline at end of file diff --git a/tools/dist-license/LICENSE b/tools/dist-license/LICENSE new file mode 100644 index 0000000000..66b61bcaef --- /dev/null +++ b/tools/dist-license/LICENSE @@ -0,0 +1,755 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= +This distribution contains the following third-party artifacts: + +FastInfoset 1.2.16 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +FastInfoset 1.2.16 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +HdrHistogram 2.1.12 licensed under 'CC0-1.0'. For details see: licenses/CC0-1.0.txt +HdrHistogram 2.1.12 licensed under 'BSD-2-Clause'. For details see: licenses/BSD-2-Clause.txt +HikariCP 4.0.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +LatencyUtils 2.0.3 licensed under 'CC0-1.0'. For details see: licenses/CC0-1.0.txt +ST4 4.3.4 licensed under 'BSD-4-Clause'. For details see: licenses/BSD-4-Clause.txt +accessors-smart 2.5.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +adapter-rxjava2 2.9.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +alibabacloud-gateway-spi 0.0.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +amqp-client 5.22.0 licensed under 'AL 2.0'. For details see: licenses/AL 2.0.txt +amqp-client 5.22.0 licensed under 'GPL v2'. For details see: licenses/GPL v2.txt +amqp-client 5.22.0 licensed under 'MPL-2.0'. For details see: licenses/MPL-2.0.txt +animal-sniffer-annotations 1.24 licensed under 'MIT'. For details see: licenses/MIT.txt +annotations 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +annotations 4.1.1.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +antlr-runtime 3.5.3 licensed under 'BSD licence'. For details see: licenses/BSD licence.txt +antlr4 4.13.1 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +antlr4-runtime 4.13.1 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +aopalliance 1.0 licensed under 'Public Domain'. For details see: licenses/Public Domain.txt +apache-client 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +api 0.18.2 licensed under 'MIT'. For details see: licenses/MIT.txt +arns 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +asm 9.3 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +asm 9.6 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +asm-analysis 9.6 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +asm-commons 9.6 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +asm-tree 9.6 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +asm-util 9.6 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +assertj-core 3.26.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +async-http-client 2.12.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +async-http-client-netty-utils 2.12.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +audience-annotations 0.12.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +auth 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +aviator 2.2.1 licensed under 'GNU LESSER GENERAL PUBLIC LICENSE'. For details see: licenses/GNU LESSER GENERAL PUBLIC LICENSE.txt +aws-core 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +aws-query-protocol 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +aws-xml-protocol 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +bcpkix-jdk15on 1.69 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcpkix-jdk15on 1.70 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcprov-ext-jdk15on 1.69 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcprov-ext-jdk15on 1.70 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcprov-jdk15on 1.69 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcprov-jdk15on 1.70 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcutil-jdk15on 1.69 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bcutil-jdk15on 1.70 licensed under 'Bouncy Castle Licence'. For details see: licenses/Bouncy Castle Licence.txt +bolt 1.42.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +bolt 1.6.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +bouncy-castle-bc 2.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +bouncy-castle-bc 2.11.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +bson 3.12.14 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +byte-buddy 1.14.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +byte-buddy 1.15.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +cache-api 1.1.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +caffeine 2.9.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.common 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.filter 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.instance.core 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.instance.manager 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.instance.spring 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.meta 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.parse 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.parse.dbsync 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.parse.driver 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.protocol 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.server 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.sink 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +canal.store 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +checker-qual 3.43.0 licensed under 'MIT'. For details see: licenses/MIT.txt +checksums 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +checksums-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +classgraph 4.8.21 licensed under 'MIT'. For details see: licenses/MIT.txt +classmate 1.5.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +client 0.18.2 licensed under 'MIT'. For details see: licenses/MIT.txt +cloudevents-api 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +cloudevents-core 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +cloudevents-http-vertx 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +cloudevents-json-jackson 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +cloudevents-kafka 2.5.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +cloudevents-protobuf 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-beanutils 1.8.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-beanutils 1.9.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-cli 1.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-codec 1.11 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-codec 1.15 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-codec 1.17.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-collections 3.2.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-collections4 4.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-compress 1.22 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-digester 2.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-io 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-lang 2.6 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-lang3 3.17.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-logging 1.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-logging 1.3.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-text 1.12.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +commons-validator 1.9.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +connector.core 1.1.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +consul-api 1.4.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +converter-jackson 2.9.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +credentials-java 0.3.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +crt-core 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +curator-client 5.7.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +curator-framework 5.7.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +curator-recipes 5.7.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +dingtalk 2.1.27 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +disruptor 3.4.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +dom4j 2.0.3 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +druid 1.2.17 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +druid 1.2.23 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +druid-spring-boot-starter 1.2.23 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +endpoint-util 0.0.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +endpoints-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +error_prone_annotations 2.28.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +eventstream 1.0.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +failsafe 3.3.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +failureaccess 1.0.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +fastjson 1.2.69_noneautotype licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +fastjson2 2.0.52 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +gateway-dingtalk 1.0.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +google-auth-library-credentials 0.22.2 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +grpc-api 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-auth 1.39.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-context 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-core 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-grpclb 1.17.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-netty 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-netty-shaded 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-protobuf 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-protobuf-lite 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-stub 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +grpc-util 1.68.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +gson 2.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +guava 33.3.0-jre licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +guava-retrying 2.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +guice 7.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +h2 2.1.210 licensed under 'MPL-2.0'. For details see: licenses/MPL-2.0.txt +h2 2.1.210 licensed under 'EPL 1.0'. For details see: licenses/EPL 1.0.txt +hessian 3.3.6 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +hessian 4.0.63 licensed under 'The Apache Software License, Version 1.1'. For details see: licenses/The Apache Software License, Version 1.1.txt +hibernate-validator 6.2.0.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +http-auth 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +http-auth-aws 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +http-auth-aws-eventstream 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +http-auth-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +http-client-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +httpasyncclient 4.1.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +httpclient 4.5.14 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +httpcore 4.4.16 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +httpcore-nio 4.4.15 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +httpmime 4.5.13 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +icu4j 72.1 licensed under 'Unicode/ICU License'. For details see: licenses/Unicode-ICU License.txt +identity-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +ini4j 0.5.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +ipaddress 5.5.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +istack-commons-runtime 3.0.8 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +j2objc-annotations 1.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +j2objc-annotations 2.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-annotations 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-core 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-databind 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-dataformat-yaml 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-datatype-jdk8 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-datatype-jsr310 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-jr-objects 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jackson-module-parameter-names 2.18.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jakarta.activation 1.2.2 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +jakarta.activation-api 1.2.1 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +jakarta.annotation-api 1.3.5 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +jakarta.annotation-api 1.3.5 licensed under 'GPL-2.0-with-classpath-exception'. For details see: licenses/GPL-2.0-with-classpath-exception.txt +jakarta.annotation-api 2.1.1 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +jakarta.annotation-api 2.1.1 licensed under 'GPL-2.0-with-classpath-exception'. For details see: licenses/GPL-2.0-with-classpath-exception.txt +jakarta.inject-api 2.0.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jakarta.servlet-api 4.0.4 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +jakarta.servlet-api 4.0.4 licensed under 'GPL-2.0-with-classpath-exception'. For details see: licenses/GPL-2.0-with-classpath-exception.txt +jakarta.validation-api 2.0.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jakarta.websocket-api 1.1.2 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +jakarta.websocket-api 1.1.2 licensed under 'GNU General Public License, version 2 with the GNU Classpath Exception'. For details see: licenses/GNU General Public License, version 2 with the GNU Classpath Exception.txt +jakarta.xml.bind-api 2.3.2 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +javassist 3.30.2-GA licensed under 'MPL-1.1'. For details see: licenses/MPL-1.1.txt +javassist 3.30.2-GA licensed under 'LGPL-2.1-only'. For details see: licenses/LGPL-2.1-only.txt +javassist 3.30.2-GA licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +javax-websocket-client-impl 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +javax-websocket-client-impl 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +javax-websocket-server-impl 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +javax-websocket-server-impl 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +javax.ws.rs-api 2.1 licensed under 'CDDL-1.1'. For details see: licenses/CDDL-1.1.txt +javax.ws.rs-api 2.1 licensed under 'GPL-2.0-with-classpath-exception'. For details see: licenses/GPL-2.0-with-classpath-exception.txt +jaxb-api 2.3.0 licensed under 'CDDL-1.1'. For details see: licenses/CDDL-1.1.txt +jaxb-api 2.3.0 licensed under 'GPL-2.0-with-classpath-exception'. For details see: licenses/GPL-2.0-with-classpath-exception.txt +jaxb-core 2.3.0 licensed under 'CDDL-1.1'. For details see: licenses/CDDL-1.1.txt +jaxb-impl 2.3.0 licensed under 'CDDL-1.1'. For details see: licenses/CDDL-1.1.txt +jaxb-runtime 2.3.2 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +jboss-logging 3.4.1.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jcl-over-slf4j 1.7.12 licensed under 'MIT'. For details see: licenses/MIT.txt +jcommander 1.82 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jctools-core 2.1.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetcd-common 0.3.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetcd-core 0.3.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetcd-resolver 0.3.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-annotations 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-annotations 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-client 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-client 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-continuation 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-continuation 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-http 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-http 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-io 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-io 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-plus 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-plus 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-security 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-security 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-server 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-server 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-servlet 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-servlet 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-servlets 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-servlets 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-util 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-util 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-util-ajax 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-util-ajax 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-webapp 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-webapp 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jetty-xml 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jetty-xml 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +jjwt-api 0.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jjwt-impl 0.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jjwt-jackson 0.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jna 4.2.2 licensed under 'LGPL, version 2.1'. For details see: licenses/LGPL, version 2.1.txt +jna 4.2.2 licensed under 'ASL, version 2'. For details see: licenses/ASL, version 2.txt +jna 5.5.0 licensed under 'LGPL, version 2.1'. For details see: licenses/LGPL, version 2.1.txt +jna 5.5.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +joda-time 2.9.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jodd-util 6.3.0 licensed under 'BSD-2-Clause'. For details see: licenses/BSD-2-Clause.txt +jraft-core 1.3.14 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +json-path 2.9.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +json-smart 2.5.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +json-utils 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jsqlparser 4.9 licensed under 'LGPL-2.1-only'. For details see: licenses/LGPL-2.1-only.txt +jsqlparser 4.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jsr305 3.0.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +jtokkit 0.5.1 licensed under 'MIT'. For details see: licenses/MIT.txt +jts-core 1.20.0 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +jts-core 1.20.0 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +kafka-clients 3.9.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +kryo 5.6.2 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +listenablefuture 9999.0-empty-to-avoid-conflict-with-guava licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +log4j-api 2.24.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +log4j-core 2.24.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +log4j-slf4j2-impl 2.24.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +logback-adapter 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +logback-classic 1.2.13 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +logback-classic 1.2.13 licensed under 'GNU Lesser General Public License'. For details see: licenses/GNU Lesser General Public License.txt +logback-core 1.2.13 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +logback-core 1.2.13 licensed under 'GNU Lesser General Public License'. For details see: licenses/GNU Lesser General Public License.txt +lz4-java 1.8.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mapstruct 1.5.5.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mbknor-jackson-jsonschema_2.12 1.0.34 licensed under 'MIT'. For details see: licenses/MIT.txt +metrics-annotation 4.2.26 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +metrics-core 4.2.26 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +metrics-healthchecks 4.2.26 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +metrics-json 4.2.26 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +metrics-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +micrometer-core 1.9.17 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +minlog 1.3.1 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +mongodb-driver 3.12.14 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mongodb-driver-core 3.12.14 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis 3.5.16 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis 3.5.6 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-plus 3.5.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-plus-annotation 3.5.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-plus-boot-starter 3.5.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-plus-core 3.5.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-plus-extension 3.5.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-plus-spring-boot-autoconfigure 3.5.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-spring 2.0.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mybatis-spring 2.1.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mysql-binlog-connector-java 0.30.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +mysql-connector-java 5.1.48 licensed under 'The GNU General Public License, Version 2'. For details see: licenses/The GNU General Public License, Version 2.txt +nacos-auth-plugin 2.4.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +nacos-client 2.4.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +nacos-encryption-plugin 2.4.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +nacos-log4j2-adapter 2.4.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +nacos-logback-adapter-12 2.4.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty 3.2.10.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-all 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-buffer 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-buffer 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-dns 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-dns 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-haproxy 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-http 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-http 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-http2 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-http2 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-memcache 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-mqtt 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-redis 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-smtp 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-socks 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-stomp 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-codec-xml 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-common 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-common 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-handler 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-handler 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-handler-proxy 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-handler-ssl-ocsp 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-nio-client 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-reactive-streams 2.0.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver-dns 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver-dns 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver-dns-classes-macos 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver-dns-native-macos 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-resolver-dns-native-macos 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-tcnative-boringssl-static 2.0.48.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-tcnative-boringssl-static 2.0.51.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-tcnative-boringssl-static 2.0.61.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-tcnative-classes 2.0.48.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-tcnative-classes 2.0.51.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-tcnative-classes 2.0.61.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-classes-epoll 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-classes-epoll 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-classes-kqueue 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-epoll 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-epoll 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-epoll 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-kqueue 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-kqueue 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-unix-common 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-native-unix-common 4.1.114.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-rxtx 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-sctp 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +netty-transport-udt 4.1.112.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +oapi-sdk 2.0.28 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +objenesis 3.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +okhttp 3.14.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +okio 1.17.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +openapiutil 0.2.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +openmessaging-api 2.2.1-pubsub licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-api 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-api-events 1.36.0-alpha licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-context 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-exporter-common 1.34.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-exporter-common 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-exporter-jaeger 1.34.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-exporter-prometheus 1.36.0-alpha licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-exporter-sender-okhttp 1.34.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-exporter-zipkin 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-extension-incubator 1.36.0-alpha licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk-common 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk-extension-autoconfigure-spi 1.34.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk-extension-autoconfigure-spi 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk-logs 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk-metrics 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-sdk-trace 1.36.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +opentelemetry-semconv 1.30.1-alpha licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +org.abego.treelayout.core 1.0.3 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +org.jacoco.agent 0.8.4 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +perfmark-api 0.27.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-annotations 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-bootstrap 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-bootstrap-core 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-commons 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-commons-buffer 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-commons-config 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-commons-profiler 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-grpc 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pinpoint-profiler 3.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pravega-client 0.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pravega-common 0.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pravega-shared-authplugin 0.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pravega-shared-controller-api 0.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pravega-shared-protocol 0.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pravega-shared-security 0.11.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +profiles 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +prometheus-metrics-config 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +prometheus-metrics-exporter-common 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +prometheus-metrics-exporter-httpserver 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +prometheus-metrics-exposition-formats 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +prometheus-metrics-model 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +prometheus-metrics-shaded-protobuf 1.1.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +proto-google-common-protos 2.41.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +protobuf-java 3.25.3 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +protobuf-java 3.25.4 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +protobuf-java-util 3.21.10 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +protobuf-java-util 3.25.4 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +protobuf-java-util 3.5.1 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +protocol-core 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pulsar-client 2.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pulsar-client 2.11.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pulsar-client-admin-api 2.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pulsar-client-admin-api 2.11.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pulsar-client-api 2.11.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +pulsar-client-api 2.11.4 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +reactive-streams 1.0.3 licensed under 'CC0-1.0'. For details see: licenses/CC0-1.0.txt +reactive-streams 1.0.4 licensed under 'MIT-0'. For details see: licenses/MIT-0.txt +reactor-core 3.6.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +redisson 3.38.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +reflectasm 1.11.9 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +regions 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +resilience4j-core 1.7.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +retries 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +retries-spi 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +retrofit 2.9.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-acl 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-broker 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-client 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-common 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-filter 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-logging 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-namesrv 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-remoting 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-srvutil 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-store 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocketmq-tools 4.9.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocksdbjni 8.8.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rocksdbjni 8.8.1 licensed under 'GNU General Public License, version 2'. For details see: licenses/GNU General Public License, version 2.txt +rpc-grpc-impl 1.3.14 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rxjava 2.0.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +rxjava 3.1.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +s3 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +scala-library 2.12.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +sdk-core 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +service 0.18.2 licensed under 'MIT'. For details see: licenses/MIT.txt +simpleclient 0.15.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +simpleclient_tracer_common 0.15.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +simpleclient_tracer_otel 0.15.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +simpleclient_tracer_otel_agent 0.15.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +slack-api-client 1.42.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +slack-api-model 1.42.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +slack-app-backend 1.42.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +slf4j-api 2.0.13 licensed under 'MIT'. For details see: licenses/MIT.txt +snakeyaml 2.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +snappy-java 1.1.10.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +sofa-common-tools 1.0.12 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-aop 5.3.15 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-aop 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-aop 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-beans 5.3.20 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-beans 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-beans 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot 2.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-autoconfigure 2.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-autoconfigure 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter 2.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter-jdbc 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter-jetty 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter-json 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter-tomcat 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter-validation 2.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-boot-starter-web 2.7.18 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-context 5.3.15 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-context 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-context 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-core 5.3.20 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-core 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-core 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-expression 5.3.15 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-expression 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-expression 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-jcl 5.3.20 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-jcl 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-jcl 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-jdbc 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-jdbc 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-messaging 5.3.20 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-orm 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-tx 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-tx 5.3.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-web 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +spring-webmvc 5.3.31 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +stax-api 1.0-2 licensed under 'GNU General Public Library'. For details see: licenses/GNU General Public Library.txt +stax-api 1.0-2 licensed under 'CDDL-1.0'. For details see: licenses/CDDL-1.0.txt +stax-ex 1.8.1 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +tea 1.2.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tea-openapi 0.3.3 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tea-util 0.2.22 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tea-xml 0.1.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +third-party-jackson-core 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tomcat-embed-core 9.0.83 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tomcat-embed-el 9.0.56 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tomcat-embed-el 9.0.83 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +tomcat-embed-websocket 9.0.83 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +txw2 2.3.2 licensed under 'BSD-3-Clause'. For details see: licenses/BSD-3-Clause.txt +utils 2.29.5 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +validation-api 1.1.0.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +validation-api 2.0.1.Final licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vavr 0.10.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vavr-match 0.10.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-auth-common 4.5.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-auth-common 4.5.8 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-auth-common 4.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-auth-common 4.5.9 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-bridge-common 4.5.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-bridge-common 4.5.8 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-core 4.5.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-core 4.5.8 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +vertx-core 4.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-core 4.5.9 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +vertx-uri-template 4.3.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-uri-template 4.3.7 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-uri-template 4.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-uri-template 4.5.9 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-web 4.5.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-web 4.5.8 licensed under 'EPL-2.0'. For details see: licenses/EPL-2.0.txt +vertx-web-client 4.3.7 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-web-client 4.3.7 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-web-client 4.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-web-client 4.5.9 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-web-common 4.5.8 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-web-common 4.5.8 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +vertx-web-common 4.5.9 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +vertx-web-common 4.5.9 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +websocket-api 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +websocket-api 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +websocket-client 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +websocket-client 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +websocket-common 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +websocket-common 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +websocket-server 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +websocket-server 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +websocket-servlet 9.4.53.v20231009 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +websocket-servlet 9.4.53.v20231009 licensed under 'EPL-1.0'. For details see: licenses/EPL-1.0.txt +xpp3 1.1.4c licensed under 'Indiana University Extreme! Lab Software License, vesion 1.1.1'. For details see: licenses/Indiana University Extreme! Lab Software License, vesion 1.1.1.txt +xpp3 1.1.4c licensed under 'Public Domain'. For details see: licenses/Public Domain.txt +xpp3 1.1.4c licensed under 'Apache-1.1'. For details see: licenses/Apache-1.1.txt +xsdlib 2013.6.1 licensed under 'BSD-4-Clause'. For details see: licenses/BSD-4-Clause.txt +zipkin 2.27.1 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +zipkin-reporter 3.3.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +zipkin-sender-okhttp3 3.3.0 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +zkclient 0.10 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +zookeeper 3.9.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +zookeeper-jute 3.9.2 licensed under 'Apache-2.0'. For details see: licenses/Apache-2.0.txt +zstd-jni 1.5.0-2 licensed under 'BSD-2-Clause'. For details see: licenses/BSD-2-Clause.txt +zstd-jni 1.5.2-2 licensed under 'BSD-2-Clause'. For details see: licenses/BSD-2-Clause.txt +zstd-jni 1.5.2-5 licensed under 'BSD-2-Clause'. For details see: licenses/BSD-2-Clause.txt +zstd-jni 1.5.6-4 licensed under 'BSD-2-Clause'. For details see: licenses/BSD-2-Clause.txt diff --git a/tools/dist-license/NOTICE b/tools/dist-license/NOTICE new file mode 100644 index 0000000000..07c88a739b --- /dev/null +++ b/tools/dist-license/NOTICE @@ -0,0 +1,7433 @@ +Apache EventMesh +Copyright 2021-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +jetty-webapp-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +objenesis-3.4 NOTICE + +======================================================================= + +// ------------------------------------------------------------------ +// NOTICE file corresponding to the section 4d of The Apache License, +// Version 2.0, in this case for Objenesis + +// ------------------------------------------------------------------ + +Objenesis +Copyright 2006-2024 Joe Walnes, Henri Tremblay, Leonardo Mesquita + + + + +======================================================================= + +protocol-core-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +httpcore-4.4.16 NOTICE + +======================================================================= + + +Apache HttpCore +Copyright 2005-2022 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +jackson-datatype-jsr310-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Licensing + +Jackson components are licensed under Apache (Software) License, version 2.0, +as per accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +jakarta.xml.bind-api-2.3.2 NOTICE + +======================================================================= + +# Notices for Eclipse Project for JAXB + +This content is produced and maintained by the Eclipse Project for JAXB project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaxb + +## Trademarks + +Eclipse Project for JAXB is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0 which is available +at http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaxb-api + +## Third-party Content + +This project leverages the following third party content. + +None + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +======================================================================= + +commons-logging-1.2 NOTICE + +======================================================================= + +Apache Commons Logging +Copyright 2003-2014 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + +======================================================================= + +rocketmq-acl-4.9.5 NOTICE + +======================================================================= + + +rocketmq-acl 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +rocketmq-broker-4.9.5 NOTICE + +======================================================================= + + +rocketmq-broker 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-context-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +spring-expression-5.3.15 NOTICE + +======================================================================= + +Spring Framework 5.3.15 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +jaxb-runtime-2.3.2 NOTICE + +======================================================================= + +# Notices for Eclipse Implementation of JAXB + +This content is produced and maintained by the Eclipse Implementation of JAXB +project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaxb-impl + +## Trademarks + +Eclipse Implementation of JAXB is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0 which is available at +http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaxb-ri +* https://github.com/eclipse-ee4j/jaxb-istack-commons +* https://github.com/eclipse-ee4j/jaxb-dtd-parser +* https://github.com/eclipse-ee4j/jaxb-fi +* https://github.com/eclipse-ee4j/jaxb-stax-ex +* https://github.com/eclipse-ee4j/jax-rpc-ri + +## Third-party Content + +This project leverages the following third party content. + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Felix (1.2.0) + +* License: Apache License, 2.0 + +args4j (2.33) + +* License: MIT License + +dom4j (1.6.1) + +* License: Custom license based on Apache 1.1 + +file-management (3.0.0) + +* License: Apache-2.0 +* Project: https://maven.apache.org/shared/file-management/ +* Source: + https://svn.apache.org/viewvc/maven/shared/tags/file-management-3.0.0/ + +JUnit (4.12) + +* License: Eclipse Public License + +JUnit (4.12) + +* License: Eclipse Public License + +maven-compat (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-compat/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-compat/3.5.2 + +maven-core (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-core/index.html +* Source: https://mvnrepository.com/artifact/org.apache.maven/maven-core/3.5.2 + +maven-plugin-annotations (3.5) + +* License: Apache-2.0 +* Project: https://maven.apache.org/plugin-tools/maven-plugin-annotations/ +* Source: + https://github.com/apache/maven-plugin-tools/tree/master/maven-plugin-annotations + +maven-plugin-api (3.5.2) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-connector-basic (1.1.1) + +* License: Apache-2.0 + +maven-resolver-impl (1.1.1) + +* License: Apache-2.0 + +maven-resolver-spi (1.1.1) + +* License: Apache-2.0 + +maven-resolver-transport-file (1.1.1) + +* License: Apache-2.0 +* Project: https://maven.apache.org/resolver/maven-resolver-transport-file/ +* Source: + https://github.com/apache/maven-resolver/tree/master/maven-resolver-transport-file + +maven-resolver-util (1.1.1) + +* License: Apache-2.0 + +maven-settings (3.5.2) + +* License: Apache-2.0 +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-settings/3.5.2 + +OSGi Service Platform Core Companion Code (6.0) + +* License: Apache License, 2.0 + +plexus-archiver (3.5) + +* License: Apache-2.0 +* Project: https://codehaus-plexus.github.io/plexus-archiver/ +* Source: https://github.com/codehaus-plexus/plexus-archiver + +plexus-io (3.0.0) + +* License: Apache-2.0 + +plexus-utils (3.1.0) + +* License: Apache- 2.0 or Apache- 1.1 or BSD or Public Domain or Indiana + University Extreme! Lab Software License V1.1.1 (Apache 1.1 style) + +relaxng-datatype (1.0) + +* License: New BSD license + +Sax (0.2) + +* License: SAX-PD +* Project: http://www.megginson.com/downloads/SAX/ +* Source: http://sourceforge.net/project/showfiles.php?group_id=29449 + +testng (6.14.2) + +* License: Apache-2.0 AND (MIT OR GPL-1.0+) +* Project: https://testng.org/doc/index.html +* Source: https://github.com/cbeust/testng + +wagon-http-lightweight (3.0.0) + +* License: Pending +* Project: https://maven.apache.org/wagon/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven.wagon/wagon-http-lightweight/3.0.0 + +xz for java (1.8) + +* License: LicenseRef-Public-Domain + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + + +======================================================================= + +pulsar-client-api-2.11.4 NOTICE + +======================================================================= + + +Pulsar Client :: API +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-core-5.3.20 NOTICE + +======================================================================= + +Spring Framework 5.3.20 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +spring-boot-starter-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +pravega-shared-security-0.11.0 NOTICE + +======================================================================= + +Copyright (c) 2021 Pravega Authors. +Copyright (c) 2017-2021 Dell Inc., or its subsidiaries. All Rights Reserved. + +This software contains source code from Apache BookKeeper, distributed under +the Apache License Version 2.0, and copyrighted to the Apache Software Foundation. +http://bookkeeper.apache.org + +======================================================================= + +websocket-servlet-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +websocket-api-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +rocketmq-srvutil-4.9.5 NOTICE + +======================================================================= + + +rocketmq-srvutil 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +FastInfoset-1.2.16 NOTICE + +======================================================================= + +# Notices for Eclipse Implementation of JAXB + +This content is produced and maintained by the Eclipse Implementation of JAXB +project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaxb-impl + +## Trademarks + +Eclipse Implementation of JAXB is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0 which is available at +http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaxb-ri +* https://github.com/eclipse-ee4j/jaxb-istack-commons +* https://github.com/eclipse-ee4j/jaxb-dtd-parser +* https://github.com/eclipse-ee4j/jaxb-fi +* https://github.com/eclipse-ee4j/jaxb-stax-ex +* https://github.com/eclipse-ee4j/jax-rpc-ri + +## Third-party Content + +This project leverages the following third party content. + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Felix (1.2.0) + +* License: Apache License, 2.0 + +args4j (2.33) + +* License: MIT License + +dom4j (1.6.1) + +* License: Custom license based on Apache 1.1 + +file-management (3.0.0) + +* License: Apache-2.0 +* Project: https://maven.apache.org/shared/file-management/ +* Source: + https://svn.apache.org/viewvc/maven/shared/tags/file-management-3.0.0/ + +JUnit (4.12) + +* License: Eclipse Public License + +JUnit (4.12) + +* License: Eclipse Public License + +maven-compat (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-compat/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-compat/3.5.2 + +maven-core (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-core/index.html +* Source: https://mvnrepository.com/artifact/org.apache.maven/maven-core/3.5.2 + +maven-plugin-annotations (3.5) + +* License: Apache-2.0 +* Project: https://maven.apache.org/plugin-tools/maven-plugin-annotations/ +* Source: + https://github.com/apache/maven-plugin-tools/tree/master/maven-plugin-annotations + +maven-plugin-api (3.5.2) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-connector-basic (1.1.1) + +* License: Apache-2.0 + +maven-resolver-impl (1.1.1) + +* License: Apache-2.0 + +maven-resolver-spi (1.1.1) + +* License: Apache-2.0 + +maven-resolver-transport-file (1.1.1) + +* License: Apache-2.0 +* Project: https://maven.apache.org/resolver/maven-resolver-transport-file/ +* Source: + https://github.com/apache/maven-resolver/tree/master/maven-resolver-transport-file + +maven-resolver-util (1.1.1) + +* License: Apache-2.0 + +maven-settings (3.5.2) + +* License: Apache-2.0 +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-settings/3.5.2 + +OSGi Service Platform Core Companion Code (6.0) + +* License: Apache License, 2.0 + +plexus-archiver (3.5) + +* License: Apache-2.0 +* Project: https://codehaus-plexus.github.io/plexus-archiver/ +* Source: https://github.com/codehaus-plexus/plexus-archiver + +plexus-io (3.0.0) + +* License: Apache-2.0 + +plexus-utils (3.1.0) + +* License: Apache- 2.0 or Apache- 1.1 or BSD or Public Domain or Indiana + University Extreme! Lab Software License V1.1.1 (Apache 1.1 style) + +relaxng-datatype (1.0) + +* License: New BSD license + +Sax (0.2) + +* License: SAX-PD +* Project: http://www.megginson.com/downloads/SAX/ +* Source: http://sourceforge.net/project/showfiles.php?group_id=29449 + +testng (6.14.2) + +* License: Apache-2.0 AND (MIT OR GPL-1.0+) +* Project: https://testng.org/doc/index.html +* Source: https://github.com/cbeust/testng + +wagon-http-lightweight (3.0.0) + +* License: Pending +* Project: https://maven.apache.org/wagon/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven.wagon/wagon-http-lightweight/3.0.0 + +xz for java (1.8) + +* License: LicenseRef-Public-Domain + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +======================================================================= + +log4j-slf4j2-impl-2.24.1 NOTICE + +======================================================================= + +SLF4J 2 Provider for Log4j API +Copyright 1999-2024 The Apache Software Foundation + + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +spring-core-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +httpcore-nio-4.4.15 NOTICE + +======================================================================= + + +Apache HttpCore NIO +Copyright 2005-2021 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +pulsar-client-api-2.11.1 NOTICE + +======================================================================= + + +Pulsar Client :: API +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-boot-autoconfigure-2.5.9 NOTICE + +======================================================================= + +Spring Boot 2.5.9 +Copyright (c) 2012-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +jetty-util-ajax-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +aws-query-protocol-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +regions-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +commons-codec-1.17.1 NOTICE + +======================================================================= + +Apache Commons Codec +Copyright 2002-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +micrometer-core-1.9.17 NOTICE + +======================================================================= + +Micrometer + +Copyright (c) 2017-Present VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://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. + +------------------------------------------------------------------------------- + +This product contains a modified portion of 'io.netty.util.internal.logging', +in the Netty/Common library distributed by The Netty Project: + + * Copyright 2013 The Netty Project + * License: Apache License v2.0 + * Homepage: https://netty.io + +This product contains a modified portion of 'StringUtils.isBlank()', +in the Commons Lang library distributed by The Apache Software Foundation: + + * Copyright 2001-2019 The Apache Software Foundation + * License: Apache License v2.0 + * Homepage: https://commons.apache.org/proper/commons-lang/ + +This product contains a modified portion of 'JsonUtf8Writer', +in the Moshi library distributed by Square, Inc: + + * Copyright 2010 Google Inc. + * License: Apache License v2.0 + * Homepage: https://github.com/square/moshi + +This product contains a modified portion of the 'org.springframework.lang' +package in the Spring Framework library, distributed by VMware, Inc: + + * Copyright 2002-2019 the original author or authors. + * License: Apache License v2.0 + * Homepage: https://spring.io/projects/spring-framework + +======================================================================= + +commons-logging-1.3.2 NOTICE + +======================================================================= + +Apache Commons Logging +Copyright 2001-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jakarta.websocket-api-1.1.2 NOTICE + +======================================================================= + +# Notices for Jakarta WebSocket + +This content is produced and maintained by the Jakarta WebSocket project. + +* Project home: https://projects.eclipse.org/projects/ee4j.websocket + +## Trademarks + +Jakarta WebSocket is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License v. 2.0 which is available at +http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made +available under the following Secondary Licenses when the conditions for such +availability set forth in the Eclipse Public License v. 2.0 are satisfied: GNU +General Public License, version 2 with the GNU Classpath Exception which is +available at https://www.gnu.org/software/classpath/license.html. + +SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/websocket-api + +## Third-party Content + +This project leverages the following third party content. + +None + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +======================================================================= + +spring-aop-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +spring-boot-starter-web-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +jakarta.inject-api-2.0.1 NOTICE + +======================================================================= + +# Notices for Eclipse Jakarta Dependency Injection + +This content is produced and maintained by the Eclipse Jakarta Dependency Injection project. + +* Project home: https://projects.eclipse.org/projects/cdi.batch + +## Trademarks + +Jakarta Dependency Injection is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Apache License, Version 2.0 which is available at +https://www.apache.org/licenses/LICENSE-2.0. + +SPDX-License-Identifier: Apache-2.0 + +## Source Code + +The project maintains the following source code repositories: + +https://github.com/eclipse-ee4j/injection-api +https://github.com/eclipse-ee4j/injection-spec +https://github.com/eclipse-ee4j/injection-tck + +## Third-party Content + +This project leverages the following third party content. + +None + +## Cryptography + +None +======================================================================= + +http-auth-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-boot-2.5.9 NOTICE + +======================================================================= + +Spring Boot 2.5.9 +Copyright (c) 2012-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +checksums-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +pravega-shared-authplugin-0.11.0 NOTICE + +======================================================================= + +Copyright (c) 2021 Pravega Authors. +Copyright (c) 2017-2021 Dell Inc., or its subsidiaries. All Rights Reserved. + +This software contains source code from Apache BookKeeper, distributed under +the Apache License Version 2.0, and copyrighted to the Apache Software Foundation. +http://bookkeeper.apache.org + +======================================================================= + +spring-web-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +jetty-continuation-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +jackson-databind-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Copyright + +Copyright 2007-, Tatu Saloranta (tatu.saloranta@iki.fi) + +## Licensing + +Jackson 2.x core and extension components are licensed under Apache License 2.0 +To find the details that apply to this artifact see the accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS(-2.x) file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +spring-boot-starter-tomcat-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +jackson-annotations-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Copyright + +Copyright 2007-, Tatu Saloranta (tatu.saloranta@iki.fi) + +## Licensing + +Jackson 2.x core and extension components are licensed under Apache License 2.0 +To find the details that apply to this artifact see the accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS(-2.x) file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +spring-beans-5.3.20 NOTICE + +======================================================================= + +Spring Framework 5.3.20 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +crt-core-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jackson-dataformat-yaml-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Copyright + +Copyright 2007-, Tatu Saloranta (tatu.saloranta@iki.fi) + +## Licensing + +Jackson components are licensed under Apache (Software) License, version 2.0, +as per accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +spring-boot-starter-jetty-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +jetty-servlets-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +byte-buddy-1.15.3 NOTICE + +======================================================================= + +Copyright 2014 - Present Rafael Winterhalter + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +======================================================================= + +netty-nio-client-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-boot-starter-validation-2.5.9 NOTICE + +======================================================================= + +Spring Boot 2.5.9 +Copyright (c) 2012-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +commons-collections4-4.4 NOTICE + +======================================================================= + +Apache Commons Collections +Copyright 2001-2019 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +aws-core-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-aop-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +spring-jcl-5.3.20 NOTICE + +======================================================================= + +Spring Framework 5.3.20 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +spring-tx-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +apache-client-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +mybatis-3.5.6 NOTICE + +======================================================================= + +iBATIS + This product includes software developed by + The Apache Software Foundation (http://www.apache.org/). + + Copyright 2010 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +OGNL +//-------------------------------------------------------------------------- +// Copyright (c) 2004, Drew Davidson and Luke Blanshard +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// Neither the name of the Drew Davidson nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +//-------------------------------------------------------------------------- + +Refactored SqlBuilder class (SQL, AbstractSQL) + + This product includes software developed by + Adam Gent (https://gist.github.com/3650165) + + Copyright 2010 Adam Gent + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= + +netty-3.2.10.Final NOTICE + +======================================================================= + + + The Netty Project + ================= + +Please visit the Netty web site for more information: + + * http://www.jboss.org/netty/ + +Copyright 2009 Red Hat, Inc. + +Red Hat licenses this product to you under the Apache License, version 2.0 (the +"License"); you may not use this product 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. + +Also, please refer to each LICENSE..txt file, which is located in +the 'license' directory of the distribution file, for the license terms of the +components that this product depends on. + +------------------------------------------------------------------------------- +This product contains the extensions to Java Collections Framework which has +been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: + + * LICENSE: + * license/LICENSE.jsr166y.txt (Public Domain) + * HOMEPAGE: + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ + * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ + +This product contains a modified version of Robert Harder's Public Domain +Base64 Encoder and Decoder, which can be obtained at: + + * LICENSE: + * license/LICENSE.base64.txt (Public Domain) + * HOMEPAGE: + * http://iharder.sourceforge.net/current/java/base64/ + +This product contains a modified version of 'JZlib', a re-implementation of +zlib in pure Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.jzlib.txt (BSD Style License) + * HOMEPAGE: + * http://www.jcraft.com/jzlib/ + +This product optionally depends on 'Protocol Buffers', Google's data +interchange format, which can be obtained at: + + * LICENSE: + * license/LICENSE.protobuf.txt (New BSD License) + * HOMEPAGE: + * http://code.google.com/p/protobuf/ + +This product optionally depends on 'SLF4J', a simple logging facade for Java, +which can be obtained at: + + * LICENSE: + * license/LICENSE.slf4j.txt (MIT License) + * HOMEPAGE: + * http://www.slf4j.org/ + +This product optionally depends on 'Apache Commons Logging', a logging +framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-logging.txt (Apache License 2.0) + * HOMEPAGE: + * http://commons.apache.org/logging/ + +This product optionally depends on 'Apache Log4J', a logging framework, +which can be obtained at: + + * LICENSE: + * license/LICENSE.log4j.txt (Apache License 2.0) + * HOMEPAGE: + * http://logging.apache.org/log4j/ + +This product optionally depends on 'JBoss Logging', a logging framework, +which can be obtained at: + + * LICENSE: + * license/LICENSE.jboss-logging.txt (GNU LGPL 2.1) + * HOMEPAGE: + * http://anonsvn.jboss.org/repos/common/common-logging-spi/ + +This product optionally depends on 'Apache Felix', an open source OSGi +framework implementation, which can be obtained at: + + * LICENSE: + * license/LICENSE.felix.txt (Apache License 2.0) + * HOMEPAGE: + * http://felix.apache.org/ + +======================================================================= + +jackson-module-parameter-names-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Licensing + +Jackson components are licensed under Apache (Software) License, version 2.0, +as per accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +checksums-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-boot-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +retries-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jetty-server-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +commons-cli-1.2 NOTICE + +======================================================================= + +Apache Commons CLI +Copyright 2001-2009 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +jetty-util-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +tomcat-embed-core-9.0.83 NOTICE + +======================================================================= + +Apache Tomcat +Copyright 1999-2023 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +The original XML Schemas for Java EE Deployment Descriptors: + - javaee_5.xsd + - javaee_web_services_1_2.xsd + - javaee_web_services_client_1_2.xsd + - javaee_6.xsd + - javaee_web_services_1_3.xsd + - javaee_web_services_client_1_3.xsd + - jsp_2_2.xsd + - web-app_3_0.xsd + - web-common_3_0.xsd + - web-fragment_3_0.xsd + - javaee_7.xsd + - javaee_web_services_1_4.xsd + - javaee_web_services_client_1_4.xsd + - jsp_2_3.xsd + - web-app_3_1.xsd + - web-common_3_1.xsd + - web-fragment_3_1.xsd + - javaee_8.xsd + - web-app_4_0.xsd + - web-common_4_0.xsd + - web-fragment_4_0.xsd + +may be obtained from: +http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/index.html + +======================================================================= + +curator-framework-5.7.0 NOTICE + +======================================================================= + +Curator Framework +Copyright 2011-2023 The Apache Software Foundation + + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +pravega-shared-controller-api-0.11.0 NOTICE + +======================================================================= + +Copyright (c) 2021 Pravega Authors. +Copyright (c) 2017-2021 Dell Inc., or its subsidiaries. All Rights Reserved. + +This software contains source code from Apache BookKeeper, distributed under +the Apache License Version 2.0, and copyrighted to the Apache Software Foundation. +http://bookkeeper.apache.org + +======================================================================= + +spring-boot-autoconfigure-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +websocket-common-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +spring-jdbc-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +http-auth-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +guice-7.0.0 NOTICE + +======================================================================= + + +Google Guice - Core Library +Copyright 2006-2023 Google, Inc. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +kafka-clients-3.9.0 NOTICE + +======================================================================= + +Apache Kafka +Copyright 2024 The Apache Software Foundation. + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +This distribution has a binary dependency on jersey, which is available under the CDDL +License. The source code of jersey can be found at https://github.com/jersey/jersey/. + +This distribution has a binary test dependency on jqwik, which is available under +the Eclipse Public License 2.0. The source code can be found at +https://github.com/jlink/jqwik. + +The streams-scala (streams/streams-scala) module was donated by Lightbend and the original code was copyrighted by them: +Copyright (C) 2018 Lightbend Inc. +Copyright (C) 2017-2018 Alexis Seigneurin. + +This project contains the following code copied from Apache Hadoop: +clients/src/main/java/org/apache/kafka/common/utils/PureJavaCrc32C.java +Some portions of this file Copyright (c) 2004-2006 Intel Corporation and licensed under the BSD license. + +This project contains the following code copied from Apache Hive: +streams/src/main/java/org/apache/kafka/streams/state/internals/Murmur3.java + +======================================================================= + +tomcat-embed-websocket-9.0.83 NOTICE + +======================================================================= + +Apache Tomcat +Copyright 1999-2023 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +http-client-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +http-auth-aws-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +redisson-3.38.1 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers, as well as supported +commercially by FasterXML.com. + +## Licensing + +Jackson core and extension components may be licensed under different licenses. +To find the details that apply to this artifact see the accompanying LICENSE file. +For more information, including possible other licensing options, contact +FasterXML.com (http://fasterxml.com). + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +# Byte Buddy + +Copyright 2014 - 2019 Rafael Winterhalter + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +======================================================================= + +pravega-client-0.11.0 NOTICE + +======================================================================= + +Copyright (c) 2021 Pravega Authors. +Copyright (c) 2017-2021 Dell Inc., or its subsidiaries. All Rights Reserved. + +This software contains source code from Apache BookKeeper, distributed under +the Apache License Version 2.0, and copyrighted to the Apache Software Foundation. +http://bookkeeper.apache.org + +======================================================================= + +endpoints-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jetty-io-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +classmate-1.5.1 NOTICE + +======================================================================= + +Java ClassMate library was originally written by Tatu Saloranta (tatu.saloranta@iki.fi) + +Other developers who have contributed code are: + +* Brian Langel + + +======================================================================= + +stax-ex-1.8.1 NOTICE + +======================================================================= + +# Notices for Eclipse Implementation of JAXB + +This content is produced and maintained by the Eclipse Implementation of JAXB +project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaxb-impl + +## Trademarks + +Eclipse Implementation of JAXB is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0 which is available at +http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaxb-ri +* https://github.com/eclipse-ee4j/jaxb-istack-commons +* https://github.com/eclipse-ee4j/jaxb-dtd-parser +* https://github.com/eclipse-ee4j/jaxb-fi +* https://github.com/eclipse-ee4j/jaxb-stax-ex +* https://github.com/eclipse-ee4j/jax-rpc-ri + +## Third-party Content + +This project leverages the following third party content. + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Felix (1.2.0) + +* License: Apache License, 2.0 + +args4j (2.33) + +* License: MIT License + +dom4j (1.6.1) + +* License: Custom license based on Apache 1.1 + +file-management (3.0.0) + +* License: Apache-2.0 +* Project: https://maven.apache.org/shared/file-management/ +* Source: + https://svn.apache.org/viewvc/maven/shared/tags/file-management-3.0.0/ + +JUnit (4.12) + +* License: Eclipse Public License + +JUnit (4.12) + +* License: Eclipse Public License + +maven-compat (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-compat/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-compat/3.5.2 + +maven-core (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-core/index.html +* Source: https://mvnrepository.com/artifact/org.apache.maven/maven-core/3.5.2 + +maven-plugin-annotations (3.5) + +* License: Apache-2.0 +* Project: https://maven.apache.org/plugin-tools/maven-plugin-annotations/ +* Source: + https://github.com/apache/maven-plugin-tools/tree/master/maven-plugin-annotations + +maven-plugin-api (3.5.2) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-connector-basic (1.1.1) + +* License: Apache-2.0 + +maven-resolver-impl (1.1.1) + +* License: Apache-2.0 + +maven-resolver-spi (1.1.1) + +* License: Apache-2.0 + +maven-resolver-transport-file (1.1.1) + +* License: Apache-2.0 +* Project: https://maven.apache.org/resolver/maven-resolver-transport-file/ +* Source: + https://github.com/apache/maven-resolver/tree/master/maven-resolver-transport-file + +maven-resolver-util (1.1.1) + +* License: Apache-2.0 + +maven-settings (3.5.2) + +* License: Apache-2.0 +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-settings/3.5.2 + +OSGi Service Platform Core Companion Code (6.0) + +* License: Apache License, 2.0 + +plexus-archiver (3.5) + +* License: Apache-2.0 +* Project: https://codehaus-plexus.github.io/plexus-archiver/ +* Source: https://github.com/codehaus-plexus/plexus-archiver + +plexus-io (3.0.0) + +* License: Apache-2.0 + +plexus-utils (3.1.0) + +* License: Apache- 2.0 or Apache- 1.1 or BSD or Public Domain or Indiana + University Extreme! Lab Software License V1.1.1 (Apache 1.1 style) + +relaxng-datatype (1.0) + +* License: New BSD license + +Sax (0.2) + +* License: SAX-PD +* Project: http://www.megginson.com/downloads/SAX/ +* Source: http://sourceforge.net/project/showfiles.php?group_id=29449 + +testng (6.14.2) + +* License: Apache-2.0 AND (MIT OR GPL-1.0+) +* Project: https://testng.org/doc/index.html +* Source: https://github.com/cbeust/testng + +wagon-http-lightweight (3.0.0) + +* License: Pending +* Project: https://maven.apache.org/wagon/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven.wagon/wagon-http-lightweight/3.0.0 + +xz for java (1.8) + +* License: LicenseRef-Public-Domain + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + + +======================================================================= + +curator-client-5.7.0 NOTICE + +======================================================================= + +Curator Client +Copyright 2011-2023 The Apache Software Foundation + + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +spring-boot-starter-jdbc-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +jackson-datatype-jdk8-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Licensing + +Jackson components are licensed under Apache (Software) License, version 2.0, +as per accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +grpc-netty-shaded-1.68.0 NOTICE + +======================================================================= + + The Netty Project + ================= + +Please visit the Netty web site for more information: + + * http://netty.io/ + +Copyright 2016 The Netty Project + +The Netty Project 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. + +------------------------------------------------------------------------------- +This product contains a forked and modified version of Tomcat Native + + * LICENSE: + * license/LICENSE.tomcat-native.txt (Apache License 2.0) + * HOMEPAGE: + * http://tomcat.apache.org/native-doc/ + * https://svn.apache.org/repos/asf/tomcat/native/ + +This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. + + * LICENSE: + * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/takari/maven-wrapper + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * license/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist + + +This product contains code from boringssl. + + * LICENSE (Combination ISC and OpenSSL license) + * license/LICENSE.boringssl.txt (Combination ISC and OpenSSL license) + * HOMEPAGE: + * https://boringssl.googlesource.com/boringssl/ + +======================================================================= + +rocketmq-namesrv-4.9.5 NOTICE + +======================================================================= + + +rocketmq-namesrv 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-boot-starter-json-2.7.18 NOTICE + +======================================================================= + +Spring Boot 2.7.18 +Copyright (c) 2012-2023 VMware, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +spring-beans-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +fastjson-1.2.69_noneautotype NOTICE + +======================================================================= + +/* + * Copyright 1999-2017 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +======================================================================= + +identity-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jetty-annotations-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +utils-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +websocket-client-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +third-party-jackson-core-2.29.5 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Copyright + +Copyright 2007-, Tatu Saloranta (tatu.saloranta@iki.fi) + +## Licensing + +Jackson 2.x core and extension components are licensed under Apache License 2.0 +To find the details that apply to this artifact see the accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS(-2.x) file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +## FastDoubleParser + +jackson-core bundles a shaded copy of FastDoubleParser . +That code is available under an MIT license +under the following copyright. + +Copyright © 2023 Werner Randelshofer, Switzerland. MIT License. + +See FastDoubleParser-NOTICE for details of other source code included in FastDoubleParser +and the licenses and copyrights that apply to that code. + +======================================================================= + +third-party-jackson-core-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-jcl-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +bouncy-castle-bc-2.11.1-pkg NOTICE + +======================================================================= + + +Apache Pulsar :: Bouncy Castle :: BC +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +jakarta.activation-1.2.2 NOTICE + +======================================================================= + +# Notices for Jakarta Activation + +This content is produced and maintained by Jakarta Activation project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaf + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0, +which is available at http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaf + +## Third-party Content + +This project leverages the following third party content. + +JUnit (4.12) + +* License: Eclipse Public License + +======================================================================= + +http-auth-aws-eventstream-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +pulsar-client-admin-api-2.11.4 NOTICE + +======================================================================= + + +Pulsar Client Admin :: API +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +tomcat-embed-el-9.0.83 NOTICE + +======================================================================= + +Apache Tomcat +Copyright 1999-2023 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +bouncy-castle-bc-2.11.4-pkg NOTICE + +======================================================================= + + +Apache Pulsar :: Bouncy Castle :: BC +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +log4j-core-2.24.1 NOTICE + +======================================================================= + +Apache Log4j Core +Copyright 1999-2012 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +ResolverUtil.java +Copyright 2005-2006 Tim Fennell +======================================================================= + +commons-validator-1.9.0 NOTICE + +======================================================================= + +Apache Commons Validator +Copyright 2002-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +rocketmq-remoting-4.9.5 NOTICE + +======================================================================= + + +rocketmq-remoting 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +jakarta.activation-api-1.2.1 NOTICE + +======================================================================= + +# Notices for Eclipse Project for JAF + +This content is produced and maintained by the Eclipse Project for JAF project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaf + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0, +which is available at http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaf + +## Third-party Content + +This project leverages the following third party content. + +JUnit (4.12) + +* License: Eclipse Public License + +======================================================================= + +profiles-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +metrics-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +sdk-core-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jackson-jr-objects-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Licensing + +Jackson components are licensed under Apache (Software) License, version 2.0, +as per accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +======================================================================= + +spring-beans-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +commons-codec-1.11 NOTICE + +======================================================================= + +Apache Commons Codec +Copyright 2002-2017 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java +contains test data from http://aspell.net/test/orig/batch0.tab. +Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) + +=============================================================================== + +The content of package org.apache.commons.codec.language.bm has been translated +from the original php source code available at http://stevemorse.org/phoneticinfo.htm +with permission from the original authors. +Original source copyright: +Copyright (c) 2008 Alexander Beider & Stephen P. Morse. + +======================================================================= + +pravega-common-0.11.0 NOTICE + +======================================================================= + +Copyright (c) 2021 Pravega Authors. +Copyright (c) 2017-2021 Dell Inc., or its subsidiaries. All Rights Reserved. + +This software contains source code from Apache BookKeeper, distributed under +the Apache License Version 2.0, and copyrighted to the Apache Software Foundation. +http://bookkeeper.apache.org + +======================================================================= + +rocketmq-client-4.9.5 NOTICE + +======================================================================= + + +rocketmq-client 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +commons-compress-1.22 NOTICE + +======================================================================= + +Apache Commons Compress +Copyright 2002-2022 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +--- + +The files in the package org.apache.commons.compress.archivers.sevenz +were derived from the LZMA SDK, version 9.20 (C/ and CPP/7zip/), +which has been placed in the public domain: + +"LZMA SDK is placed in the public domain." (http://www.7-zip.org/sdk.html) + +--- + +The test file lbzip2_32767.bz2 has been copied from libbzip2's source +repository: + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2019 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@acm.org + +======================================================================= + +byte-buddy-1.14.18 NOTICE + +======================================================================= + +Copyright 2014 - Present Rafael Winterhalter + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +======================================================================= + +rocketmq-store-4.9.5 NOTICE + +======================================================================= + + +rocketmq-store 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +tomcat-embed-el-9.0.56 NOTICE + +======================================================================= + +Apache Tomcat +Copyright 1999-2021 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +jetty-plus-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +json-utils-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-messaging-5.3.20 NOTICE + +======================================================================= + +Spring Framework 5.3.20 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +jetty-servlet-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +pravega-shared-protocol-0.11.0 NOTICE + +======================================================================= + +Copyright (c) 2021 Pravega Authors. +Copyright (c) 2017-2021 Dell Inc., or its subsidiaries. All Rights Reserved. + +This software contains source code from Apache BookKeeper, distributed under +the Apache License Version 2.0, and copyrighted to the Apache Software Foundation. +http://bookkeeper.apache.org + +======================================================================= + +commons-collections-3.2.2 NOTICE + +======================================================================= + +Apache Commons Collections +Copyright 2001-2015 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +commons-codec-1.15 NOTICE + +======================================================================= + +Apache Commons Codec +Copyright 2002-2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java +contains test data from http://aspell.net/test/orig/batch0.tab. +Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) + +=============================================================================== + +The content of package org.apache.commons.codec.language.bm has been translated +from the original php source code available at http://stevemorse.org/phoneticinfo.htm +with permission from the original authors. +Original source copyright: +Copyright (c) 2008 Alexander Beider & Stephen P. Morse. + +======================================================================= + +annotations-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +pulsar-client-admin-api-2.11.1 NOTICE + +======================================================================= + + +Pulsar Client Admin :: API +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-jdbc-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +httpasyncclient-4.1.5 NOTICE + +======================================================================= + + +Apache HttpAsyncClient +Copyright 2010-2021 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +commons-lang3-3.17.0 NOTICE + +======================================================================= + +Apache Commons Lang +Copyright 2001-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +commons-beanutils-1.8.2 NOTICE + +======================================================================= + +Apache Commons BeanUtils +Copyright 2000-2009 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +rocketmq-tools-4.9.5 NOTICE + +======================================================================= + + +rocketmq-tools 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +mybatis-spring-2.0.4 NOTICE + +======================================================================= + +MyBatis Spring +Copyright 2010-2013 + +This product includes software developed by +The MyBatis Team (http://www.mybatis.org/). + +iBATIS + This product includes software developed by + The Apache Software Foundation (http://www.apache.org/). + + Copyright 2010 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Spring Framework + All Spring projects are licensed under the terms of the Apache License, Version 2.0 + + Copyright 2002-2010 the original author or authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= + +spring-expression-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +javax-websocket-server-impl-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +retries-spi-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-aop-5.3.15 NOTICE + +======================================================================= + +Spring Framework 5.3.15 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +jakarta.annotation-api-1.3.5 NOTICE + +======================================================================= + +# Notices for Jakarta Annotations + +This content is produced and maintained by the Jakarta Annotations project. + + * Project home: https://projects.eclipse.org/projects/ee4j.ca + +## Trademarks + +Jakarta Annotations is a trademark of the Eclipse Foundation. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License v. 2.0 which is available at +http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made +available under the following Secondary Licenses when the conditions for such +availability set forth in the Eclipse Public License v. 2.0 are satisfied: GNU +General Public License, version 2 with the GNU Classpath Exception which is +available at https://www.gnu.org/software/classpath/license.html. + +SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + +## Source Code + +The project maintains the following source code repositories: + + * https://github.com/eclipse-ee4j/common-annotations-api + +## Third-party Content + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +======================================================================= + +audience-annotations-0.12.0 NOTICE + +======================================================================= + + +Apache Yetus - Audience Annotations +Copyright 2015-2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +commons-io-2.18.0 NOTICE + +======================================================================= + +Apache Commons IO +Copyright 2002-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +mybatis-spring-2.1.2 NOTICE + +======================================================================= + +MyBatis Spring +Copyright 2010-2013 + +This product includes software developed by +The MyBatis Team (http://www.mybatis.org/). + +iBATIS + This product includes software developed by + The Apache Software Foundation (http://www.apache.org/). + + Copyright 2010 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Spring Framework + All Spring projects are licensed under the terms of the Apache License, Version 2.0 + + Copyright 2002-2010 the original author or authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= + +okhttp-3.14.9 NOTICE + +======================================================================= + +Note that publicsuffixes.gz is compiled from The Public Suffix List: +https://publicsuffix.org/list/public_suffix_list.dat + +It is subject to the terms of the Mozilla Public License, v. 2.0: +https://mozilla.org/MPL/2.0/ + +======================================================================= + +commons-beanutils-1.9.4 NOTICE + +======================================================================= + +Apache Commons BeanUtils +Copyright 2000-2019 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +nacos-client-2.4.1 NOTICE + +======================================================================= + + The Netty Project + ================= + +Please visit the Netty web site for more information: + + * http://netty.io/ + +Copyright 2016 The Netty Project + +The Netty Project 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. + +------------------------------------------------------------------------------- +This product contains a forked and modified version of Tomcat Native + + * LICENSE: + * license/LICENSE.tomcat-native.txt (Apache License 2.0) + * HOMEPAGE: + * http://tomcat.apache.org/native-doc/ + * https://svn.apache.org/repos/asf/tomcat/native/ + +This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. + + * LICENSE: + * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/takari/maven-wrapper + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * license/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist + + +This product contains code from boringssl. + + * LICENSE (Combination ISC and OpenSSL license) + * license/LICENSE.boringssl.txt (Combination ISC and OpenSSL license) + * HOMEPAGE: + * https://boringssl.googlesource.com/boringssl/ + +======================================================================= + +istack-commons-runtime-3.0.8 NOTICE + +======================================================================= + +# Notices for Eclipse Implementation of JAXB + +This content is produced and maintained by the Eclipse Implementation of JAXB +project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaxb-impl + +## Trademarks + +Eclipse Implementation of JAXB is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0 which is available at +http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaxb-ri +* https://github.com/eclipse-ee4j/jaxb-istack-commons +* https://github.com/eclipse-ee4j/jaxb-dtd-parser +* https://github.com/eclipse-ee4j/jaxb-fi +* https://github.com/eclipse-ee4j/jaxb-stax-ex +* https://github.com/eclipse-ee4j/jax-rpc-ri + +## Third-party Content + +This project leverages the following third party content. + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Felix (1.2.0) + +* License: Apache License, 2.0 + +args4j (2.33) + +* License: MIT License + +dom4j (1.6.1) + +* License: Custom license based on Apache 1.1 + +file-management (3.0.0) + +* License: Apache-2.0 +* Project: https://maven.apache.org/shared/file-management/ +* Source: + https://svn.apache.org/viewvc/maven/shared/tags/file-management-3.0.0/ + +JUnit (4.12) + +* License: Eclipse Public License + +JUnit (4.12) + +* License: Eclipse Public License + +maven-compat (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-compat/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-compat/3.5.2 + +maven-core (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-core/index.html +* Source: https://mvnrepository.com/artifact/org.apache.maven/maven-core/3.5.2 + +maven-plugin-annotations (3.5) + +* License: Apache-2.0 +* Project: https://maven.apache.org/plugin-tools/maven-plugin-annotations/ +* Source: + https://github.com/apache/maven-plugin-tools/tree/master/maven-plugin-annotations + +maven-plugin-api (3.5.2) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-connector-basic (1.1.1) + +* License: Apache-2.0 + +maven-resolver-impl (1.1.1) + +* License: Apache-2.0 + +maven-resolver-spi (1.1.1) + +* License: Apache-2.0 + +maven-resolver-transport-file (1.1.1) + +* License: Apache-2.0 +* Project: https://maven.apache.org/resolver/maven-resolver-transport-file/ +* Source: + https://github.com/apache/maven-resolver/tree/master/maven-resolver-transport-file + +maven-resolver-util (1.1.1) + +* License: Apache-2.0 + +maven-settings (3.5.2) + +* License: Apache-2.0 +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-settings/3.5.2 + +OSGi Service Platform Core Companion Code (6.0) + +* License: Apache License, 2.0 + +plexus-archiver (3.5) + +* License: Apache-2.0 +* Project: https://codehaus-plexus.github.io/plexus-archiver/ +* Source: https://github.com/codehaus-plexus/plexus-archiver + +plexus-io (3.0.0) + +* License: Apache-2.0 + +plexus-utils (3.1.0) + +* License: Apache- 2.0 or Apache- 1.1 or BSD or Public Domain or Indiana + University Extreme! Lab Software License V1.1.1 (Apache 1.1 style) + +relaxng-datatype (1.0) + +* License: New BSD license + +Sax (0.2) + +* License: SAX-PD +* Project: http://www.megginson.com/downloads/SAX/ +* Source: http://sourceforge.net/project/showfiles.php?group_id=29449 + +testng (6.14.2) + +* License: Apache-2.0 AND (MIT OR GPL-1.0+) +* Project: https://testng.org/doc/index.html +* Source: https://github.com/cbeust/testng + +wagon-http-lightweight (3.0.0) + +* License: Pending +* Project: https://maven.apache.org/wagon/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven.wagon/wagon-http-lightweight/3.0.0 + +xz for java (1.8) + +* License: LicenseRef-Public-Domain + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +======================================================================= + +jakarta.annotation-api-2.1.1 NOTICE + +======================================================================= + +# Notices for Jakarta Annotations + +This content is produced and maintained by the Jakarta Annotations project. + + * Project home: https://projects.eclipse.org/projects/ee4j.ca + +## Trademarks + +Jakarta Annotations is a trademark of the Eclipse Foundation. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License v. 2.0 which is available at +http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made +available under the following Secondary Licenses when the conditions for such +availability set forth in the Eclipse Public License v. 2.0 are satisfied: GNU +General Public License, version 2 with the GNU Classpath Exception which is +available at https://www.gnu.org/software/classpath/license.html. + +SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + +## Source Code + +The project maintains the following source code repositories: + + * https://github.com/eclipse-ee4j/common-annotations-api + +## Third-party Content + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + +======================================================================= + +log4j-api-2.24.1 NOTICE + +======================================================================= + +Apache Log4j API +Copyright 1999-2024 The Apache Software Foundation + + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +jetty-security-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +pulsar-client-2.11.1 NOTICE + +======================================================================= + + +Pulsar Client Java +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +pulsar-client-2.11.1 NOTICE + +======================================================================= + +Apache Commons Lang +Copyright 2001-2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +rocketmq-logging-4.9.5 NOTICE + +======================================================================= + + +rocketmq-logging 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-tx-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +curator-recipes-5.7.0 NOTICE + +======================================================================= + +Curator Recipes +Copyright 2011-2023 The Apache Software Foundation + + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +joda-time-2.9.4 NOTICE + +======================================================================= + +============================================================================= += NOTICE file corresponding to section 4d of the Apache License Version 2.0 = +============================================================================= +This product includes software developed by +Joda.org (http://www.joda.org/). + +======================================================================= + +spring-orm-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +commons-lang-2.6 NOTICE + +======================================================================= + +Apache Commons Lang +Copyright 2001-2011 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +aws-xml-protocol-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +commons-digester-2.1 NOTICE + +======================================================================= + +Apache Commons Digester +Copyright 2001-2010 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +======================================================================= + +spring-context-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +websocket-server-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +spring-core-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +arns-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +jetty-http-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +commons-text-1.12.0 NOTICE + +======================================================================= + +Apache Commons Text +Copyright 2014-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +javax-websocket-client-impl-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +auth-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +spring-boot-starter-2.5.9 NOTICE + +======================================================================= + +Spring Boot 2.5.9 +Copyright (c) 2012-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. +======================================================================= + +spring-webmvc-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +txw2-2.3.2 NOTICE + +======================================================================= + +# Notices for Eclipse Implementation of JAXB + +This content is produced and maintained by the Eclipse Implementation of JAXB +project. + +* Project home: https://projects.eclipse.org/projects/ee4j.jaxb-impl + +## Trademarks + +Eclipse Implementation of JAXB is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v. 1.0 which is available at +http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ee4j/jaxb-ri +* https://github.com/eclipse-ee4j/jaxb-istack-commons +* https://github.com/eclipse-ee4j/jaxb-dtd-parser +* https://github.com/eclipse-ee4j/jaxb-fi +* https://github.com/eclipse-ee4j/jaxb-stax-ex +* https://github.com/eclipse-ee4j/jax-rpc-ri + +## Third-party Content + +This project leverages the following third party content. + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Ant (1.10.2) + +* License: Apache-2.0 AND W3C AND LicenseRef-Public-Domain + +Apache Felix (1.2.0) + +* License: Apache License, 2.0 + +args4j (2.33) + +* License: MIT License + +dom4j (1.6.1) + +* License: Custom license based on Apache 1.1 + +file-management (3.0.0) + +* License: Apache-2.0 +* Project: https://maven.apache.org/shared/file-management/ +* Source: + https://svn.apache.org/viewvc/maven/shared/tags/file-management-3.0.0/ + +JUnit (4.12) + +* License: Eclipse Public License + +JUnit (4.12) + +* License: Eclipse Public License + +maven-compat (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-compat/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-compat/3.5.2 + +maven-core (3.5.2) + +* License: Apache-2.0 +* Project: https://maven.apache.org/ref/3.5.2/maven-core/index.html +* Source: https://mvnrepository.com/artifact/org.apache.maven/maven-core/3.5.2 + +maven-plugin-annotations (3.5) + +* License: Apache-2.0 +* Project: https://maven.apache.org/plugin-tools/maven-plugin-annotations/ +* Source: + https://github.com/apache/maven-plugin-tools/tree/master/maven-plugin-annotations + +maven-plugin-api (3.5.2) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-api (1.1.1) + +* License: Apache-2.0 + +maven-resolver-connector-basic (1.1.1) + +* License: Apache-2.0 + +maven-resolver-impl (1.1.1) + +* License: Apache-2.0 + +maven-resolver-spi (1.1.1) + +* License: Apache-2.0 + +maven-resolver-transport-file (1.1.1) + +* License: Apache-2.0 +* Project: https://maven.apache.org/resolver/maven-resolver-transport-file/ +* Source: + https://github.com/apache/maven-resolver/tree/master/maven-resolver-transport-file + +maven-resolver-util (1.1.1) + +* License: Apache-2.0 + +maven-settings (3.5.2) + +* License: Apache-2.0 +* Source: + https://mvnrepository.com/artifact/org.apache.maven/maven-settings/3.5.2 + +OSGi Service Platform Core Companion Code (6.0) + +* License: Apache License, 2.0 + +plexus-archiver (3.5) + +* License: Apache-2.0 +* Project: https://codehaus-plexus.github.io/plexus-archiver/ +* Source: https://github.com/codehaus-plexus/plexus-archiver + +plexus-io (3.0.0) + +* License: Apache-2.0 + +plexus-utils (3.1.0) + +* License: Apache- 2.0 or Apache- 1.1 or BSD or Public Domain or Indiana + University Extreme! Lab Software License V1.1.1 (Apache 1.1 style) + +relaxng-datatype (1.0) + +* License: New BSD license + +Sax (0.2) + +* License: SAX-PD +* Project: http://www.megginson.com/downloads/SAX/ +* Source: http://sourceforge.net/project/showfiles.php?group_id=29449 + +testng (6.14.2) + +* License: Apache-2.0 AND (MIT OR GPL-1.0+) +* Project: https://testng.org/doc/index.html +* Source: https://github.com/cbeust/testng + +wagon-http-lightweight (3.0.0) + +* License: Pending +* Project: https://maven.apache.org/wagon/ +* Source: + https://mvnrepository.com/artifact/org.apache.maven.wagon/wagon-http-lightweight/3.0.0 + +xz for java (1.8) + +* License: LicenseRef-Public-Domain + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. + + +======================================================================= + +jetty-xml-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +spring-jcl-5.3.9 NOTICE + +======================================================================= + +Spring Framework 5.3.9 +Copyright (c) 2002-2021 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +mybatis-3.5.16 NOTICE + +======================================================================= + +MyBatis +Copyright 2010-2023 + +This product includes software developed by +The MyBatis Team (https://www.mybatis.org/). + +iBATIS + This product includes software developed by + The Apache Software Foundation (https://www.apache.org/). + + Copyright 2010 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://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. + +OGNL +//-------------------------------------------------------------------------- +// Copyright (c) 2004, Drew Davidson and Luke Blanshard +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// Neither the name of the Drew Davidson nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +//-------------------------------------------------------------------------- + +Refactored SqlBuilder class (SQL, AbstractSQL) + + This product includes software developed by + Adam Gent (https://gist.github.com/3650165) + + Copyright 2010 Adam Gent + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://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. + +======================================================================= + +httpclient-4.5.14 NOTICE + +======================================================================= + + +Apache HttpClient +Copyright 1999-2022 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +jetty-client-9.4.53.v20231009 NOTICE + +======================================================================= + +============================================================== + Jetty Web Container + Copyright 1995-2018 Mort Bay Consulting Pty Ltd. +============================================================== + +The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd +unless otherwise noted. + +Jetty is dual licensed under both + + * The Apache 2.0 License + http://www.apache.org/licenses/LICENSE-2.0.html + + and + + * The Eclipse Public 1.0 License + http://www.eclipse.org/legal/epl-v10.html + +Jetty may be distributed under either license. + +------ +Eclipse + +The following artifacts are EPL. + * org.eclipse.jetty.orbit:org.eclipse.jdt.core + +The following artifacts are EPL and ASL2. + * org.eclipse.jetty.orbit:javax.security.auth.message + + +The following artifacts are EPL and CDDL 1.0. + * org.eclipse.jetty.orbit:javax.mail.glassfish + + +------ +Oracle + +The following artifacts are CDDL + GPLv2 with classpath exception. +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + + * javax.servlet:javax.servlet-api + * javax.annotation:javax.annotation-api + * javax.transaction:javax.transaction-api + * javax.websocket:javax.websocket-api + +------ +Oracle OpenJDK + +If ALPN is used to negotiate HTTP/2 connections, then the following +artifacts may be included in the distribution or downloaded when ALPN +module is selected. + + * java.sun.security.ssl + +These artifacts replace/modify OpenJDK classes. The modififications +are hosted at github and both modified and original are under GPL v2 with +classpath exceptions. +http://openjdk.java.net/legal/gplv2+ce.html + + +------ +OW2 + +The following artifacts are licensed by the OW2 Foundation according to the +terms of http://asm.ow2.org/license.html + +org.ow2.asm:asm-commons +org.ow2.asm:asm + + +------ +Apache + +The following artifacts are ASL2 licensed. + +org.apache.taglibs:taglibs-standard-spec +org.apache.taglibs:taglibs-standard-impl + + +------ +MortBay + +The following artifacts are ASL2 licensed. Based on selected classes from +following Apache Tomcat jars, all ASL2 licensed. + +org.mortbay.jasper:apache-jsp + org.apache.tomcat:tomcat-jasper + org.apache.tomcat:tomcat-juli + org.apache.tomcat:tomcat-jsp-api + org.apache.tomcat:tomcat-el-api + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-api + org.apache.tomcat:tomcat-util-scan + org.apache.tomcat:tomcat-util + +org.mortbay.jasper:apache-el + org.apache.tomcat:tomcat-jasper-el + org.apache.tomcat:tomcat-el-api + + +------ +Mortbay + +The following artifacts are CDDL + GPLv2 with classpath exception. + +https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html + +org.eclipse.jetty.toolchain:jetty-schemas + +------ +Assorted + +The UnixCrypt.java code implements the one way cryptography used by +Unix systems for simple password protection. Copyright 1996 Aki Yoshida, +modified April 2001 by Iris Van den Broeke, Daniel Deville. +Permission to use, copy, modify and distribute UnixCrypt +for non-commercial or commercial purposes and without fee is +granted provided that the copyright notice appears in all copies. + +======================================================================= + +rocketmq-common-4.9.5 NOTICE + +======================================================================= + + +rocketmq-common 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +netty-tcnative-boringssl-static-2.0.48.Final NOTICE + +======================================================================= + + The Netty Project + ================= + +Please visit the Netty web site for more information: + + * http://netty.io/ + +Copyright 2016 The Netty Project + +The Netty Project 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. + +------------------------------------------------------------------------------- +This product contains a forked and modified version of Tomcat Native + + * LICENSE: + * license/LICENSE.tomcat-native.txt (Apache License 2.0) + * HOMEPAGE: + * http://tomcat.apache.org/native-doc/ + * https://svn.apache.org/repos/asf/tomcat/native/ + +This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. + + * LICENSE: + * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/takari/maven-wrapper + +This product contains small piece of code to support AIX, taken from netbsd. + + * LICENSE: + * license/LICENSE.aix-netbsd.txt (OpenSSL License) + * HOMEPAGE: + * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist + + +This product contains code from boringssl. + + * LICENSE (Combination ISC and OpenSSL license) + * license/LICENSE.boringssl.txt (Combination ISC and OpenSSL license) + * HOMEPAGE: + * https://boringssl.googlesource.com/boringssl/ + +======================================================================= + +s3-2.29.5 NOTICE + +======================================================================= + +AWS SDK for Java 2.0 +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). + +********************** +THIRD PARTY COMPONENTS +********************** +This software includes third party software subject to the following copyrights: +- XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty. +- PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc. +- Apache Commons Lang - https://github.com/apache/commons-lang +- Netty Reactive Streams - https://github.com/playframework/netty-reactive-streams +- Jackson-core - https://github.com/FasterXML/jackson-core +- Jackson-dataformat-cbor - https://github.com/FasterXML/jackson-dataformats-binary + +The licenses for these third party components are included in LICENSE.txt + +- For Apache Commons Lang see also this required NOTICE: + Apache Commons Lang + Copyright 2001-2020 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +pulsar-client-2.11.4 NOTICE + +======================================================================= + + +Pulsar Client Java +Copyright 2017-2020 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +pulsar-client-2.11.4 NOTICE + +======================================================================= + +Apache Commons Lang +Copyright 2001-2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +======================================================================= + +httpmime-4.5.13 NOTICE + +======================================================================= + + +Apache HttpClient Mime +Copyright 1999-2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + +======================================================================= + +spring-context-5.3.15 NOTICE + +======================================================================= + +Spring Framework 5.3.15 +Copyright (c) 2002-2022 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +spring-expression-5.3.31 NOTICE + +======================================================================= + +Spring Framework 5.3.31 +Copyright (c) 2002-2023 Pivotal, Inc. + +This product is licensed to you under the Apache License, Version 2.0 +(the "License"). You may not use this product except in compliance with +the License. + +This product may include a number of subcomponents with separate +copyright notices and license terms. Your use of the source code for +these subcomponents is subject to the terms and conditions of the +subcomponent's license, as noted in the license.txt file. + +======================================================================= + +jackson-core-2.18.0 NOTICE + +======================================================================= + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers. + +## Copyright + +Copyright 2007-, Tatu Saloranta (tatu.saloranta@iki.fi) + +## Licensing + +Jackson 2.x core and extension components are licensed under Apache License 2.0 +To find the details that apply to this artifact see the accompanying LICENSE file. + +## Credits + +A list of contributors may be found from CREDITS(-2.x) file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +## FastDoubleParser + +jackson-core bundles a shaded copy of FastDoubleParser . +That code is available under an MIT license +under the following copyright. + +Copyright © 2023 Werner Randelshofer, Switzerland. MIT License. + +See FastDoubleParser-NOTICE for details of other source code included in FastDoubleParser +and the licenses and copyrights that apply to that code. + +======================================================================= + +rocketmq-filter-4.9.5 NOTICE + +======================================================================= + + +rocketmq-filter 4.9.5 +Copyright 2012-2023 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cespare-xxhash-v2.txt b/tools/dist-license/licenses/go/LICENSE-github.com-cespare-xxhash-v2.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-cespare-xxhash-v2.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-cespare-xxhash-v2.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cespare-xxhash.txt b/tools/dist-license/licenses/go/LICENSE-github.com-cespare-xxhash.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-cespare-xxhash.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-cespare-xxhash.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cloudevents-sdk-go-v2.txt b/tools/dist-license/licenses/go/LICENSE-github.com-cloudevents-sdk-go-v2.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-cloudevents-sdk-go-v2.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-cloudevents-sdk-go-v2.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-uuid.txt b/tools/dist-license/licenses/go/LICENSE-github.com-google-uuid.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-google-uuid.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-google-uuid.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-json-iterator-go.txt b/tools/dist-license/licenses/go/LICENSE-github.com-json-iterator-go.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-json-iterator-go.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-json-iterator-go.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-panjf2000-ants.txt b/tools/dist-license/licenses/go/LICENSE-github.com-panjf2000-ants.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-panjf2000-ants.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-panjf2000-ants.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-sony-sonyflake.txt b/tools/dist-license/licenses/go/LICENSE-github.com-sony-sonyflake.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-sony-sonyflake.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-sony-sonyflake.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-stretchr-testify.txt b/tools/dist-license/licenses/go/LICENSE-github.com-stretchr-testify.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-github.com-stretchr-testify.txt rename to tools/dist-license/licenses/go/LICENSE-github.com-stretchr-testify.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-atomic.txt b/tools/dist-license/licenses/go/LICENSE-go.uber.org-atomic.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-atomic.txt rename to tools/dist-license/licenses/go/LICENSE-go.uber.org-atomic.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-zap.txt b/tools/dist-license/licenses/go/LICENSE-go.uber.org-zap.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-zap.txt rename to tools/dist-license/licenses/go/LICENSE-go.uber.org-zap.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-grpc.txt b/tools/dist-license/licenses/go/LICENSE-google.golang.org-grpc.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-grpc.txt rename to tools/dist-license/licenses/go/LICENSE-google.golang.org-grpc.txt diff --git a/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-protobuf.txt b/tools/dist-license/licenses/go/LICENSE-google.golang.org-protobuf.txt similarity index 100% rename from tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-protobuf.txt rename to tools/dist-license/licenses/go/LICENSE-google.golang.org-protobuf.txt diff --git a/tools/dist-license/licenses/java/AL 2.0-downloaded-LICENSE-2.0.html b/tools/dist-license/licenses/java/AL 2.0-downloaded-LICENSE-2.0.html new file mode 100644 index 0000000000..fd2be6350e --- /dev/null +++ b/tools/dist-license/licenses/java/AL 2.0-downloaded-LICENSE-2.0.html @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Apache License, Version 2.0 | Apache Software Foundations + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Introducing The ASF’s New Logo Read Now

+
+
+
+
+ +
+
+ +
+ + + + + +
+ +
+
+ + +

Apache License, Version 2.0

+
+
ASF Oak Leaf Icon
+
+
+ +
+
+

The 2.0 version of the Apache License, approved by the ASF in 2004, helps us achieve our goal of providing +reliable and long-lived software products through collaborative, open-source software development.

+

All packages produced by the ASF are implicitly licensed under the Apache +License, Version 2.0, unless otherwise explicitly stated.

+
+

+Apache License
Version 2.0, January 2004
+http://www.apache.org/licenses/ +

+

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

1. Definitions.

+
+

"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document.

+

"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License.

+

"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control with +that entity. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty +percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity.

+

"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License.

+

"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files.

+

"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled +object code, generated documentation, and conversions to other media types.

+

"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the +Appendix below).

+

"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, as +a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, or +merely link (or bind by name) to the interfaces of, the Work and Derivative +Works thereof.

+

"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, +verbal, or written communication sent to the Licensor or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that +are managed by, or on behalf of, the Licensor for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously +marked or otherwise designated in writing by the copyright owner as "Not a +Contribution."

+

"Contributor" shall mean Licensor and any individual or Legal Entity on +behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work.

+
+

2. Grant of Copyright License. Subject to the +terms and conditions of this License, each Contributor hereby grants to You +a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, publicly +display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form.

+

3. Grant of Patent License. Subject to the terms +and conditions of this License, each Contributor hereby grants to You a +perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, use, +offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by +combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes +direct or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate as of the +date such litigation is filed.

+

4. Redistribution. You may reproduce and +distribute copies of the Work or Derivative Works thereof in any medium, +with or without modifications, and in Source or Object form, provided that +You meet the following conditions:

+
    +
  1. You must give any other recipients of the Work or Derivative Works a +copy of this License; and
  2. +
  3. You must cause any modified files to carry prominent notices stating +that You changed the files; and
  4. +
  5. You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices from +the Source form of the Work, excluding those notices that do not pertain to +any part of the Derivative Works; and
  6. +
  7. If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy +of the attribution notices contained within such NOTICE file, excluding +those notices that do not pertain to any part of the Derivative Works, in +at least one of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or documentation, +if provided along with the Derivative Works; or, within a display generated +by the Derivative Works, if and wherever such third-party notices normally +appear. The contents of the NOTICE file are for informational purposes only +and do not modify the License. You may add Your own attribution notices +within Derivative Works that You distribute, alongside or as an addendum to +the NOTICE text from the Work, provided that such additional attribution +notices cannot be construed as modifying the License. +
  8. +
+

You may add Your own copyright statement to Your modifications and may +provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such +Derivative Works as a whole, provided Your use, reproduction, and +distribution of the Work otherwise complies with the conditions stated in +this License.

+

5. Submission of Contributions. Unless You +explicitly state otherwise, any Contribution intentionally submitted for +inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the +terms of any separate license agreement you may have executed with Licensor +regarding such Contributions.

+

6. Trademarks. This License does not grant +permission to use the trade names, trademarks, service marks, or product +names of the Licensor, except as required for reasonable and customary use +in describing the origin of the Work and reproducing the content of the +NOTICE file.

+

7. Disclaimer of Warranty. Unless required by +applicable law or agreed to in writing, Licensor provides the Work (and +each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You +are solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise +of permissions under this License.

+

8. Limitation of Liability. In no event and +under no legal theory, whether in tort (including negligence), contract, or +otherwise, unless required by applicable law (such as deliberate and +grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a result +of this License or out of the use or inability to use the Work (including +but not limited to damages for loss of goodwill, work stoppage, computer +failure or malfunction, or any and all other commercial damages or losses), +even if such Contributor has been advised of the possibility of such +damages.

+

9. Accepting Warranty or Additional Liability. +While redistributing the Work or Derivative Works thereof, You may choose +to offer, and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf +and on Your sole responsibility, not on behalf of any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor +harmless for any liability incurred by, or claims asserted against, such +Contributor by reason of your accepting any such warranty or additional +liability.

+

END OF TERMS AND CONDITIONS

+
+

How to apply the Apache License to your work

+

Include a copy of the Apache License, typically in a file called +LICENSE, in your work, and consider also including a NOTICE file that references the License.

+

To apply the Apache License to specific files in your work, attach the following boilerplate +declaration, replacing the fields enclosed by brackets "[]" with your own +identifying information. (Don't include the brackets!) Enclose the text in the appropriate comment syntax for the file format. We also +recommend that you include a file or class name and description of purpose on the same "printed page" as the copyright notice for easier +identification within third-party archives.

+
Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/tools/dist-license/licenses/java/AL 2.0.txt b/tools/dist-license/licenses/java/AL 2.0.txt new file mode 100644 index 0000000000..f54e3f8ebc --- /dev/null +++ b/tools/dist-license/licenses/java/AL 2.0.txt @@ -0,0 +1 @@ +https://www.apache.org/licenses/LICENSE-2.0.html \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-assertj-core.txt b/tools/dist-license/licenses/java/ASL, version 2-downloaded-LICENSE-2.0.txt similarity index 100% rename from tools/third-party-licenses/licenses/java/LICENSE-assertj-core.txt rename to tools/dist-license/licenses/java/ASL, version 2-downloaded-LICENSE-2.0.txt diff --git a/tools/dist-license/licenses/java/ASL, version 2.txt b/tools/dist-license/licenses/java/ASL, version 2.txt new file mode 100644 index 0000000000..5456b5aa73 --- /dev/null +++ b/tools/dist-license/licenses/java/ASL, version 2.txt @@ -0,0 +1 @@ +http://www.apache.org/licenses/LICENSE-2.0.txt \ No newline at end of file diff --git a/tools/dist-license/licenses/java/Apache-1.1.txt b/tools/dist-license/licenses/java/Apache-1.1.txt new file mode 100644 index 0000000000..2f0168af9c --- /dev/null +++ b/tools/dist-license/licenses/java/Apache-1.1.txt @@ -0,0 +1,21 @@ +Apache License 1.1 + +Copyright (c) 2000 The Apache Software Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: +"This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." +Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. + +4. The names "Apache" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact apache@apache.org. + +5. Products derived from this software may not be called "Apache" [ex. "Jakarta," "Apache," or "Apache Commons,"] nor may "Apache" [ex. the names] appear in their name, without prior written permission of the Apache Software Foundation. + +THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For more information on the Apache Software Foundation, please see http://www.apache.org/. Portions of this software are based upon public domain software originally written at the National Center for Supercomputing Applications, University of Illinois, Urbana-Champaign. diff --git a/tools/dist-license/licenses/java/Apache-2.0.txt b/tools/dist-license/licenses/java/Apache-2.0.txt new file mode 100644 index 0000000000..137069b823 --- /dev/null +++ b/tools/dist-license/licenses/java/Apache-2.0.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/tools/dist-license/licenses/java/BSD licence-downloaded-license.html b/tools/dist-license/licenses/java/BSD licence-downloaded-license.html new file mode 100644 index 0000000000..47c66bbb96 --- /dev/null +++ b/tools/dist-license/licenses/java/BSD licence-downloaded-license.html @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + ANTLR v4 License + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +ANTLR + + + + +
+ +
+
+ +
+ +
+ +

ANTLR 4 License

+ +[The BSD License]
+Copyright (c) 2012 Terence Parr and Sam Harwell
+All rights reserved.
+ +

+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +

    +
  • +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +
  • Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +
+ +

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ +
+

Developer's Certificate of Origin

+ +

As of 4.10, ANTLR uses the Linux Foundation's Developer Certificate of Origin, DCO, version 1.1. See certificate +of origin. To contribute:

+ +
    +
  • fork the dev branch of the ANTLR v4 github repository +
  • make your changes +
  • commit your changes, signing your commits with git commit -s .... +
  • send a pull request +
+ +
+ + + +
+ + +
+ +
+
+ +
+ +
+ + + + + diff --git a/tools/dist-license/licenses/java/BSD licence.txt b/tools/dist-license/licenses/java/BSD licence.txt new file mode 100644 index 0000000000..70aa2f4d21 --- /dev/null +++ b/tools/dist-license/licenses/java/BSD licence.txt @@ -0,0 +1 @@ +http://antlr.org/license.html \ No newline at end of file diff --git a/tools/dist-license/licenses/java/BSD-2-Clause.txt b/tools/dist-license/licenses/java/BSD-2-Clause.txt new file mode 100644 index 0000000000..5f662b354c --- /dev/null +++ b/tools/dist-license/licenses/java/BSD-2-Clause.txt @@ -0,0 +1,9 @@ +Copyright (c) + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/dist-license/licenses/java/BSD-3-Clause.txt b/tools/dist-license/licenses/java/BSD-3-Clause.txt new file mode 100644 index 0000000000..ea890afbc7 --- /dev/null +++ b/tools/dist-license/licenses/java/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) . + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/dist-license/licenses/java/BSD-4-Clause.txt b/tools/dist-license/licenses/java/BSD-4-Clause.txt new file mode 100644 index 0000000000..1e67e146f8 --- /dev/null +++ b/tools/dist-license/licenses/java/BSD-4-Clause.txt @@ -0,0 +1,14 @@ +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. All advertising materials mentioning features or use of this software must display the following acknowledgement: +This product includes software developed by the organization. + +4. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/dist-license/licenses/java/Bouncy Castle Licence-downloaded-licence.html b/tools/dist-license/licenses/java/Bouncy Castle Licence-downloaded-licence.html new file mode 100644 index 0000000000..96d7e64d27 --- /dev/null +++ b/tools/dist-license/licenses/java/Bouncy Castle Licence-downloaded-licence.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + bouncycastle.org + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +

Please note the Bouncy Caste License should be read in the same way as the MIT license.

+

Please also note this licensing model is made possible through funding from donations and the sale of support contracts.

+

Bouncy Castle License

+

Copyright (c) 2000 - 2024 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) +

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +

Third party licenses

+ +

The OpenPGP library and the MLS library both make use of additional open source code: +

+

+
+
 
+ +
+
+
 
+ + + + + + diff --git a/tools/dist-license/licenses/java/Bouncy Castle Licence.txt b/tools/dist-license/licenses/java/Bouncy Castle Licence.txt new file mode 100644 index 0000000000..c38ac6fce7 --- /dev/null +++ b/tools/dist-license/licenses/java/Bouncy Castle Licence.txt @@ -0,0 +1 @@ +https://www.bouncycastle.org/licence.html \ No newline at end of file diff --git a/tools/dist-license/licenses/java/CC0-1.0.txt b/tools/dist-license/licenses/java/CC0-1.0.txt new file mode 100644 index 0000000000..0e259d42c9 --- /dev/null +++ b/tools/dist-license/licenses/java/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/tools/dist-license/licenses/java/CDDL-1.0.txt b/tools/dist-license/licenses/java/CDDL-1.0.txt new file mode 100644 index 0000000000..2a5d7f18fc --- /dev/null +++ b/tools/dist-license/licenses/java/CDDL-1.0.txt @@ -0,0 +1,119 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) +Version 1.0 + +1. Definitions. + +1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + +1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + +1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + +1.4. “Executable” means the Covered Software in any form other than Source Code. + +1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + +1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + +1.7. “License” means this document. + +1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + +1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + +1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + +1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + +1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + +1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + +2.1. The Initial Developer Grant. +Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + +2.2. Contributor Grant. +Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + +3.1. Availability of Source Code. +Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + +3.2. Modifications. +The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + +3.3. Required Notices. +You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + +3.4. Application of Additional Terms. +You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + +3.5. Distribution of Executable Versions. +You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + +3.6. Larger Works. +You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + +4.1. New Versions. +Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + +4.2. Effect of New Versions. +You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + +4.3. Modified Versions. +When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +6. TERMINATION. + +6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + +6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + +6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. + +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. diff --git a/tools/dist-license/licenses/java/CDDL-1.1.txt b/tools/dist-license/licenses/java/CDDL-1.1.txt new file mode 100644 index 0000000000..f5479ec406 --- /dev/null +++ b/tools/dist-license/licenses/java/CDDL-1.1.txt @@ -0,0 +1,123 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) +Version 1.1 + +1. Definitions. + +1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + +1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + +1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + +1.4. “Executable” means the Covered Software in any form other than Source Code. + +1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + +1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + +1.7. “License” means this document. + +1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + +1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + +1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + +1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + +1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + +1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + +2.1. The Initial Developer Grant. +Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + +2.2. Contributor Grant. +Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + +3.1. Availability of Source Code. +Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + +3.2. Modifications. +The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + +3.3. Required Notices. +You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + +3.4. Application of Additional Terms. +You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients' rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + +3.5. Distribution of Executable Versions. +You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient's rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + +3.6. Larger Works. +You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + +4.1. New Versions. +Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + +4.2. Effect of New Versions. +You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + +4.3. Modified Versions. +When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +6. TERMINATION. + +6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + +6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + +6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + +6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. + +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) +The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. diff --git a/tools/dist-license/licenses/java/EPL 1.0-downloaded-eclipse-1.0.php b/tools/dist-license/licenses/java/EPL 1.0-downloaded-eclipse-1.0.php new file mode 100644 index 0000000000..7fd800529e --- /dev/null +++ b/tools/dist-license/licenses/java/EPL 1.0-downloaded-eclipse-1.0.php @@ -0,0 +1,1543 @@ + + + + + + + + Eclipse Public License -v 1.0 – Open Source Initiative + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+
+
+
+
+ + + +

Eclipse Public License -v 1.0

+ Version 1.0Submitted: March 8, 2004Submitter: Philip Ma + SPDX short identifier: + EPL-1.0 +

+ +
+
+ Open Source Initiative Approved License +
+
+
+
+
+ +
+
+

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT.

+

1. DEFINITIONS

+

“Contribution” means:

+

a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and

+

b) in the case of each subsequent Contributor:

+

i) changes to the Program, and

+

ii) additions to the Program;

+

where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution ‘originates’ from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor’s behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.

+

“Contributor” means any person or entity that distributes the Program.

+

“Licensed Patents ” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

+

“Program” means the Contributions distributed in accordance with this Agreement.

+

“Recipient” means anyone who receives the Program under this Agreement, including all Contributors.

+

2. GRANT OF RIGHTS

+

a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.

+

b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.

+

c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient’s responsibility to acquire that license before distributing the Program.

+

d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.

+

3. REQUIREMENTS

+

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:

+

a) it complies with the terms and conditions of this Agreement; and

+

b) its license agreement:

+

i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;

+

ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;

+

iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and

+

iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.

+

When the Program is made available in source code form:

+

a) it must be made available under this Agreement; and

+

b) a copy of this Agreement must be included with each copy of the Program.

+

Contributors may not remove or alter any copyright notices contained within the Program.

+

Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.

+

4. COMMERCIAL DISTRIBUTION

+

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

+

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor’s responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

+

5. NO WARRANTY

+

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

+

6. DISCLAIMER OF LIABILITY

+

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

+

7. GENERAL

+

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

+

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient’s patent(s), then such Recipient’s rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

+

All Recipient’s rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient’s rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient’s obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

+

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

+

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

+ +
+
+
+
+ + +
+ + + +
+
+
+ + +
+ + + + +
+ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/dist-license/licenses/java/EPL 1.0.txt b/tools/dist-license/licenses/java/EPL 1.0.txt new file mode 100644 index 0000000000..dfa398f7fe --- /dev/null +++ b/tools/dist-license/licenses/java/EPL 1.0.txt @@ -0,0 +1 @@ +https://opensource.org/licenses/eclipse-1.0.php \ No newline at end of file diff --git a/tools/dist-license/licenses/java/EPL-1.0.txt b/tools/dist-license/licenses/java/EPL-1.0.txt new file mode 100644 index 0000000000..70ed0f3839 --- /dev/null +++ b/tools/dist-license/licenses/java/EPL-1.0.txt @@ -0,0 +1,73 @@ +Eclipse Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the Program. +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. diff --git a/tools/dist-license/licenses/java/EPL-2.0.txt b/tools/dist-license/licenses/java/EPL-2.0.txt new file mode 100644 index 0000000000..78756b5e9a --- /dev/null +++ b/tools/dist-license/licenses/java/EPL-2.0.txt @@ -0,0 +1,80 @@ +Eclipse Public License - v 2.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS +“Contribution” means: + +a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. +“Contributor” means any person or entity that Distributes the Program. + +“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +“Program” means the Contributions Distributed in accordance with this Agreement. + +“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. + +“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. + +“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. + +“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. + +“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. + +“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. + +2. GRANT OF RIGHTS +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). +3. REQUIREMENTS +3.1 If a Contributor Distributes the Program in any form, then: + +a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and +b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: +i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and +iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. +3.2 When the Program is Distributed as Source Code: + +a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and +b) a copy of this Agreement must be included with each copy of the Program. +3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. + +Exhibit A – Form of Secondary Licenses Notice +“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.” + +Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. diff --git a/tools/dist-license/licenses/java/GNU General Public Library.txt b/tools/dist-license/licenses/java/GNU General Public Library.txt new file mode 100644 index 0000000000..81a9b13265 --- /dev/null +++ b/tools/dist-license/licenses/java/GNU General Public Library.txt @@ -0,0 +1 @@ +http://www.gnu.org/licenses/gpl.txt \ No newline at end of file diff --git a/tools/dist-license/licenses/java/GNU General Public License, version 2 with the GNU Classpath Exception-downloaded-secondary-gpl-2.0-cp b/tools/dist-license/licenses/java/GNU General Public License, version 2 with the GNU Classpath Exception-downloaded-secondary-gpl-2.0-cp new file mode 100644 index 0000000000..f764de91de --- /dev/null +++ b/tools/dist-license/licenses/java/GNU General Public License, version 2 with the GNU Classpath Exception-downloaded-secondary-gpl-2.0-cp @@ -0,0 +1,901 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception | projects.eclipse.org + + + + + + + + +
+ + +
+ +
+
+ + + +
+
+
+ + +
+ +
+ +
+ + + +
+
+
+ +
+ projects.eclipse.org +
+
+ + + +
+ Download + +
+
+
+
+ +
+ + + + + +
+ +
+ + +
+ + + +
+ + + +
+
+ +
+ + +
+
+ + +
+ +
+ + + + +
+ +

+一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception +

+ + +
+ + + + + +
+ +

This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License, version 2 with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.

+
+ + + + + +
+ + + + + +
+ +
+ +
+ + +
+ + + +
+ + + +
+
+ + + + + +
+ + + + + + + diff --git a/tools/dist-license/licenses/java/GNU General Public License, version 2 with the GNU Classpath Exception.txt b/tools/dist-license/licenses/java/GNU General Public License, version 2 with the GNU Classpath Exception.txt new file mode 100644 index 0000000000..37b86a6d9b --- /dev/null +++ b/tools/dist-license/licenses/java/GNU General Public License, version 2 with the GNU Classpath Exception.txt @@ -0,0 +1 @@ +https://projects.eclipse.org/license/secondary-gpl-2.0-cp \ No newline at end of file diff --git a/tools/dist-license/licenses/java/GNU General Public License, version 2.txt b/tools/dist-license/licenses/java/GNU General Public License, version 2.txt new file mode 100644 index 0000000000..5de3c76da4 --- /dev/null +++ b/tools/dist-license/licenses/java/GNU General Public License, version 2.txt @@ -0,0 +1 @@ +http://www.gnu.org/licenses/gpl-2.0.html \ No newline at end of file diff --git a/tools/dist-license/licenses/java/GNU LESSER GENERAL PUBLIC LICENSE.txt b/tools/dist-license/licenses/java/GNU LESSER GENERAL PUBLIC LICENSE.txt new file mode 100644 index 0000000000..6e4e7fc82e --- /dev/null +++ b/tools/dist-license/licenses/java/GNU LESSER GENERAL PUBLIC LICENSE.txt @@ -0,0 +1 @@ +http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html \ No newline at end of file diff --git a/tools/dist-license/licenses/java/GPL v2.txt b/tools/dist-license/licenses/java/GPL v2.txt new file mode 100644 index 0000000000..c0aa16e535 --- /dev/null +++ b/tools/dist-license/licenses/java/GPL v2.txt @@ -0,0 +1 @@ +https://www.gnu.org/licenses/gpl-2.0.txt \ No newline at end of file diff --git a/tools/dist-license/licenses/java/GPL-2.0-with-classpath-exception.txt b/tools/dist-license/licenses/java/GPL-2.0-with-classpath-exception.txt new file mode 100644 index 0000000000..1becba2bb0 --- /dev/null +++ b/tools/dist-license/licenses/java/GPL-2.0-with-classpath-exception.txt @@ -0,0 +1 @@ +404: Not Found \ No newline at end of file diff --git a/tools/dist-license/licenses/java/Indiana University Extreme! Lab Software License, vesion 1.1.1.txt b/tools/dist-license/licenses/java/Indiana University Extreme! Lab Software License, vesion 1.1.1.txt new file mode 100644 index 0000000000..0769a4a78b --- /dev/null +++ b/tools/dist-license/licenses/java/Indiana University Extreme! Lab Software License, vesion 1.1.1.txt @@ -0,0 +1 @@ +http://www.extreme.indiana.edu/viewcvs/~checkout~/XPP3/java/LICENSE.txt \ No newline at end of file diff --git a/tools/dist-license/licenses/java/LGPL, version 2.1.txt b/tools/dist-license/licenses/java/LGPL, version 2.1.txt new file mode 100644 index 0000000000..3a12067566 --- /dev/null +++ b/tools/dist-license/licenses/java/LGPL, version 2.1.txt @@ -0,0 +1 @@ +http://www.gnu.org/licenses/licenses.html \ No newline at end of file diff --git a/tools/dist-license/licenses/java/LGPL-2.1-only.txt b/tools/dist-license/licenses/java/LGPL-2.1-only.txt new file mode 100644 index 0000000000..c9aa53018e --- /dev/null +++ b/tools/dist-license/licenses/java/LGPL-2.1-only.txt @@ -0,0 +1,175 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. + + e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/tools/dist-license/licenses/java/MIT-0.txt b/tools/dist-license/licenses/java/MIT-0.txt new file mode 100644 index 0000000000..a4e9dc9061 --- /dev/null +++ b/tools/dist-license/licenses/java/MIT-0.txt @@ -0,0 +1,16 @@ +MIT No Attribution + +Copyright + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dist-license/licenses/java/MIT.txt b/tools/dist-license/licenses/java/MIT.txt new file mode 100644 index 0000000000..2071b23b0e --- /dev/null +++ b/tools/dist-license/licenses/java/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dist-license/licenses/java/MPL-1.1.txt b/tools/dist-license/licenses/java/MPL-1.1.txt new file mode 100644 index 0000000000..e1c842828c --- /dev/null +++ b/tools/dist-license/licenses/java/MPL-1.1.txt @@ -0,0 +1,143 @@ +Mozilla Public License Version 1.1 + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source Code. + + 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. + + 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: +Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. +Any new file that contains any part of the Original Code or previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: + + a. under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and + b. under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). + c. the licenses granted in this Section 2.1 (a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. + d. Notwithstanding Section 2.1 (b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license + + a. under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and + b. under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + c. the licenses granted in Sections 2.2 (a) and 2.2 (b) are effective on the date Contributor first makes Commercial Use of the Covered Code. + d. Notwithstanding Section 2.2 (b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. + + 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + + (a) Third Party Claims + If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. + + (b) Contributor APIs + If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to Section 3.4 (a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. + + 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Sections 3.1, 3.2, 3.3, 3.4 and 3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Application of this License. +This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions + Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. + + 6.2. Effect of New Versions + Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. + + 6.3. Derivative Works + If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) + +7. DISCLAIMER OF WARRANTY +COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. Termination + + 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: + + a. such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. + b. any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. + + 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. government end users +The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. + +11. Miscellaneous +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. + +12. Responsibility for claims +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. + +13. Multiple-licensed code +Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the MPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. + +Exhibit A - Mozilla Public License. + +"The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. + +The Original Code is ______________________________________. + +The Initial Developer of the Original Code is ________________________. +Portions created by ______________________ are Copyright (C) ______ +_______________________. All Rights Reserved. + +Contributor(s): ______________________________________. + +Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." + +NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications. diff --git a/tools/dist-license/licenses/java/MPL-2.0.txt b/tools/dist-license/licenses/java/MPL-2.0.txt new file mode 100644 index 0000000000..ee6256cdb6 --- /dev/null +++ b/tools/dist-license/licenses/java/MPL-2.0.txt @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/tools/dist-license/licenses/java/Public Domain.txt b/tools/dist-license/licenses/java/Public Domain.txt new file mode 100644 index 0000000000..7dcf008e6d --- /dev/null +++ b/tools/dist-license/licenses/java/Public Domain.txt @@ -0,0 +1 @@ +http://creativecommons.org/licenses/publicdomain \ No newline at end of file diff --git a/tools/dist-license/licenses/java/The Apache Software License, Version 1.1-downloaded-LICENSE-1.1.txt b/tools/dist-license/licenses/java/The Apache Software License, Version 1.1-downloaded-LICENSE-1.1.txt new file mode 100644 index 0000000000..8ee3701375 --- /dev/null +++ b/tools/dist-license/licenses/java/The Apache Software License, Version 1.1-downloaded-LICENSE-1.1.txt @@ -0,0 +1,65 @@ +=== An example Apache Software License 1.1 file === + +The 1.1 version of the Apache License was approved by the ASF in 2000. + +The primary change from the 1.0 license was in the removal of the 'advertising clause' (section 3 of the 1.0 license); derived products are no longer required to include attribution in their advertising materials, only in their documentation. + + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + diff --git a/tools/dist-license/licenses/java/The Apache Software License, Version 1.1.txt b/tools/dist-license/licenses/java/The Apache Software License, Version 1.1.txt new file mode 100644 index 0000000000..519548056f --- /dev/null +++ b/tools/dist-license/licenses/java/The Apache Software License, Version 1.1.txt @@ -0,0 +1 @@ +http://www.apache.org/licenses/LICENSE-1.1.txt \ No newline at end of file diff --git a/tools/dist-license/licenses/java/The GNU General Public License, Version 2.txt b/tools/dist-license/licenses/java/The GNU General Public License, Version 2.txt new file mode 100644 index 0000000000..036b20977c --- /dev/null +++ b/tools/dist-license/licenses/java/The GNU General Public License, Version 2.txt @@ -0,0 +1 @@ +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html \ No newline at end of file diff --git a/tools/dist-license/licenses/java/Unicode-ICU License-downloaded-LICENSE b/tools/dist-license/licenses/java/Unicode-ICU License-downloaded-LICENSE new file mode 100644 index 0000000000..5a2eda6295 --- /dev/null +++ b/tools/dist-license/licenses/java/Unicode-ICU License-downloaded-LICENSE @@ -0,0 +1,568 @@ +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 2016-2025 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +SPDX-License-Identifier: Unicode-3.0 + +---------------------------------------------------------------------- + +Third-Party Software Licenses + +This section contains third-party software notices and/or additional +terms for licensed third-party software components included within ICU +libraries. + +---------------------------------------------------------------------- + +ICU License - ICU 1.8.1 to ICU 57.1 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1995-2016 International Business Machines Corporation and others +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +All trademarks and registered trademarks mentioned herein are the +property of their respective owners. + +---------------------------------------------------------------------- + +Chinese/Japanese Word Break Dictionary Data (cjdict.txt) + + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. + # + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. + # + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. + # + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. + # + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. + # + # ---------COPYING.libtabe ---- BEGIN-------------------- + # + # /* + # * Copyright (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # + # ---------------COPYING.libtabe-----END-------------------------------- + # + # + # ---------------COPYING.ipadic-----BEGIN------------------------------- + # + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. + # + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. + # + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. + # + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. + # + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. + # + # NO WARRANTY + # + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. + # + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. + # + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. + # + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. + # + # ---------------COPYING.ipadic-----END---------------------------------- + +---------------------------------------------------------------------- + +Lao Word Break Dictionary Data (laodict.txt) + + # Copyright (C) 2016 and later: Unicode, Inc. and others. + # License & terms of use: http://www.unicode.org/copyright.html + # Copyright (c) 2015 International Business Machines Corporation + # and others. All Rights Reserved. + # + # Project: https://github.com/rober42539/lao-dictionary + # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt + # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt + # (copied below) + # + # This file is derived from the above dictionary version of Nov 22, 2020 + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in binary + # form must reproduce the above copyright notice, this list of conditions and + # the following disclaimer in the documentation and/or other materials + # provided with the distribution. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- + +---------------------------------------------------------------------- + +Burmese Word Break Dictionary Data (burmesedict.txt) + + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. + # + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists + # + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. + # + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- + +---------------------------------------------------------------------- + +Time Zone Database + + ICU uses the public domain data and code derived from Time Zone +Database for its time zone support. The ownership of the TZ database +is explained in BCP 175: Procedure for Maintaining the Time Zone +Database section 7. + + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. + +---------------------------------------------------------------------- + +Google double-conversion + +Copyright 2006-2011, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- + +JSON parsing library (nlohmann/json) + +File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C) + +MIT License + +Copyright (c) 2013-2022 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------- + +File: aclocal.m4 (only for ICU4C) +Section: pkg.m4 - Macros to locate and utilise pkg-config. + + +Copyright © 2004 Scott James Remnant . +Copyright © 2012-2015 Dan Nicholson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + +As a special exception to the GNU General Public License, if you +distribute this file as part of a program that contains a +configuration script generated by Autoconf, you may include it under +the same distribution terms that you use for the rest of that +program. + + +(The condition for the exception is fulfilled because +ICU4C includes a configuration script generated by Autoconf, +namely the `configure` script.) + +---------------------------------------------------------------------- + +File: config.guess (only for ICU4C) + + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . + +As a special exception to the GNU General Public License, if you +distribute this file as part of a program that contains a +configuration script generated by Autoconf, you may include it under +the same distribution terms that you use for the rest of that +program. This Exception is an additional permission under section 7 +of the GNU General Public License, version 3 ("GPLv3"). + + +(The condition for the exception is fulfilled because +ICU4C includes a configuration script generated by Autoconf, +namely the `configure` script.) + +---------------------------------------------------------------------- + +File: install-sh (only for ICU4C) + + +Copyright 1991 by the Massachusetts Institute of Technology + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name of M.I.T. not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. M.I.T. makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +---------------------------------------------------------------------- + +File: sorttable.js (only for ICU4J) + +The MIT Licence, for code from kryogenix.org + +Code downloaded from the Browser Experiments section of kryogenix.org is +licenced under the so-called MIT licence. The licence is below. + +Copyright (c) 1997-date Stuart Langridge + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/dist-license/licenses/java/Unicode-ICU License.txt b/tools/dist-license/licenses/java/Unicode-ICU License.txt new file mode 100644 index 0000000000..e8bd706995 --- /dev/null +++ b/tools/dist-license/licenses/java/Unicode-ICU License.txt @@ -0,0 +1 @@ +https://raw.githubusercontent.com/unicode-org/icu/main/icu4c/LICENSE \ No newline at end of file diff --git a/tools/third-party-licenses/LICENSE b/tools/third-party-licenses/LICENSE deleted file mode 100644 index 2e6d1e2b0e..0000000000 --- a/tools/third-party-licenses/LICENSE +++ /dev/null @@ -1,487 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -======================================================================= -Apache EventMesh (incubating) Subcomponents: - -The Apache EventMesh (incubating) project contains subcomponents with separate copyright -notices and license terms. Your use of the source code for the these -subcomponents is subject to the terms and conditions of the following -licenses. - -======================================================================== -Apache 2.0 licenses -======================================================================== - -The following components are provided under the Apache License. See project link for details. -The text of each license is also included at licenses/LICENSE-[project].txt. - - assertj-core 2.6.0: https://github.com/assertj/assertj-core, Apache 2.0 - cloudevents-api 2.2.0: https://github.com/cloudevents/sdk-java, Apache 2.0 - cloudevents-core 2.2.0: https://github.com/cloudevents/sdk-java, Apache 2.0 - cloudevents-json-jackson 2.2.0: https://github.com/cloudevents/sdk-java, Apache 2.0 - commons-beanutils 1.9.4: https://github.com/apache/commons-beanutils, Apache 2.0 - commons-cli 1.2: https://github.com/apache/commons-cli, Apache 2.0 - commons-codec 1.11: https://github.com/apache/commons-codec, Apache 2.0 - commons-collections 3.2.2: https://github.com/apache/commons-collections, Apache 2.0 - commons-collections4 4.1: https://github.com/apache/commons-collections, Apache 2.0 - commons-digester 2.1: https://github.com/apache/commons-digester, Apache 2.0 - commons-lang3 3.6: https://github.com/apache/commons-lang, Apache 2.0 - commons-logging 1.2: https://github.com/apache/commons-logging, Apache 2.0 - commons-text 1.9: https://github.com/apache/commons-text, Apache 2.0 - commons-validator 1.7: https://github.com/apache/commons-validator, Apache 2.0 - disruptor 3.4.2: https://github.com/LMAX-Exchange/disruptor, Apache 2.0 - dledger 0.2.3: https://github.com/openmessaging/dledger, Apache 2.0 - error_prone_annotations 2.7.1: https://github.com/google/error-prone, Apache 2.0 - failureaccess 1.0.1: https://github.com/google/guava, Apache 2.0 - listenablefuture 9999.0-empty-to-avoid-conflict-with-guava: https://github.com/google/guava, Apache 2.0 - fastjson 1.2.76: https://github.com/alibaba/fastjson, Apache 2.0 - guava 31.0.1-jre: https://github.com/google/guava, Apache 2.0 - grpc-context 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-core 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-netty 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-netty-shaded 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-protobuf 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-protobuf-lite 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-stub 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - grpc-grpclb 1.17.1: https://github.com/grpc/grpc-java, Apache 2.0 - gson 2.8.2: https://github.com/google/gson, Apache 2.0 - httpasyncclient 4.1.3: https://github.com/apache/httpasyncclient, Apache 2.0 - httpclient 4.5.13: https://github.com/apache/httpcomponents-client, Apache 2.0 - httpcore 4.4.13: https://github.com/apache/httpcomponents-core, Apache 2.0 - j2objc-annotations 1.3: https://github.com/google/j2objc, Apache 2.0 - jackson-annotations 2.13.0: https://github.com/FasterXML/jackson-annotations, Apache 2.0 - jackson-core 2.13.0: https://github.com/FasterXML/jackson-core, Apache 2.0 - jackson-databind 2.13.0: https://github.com/FasterXML/jackson-databind, Apache 2.0 - javassist 3.24.0-GA/3.24.0-GA: https://github.com/jboss-javassist/javassist, Apache 2.0 - jcommander 1.72: https://github.com/cbeust/jcommander, Apache 2.0 - jetcd-common 0.3.0: https://github.com/etcd-io/jetcd, Apache 2.0 - jetcd-core 0.3.0: https://github.com/etcd-io/jetcd, Apache 2.0 - jetcd-resolver 0.3.0: https://github.com/etcd-io/jetcd, Apache 2.0 - jna 4.2.2: https://github.com/java-native-access/jna, Apache 2.0 - log4j-api 2.17.1: https://github.com/apache/logging-log4j2, Apache 2.0 - log4j-core 2.17.1: https://github.com/apache/logging-log4j2, Apache 2.0 - log4j-slf4j-impl 2.17.1: https://github.com/apache/logging-log4j2, Apache 2.0 - metrics-annotation 4.1.0: https://github.com/dropwizard/metrics, Apache 2.0 - metrics-core 4.1.0: https://github.com/dropwizard/metrics, Apache 2.0 - metrics-healthchecks 4.1.0: https://github.com/dropwizard/metrics, Apache 2.0 - metrics-json 4.1.0: https://github.com/dropwizard/metrics, Apache 2.0 - nacos-client 2.0.4: https://github.com/alibaba/nacos, Apache 2.0 - netty-all 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-buffer 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-dns 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-haproxy 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-http 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-http2 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-memcache 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-mqtt 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-redis 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-smtp 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-socks 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-stomp 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-codec-xml 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-common 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-handler 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-handler-proxy 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-resolver 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-resolver-dns 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-resolver-dns-classes-macos 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-resolver-dns-native-macos 4.1.73.Final-osx-aarch_64: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-resolver-dns-native-macos 4.1.73.Final-osx-x86_64: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-tcnative-classes 2.0.46.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-classes-epoll 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-classes-kqueue 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-native-epoll 4.1.73.Final-linux-aarch_64: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-native-epoll 4.1.73.Final-linux-x86_64: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-native-kqueue 4.1.73.Final-osx-aarch_64: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-native-kqueue 4.1.73.Final-osx-x86_64: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-native-unix-common 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-rxtx 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-sctp 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - netty-transport-udt 4.1.73.Final: https://github.com/netty/netty/tree/netty-4.1.73.Final, Apache 2.0 - okio 1.17.2: https://github.com/square/okio, Apache 2.0 - okhttp 3.14.9: https://github.com/square/okhttp, Apache 2.0 - opencensus-api 0.12.3: https://github.com/census-instrumentation/opencensus-java, Apache 2.0 - opencensus-contrib-grpc-metrics 0.12.3: https://github.com/census-instrumentation/opencensus-java, Apache 2.0 - openmessaging-api 2.22.1-pubsub: https://github.com/openmessaging/dledger, Apache 2.0 - opentelemetry-api 1.3.0: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-api-metrics 1.3.0-alpha: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-context 1.3.0: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-exporter-prometheus 1.3.0-alpha: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-exporter-zipkin 1.3.0: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-sdk 1.3.0: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-sdk-common 1.3.0: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-sdk-metrics 1.3.0-alpha: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-sdk-trace 1.3.0: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - opentelemetry-semconv 1.3.0-alpha: https://github.com/open-telemetry/opentelemetry-java, Apache 2.0 - proto-google-common-protos 1.0.0: https://github.com/googleapis/common-protos-java, Apache 2.0 - rocketmq-acl 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-broker 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-client 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-common 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-filter 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-logging 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-namesrv 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-remoting 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-srvutil 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-store 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-test 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - rocketmq-tools 4.9.3: https://github.com/apache/rocketmq, Apache 2.0 - simpleclient 0.8.1: https://github.com/prometheus/client_java, Apache 2.0 - simpleclient_common 0.8.1: https://github.com/prometheus/client_java, Apache 2.0 - simpleclient_httpserver 0.8.1: https://github.com/prometheus/client_java, Apache 2.0 - snakeyaml 1.30: https://bitbucket.org/asomov/snakeyaml, Apache 2.0 - truth 0.30: https://github.com/google/truth, Apache 2.0 - zipkin 2.23.2: https://github.com/openzipkin/zipkin, Apache 2.0 - zipkin-reporter 2.16.3: https://github.com/openzipkin/zipkin-reporter-java, Apache 2.0 - zipkin-sender-okhttp3 2.16.3: https://github.com/openzipkin/zipkin-reporter-java, Apache 2.0 - bcpkix-jdk15on 1.69: https://github.com/bcgit/bc-java, Apache 2.0 - bcprov-jdk15on 1.69: https://github.com/bcgit/bc-java, Apache 2.0 - bcutil-jdk15on 1.69: https://github.com/bcgit/bc-java, Apache 2.0 - cloud.google.com/go v0.34.0 Apache-2.0 - github.com/OneOfOne/xxhash v1.2.2 Apache-2.0 - github.com/census-instrumentation/opencensus-proto v0.2.1 Apache-2.0 - github.com/cloudevents/sdk-go/v2 v2.6.0 Apache-2.0 - github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 Apache-2.0 - github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 Apache-2.0 - github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 Apache-2.0 - github.com/envoyproxy/protoc-gen-validate v0.1.0 Apache-2.0 - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b Apache-2.0 - github.com/golang/mock v1.1.1 Apache-2.0 - github.com/google/gofuzz v1.0.0 Apache-2.0 - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 Apache-2.0 - github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 Apache-2.0 - github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 Apache-2.0 - go.opentelemetry.io/proto/otlp v0.7.0 Apache-2.0 - google.golang.org/appengine v1.4.0 Apache-2.0 - google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 Apache-2.0 - google.golang.org/grpc v1.45.0 Apache-2.0 - gopkg.in/yaml.v2 v2.3.0 Apache-2.0 - -======================================================================== -BSD licenses -======================================================================== - -The following components are provided under a BSD license. See project link for details. -The text of each license is also included at licenses/LICENSE-[project].txt. - - hamcrest-core 1.3: https://github.com/hamcrest/JavaHamcrest, BSD - jsr305 3.0.2: https://code.google.com/archive/p/jsr-305, BSD - protobuf-java 3.5.1: https://github.com/protocolbuffers/protobuf, BSD - protobuf-java-util 3.5.1: https://github.com/protocolbuffers/protobuf, BSD - -======================================================================== -CDDL licenses -======================================================================== - -The following components are provided under the CDDL License. See project link for details. -The text of each license is also included at licenses/LICENSE-[project].txt. - - javax.annotation-api 1.3.2: https://github.com/javaee/javax.annotation , CDDL1.1 - -======================================================================== -CPL licenses -======================================================================== - -The following components are provided under the CPL License. See project link for details. -The text of each license is also included at licenses/LICENSE-[project].txt. - - system-rules 1.16.1: https://github.com/stefanbirkner/system-rules - -======================================================================== -EPL licenses -======================================================================== - -The following components are provided under the EPL License. See project link for details. -The text of each license is also included at licenses/LICENSE-[project].txt. - - junit 4.13.2: https://github.com/junit-team/junit5, EPL - -======================================================================== -MIT licenses -======================================================================== - -The following components are provided under the MIT license. See project link for details. -The text of each license is also included at licenses/LICENSE-[project].txt. - - animal-sniffer-annotations 1.17: https://github.com/mojohaus/animal-sniffer, MIT - bcpkix-jdk15on 1.69: https://github.com/bcgit/bc-java, MIT - bcprov-jdk15on 1.69: https://github.com/bcgit/bc-java, MIT - bcutil-jdk15on 1.69: https://github.com/bcgit/bc-java, MIT - checker-qual 3.12.0: https://github.com/typetools/checker-framework, MIT - slf4j-api 1.7.30: https://github.com/qos-ch/slf4j, MIT - github.com/BurntSushi/toml v0.3.1 MIT - github.com/antihax/optional v1.0.0 MIT - github.com/cespare/xxhash v1.1.0 MIT - github.com/cespare/xxhash/v2 v2.1.1 MIT - github.com/client9/misspell v0.3.4 MIT - github.com/creack/pty v1.1.9 MIT - github.com/deckarep/golang-set v1.7.1 - github.com/ghodss/yaml v1.0.0 MIT - github.com/json-iterator/go v1.1.10 MIT - github.com/kr/pty v1.1.1 MIT - github.com/kr/text v0.2.0 MIT - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e MIT - github.com/panjf2000/ants v1.3.0 MIT - github.com/sony/sonyflake v1.0.0 MIT - github.com/stretchr/objx v0.1.1 MIT - github.com/stretchr/testify v1.7.0 MIT - github.com/valyala/bytebufferpool v1.0.0 MIT - go.uber.org/atomic v1.4.0 MIT - go.uber.org/multierr v1.1.0 MIT - go.uber.org/zap v1.10.0 MIT - honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc MIT - -======================================================================== -BSD-3-Clause licenses -======================================================================== - -The following components are provided under the BSD-3-Clause License. See project link for details. -The text of each license is also included at licenses/license-[project].txt. - - github.com/golang/protobuf v1.5.2 BSD-3-Clause - github.com/google/go-cmp v0.5.5 BSD-3-Clause - github.com/google/uuid v1.3.0 BSD-3-Clause - github.com/grpc-ecosystem/grpc-gateway v1.16.0 BSD-3-Clause - github.com/pmezard/go-difflib v1.0.0 BSD-3-Clause - github.com/rogpeppe/fastuuid v1.2.0 BSD-3-Clause - github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 BSD-3-Clause - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 BSD-3-Clause - golang.org/x/exp v0.0.0-20190121172915-509febef88a4 BSD-3-Clause - golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 BSD-3-Clause - golang.org/x/net v0.0.0-20200822124328-c89045814202 BSD-3-Clause - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d BSD-3-Clause - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e BSD-3-Clause - golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd BSD-3-Clause - golang.org/x/text v0.3.0 BSD-3-Clause - golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 BSD-3-Clause - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 BSD-3-Clause - -======================================================================== -ISC licenses -======================================================================== - -The following components are provided under the ISC License. See project link for details. -The text of each license is also included at licenses/license-[project].txt. - - github.com/davecgh/go-spew v1.1.1 ISC - -======================================================================== -BSD-2-Clause licenses -======================================================================== - -The following components are provided under the BSD-2-Clause License. See project link for details. -The text of each license is also included at licenses/license-[project].txt. - - github.com/pkg/errors v0.9.1 BSD-2-Clause - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f BSD-2-Clause - -======================================================================== -MIT and Apache licenses -======================================================================== - -The following components are provided under the MIT and Apache License. See project link for details. -The text of each license is also included at licenses/license-[project].txt. - - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c MIT and Apache diff --git a/tools/third-party-licenses/NOTICE b/tools/third-party-licenses/NOTICE deleted file mode 100644 index 3f73a3ba6a..0000000000 --- a/tools/third-party-licenses/NOTICE +++ /dev/null @@ -1,543 +0,0 @@ -Apache EventMesh (incubating) -Copyright 2021-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -======================================================================== - -Apache Commons BeanUtils NOTICE - -========================================================================= -Apache Commons BeanUtils -Copyright 2000-2019 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -========================================================================= - -Apache Commons CLI NOTICE - -========================================================================= -Apache Commons CLI -Copyright 2002-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (https://www.apache.org/). - -========================================================================= - -Apache Commons Codec NOTICE -========================================================================= -Apache Commons Codec -Copyright 2002-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (https://www.apache.org/). - -src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java -contains test data from http://aspell.net/test/orig/batch0.tab. -Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) - -=============================================================================== - -The content of package org.apache.commons.codec.language.bm has been translated -from the original php source code available at http://stevemorse.org/phoneticinfo.htm -with permission from the original authors. -Original source copyright: -Copyright (c) 2008 Alexander Beider & Stephen P. Morse. - -=============================================================================== - -Apache Commons Collections NOTICE -=============================================================================== - -Apache Commons Collections -Copyright 2001-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Apache Commons Collections NOTICE - -=============================================================================== -Apache Commons Collections -Copyright 2001-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Apache Commons Digester NOTICE - -=============================================================================== -Apache Commons Digester -Copyright 2001-2016 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Apache Commons Lang NOTICE - -=============================================================================== -Apache Commons Lang -Copyright 2001-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (https://www.apache.org/). - -=============================================================================== - -Apache Commons Logging NOTICE - -=============================================================================== -Apache Commons Logging -Copyright 2003-2016 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Apache Commons Text NOTICE - -=============================================================================== -Apache Commons Text -Copyright 2014-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (https://www.apache.org/). - -=============================================================================== - -Apache Commons Validator NOTICE - -=============================================================================== -Apache Commons Validator -Copyright 2001-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -grpc-java NOTICE - -=============================================================================== -Copyright 2014 The gRPC Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - ------------------------------------------------------------------------ - - -This product contains a modified portion of 'OkHttp', an open source -HTTP & SPDY client for Android and Java applications, which can be obtained -at: - - * LICENSE: - * okhttp/third_party/okhttp/LICENSE (Apache License 2.0) - * HOMEPAGE: - * https://github.com/square/okhttp - * LOCATION_IN_GRPC: - * okhttp/third_party/okhttp - -This product contains a modified portion of 'Envoy', an open source -cloud-native high-performance edge/middle/service proxy, which can be -obtained at: - - * LICENSE: - * xds/third_party/envoy/LICENSE (Apache License 2.0) - * NOTICE: - * xds/third_party/envoy/NOTICE - * HOMEPAGE: - * https://www.envoyproxy.io - * LOCATION_IN_GRPC: - * xds/third_party/envoy - -This product contains a modified portion of 'protoc-gen-validate (PGV)', -an open source protoc plugin to generate polyglot message validators, -which can be obtained at: - - * LICENSE: - * xds/third_party/protoc-gen-validate/LICENSE (Apache License 2.0) - * NOTICE: - * xds/third_party/protoc-gen-validate/NOTICE - * HOMEPAGE: - * https://github.com/envoyproxy/protoc-gen-validate - * LOCATION_IN_GRPC: - * xds/third_party/protoc-gen-validate - -This product contains a modified portion of 'udpa', -an open source universal data plane API, which can be obtained at: - - * LICENSE: - * xds/third_party/udpa/LICENSE (Apache License 2.0) - * HOMEPAGE: - * https://github.com/cncf/udpa - * LOCATION_IN_GRPC: - * xds/third_party/udpa - -=============================================================================== - -Apache HttpComponents Client NOTICE - -=============================================================================== -Apache HttpComponents Client -Copyright 1999-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Apache HttpComponents Core - -=============================================================================== -Apache HttpComponents Core -Copyright 2005-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Apache Log4j NOTICE - -=============================================================================== -Apache Log4j -Copyright 1999-2021 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - -TimeoutBlockingWaitStrategy.java and parts of Util.java -Copyright 2011 LMAX Ltd. - -=============================================================================== - -The Netty Project NOTICE - -=============================================================================== - The Netty Project - ================= - -Please visit the Netty web site for more information: - - * https://netty.io/ - -Copyright 2014 The Netty Project - -The Netty Project 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: - - https://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. - -Also, please refer to each LICENSE..txt file, which is located in -the 'license' directory of the distribution file, for the license terms of the -components that this product depends on. - -------------------------------------------------------------------------------- -This product contains the extensions to Java Collections Framework which has -been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: - - * LICENSE: - * license/LICENSE.jsr166y.txt (Public Domain) - * HOMEPAGE: - * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ - * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ - -This product contains a modified version of Robert Harder's Public Domain -Base64 Encoder and Decoder, which can be obtained at: - - * LICENSE: - * license/LICENSE.base64.txt (Public Domain) - * HOMEPAGE: - * http://iharder.sourceforge.net/current/java/base64/ - -This product contains a modified portion of 'Webbit', an event based -WebSocket and HTTP server, which can be obtained at: - - * LICENSE: - * license/LICENSE.webbit.txt (BSD License) - * HOMEPAGE: - * https://github.com/joewalnes/webbit - -This product contains a modified portion of 'SLF4J', a simple logging -facade for Java, which can be obtained at: - - * LICENSE: - * license/LICENSE.slf4j.txt (MIT License) - * HOMEPAGE: - * https://www.slf4j.org/ - -This product contains a modified portion of 'Apache Harmony', an open source -Java SE, which can be obtained at: - - * NOTICE: - * license/NOTICE.harmony.txt - * LICENSE: - * license/LICENSE.harmony.txt (Apache License 2.0) - * HOMEPAGE: - * https://archive.apache.org/dist/harmony/ - -This product contains a modified portion of 'jbzip2', a Java bzip2 compression -and decompression library written by Matthew J. Francis. It can be obtained at: - - * LICENSE: - * license/LICENSE.jbzip2.txt (MIT License) - * HOMEPAGE: - * https://code.google.com/p/jbzip2/ - -This product contains a modified portion of 'libdivsufsort', a C API library to construct -the suffix array and the Burrows-Wheeler transformed string for any input string of -a constant-size alphabet written by Yuta Mori. It can be obtained at: - - * LICENSE: - * license/LICENSE.libdivsufsort.txt (MIT License) - * HOMEPAGE: - * https://github.com/y-256/libdivsufsort - -This product contains a modified portion of Nitsan Wakart's 'JCTools', Java Concurrency Tools for the JVM, - which can be obtained at: - - * LICENSE: - * license/LICENSE.jctools.txt (ASL2 License) - * HOMEPAGE: - * https://github.com/JCTools/JCTools - -This product optionally depends on 'JZlib', a re-implementation of zlib in -pure Java, which can be obtained at: - - * LICENSE: - * license/LICENSE.jzlib.txt (BSD style License) - * HOMEPAGE: - * http://www.jcraft.com/jzlib/ - -This product optionally depends on 'Compress-LZF', a Java library for encoding and -decoding data in LZF format, written by Tatu Saloranta. It can be obtained at: - - * LICENSE: - * license/LICENSE.compress-lzf.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/ning/compress - -This product optionally depends on 'lz4', a LZ4 Java compression -and decompression library written by Adrien Grand. It can be obtained at: - - * LICENSE: - * license/LICENSE.lz4.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/jpountz/lz4-java - -This product optionally depends on 'lzma-java', a LZMA Java compression -and decompression library, which can be obtained at: - - * LICENSE: - * license/LICENSE.lzma-java.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/jponge/lzma-java - -This product optionally depends on 'zstd-jni', a zstd-jni Java compression -and decompression library, which can be obtained at: - - * LICENSE: - * license/LICENSE.zstd-jni.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/luben/zstd-jni - -This product contains a modified portion of 'jfastlz', a Java port of FastLZ compression -and decompression library written by William Kinney. It can be obtained at: - - * LICENSE: - * license/LICENSE.jfastlz.txt (MIT License) - * HOMEPAGE: - * https://code.google.com/p/jfastlz/ - -This product contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data -interchange format, which can be obtained at: - - * LICENSE: - * license/LICENSE.protobuf.txt (New BSD License) - * HOMEPAGE: - * https://github.com/google/protobuf - -This product optionally depends on 'Bouncy Castle Crypto APIs' to generate -a temporary self-signed X.509 certificate when the JVM does not provide the -equivalent functionality. It can be obtained at: - - * LICENSE: - * license/LICENSE.bouncycastle.txt (MIT License) - * HOMEPAGE: - * https://www.bouncycastle.org/ - -This product optionally depends on 'Snappy', a compression library produced -by Google Inc, which can be obtained at: - - * LICENSE: - * license/LICENSE.snappy.txt (New BSD License) - * HOMEPAGE: - * https://github.com/google/snappy - -This product optionally depends on 'JBoss Marshalling', an alternative Java -serialization API, which can be obtained at: - - * LICENSE: - * license/LICENSE.jboss-marshalling.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/jboss-remoting/jboss-marshalling - -This product optionally depends on 'Caliper', Google's micro- -benchmarking framework, which can be obtained at: - - * LICENSE: - * license/LICENSE.caliper.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/google/caliper - -This product optionally depends on 'Apache Commons Logging', a logging -framework, which can be obtained at: - - * LICENSE: - * license/LICENSE.commons-logging.txt (Apache License 2.0) - * HOMEPAGE: - * https://commons.apache.org/logging/ - -This product optionally depends on 'Apache Log4J', a logging framework, which -can be obtained at: - - * LICENSE: - * license/LICENSE.log4j.txt (Apache License 2.0) - * HOMEPAGE: - * https://logging.apache.org/log4j/ - -This product optionally depends on 'Aalto XML', an ultra-high performance -non-blocking XML processor, which can be obtained at: - - * LICENSE: - * license/LICENSE.aalto-xml.txt (Apache License 2.0) - * HOMEPAGE: - * https://wiki.fasterxml.com/AaltoHome - -This product contains a modified version of 'HPACK', a Java implementation of -the HTTP/2 HPACK algorithm written by Twitter. It can be obtained at: - - * LICENSE: - * license/LICENSE.hpack.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/twitter/hpack - -This product contains a modified version of 'HPACK', a Java implementation of -the HTTP/2 HPACK algorithm written by Cory Benfield. It can be obtained at: - - * LICENSE: - * license/LICENSE.hyper-hpack.txt (MIT License) - * HOMEPAGE: - * https://github.com/python-hyper/hpack/ - -This product contains a modified version of 'HPACK', a Java implementation of -the HTTP/2 HPACK algorithm written by Tatsuhiro Tsujikawa. It can be obtained at: - - * LICENSE: - * license/LICENSE.nghttp2-hpack.txt (MIT License) - * HOMEPAGE: - * https://github.com/nghttp2/nghttp2/ - -This product contains a modified portion of 'Apache Commons Lang', a Java library -provides utilities for the java.lang API, which can be obtained at: - - * LICENSE: - * license/LICENSE.commons-lang.txt (Apache License 2.0) - * HOMEPAGE: - * https://commons.apache.org/proper/commons-lang/ - - -This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. - - * LICENSE: - * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/takari/maven-wrapper - -This product contains the dnsinfo.h header file, that provides a way to retrieve the system DNS configuration on MacOS. -This private header is also used by Apple's open source - mDNSResponder (https://opensource.apple.com/tarballs/mDNSResponder/). - - * LICENSE: - * license/LICENSE.dnsinfo.txt (Apple Public Source License 2.0) - * HOMEPAGE: - * https://www.opensource.apple.com/source/configd/configd-453.19/dnsinfo/dnsinfo.h - -This product optionally depends on 'Brotli4j', Brotli compression and -decompression for Java., which can be obtained at: - - * LICENSE: - * license/LICENSE.brotli4j.txt (Apache License 2.0) - * HOMEPAGE: - * https://github.com/hyperxpro/Brotli4j - -=============================================================================== - -Apache RocketMQ NOTICE - -=============================================================================== -Apache RocketMQ -Copyright 2016-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -=============================================================================== - -Prometheus client_java NOTICE - -=============================================================================== -Prometheus instrumentation library for JVM applications -Copyright 2012-2015 The Prometheus Authors - -This product includes software developed at -Boxever Ltd. (http://www.boxever.com/). - -This product includes software developed at -SoundCloud Ltd. (http://soundcloud.com/). - -This product includes software developed as part of the -Ocelli project by Netflix Inc. (https://github.com/Netflix/ocelli/). - -=============================================================================== - diff --git a/tools/third-party-licenses/licenses/go/LICENSE-cloud.google.com-go.txt b/tools/third-party-licenses/licenses/go/LICENSE-cloud.google.com-go.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-cloud.google.com-go.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-BurntSushi-toml.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-BurntSushi-toml.txt deleted file mode 100644 index 01b5743200..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-BurntSushi-toml.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 TOML authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-OneOfOne-xxhash.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-OneOfOne-xxhash.txt deleted file mode 100644 index e64dffa0a9..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-OneOfOne-xxhash.txt +++ /dev/null @@ -1,187 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-antihax-optional.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-antihax-optional.txt deleted file mode 100644 index 6a2c64ab1f..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-antihax-optional.txt +++ /dev/null @@ -1,8 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2016 Adam Hintz - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-census-instrumentation-opencensus-proto.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-census-instrumentation-opencensus-proto.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-census-instrumentation-opencensus-proto.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-client9-misspell.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-client9-misspell.txt deleted file mode 100644 index bfcfcd3013..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-client9-misspell.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2017 Nick Galbreath - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cncf-udpa-go.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-cncf-udpa-go.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cncf-udpa-go.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cncf-xds-go.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-cncf-xds-go.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-cncf-xds-go.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-creack-pty.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-creack-pty.txt deleted file mode 100644 index 6b761042bf..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-creack-pty.txt +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2011 Keith Rarick - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall -be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-davecgh-go-spew.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-davecgh-go-spew.txt deleted file mode 100644 index 7304bdf8cb..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-davecgh-go-spew.txt +++ /dev/null @@ -1,15 +0,0 @@ -ISC License - -Copyright (c) 2012-2016 Dave Collins - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-deckarep-golang-set.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-deckarep-golang-set.txt deleted file mode 100644 index efd4827e21..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-deckarep-golang-set.txt +++ /dev/null @@ -1,22 +0,0 @@ -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-envoyproxy-go-control-plane.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-envoyproxy-go-control-plane.txt deleted file mode 100644 index 9c8f3ea087..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-envoyproxy-go-control-plane.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-envoyproxy-protoc-gen-validate.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-envoyproxy-protoc-gen-validate.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-envoyproxy-protoc-gen-validate.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-ghodss-yaml.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-ghodss-yaml.txt deleted file mode 100644 index e137618b0f..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-ghodss-yaml.txt +++ /dev/null @@ -1,50 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Sam Ghods - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-glog.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-glog.txt deleted file mode 100644 index 8405e89a0b..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-glog.txt +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-mock.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-mock.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-mock.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-protobuf.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-protobuf.txt deleted file mode 100644 index 8e63345bc2..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-golang-protobuf.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2010 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-go-cmp.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-go-cmp.txt deleted file mode 100644 index d9b732cfd3..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-go-cmp.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2017 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-gofuzz.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-gofuzz.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-google-gofuzz.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-grpc-ecosystem-grpc-gateway.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-grpc-ecosystem-grpc-gateway.txt deleted file mode 100644 index 6e59e318a1..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-grpc-ecosystem-grpc-gateway.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015, Gengo, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of Gengo, Inc. nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-kr-pty.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-kr-pty.txt deleted file mode 100644 index 35934dbf5e..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-kr-pty.txt +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2019 Keith Rarick - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall -be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-kr-text.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-kr-text.txt deleted file mode 100644 index 2e9e336a3f..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-kr-text.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2012 Keith Rarick - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-modern-go-concurrent.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-modern-go-concurrent.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-modern-go-concurrent.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-modern-go-reflect2.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-modern-go-reflect2.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-modern-go-reflect2.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-niemeyer-pretty.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-niemeyer-pretty.txt deleted file mode 100644 index 2e9e336a3f..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-niemeyer-pretty.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2012 Keith Rarick - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-pkg-errors.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-pkg-errors.txt deleted file mode 100644 index 1906e68097..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-pkg-errors.txt +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2015, Dave Cheney -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-pmezard-go-difflib.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-pmezard-go-difflib.txt deleted file mode 100644 index 485be13c67..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-pmezard-go-difflib.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013, Patrick Mezard -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - The names of its contributors may not be used to endorse or promote -products derived from this software without specific prior written -permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-prometheus-client_model.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-prometheus-client_model.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-prometheus-client_model.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-rogpeppe-fastuuid.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-rogpeppe-fastuuid.txt deleted file mode 100644 index f84b5232e7..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-rogpeppe-fastuuid.txt +++ /dev/null @@ -1,26 +0,0 @@ -Copyright © 2014, Roger Peppe -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of this project nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-spaolacci-murmur3.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-spaolacci-murmur3.txt deleted file mode 100644 index 8eeb61967a..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-spaolacci-murmur3.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright 2013, Sébastien Paolacci. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the library nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-stretchr-objx.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-stretchr-objx.txt deleted file mode 100644 index 5b30a3704f..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-stretchr-objx.txt +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License - -Copyright (c) 2014 Stretchr, Inc. -Copyright (c) 2017-2018 objx contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-github.com-valyala-bytebufferpool.txt b/tools/third-party-licenses/licenses/go/LICENSE-github.com-valyala-bytebufferpool.txt deleted file mode 100644 index 8d25e9a147..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-github.com-valyala-bytebufferpool.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-go.opentelemetry.io-proto-otlp.txt b/tools/third-party-licenses/licenses/go/LICENSE-go.opentelemetry.io-proto-otlp.txt deleted file mode 100644 index 30f8920b6a..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-go.opentelemetry.io-proto-otlp.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-multierr.txt b/tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-multierr.txt deleted file mode 100644 index 5bfe7bb6d9..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-go.uber.org-multierr.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2017-2021 Uber Technologies, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-crypto.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-crypto.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-crypto.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-exp.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-exp.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-exp.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-lint.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-lint.txt deleted file mode 100644 index 65d761bc9f..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-lint.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-net.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-net.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-net.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-oauth2.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-oauth2.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-oauth2.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-sync.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-sync.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-sync.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-sys.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-sys.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-sys.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-text.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-text.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-text.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-tools.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-tools.txt deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-tools.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-xerrors.txt b/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-xerrors.txt deleted file mode 100644 index e4a47e17f1..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-golang.org-x-xerrors.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2019 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-appengine.txt b/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-appengine.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-appengine.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-genproto.txt b/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-genproto.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-google.golang.org-genproto.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-check.v1.txt b/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-check.v1.txt deleted file mode 100644 index eea77e192a..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-check.v1.txt +++ /dev/null @@ -1,25 +0,0 @@ -Gocheck - A rich testing framework for Go - -Copyright (c) 2010-2013 Gustavo Niemeyer - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-yaml.v2.txt b/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-yaml.v2.txt deleted file mode 100644 index 9c8f3ea087..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-yaml.v2.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-yaml.v3.txt b/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-yaml.v3.txt deleted file mode 100644 index ce5fc85d7b..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-gopkg.in-yaml.v3.txt +++ /dev/null @@ -1,50 +0,0 @@ - -This project is covered by two different licenses: MIT and Apache. - -#### MIT License #### - -The following files were ported to Go from C files of libyaml, and thus -are still covered by their original MIT license, with the additional -copyright staring in 2011 when the project was ported over: - - apic.go emitterc.go parserc.go readerc.go scannerc.go - writerc.go yamlh.go yamlprivateh.go - -Copyright (c) 2006-2010 Kirill Simonov -Copyright (c) 2006-2011 Kirill Simonov - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -### Apache License ### - -All the remaining project files are covered by the Apache license: - -Copyright (c) 2011-2019 Canonical Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/go/LICENSE-honnef.co-go-tools.txt b/tools/third-party-licenses/licenses/go/LICENSE-honnef.co-go-tools.txt deleted file mode 100644 index 0dd5c21067..0000000000 --- a/tools/third-party-licenses/licenses/go/LICENSE-honnef.co-go-tools.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-animal-sniffer-annotations.txt b/tools/third-party-licenses/licenses/java/LICENSE-animal-sniffer-annotations.txt deleted file mode 100644 index 370fb559bb..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-animal-sniffer-annotations.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2009 codehaus.org. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-bcpkix-jdk15on.txt b/tools/third-party-licenses/licenses/java/LICENSE-bcpkix-jdk15on.txt deleted file mode 100644 index 60d984a9f1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-bcpkix-jdk15on.txt +++ /dev/null @@ -1,22 +0,0 @@ - - - -Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) -

-Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -

-The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. -

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - - \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-bcprov-jdk15on.txt b/tools/third-party-licenses/licenses/java/LICENSE-bcprov-jdk15on.txt deleted file mode 100644 index 60d984a9f1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-bcprov-jdk15on.txt +++ /dev/null @@ -1,22 +0,0 @@ - - - -Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) -

-Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -

-The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. -

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - - \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-bcutil-jdk15on.txt b/tools/third-party-licenses/licenses/java/LICENSE-bcutil-jdk15on.txt deleted file mode 100644 index 60d984a9f1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-bcutil-jdk15on.txt +++ /dev/null @@ -1,22 +0,0 @@ - - - -Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) -

-Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -

-The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. -

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - - \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-checker-qual.txt b/tools/third-party-licenses/licenses/java/LICENSE-checker-qual.txt deleted file mode 100644 index f490f98ba6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-checker-qual.txt +++ /dev/null @@ -1,413 +0,0 @@ -The Checker Framework -Copyright 2004-present by the Checker Framework developers - - -Most of the Checker Framework is licensed under the GNU General Public -License, version 2 (GPL2), with the classpath exception. The text of this -license appears below. This is the same license used for OpenJDK. - -A few parts of the Checker Framework have more permissive licenses. - - * The annotations are licensed under the MIT License. (The text of this - license appears below.) More specifically, all the parts of the Checker - Framework that you might want to include with your own program use the - MIT License. This is the checker-qual.jar file and all the files that - appear in it: every file in a qual/ directory, plus utility files such - as NullnessUtil.java, RegexUtil.java, SignednessUtil.java, etc. - In addition, the cleanroom implementations of third-party annotations, - which the Checker Framework recognizes as aliases for its own - annotations, are licensed under the MIT License. - -Some external libraries that are included with the Checker Framework have -different licenses. - - * javaparser is dual licensed under the LGPL or the Apache license -- you - may use it under whichever one you want. (The javaparser source code - contains a file with the text of the GPL, but it is not clear why, since - javaparser does not use the GPL.) See file stubparser/LICENSE - and the source code of all its files. - - * JUnit is licensed under the Common Public License v1.0 (see - http://www.junit.org/license), with parts (Hamcrest) licensed under the - BSD License (see http://hamcrest.org/JavaHamcrest/). - - * Libraries in plume-lib (https://github.com/plume-lib/) are licensed - under the MIT License. - -The Checker Framework includes annotations for the JDK in directory -checker/jdk/, and for some other libraries. Each annotated library uses -the same license as the unannotated version of the library. - -=========================================================================== - -The GNU General Public License (GPL) - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to share -and change it. By contrast, the GNU General Public License is intended to -guarantee your freedom to share and change free software--to make sure the -software is free for all its users. This General Public License applies to -most of the Free Software Foundation's software and to any other program whose -authors commit to using it. (Some other Free Software Foundation software is -covered by the GNU Library General Public License instead.) You can apply it to -your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom to -distribute copies of free software (and charge for this service if you wish), -that you receive source code or can get it if you want it, that you can change -the software or use pieces of it in new free programs; and that you know you -can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to deny -you these rights or to ask you to surrender the rights. These restrictions -translate to certain responsibilities for you if you distribute copies of the -software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or for -a fee, you must give the recipients all the rights that you have. You must -make sure that they, too, receive or can get the source code. And you must -show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If the -software is modified by someone else and passed on, we want its recipients to -know that what they have is not the original, so that any problems introduced -by others will not reflect on the original authors' reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program proprietary. -To prevent this, we have made it clear that any patent must be licensed for -everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice -placed by the copyright holder saying it may be distributed under the terms of -this General Public License. The "Program", below, refers to any such program -or work, and a "work based on the Program" means either the Program or any -derivative work under copyright law: that is to say, a work containing the -Program or a portion of it, either verbatim or with modifications and/or -translated into another language. (Hereinafter, translation is included -without limitation in the term "modification".) Each licensee is addressed as -"you". - -Activities other than copying, distribution and modification are not covered by -this License; they are outside its scope. The act of running the Program is -not restricted, and the output from the Program is covered only if its contents -constitute a work based on the Program (independent of having been made by -running the Program). Whether that is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source code as -you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this License -and to the absence of any warranty; and give any other recipients of the -Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and you may -at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, thus -forming a work based on the Program, and copy and distribute such modifications -or work under the terms of Section 1 above, provided that you also meet all of -these conditions: - - a) You must cause the modified files to carry prominent notices stating - that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in whole or - in part contains or is derived from the Program or any part thereof, to be - licensed as a whole at no charge to all third parties under the terms of - this License. - - c) If the modified program normally reads commands interactively when run, - you must cause it, when started running for such interactive use in the - most ordinary way, to print or display an announcement including an - appropriate copyright notice and a notice that there is no warranty (or - else, saying that you provide a warranty) and that users may redistribute - the program under these conditions, and telling the user how to view a copy - of this License. (Exception: if the Program itself is interactive but does - not normally print such an announcement, your work based on the Program is - not required to print an announcement.) - -These requirements apply to the modified work as a whole. If identifiable -sections of that work are not derived from the Program, and can be reasonably -considered independent and separate works in themselves, then this License, and -its terms, do not apply to those sections when you distribute them as separate -works. But when you distribute the same sections as part of a whole which is a -work based on the Program, the distribution of the whole must be on the terms -of this License, whose permissions for other licensees extend to the entire -whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your -rights to work written entirely by you; rather, the intent is to exercise the -right to control the distribution of derivative or collective works based on -the Program. - -In addition, mere aggregation of another work not based on the Program with the -Program (or with a work based on the Program) on a volume of a storage or -distribution medium does not bring the other work under the scope of this -License. - -3. You may copy and distribute the Program (or a work based on it, under -Section 2) in object code or executable form under the terms of Sections 1 and -2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable source - code, which must be distributed under the terms of Sections 1 and 2 above - on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three years, to - give any third party, for a charge no more than your cost of physically - performing source distribution, a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed only - for noncommercial distribution and only if you received the program in - object code or executable form with such an offer, in accord with - Subsection b above.) - -The source code for a work means the preferred form of the work for making -modifications to it. For an executable work, complete source code means all -the source code for all modules it contains, plus any associated interface -definition files, plus the scripts used to control compilation and installation -of the executable. However, as a special exception, the source code -distributed need not include anything that is normally distributed (in either -source or binary form) with the major components (compiler, kernel, and so on) -of the operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the source -code from the same place counts as distribution of the source code, even though -third parties are not compelled to copy the source along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as -expressly provided under this License. Any attempt otherwise to copy, modify, -sublicense or distribute the Program is void, and will automatically terminate -your rights under this License. However, parties who have received copies, or -rights, from you under this License will not have their licenses terminated so -long as such parties remain in full compliance. - -5. You are not required to accept this License, since you have not signed it. -However, nothing else grants you permission to modify or distribute the Program -or its derivative works. These actions are prohibited by law if you do not -accept this License. Therefore, by modifying or distributing the Program (or -any work based on the Program), you indicate your acceptance of this License to -do so, and all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the Program), -the recipient automatically receives a license from the original licensor to -copy, distribute or modify the Program subject to these terms and conditions. -You may not impose any further restrictions on the recipients' exercise of the -rights granted herein. You are not responsible for enforcing compliance by -third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), conditions -are imposed on you (whether by court order, agreement or otherwise) that -contradict the conditions of this License, they do not excuse you from the -conditions of this License. If you cannot distribute so as to satisfy -simultaneously your obligations under this License and any other pertinent -obligations, then as a consequence you may not distribute the Program at all. -For example, if a patent license would not permit royalty-free redistribution -of the Program by all those who receive copies directly or indirectly through -you, then the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply and -the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or -other property right claims or to contest validity of any such claims; this -section has the sole purpose of protecting the integrity of the free software -distribution system, which is implemented by public license practices. Many -people have made generous contributions to the wide range of software -distributed through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing to -distribute software through any other system and a licensee cannot impose that -choice. - -This section is intended to make thoroughly clear what is believed to be a -consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain -countries either by patents or by copyrighted interfaces, the original -copyright holder who places the Program under this License may add an explicit -geographical distribution limitation excluding those countries, so that -distribution is permitted only in or among countries not thus excluded. In -such case, this License incorporates the limitation as if written in the body -of this License. - -9. The Free Software Foundation may publish revised and/or new versions of the -General Public License from time to time. Such new versions will be similar in -spirit to the present version, but may differ in detail to address new problems -or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any later -version", you have the option of following the terms and conditions either of -that version or of any later version published by the Free Software Foundation. -If the Program does not specify a version number of this License, you may -choose any version ever published by the Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs -whose distribution conditions are different, write to the author to ask for -permission. For software which is copyrighted by the Free Software Foundation, -write to the Free Software Foundation; we sometimes make exceptions for this. -Our decision will be guided by the two goals of preserving the free status of -all derivatives of our free software and of promoting the sharing and reuse of -software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR -THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE -STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE -PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND -PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, -YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL -ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE -PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR -INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA -BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER -OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible -use to the public, the best way to achieve this is to make it free software -which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach -them to the start of each source file to most effectively convey the exclusion -of warranty; and each file should have at least the "copyright" line and a -pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - - Copyright (C) - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when it -starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author Gnomovision comes - with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free - software, and you are welcome to redistribute it under certain conditions; - type 'show c' for details. - -The hypothetical commands 'show w' and 'show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may be -called something other than 'show w' and 'show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your school, -if any, to sign a "copyright disclaimer" for the program, if necessary. Here -is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - 'Gnomovision' (which makes passes at compilers) written by James Hacker. - - signature of Ty Coon, 1 April 1989 - - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General Public -License instead of this License. - - -"CLASSPATH" EXCEPTION TO THE GPL - -Certain source files distributed by Oracle America and/or its affiliates are -subject to the following clarification and special exception to the GPL, but -only where Oracle has expressly included in the particular source file's header -the words "Oracle designates this particular file as subject to the "Classpath" -exception as provided by Oracle in the LICENSE file that accompanied this code." - - Linking this library statically or dynamically with other modules is making - a combined work based on this library. Thus, the terms and conditions of - the GNU General Public License cover the whole combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent modules, - and to copy and distribute the resulting executable under terms of your - choice, provided that you also meet, for each linked independent module, - the terms and conditions of the license of that module. An independent - module is a module which is not derived from or based on this library. If - you modify this library, you may extend this exception to your version of - the library, but you are not obligated to do so. If you do not wish to do - so, delete this exception statement from your version. - -=========================================================================== - -MIT License: - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -=========================================================================== \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-api.txt deleted file mode 100644 index 1a7891acd6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-api.txt +++ /dev/null @@ -1,203 +0,0 @@ - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-Present The CloudEvents Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-core.txt deleted file mode 100644 index 1a7891acd6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-core.txt +++ /dev/null @@ -1,203 +0,0 @@ - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-Present The CloudEvents Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-json-jackson.txt b/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-json-jackson.txt deleted file mode 100644 index 1a7891acd6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-cloudevents-json-jackson.txt +++ /dev/null @@ -1,203 +0,0 @@ - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-Present The CloudEvents Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-beanutils.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-beanutils.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-beanutils.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-cli.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-cli.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-cli.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-codec.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-codec.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-codec.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-collections.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-collections.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-collections.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-collections4.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-collections4.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-collections4.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-digester.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-digester.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-digester.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-lang3.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-lang3.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-lang3.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-logging.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-logging.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-logging.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-text.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-text.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-text.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-commons-validator.txt b/tools/third-party-licenses/licenses/java/LICENSE-commons-validator.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-commons-validator.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-consul-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-consul-api.txt deleted file mode 100644 index 5a5a8ce54c..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-consul-api.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-disruptor.txt b/tools/third-party-licenses/licenses/java/LICENSE-disruptor.txt deleted file mode 100644 index 50086f8b44..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-disruptor.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-dledger.txt b/tools/third-party-licenses/licenses/java/LICENSE-dledger.txt deleted file mode 100644 index b90520c005..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-dledger.txt +++ /dev/null @@ -1,203 +0,0 @@ - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (properties) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017-2020 the original author or authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-error_prone_annotations.txt b/tools/third-party-licenses/licenses/java/LICENSE-error_prone_annotations.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-error_prone_annotations.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-failureaccess.txt b/tools/third-party-licenses/licenses/java/LICENSE-failureaccess.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-failureaccess.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-fastjson.txt b/tools/third-party-licenses/licenses/java/LICENSE-fastjson.txt deleted file mode 100644 index 59f9c59414..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-fastjson.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 1999-2019 Alibaba Group Holding Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-context.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-context.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-context.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-core.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-core.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-grpclb.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-grpclb.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-grpclb.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-netty-shaded.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-netty-shaded.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-netty-shaded.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-netty.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-netty.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-netty.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-protobuf-lite.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-protobuf-lite.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-protobuf-lite.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-protobuf.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-protobuf.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-protobuf.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-grpc-stub.txt b/tools/third-party-licenses/licenses/java/LICENSE-grpc-stub.txt deleted file mode 100644 index cf3c829a19..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-grpc-stub.txt +++ /dev/null @@ -1,242 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------ - -BSD 3-Clause License - -Copyright 2016, Google Inc. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------ - -Mozilla Public License, v. 2.0 - -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can -obtain one at https://mozilla.org/MPL/2.0/. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-gson.txt b/tools/third-party-licenses/licenses/java/LICENSE-gson.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-gson.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-guava.txt b/tools/third-party-licenses/licenses/java/LICENSE-guava.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-guava.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-hamcrest-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-hamcrest-core.txt deleted file mode 100644 index 0bf62645cf..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-hamcrest-core.txt +++ /dev/null @@ -1,27 +0,0 @@ -BSD License - -Copyright (c) 2000-2015 www.hamcrest.org -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer in -the documentation and/or other materials provided with the distribution. - -Neither the name of Hamcrest nor the names of its contributors may be used to endorse -or promote products derived from this software without specific prior written -permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY -WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-httpasyncclient.txt b/tools/third-party-licenses/licenses/java/LICENSE-httpasyncclient.txt deleted file mode 100644 index 8dada3edaf..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-httpasyncclient.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-httpclient.txt b/tools/third-party-licenses/licenses/java/LICENSE-httpclient.txt deleted file mode 100644 index 437923f350..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-httpclient.txt +++ /dev/null @@ -1,558 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - -========================================================================= - -This project includes Public Suffix List copied from - -licensed under the terms of the Mozilla Public License, v. 2.0 - -Full license text: - -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-httpcore-nio.txt b/tools/third-party-licenses/licenses/java/LICENSE-httpcore-nio.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-httpcore-nio.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-httpcore.txt b/tools/third-party-licenses/licenses/java/LICENSE-httpcore.txt deleted file mode 100644 index 4947287f7b..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-httpcore.txt +++ /dev/null @@ -1,177 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-ipaddress.txt b/tools/third-party-licenses/licenses/java/LICENSE-ipaddress.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-ipaddress.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-j2objc-annotations.txt b/tools/third-party-licenses/licenses/java/LICENSE-j2objc-annotations.txt deleted file mode 100644 index 2b004c3eee..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-j2objc-annotations.txt +++ /dev/null @@ -1,232 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --------------------------------------------------------------------------------- -The next section, BSD-3-Clause, applies to the files in: -jre_emul/android/platform/libcore/ojluni/src/main/java/java/time --------------------------------------------------------------------------------- -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of JSR-310 nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jackson-annotations.txt b/tools/third-party-licenses/licenses/java/LICENSE-jackson-annotations.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jackson-annotations.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jackson-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-jackson-core.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jackson-core.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jackson-databind.txt b/tools/third-party-licenses/licenses/java/LICENSE-jackson-databind.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jackson-databind.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-javassist.txt b/tools/third-party-licenses/licenses/java/LICENSE-javassist.txt deleted file mode 100644 index a8d8dfd737..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-javassist.txt +++ /dev/null @@ -1,141 +0,0 @@ -MOZILLA PUBLIC LICENSE -Version 1.1 -1. Definitions. - -1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. -1.1. ''Contributor'' means each entity that creates or contributes to the creation of Modifications. - -1.2. ''Contributor Version'' means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. - -1.3. ''Covered Code'' means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. - -1.4. ''Electronic Distribution Mechanism'' means a mechanism generally accepted in the software development community for the electronic transfer of data. - -1.5. ''Executable'' means Covered Code in any form other than Source Code. - -1.6. ''Initial Developer'' means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. - -1.7. ''Larger Work'' means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. - -1.8. ''License'' means this document. - -1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. - -1.9. ''Modifications'' means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: - -A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. -B. Any new file that contains any part of the Original Code or previous Modifications. - - -1.10. ''Original Code'' means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. -1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. - -1.11. ''Source Code'' means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. - -1.12. "You'' (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You'' includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control'' means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. - -2. Source Code License. -2.1. The Initial Developer Grant. -The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: -(a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and -(b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). - -(c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. -(d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. - - -2.2. Contributor Grant. -Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license - -(a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and -(b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). - -(c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. - -(d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. - - -3. Distribution Obligations. - -3.1. Application of License. -The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. -3.2. Availability of Source Code. -Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. - -3.3. Description of Modifications. -You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. - -3.4. Intellectual Property Matters - -(a) Third Party Claims. -If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL'' which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. -(b) Contributor APIs. -If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. - - - (c) Representations. -Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. - -3.5. Required Notices. -You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. - -3.6. Distribution of Executable Versions. -You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. - -3.7. Larger Works. -You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. -If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. -5. Application of this License. -This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. -6. Versions of the License. -6.1. New Versions. -Netscape Communications Corporation (''Netscape'') may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. -6.2. Effect of New Versions. -Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. - -6.3. Derivative Works. -If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases ''Mozilla'', ''MOZILLAPL'', ''MOZPL'', ''Netscape'', "MPL", ''NPL'' or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) - -7. DISCLAIMER OF WARRANTY. -COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS'' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. -8. TERMINATION. -8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. -8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: - -(a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. - -(b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. - -8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. - -8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. -UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. -10. U.S. GOVERNMENT END USERS. -The Covered Code is a ''commercial item,'' as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of ''commercial computer software'' and ''commercial computer software documentation,'' as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. -11. MISCELLANEOUS. -This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. -12. RESPONSIBILITY FOR CLAIMS. -As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. -13. MULTIPLE-LICENSED CODE. -Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the MPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - -The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ -Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -ANY KIND, either express or implied. See the License for the specific language governing rights and -limitations under the License. - -The Original Code is Javassist. - -The Initial Developer of the Original Code is Shigeru Chiba. Portions created by the Initial Developer are - Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. - -Contributor(s): __Bill Burke, Jason T. Greene______________. - -Alternatively, the contents of this software may be used under the terms of the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), or the Apache License Version 2.0 (the "AL"), in which case the provisions of the LGPL or the AL are applicable instead of those above. If you wish to allow use of your version of this software only under the terms of either the LGPL or the AL, and not to allow others to use your version of this software under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL or the AL. If you do not delete the provisions above, a recipient may use your version of this software under the terms of any one of the MPL, the LGPL or the AL. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-javax.annotation-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-javax.annotation-api.txt deleted file mode 100644 index 68076ad96b..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-javax.annotation-api.txt +++ /dev/null @@ -1,759 +0,0 @@ -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1 - -1. Definitions. - - 1.1. "Contributor" means each individual or entity that creates or - contributes to the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Software, prior Modifications used by a Contributor (if any), and - the Modifications made by that particular Contributor. - - 1.3. "Covered Software" means (a) the Original Software, or (b) - Modifications, or (c) the combination of files containing Original - Software with files containing Modifications, in each case including - portions thereof. - - 1.4. "Executable" means the Covered Software in any form other than - Source Code. - - 1.5. "Initial Developer" means the individual or entity that first - makes Original Software available under this License. - - 1.6. "Larger Work" means a work which combines Covered Software or - portions thereof with code not governed by the terms of this License. - - 1.7. "License" means this document. - - 1.8. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means the Source Code and Executable form of - any of the following: - - A. Any file that results from an addition to, deletion from or - modification of the contents of a file containing Original Software - or previous Modifications; - - B. Any new file that contains any part of the Original Software or - previous Modification; or - - C. Any new file that is contributed or otherwise made available - under the terms of this License. - - 1.10. "Original Software" means the Source Code and Executable form - of computer software code that is originally released under this - License. - - 1.11. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.12. "Source Code" means (a) the common form of computer software - code in which modifications are made and (b) associated - documentation included in or with such code. - - 1.13. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, - this License. For legal entities, "You" includes any entity which - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants. - - 2.1. The Initial Developer Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, the Initial Developer - hereby grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer, to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Software (or portions thereof), with or without Modifications, - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using or selling of - Original Software, to make, have made, use, practice, sell, and - offer for sale, and/or otherwise dispose of the Original Software - (or portions thereof). - - (c) The licenses granted in Sections 2.1(a) and (b) are effective on - the date Initial Developer first distributes or otherwise makes the - Original Software available to a third party under the terms of this - License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: (1) for code that You delete from the Original Software, or - (2) for infringements caused by: (i) the modification of the - Original Software, or (ii) the combination of the Original Software - with other software or devices. - - 2.2. Contributor Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, each Contributor hereby - grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof), either on an - unmodified basis, with other Modifications, as Covered Software - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or selling - of Modifications made by that Contributor either alone and/or in - combination with its Contributor Version (or portions of such - combination), to make, use, sell, offer for sale, have made, and/or - otherwise dispose of: (1) Modifications made by that Contributor (or - portions thereof); and (2) the combination of Modifications made by - that Contributor with its Contributor Version (or portions of such - combination). - - (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective - on the date Contributor first distributes or otherwise makes the - Modifications available to a third party. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: (1) for any code that Contributor has deleted from the - Contributor Version; (2) for infringements caused by: (i) third - party modifications of Contributor Version, or (ii) the combination - of Modifications made by that Contributor with other software - (except as part of the Contributor Version) or other devices; or (3) - under Patent Claims infringed by Covered Software in the absence of - Modifications made by that Contributor. - -3. Distribution Obligations. - - 3.1. Availability of Source Code. - - Any Covered Software that You distribute or otherwise make available - in Executable form must also be made available in Source Code form - and that Source Code form must be distributed only under the terms - of this License. You must include a copy of this License with every - copy of the Source Code form of the Covered Software You distribute - or otherwise make available. You must inform recipients of any such - Covered Software in Executable form as to how they can obtain such - Covered Software in Source Code form in a reasonable manner on or - through a medium customarily used for software exchange. - - 3.2. Modifications. - - The Modifications that You create or to which You contribute are - governed by the terms of this License. You represent that You - believe Your Modifications are Your original creation(s) and/or You - have sufficient rights to grant the rights conveyed by this License. - - 3.3. Required Notices. - - You must include a notice in each of Your Modifications that - identifies You as the Contributor of the Modification. You may not - remove or alter any copyright, patent or trademark notices contained - within the Covered Software, or any notices of licensing or any - descriptive text giving attribution to any Contributor or the - Initial Developer. - - 3.4. Application of Additional Terms. - - You may not offer or impose any terms on any Covered Software in - Source Code form that alters or restricts the applicable version of - this License or the recipients' rights hereunder. You may choose to - offer, and to charge a fee for, warranty, support, indemnity or - liability obligations to one or more recipients of Covered Software. - However, you may do so only on Your own behalf, and not on behalf of - the Initial Developer or any Contributor. You must make it - absolutely clear that any such warranty, support, indemnity or - liability obligation is offered by You alone, and You hereby agree - to indemnify the Initial Developer and every Contributor for any - liability incurred by the Initial Developer or such Contributor as a - result of warranty, support, indemnity or liability terms You offer. - - 3.5. Distribution of Executable Versions. - - You may distribute the Executable form of the Covered Software under - the terms of this License or under the terms of a license of Your - choice, which may contain terms different from this License, - provided that You are in compliance with the terms of this License - and that the license for the Executable form does not attempt to - limit or alter the recipient's rights in the Source Code form from - the rights set forth in this License. If You distribute the Covered - Software in Executable form under a different license, You must make - it absolutely clear that any terms which differ from this License - are offered by You alone, not by the Initial Developer or - Contributor. You hereby agree to indemnify the Initial Developer and - every Contributor for any liability incurred by the Initial - Developer or such Contributor as a result of any such terms You offer. - - 3.6. Larger Works. - - You may create a Larger Work by combining Covered Software with - other code not governed by the terms of this License and distribute - the Larger Work as a single product. In such a case, You must make - sure the requirements of this License are fulfilled for the Covered - Software. - -4. Versions of the License. - - 4.1. New Versions. - - Oracle is the initial license steward and may publish revised and/or - new versions of this License from time to time. Each version will be - given a distinguishing version number. Except as provided in Section - 4.3, no one other than the license steward has the right to modify - this License. - - 4.2. Effect of New Versions. - - You may always continue to use, distribute or otherwise make the - Covered Software available under the terms of the version of the - License under which You originally received the Covered Software. If - the Initial Developer includes a notice in the Original Software - prohibiting it from being distributed or otherwise made available - under any subsequent version of the License, You must distribute and - make the Covered Software available under the terms of the version - of the License under which You originally received the Covered - Software. Otherwise, You may also choose to use, distribute or - otherwise make the Covered Software available under the terms of any - subsequent version of the License published by the license steward. - - 4.3. Modified Versions. - - When You are an Initial Developer and You want to create a new - license for Your Original Software, You may create and use a - modified version of this License if You: (a) rename the license and - remove any references to the name of the license steward (except to - note that the license differs from this License); and (b) otherwise - make it clear that the license contains terms which differ from this - License. - -5. DISCLAIMER OF WARRANTY. - - COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE - IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR - NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF - THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE - DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY - OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, - REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN - ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS - AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -6. TERMINATION. - - 6.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to - cure such breach within 30 days of becoming aware of the breach. - Provisions which, by their nature, must remain in effect beyond the - termination of this License shall survive. - - 6.2. If You assert a patent infringement claim (excluding - declaratory judgment actions) against Initial Developer or a - Contributor (the Initial Developer or Contributor against whom You - assert such claim is referred to as "Participant") alleging that the - Participant Software (meaning the Contributor Version where the - Participant is a Contributor or the Original Software where the - Participant is the Initial Developer) directly or indirectly - infringes any patent, then any and all rights granted directly or - indirectly to You by such Participant, the Initial Developer (if the - Initial Developer is not the Participant) and all Contributors under - Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice - from Participant terminate prospectively and automatically at the - expiration of such 60 day notice period, unless if within such 60 - day period You withdraw Your claim with respect to the Participant - Software against such Participant either unilaterally or pursuant to - a written agreement with Participant. - - 6.3. If You assert a patent infringement claim against Participant - alleging that the Participant Software directly or indirectly - infringes any patent where such claim is resolved (such as by - license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 6.4. In the event of termination under Sections 6.1 or 6.2 above, - all end user licenses that have been validly granted by You or any - distributor hereunder prior to termination (excluding licenses - granted to You by any distributor) shall survive termination. - -7. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE - INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF - COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE - TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT - LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER - FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR - LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE - POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT - APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH - PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH - LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR - LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION - AND LIMITATION MAY NOT APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. - - The Covered Software is a "commercial item," as that term is defined - in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" (as that term is defined at 48 C.F.R. § - 252.227-7014(a)(1)) and "commercial computer software documentation" - as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent - with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 - (June 1995), all U.S. Government End Users acquire Covered Software - with only those rights set forth herein. This U.S. Government Rights - clause is in lieu of, and supersedes, any other FAR, DFAR, or other - clause or provision that addresses Government rights in computer - software under this License. - -9. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - the law of the jurisdiction specified in a notice contained within - the Original Software (except to the extent applicable law, if any, - provides otherwise), excluding such jurisdiction's conflict-of-law - provisions. Any litigation relating to this License shall be subject - to the jurisdiction of the courts located in the jurisdiction and - venue specified in a notice contained within the Original Software, - with the losing party responsible for costs, including, without - limitation, court costs and reasonable attorneys' fees and expenses. - The application of the United Nations Convention on Contracts for - the International Sale of Goods is expressly excluded. Any law or - regulation which provides that the language of a contract shall be - construed against the drafter shall not apply to this License. You - agree that You alone are responsible for compliance with the United - States export administration regulations (and the export control - laws and regulation of any other countries) when You use, distribute - or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - ------------------------------------------------------------------------- - -NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION -LICENSE (CDDL) - -The code released under the CDDL shall be governed by the laws of the -State of California (excluding conflict-of-law provisions). Any -litigation relating to this License shall be subject to the jurisdiction -of the Federal Courts of the Northern District of California and the -state courts of the State of California, with venue lying in Santa Clara -County, California. - - - - The GNU General Public License (GPL) Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor -Boston, MA 02110-1335 -USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is -intended to guarantee your freedom to share and change free software--to -make sure the software is free for all its users. This General Public -License applies to most of the Free Software Foundation's software and -to any other program whose authors commit to using it. (Some other Free -Software Foundation software is covered by the GNU Library General -Public License instead.) You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. -Our General Public Licenses are designed to make sure that you have the -freedom to distribute copies of free software (and charge for this -service if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone -to deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis -or for a fee, you must give the recipients all the rights that you have. -You must make sure that they, too, receive or can get the source code. -And you must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - -Finally, any free program is threatened constantly by software patents. -We wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must -be licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and -modification follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a -notice placed by the copyright holder saying it may be distributed under -the terms of this General Public License. The "Program", below, refers -to any such program or work, and a "work based on the Program" means -either the Program or any derivative work under copyright law: that is -to say, a work containing the Program or a portion of it, either -verbatim or with modifications and/or translated into another language. -(Hereinafter, translation is included without limitation in the term -"modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of running -the Program is not restricted, and the output from the Program is -covered only if its contents constitute a work based on the Program -(independent of having been made by running the Program). Whether that -is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously -and appropriately publish on each copy an appropriate copyright notice -and disclaimer of warranty; keep intact all the notices that refer to -this License and to the absence of any warranty; and give any other -recipients of the Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of -it, thus forming a work based on the Program, and copy and distribute -such modifications or work under the terms of Section 1 above, provided -that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this License. - (Exception: if the Program itself is interactive but does not - normally print such an announcement, your work based on the Program - is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, and -can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based on -the Program, the distribution of the whole must be on the terms of this -License, whose permissions for other licensees extend to the entire -whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of a -storage or distribution medium does not bring the other work under the -scope of this License. - -3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your cost - of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source code -means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to control -compilation and installation of the executable. However, as a special -exception, the source code distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies the -executable. - -If distribution of executable or object code is made by offering access -to copy from a designated place, then offering equivalent access to copy -the source code from the same place counts as distribution of the source -code, even though third parties are not compelled to copy the source -along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt otherwise -to copy, modify, sublicense or distribute the Program is void, and will -automatically terminate your rights under this License. However, parties -who have received copies, or rights, from you under this License will -not have their licenses terminated so long as such parties remain in -full compliance. - -5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and all -its terms and conditions for copying, distributing or modifying the -Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further restrictions -on the recipients' exercise of the rights granted herein. You are not -responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot distribute -so as to satisfy simultaneously your obligations under this License and -any other pertinent obligations, then as a consequence you may not -distribute the Program at all. For example, if a patent license would -not permit royalty-free redistribution of the Program by all those who -receive copies directly or indirectly through you, then the only way you -could satisfy both it and this License would be to refrain entirely from -distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is implemented -by public license practices. Many people have made generous -contributions to the wide range of software distributed through that -system in reliance on consistent application of that system; it is up to -the author/donor to decide if he or she is willing to distribute -software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be -a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License may -add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among countries -not thus excluded. In such case, this License incorporates the -limitation as if written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new -versions of the General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Program does not specify a version -number of this License, you may choose any version ever published by the -Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the -author to ask for permission. For software which is copyrighted by the -Free Software Foundation, write to the Free Software Foundation; we -sometimes make exceptions for this. Our decision will be guided by the -two goals of preserving the free status of all derivatives of our free -software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH -YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR -DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL -DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF -THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR -OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type - `show w'. This is free software, and you are welcome to redistribute - it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the commands -you use may be called something other than `show w' and `show c'; they -could even be mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (which makes passes at compilers) written by - James Hacker. - - signature of Ty Coon, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications -with the library. If this is what you want to do, use the GNU Library -General Public License instead of this License. - -# - -Certain source files distributed by Oracle America, Inc. and/or its -affiliates are subject to the following clarification and special -exception to the GPLv2, based on the GNU Project exception for its -Classpath libraries, known as the GNU Classpath Exception, but only -where Oracle has expressly included in the particular source file's -header the words "Oracle designates this particular file as subject to -the "Classpath" exception as provided by Oracle in the LICENSE file -that accompanied this code." - -You should also note that Oracle includes multiple, independent -programs in this software package. Some of those programs are provided -under licenses deemed incompatible with the GPLv2 by the Free Software -Foundation and others. For example, the package includes programs -licensed under the Apache License, Version 2.0. Such programs are -licensed to you under their original licenses. - -Oracle facilitates your further distribution of this package by adding -the Classpath Exception to the necessary parts of its GPLv2 code, which -permits you to use that code in combination with other independent -modules not licensed under the GPLv2. However, note that this would -not permit you to commingle code under an incompatible license with -Oracle's GPLv2 licensed code by, for example, cutting and pasting such -code into a file also containing Oracle's GPLv2 licensed code and then -distributing the result. Additionally, if you were to remove the -Classpath Exception from any of the files to which it applies and -distribute the result, you would likely be required to license some or -all of the other code in that distribution under the GPLv2 as well, and -since the GPLv2 is incompatible with the license terms of some items -included in the distribution by Oracle, removing the Classpath -Exception could therefore effectively compromise your ability to -further distribute the package. - -Proceed with caution and we recommend that you obtain the advice of a -lawyer skilled in open source matters before removing the Classpath -Exception or making modifications to this package which may -subsequently be redistributed and/or involve the use of third party -software. - -CLASSPATH EXCEPTION -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License version 2 cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from or -based on this library. If you modify this library, you may extend this -exception to your version of the library, but you are not obligated to -do so. If you do not wish to do so, delete this exception statement -from your version. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jcommander.txt b/tools/third-party-licenses/licenses/java/LICENSE-jcommander.txt deleted file mode 100644 index 477eb7b7ba..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jcommander.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2012, Cedric Beust - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jetcd-common.txt b/tools/third-party-licenses/licenses/java/LICENSE-jetcd-common.txt deleted file mode 100644 index 477eb7b7ba..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jetcd-common.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2012, Cedric Beust - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jetcd-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-jetcd-core.txt deleted file mode 100644 index 477eb7b7ba..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jetcd-core.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2012, Cedric Beust - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jetcd-resolver.txt b/tools/third-party-licenses/licenses/java/LICENSE-jetcd-resolver.txt deleted file mode 100644 index 477eb7b7ba..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jetcd-resolver.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2012, Cedric Beust - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jna.txt b/tools/third-party-licenses/licenses/java/LICENSE-jna.txt deleted file mode 100644 index b456098518..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jna.txt +++ /dev/null @@ -1,26 +0,0 @@ -SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1 - -Java Native Access (JNA) is licensed under the LGPL, version 2.1 -or later, or (from version 4.0 onward) the Apache License, -version 2.0. - -You can freely decide which license you want to apply to the project. - -You may obtain a copy of the LGPL License at: - -http://www.gnu.org/licenses/licenses.html - -A copy is also included in the downloadable source code package -containing JNA, in file "LGPL2.1", under the same directory -as this file. - -You may obtain a copy of the Apache License at: - -http://www.apache.org/licenses/ - -A copy is also included in the downloadable source code package -containing JNA, in file "AL2.0", under the same directory -as this file. - -Commercial support may be available, please e-mail -twall[at]users[dot]sf[dot]net. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-jsr305.txt b/tools/third-party-licenses/licenses/java/LICENSE-jsr305.txt deleted file mode 100644 index 7fb51fb895..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-jsr305.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2007-2009, JSR305 expert group -All rights reserved. - -https://opensource.org/licenses/BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the JSR305 expert group nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-junit.txt b/tools/third-party-licenses/licenses/java/LICENSE-junit.txt deleted file mode 100644 index 7b5e981e7c..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-junit.txt +++ /dev/null @@ -1,213 +0,0 @@ -JUnit - -Eclipse Public License - v 1.0 - -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC -LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM -CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate from and are -distributed by that particular Contributor. A Contribution 'originates' from a -Contributor if it was added to the Program by such Contributor itself or anyone -acting on such Contributor's behalf. Contributions do not include additions to -the Program which: (i) are separate modules of software distributed in -conjunction with the Program under their own license agreement, and (ii) are -not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents " mean patent claims licensable by a Contributor which are -necessarily infringed by the use or sale of its Contribution alone or when -combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, -including all Contributors. - -2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free copyright license to -reproduce, prepare derivative works of, publicly display, publicly perform, -distribute and sublicense the Contribution of such Contributor, if any, and -such derivative works, in source code and object code form. - - b) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free patent license under -Licensed Patents to make, use, sell, offer to sell, import and otherwise -transfer the Contribution of such Contributor, if any, in source code and -object code form. This patent license shall apply to the combination of the -Contribution and the Program if, at the time the Contribution is added by the -Contributor, such addition of the Contribution causes such combination to be -covered by the Licensed Patents. The patent license shall not apply to any -other combinations which include the Contribution. No hardware per se is -licensed hereunder. - - c) Recipient understands that although each Contributor grants the -licenses to its Contributions set forth herein, no assurances are provided by -any Contributor that the Program does not infringe the patent or other -intellectual property rights of any other entity. Each Contributor disclaims -any liability to Recipient for claims brought by any other entity based on -infringement of intellectual property rights or otherwise. As a condition to -exercising the rights and licenses granted hereunder, each Recipient hereby -assumes sole responsibility to secure any other intellectual property rights -needed, if any. For example, if a third party patent license is required to -allow Recipient to distribute the Program, it is Recipient's responsibility to -acquire that license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has sufficient -copyright rights in its Contribution, if any, to grant the copyright license -set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under -its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all liability for -damages, including direct, indirect, special, incidental and consequential -damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement are -offered by that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from such -Contributor, and informs licensees how to obtain it in a reasonable manner on -or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of the -Program. - -Contributors may not remove or alter any copyright notices contained within the -Program. - -Each Contributor must identify itself as the originator of its Contribution, if -any, in a manner that reasonably allows subsequent Recipients to identify the -originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with -respect to end users, business partners and the like. While this license is -intended to facilitate the commercial use of the Program, the Contributor who -includes the Program in a commercial product offering should do so in a manner -which does not create potential liability for other Contributors. Therefore, if -a Contributor includes the Program in a commercial product offering, such -Contributor ("Commercial Contributor") hereby agrees to defend and indemnify -every other Contributor ("Indemnified Contributor") against any losses, damages -and costs (collectively "Losses") arising from claims, lawsuits and other legal -actions brought by a third party against the Indemnified Contributor to the -extent caused by the acts or omissions of such Commercial Contributor in -connection with its distribution of the Program in a commercial product -offering. The obligations in this section do not apply to any claims or Losses -relating to any actual or alleged intellectual property infringement. In order -to qualify, an Indemnified Contributor must: a) promptly notify the Commercial -Contributor in writing of such claim, and b) allow the Commercial Contributor -to control, and cooperate with the Commercial Contributor in, the defense and -any related settlement negotiations. The Indemnified Contributor may -participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product -offering, Product X. That Contributor is then a Commercial Contributor. If that -Commercial Contributor then makes performance claims, or offers warranties -related to Product X, those performance claims and warranties are such -Commercial Contributor's responsibility alone. Under this section, the -Commercial Contributor would have to defend claims against the other -Contributors related to those performance claims and warranties, and if a court -requires any other Contributor to pay any damages as a result, the Commercial -Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR -IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, -NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each -Recipient is solely responsible for determining the appropriateness of using -and distributing the Program and assumes all risks associated with its exercise -of rights under this Agreement, including but not limited to the risks and -costs of program errors, compliance with applicable laws, damage to or loss of -data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY -CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST -PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY -WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS -GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable -law, it shall not affect the validity or enforceability of the remainder of the -terms of this Agreement, and without further action by the parties hereto, such -provision shall be reformed to the minimum extent necessary to make such -provision valid and enforceable. - -If Recipient institutes patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging that the -Program itself (excluding combinations of the Program with other software or -hardware) infringes such Recipient's patent(s), then such Recipient's rights -granted under Section 2(b) shall terminate as of the date such litigation is -filed. - -All Recipient's rights under this Agreement shall terminate if it fails to -comply with any of the material terms or conditions of this Agreement and does -not cure such failure in a reasonable period of time after becoming aware of -such noncompliance. If all Recipient's rights under this Agreement terminate, -Recipient agrees to cease use and distribution of the Program as soon as -reasonably practicable. However, Recipient's obligations under this Agreement -and any licenses granted by Recipient relating to the Program shall continue -and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in -order to avoid inconsistency the Agreement is copyrighted and may only be -modified in the following manner. The Agreement Steward reserves the right to -publish new versions (including revisions) of this Agreement from time to time. -No one other than the Agreement Steward has the right to modify this Agreement. -The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to -serve as the Agreement Steward to a suitable separate entity. Each new version -of the Agreement will be given a distinguishing version number. The Program -(including Contributions) may always be distributed subject to the version of -the Agreement under which it was received. In addition, after a new version of -the Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly stated -in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to -the intellectual property of any Contributor under this Agreement, whether -expressly, by implication, estoppel or otherwise. All rights in the Program not -expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the -intellectual property laws of the United States of America. No party to this -Agreement will bring a legal action under this Agreement more than one year -after the cause of action arose. Each party waives its rights to a jury trial -in any resulting litigation. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-listenablefuture.txt b/tools/third-party-licenses/licenses/java/LICENSE-listenablefuture.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-listenablefuture.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-log4j-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-log4j-api.txt deleted file mode 100644 index 98a324cf06..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-log4j-api.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 1999-2005 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-log4j-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-log4j-core.txt deleted file mode 100644 index 98a324cf06..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-log4j-core.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 1999-2005 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-log4j-slf4j-impl.txt b/tools/third-party-licenses/licenses/java/LICENSE-log4j-slf4j-impl.txt deleted file mode 100644 index 98a324cf06..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-log4j-slf4j-impl.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 1999-2005 The Apache Software Foundation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-logback-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-logback-core.txt deleted file mode 100644 index 8953762a3c..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-logback-core.txt +++ /dev/null @@ -1,14 +0,0 @@ -Logback LICENSE ---------------- - -Logback: the reliable, generic, fast and flexible logging framework. -Copyright (C) 1999-2015, QOS.ch. All rights reserved. - -This program and the accompanying materials are dual-licensed under -either the terms of the Eclipse Public License v1.0 as published by -the Eclipse Foundation - - or (per the licensee's choosing) - -under the terms of the GNU Lesser General Public License version 2.1 -as published by the Free Software Foundation. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-metrics-annotation.txt b/tools/third-party-licenses/licenses/java/LICENSE-metrics-annotation.txt deleted file mode 100644 index 52823540de..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-metrics-annotation.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2020 Dropwizard Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-metrics-core.txt b/tools/third-party-licenses/licenses/java/LICENSE-metrics-core.txt deleted file mode 100644 index 52823540de..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-metrics-core.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2020 Dropwizard Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-metrics-healthchecks.txt b/tools/third-party-licenses/licenses/java/LICENSE-metrics-healthchecks.txt deleted file mode 100644 index 52823540de..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-metrics-healthchecks.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2020 Dropwizard Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-metrics-json.txt b/tools/third-party-licenses/licenses/java/LICENSE-metrics-json.txt deleted file mode 100644 index 52823540de..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-metrics-json.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2010-2013 Coda Hale and Yammer, Inc., 2014-2020 Dropwizard Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-nacos-client.txt b/tools/third-party-licenses/licenses/java/LICENSE-nacos-client.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-nacos-client.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-all.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-all.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-all.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-buffer.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-buffer.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-buffer.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-dns.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-dns.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-dns.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-haproxy.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-haproxy.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-haproxy.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-http.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-http.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-http.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-http2.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-http2.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-http2.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-memcache.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-memcache.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-memcache.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-mqtt.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-mqtt.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-mqtt.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-redis.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-redis.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-redis.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-smtp.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-smtp.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-smtp.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-socks.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-socks.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-socks.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-stomp.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-stomp.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-stomp.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-xml.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-xml.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec-xml.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-codec.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-codec.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-common.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-common.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-common.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-handler-proxy.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-handler-proxy.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-handler-proxy.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-handler.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-handler.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-handler.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns-classes-macos.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns-classes-macos.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns-classes-macos.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns-native-macos.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns-native-macos.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns-native-macos.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver-dns.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-resolver.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-tcnative-boringssl-static.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-tcnative-boringssl-static.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-tcnative-boringssl-static.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-tcnative-classes.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-tcnative-classes.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-tcnative-classes.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-classes-epoll.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-classes-epoll.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-classes-epoll.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-classes-kqueue.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-classes-kqueue.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-classes-kqueue.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-epoll.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-epoll.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-epoll.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-kqueue.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-kqueue.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-kqueue.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-unix-common.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-unix-common.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-native-unix-common.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-rxtx.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-rxtx.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-rxtx.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-sctp.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-sctp.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-sctp.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-udt.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-udt.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport-udt.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport.txt b/tools/third-party-licenses/licenses/java/LICENSE-netty-transport.txt deleted file mode 100644 index e25e752cf1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-netty-transport.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-okhttp.txt b/tools/third-party-licenses/licenses/java/LICENSE-okhttp.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-okhttp.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-okio.txt b/tools/third-party-licenses/licenses/java/LICENSE-okio.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-okio.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opencensus-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-opencensus-api.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opencensus-api.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opencensus-contrib-grpc-metrics.txt b/tools/third-party-licenses/licenses/java/LICENSE-opencensus-contrib-grpc-metrics.txt deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opencensus-contrib-grpc-metrics.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-openmessaging-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-openmessaging-api.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-openmessaging-api.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-api-metrics.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-api-metrics.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-api-metrics.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-api.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-api.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-context.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-context.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-context.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-exporter-prometheus.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-exporter-prometheus.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-exporter-prometheus.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-exporter-zipkin.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-exporter-zipkin.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-exporter-zipkin.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-common.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-common.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-common.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-metrics.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-metrics.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-metrics.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-trace.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-trace.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk-trace.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-sdk.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-semconv.txt b/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-semconv.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-opentelemetry-semconv.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-proto-google-common-protos.txt b/tools/third-party-licenses/licenses/java/LICENSE-proto-google-common-protos.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-proto-google-common-protos.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-protobuf-java-util.txt b/tools/third-party-licenses/licenses/java/LICENSE-protobuf-java-util.txt deleted file mode 100644 index c80f6413d1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-protobuf-java-util.txt +++ /dev/null @@ -1,48 +0,0 @@ -The 3-Clause BSD License -SPDX short identifier: BSD-3-Clause - -Further resources on the 3-clause BSD license -Note: This license has also been called the "New BSD License" or "Modified BSD License". See also the 2-clause BSD License. - -This license applies to all parts of Protocol Buffers except the following: - - - Atomicops support for generic gcc, located in - src/google/protobuf/stubs/atomicops_internals_generic_gcc.h. - This file is copyrighted by Red Hat Inc. - - - Atomicops support for AIX/POWER, located in - src/google/protobuf/stubs/atomicops_internals_power.h. - This file is copyrighted by Bloomberg Finance LP. - -Copyright 2014, Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Code generated by the Protocol Buffer compiler is owned by the owner -of the input file used when generating it. This code is not -standalone and requires a support library to be linked with it. This -support library is itself covered by the above license. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-protobuf-java.txt b/tools/third-party-licenses/licenses/java/LICENSE-protobuf-java.txt deleted file mode 100644 index c80f6413d1..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-protobuf-java.txt +++ /dev/null @@ -1,48 +0,0 @@ -The 3-Clause BSD License -SPDX short identifier: BSD-3-Clause - -Further resources on the 3-clause BSD license -Note: This license has also been called the "New BSD License" or "Modified BSD License". See also the 2-clause BSD License. - -This license applies to all parts of Protocol Buffers except the following: - - - Atomicops support for generic gcc, located in - src/google/protobuf/stubs/atomicops_internals_generic_gcc.h. - This file is copyrighted by Red Hat Inc. - - - Atomicops support for AIX/POWER, located in - src/google/protobuf/stubs/atomicops_internals_power.h. - This file is copyrighted by Bloomberg Finance LP. - -Copyright 2014, Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Code generated by the Protocol Buffer compiler is owned by the owner -of the input file used when generating it. This code is not -standalone and requires a support library to be linked with it. This -support library is itself covered by the above license. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-reflections.txt b/tools/third-party-licenses/licenses/java/LICENSE-reflections.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-reflections.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-acl.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-acl.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-acl.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-broker.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-broker.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-broker.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-client.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-client.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-client.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-common.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-common.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-common.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-filter.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-filter.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-filter.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-logging.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-logging.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-logging.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-namesrv.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-namesrv.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-namesrv.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-remoting.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-remoting.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-remoting.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-srvutil.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-srvutil.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-srvutil.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-store.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-store.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-store.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-test.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-test.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-test.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-tools.txt b/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-tools.txt deleted file mode 100644 index f49a4e16e6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-rocketmq-tools.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-simpleclient.txt b/tools/third-party-licenses/licenses/java/LICENSE-simpleclient.txt deleted file mode 100644 index 835428fbaa..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-simpleclient.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-simpleclient_common.txt b/tools/third-party-licenses/licenses/java/LICENSE-simpleclient_common.txt deleted file mode 100644 index 835428fbaa..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-simpleclient_common.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-simpleclient_httpserver.txt b/tools/third-party-licenses/licenses/java/LICENSE-simpleclient_httpserver.txt deleted file mode 100644 index 835428fbaa..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-simpleclient_httpserver.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-slf4j-api.txt b/tools/third-party-licenses/licenses/java/LICENSE-slf4j-api.txt deleted file mode 100644 index 744377c437..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-slf4j-api.txt +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2004-2017 QOS.ch -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-snakeyaml.txt b/tools/third-party-licenses/licenses/java/LICENSE-snakeyaml.txt deleted file mode 100644 index 1a7891acd6..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-snakeyaml.txt +++ /dev/null @@ -1,203 +0,0 @@ - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-Present The CloudEvents Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-system-rules.txt b/tools/third-party-licenses/licenses/java/LICENSE-system-rules.txt deleted file mode 100644 index 3a4c72849d..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-system-rules.txt +++ /dev/null @@ -1,213 +0,0 @@ -Common Public License Version 1.0 - -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC -LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM -CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and -documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are -distributed by that particular Contributor. A Contribution 'originates' from a -Contributor if it was added to the Program by such Contributor itself or anyone -acting on such Contributor's behalf. Contributions do not include additions to -the Program which: (i) are separate modules of software distributed in -conjunction with the Program under their own license agreement, and (ii) are not -derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents " mean patent claims licensable by a Contributor which are -necessarily infringed by the use or sale of its Contribution alone or when -combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, -including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free copyright license to -reproduce, prepare derivative works of, publicly display, publicly perform, -distribute and sublicense the Contribution of such Contributor, if any, and such -derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed -Patents to make, use, sell, offer to sell, import and otherwise transfer the -Contribution of such Contributor, if any, in source code and object code form. -This patent license shall apply to the combination of the Contribution and the -Program if, at the time the Contribution is added by the Contributor, such -addition of the Contribution causes such combination to be covered by the -Licensed Patents. The patent license shall not apply to any other combinations -which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses -to its Contributions set forth herein, no assurances are provided by any -Contributor that the Program does not infringe the patent or other intellectual -property rights of any other entity. Each Contributor disclaims any liability to -Recipient for claims brought by any other entity based on infringement of -intellectual property rights or otherwise. As a condition to exercising the -rights and licenses granted hereunder, each Recipient hereby assumes sole -responsibility to secure any other intellectual property rights needed, if any. -For example, if a third party patent license is required to allow Recipient to -distribute the Program, it is Recipient's responsibility to acquire that license -before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient -copyright rights in its Contribution, if any, to grant the copyright license set -forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its -own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title and -non-infringement, and implied warranties or conditions of merchantability and -fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for -damages, including direct, indirect, special, incidental and consequential -damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered -by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such -Contributor, and informs licensees how to obtain it in a reasonable manner on or -through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the -Program. - -Each Contributor must identify itself as the originator of its Contribution, if -any, in a manner that reasonably allows subsequent Recipients to identify the -originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with -respect to end users, business partners and the like. While this license is -intended to facilitate the commercial use of the Program, the Contributor who -includes the Program in a commercial product offering should do so in a manner -which does not create potential liability for other Contributors. Therefore, if -a Contributor includes the Program in a commercial product offering, such -Contributor ("Commercial Contributor") hereby agrees to defend and indemnify -every other Contributor ("Indemnified Contributor") against any losses, damages -and costs (collectively "Losses") arising from claims, lawsuits and other legal -actions brought by a third party against the Indemnified Contributor to the -extent caused by the acts or omissions of such Commercial Contributor in -connection with its distribution of the Program in a commercial product -offering. The obligations in this section do not apply to any claims or Losses -relating to any actual or alleged intellectual property infringement. In order -to qualify, an Indemnified Contributor must: a) promptly notify the Commercial -Contributor in writing of such claim, and b) allow the Commercial Contributor to -control, and cooperate with the Commercial Contributor in, the defense and any -related settlement negotiations. The Indemnified Contributor may participate in -any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product -offering, Product X. That Contributor is then a Commercial Contributor. If that -Commercial Contributor then makes performance claims, or offers warranties -related to Product X, those performance claims and warranties are such -Commercial Contributor's responsibility alone. Under this section, the -Commercial Contributor would have to defend claims against the other -Contributors related to those performance claims and warranties, and if a court -requires any other Contributor to pay any damages as a result, the Commercial -Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR -IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, -NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each -Recipient is solely responsible for determining the appropriateness of using and -distributing the Program and assumes all risks associated with its exercise of -rights under this Agreement, including but not limited to the risks and costs of -program errors, compliance with applicable laws, damage to or loss of data, -programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY -CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST -PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS -GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable -law, it shall not affect the validity or enforceability of the remainder of the -terms of this Agreement, and without further action by the parties hereto, such -provision shall be reformed to the minimum extent necessary to make such -provision valid and enforceable. - -If Recipient institutes patent litigation against a Contributor with respect to -a patent applicable to software (including a cross-claim or counterclaim in a -lawsuit), then any patent licenses granted by that Contributor to such Recipient -under this Agreement shall terminate as of the date such litigation is filed. In -addition, if Recipient institutes patent litigation against any entity -(including a cross-claim or counterclaim in a lawsuit) alleging that the Program -itself (excluding combinations of the Program with other software or hardware) -infringes such Recipient's patent(s), then such Recipient's rights granted under -Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to -comply with any of the material terms or conditions of this Agreement and does -not cure such failure in a reasonable period of time after becoming aware of -such noncompliance. If all Recipient's rights under this Agreement terminate, -Recipient agrees to cease use and distribution of the Program as soon as -reasonably practicable. However, Recipient's obligations under this Agreement -and any licenses granted by Recipient relating to the Program shall continue and -survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in -order to avoid inconsistency the Agreement is copyrighted and may only be -modified in the following manner. The Agreement Steward reserves the right to -publish new versions (including revisions) of this Agreement from time to time. -No one other than the Agreement Steward has the right to modify this Agreement. -IBM is the initial Agreement Steward. IBM may assign the responsibility to serve -as the Agreement Steward to a suitable separate entity. Each new version of the -Agreement will be given a distinguishing version number. The Program (including -Contributions) may always be distributed subject to the version of the Agreement -under which it was received. In addition, after a new version of the Agreement -is published, Contributor may elect to distribute the Program (including its -Contributions) under the new version. Except as expressly stated in Sections -2(a) and 2(b) above, Recipient receives no rights or licenses to the -intellectual property of any Contributor under this Agreement, whether -expressly, by implication, estoppel or otherwise. All rights in the Program not -expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the -intellectual property laws of the United States of America. No party to this -Agreement will bring a legal action under this Agreement more than one year -after the cause of action arose. Each party waives its rights to a jury trial in -any resulting litigation. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-truth.txt b/tools/third-party-licenses/licenses/java/LICENSE-truth.txt deleted file mode 100644 index d645695673..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-truth.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-zipkin-reporter.txt b/tools/third-party-licenses/licenses/java/LICENSE-zipkin-reporter.txt deleted file mode 100644 index 9c8f3ea087..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-zipkin-reporter.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/tools/third-party-licenses/licenses/java/LICENSE-zipkin-sender-okhttp3.txt b/tools/third-party-licenses/licenses/java/LICENSE-zipkin-sender-okhttp3.txt deleted file mode 100644 index 8dada3edaf..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-zipkin-sender-okhttp3.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/third-party-licenses/licenses/java/LICENSE-zipkin.txt b/tools/third-party-licenses/licenses/java/LICENSE-zipkin.txt deleted file mode 100644 index 0c1111bc79..0000000000 --- a/tools/third-party-licenses/licenses/java/LICENSE-zipkin.txt +++ /dev/null @@ -1,216 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -This product contains a modified part of Gson, distributed by Google: - - * License: Apache License v2.0 - * Homepage: https://github.com/google/gson - -This product contains a modified part of Guava, distributed by Google: - - * License: Apache License v2.0 - * Homepage: https://github.com/google/guava - -This product contains a modified part of Okio, distributed by Square: - - * License: Apache License v2.0 - * Homepage: https://github.com/square/okio